Merge branch 'develop' into patch-8
This commit is contained in:
commit
758f0f0780
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate, now_datetime
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
||||||
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
|
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
|
||||||
@ -13,27 +13,28 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
|
|||||||
|
|
||||||
class TestBudget(unittest.TestCase):
|
class TestBudget(unittest.TestCase):
|
||||||
def test_monthly_budget_crossed_ignore(self):
|
def test_monthly_budget_crossed_ignore(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||||
|
|
||||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||||
|
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
jv.cancel()
|
||||||
|
|
||||||
def test_monthly_budget_crossed_stop1(self):
|
def test_monthly_budget_crossed_stop1(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28")
|
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -41,14 +42,14 @@ class TestBudget(unittest.TestCase):
|
|||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_exception_approver_role(self):
|
def test_exception_approver_role(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-03-02")
|
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -112,16 +113,17 @@ class TestBudget(unittest.TestCase):
|
|||||||
|
|
||||||
budget.load_from_db()
|
budget.load_from_db()
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
po.cancel()
|
||||||
|
|
||||||
def test_monthly_budget_crossed_stop2(self):
|
def test_monthly_budget_crossed_stop2(self):
|
||||||
set_total_expense_zero("2013-02-28", "project")
|
set_total_expense_zero(nowdate(), "project")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-02-28")
|
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -129,86 +131,76 @@ class TestBudget(unittest.TestCase):
|
|||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_yearly_budget_crossed_stop1(self):
|
def test_yearly_budget_crossed_stop1(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", posting_date="2013-03-28")
|
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_yearly_budget_crossed_stop2(self):
|
def test_yearly_budget_crossed_stop2(self):
|
||||||
set_total_expense_zero("2013-02-28", "project")
|
set_total_expense_zero(nowdate(), "project")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-03-28")
|
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_monthly_budget_on_cancellation1(self):
|
def test_monthly_budget_on_cancellation1(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
|
||||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
for i in range(now_datetime().month):
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||||
|
|
||||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||||
|
|
||||||
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
|
||||||
|
|
||||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
|
||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv1.cancel)
|
self.assertRaises(BudgetError, jv.cancel)
|
||||||
|
|
||||||
budget.load_from_db()
|
budget.load_from_db()
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_monthly_budget_on_cancellation2(self):
|
def test_monthly_budget_on_cancellation2(self):
|
||||||
set_total_expense_zero("2013-02-28", "project")
|
set_total_expense_zero(nowdate(), "project")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
|
|
||||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
for i in range(now_datetime().month):
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
|
||||||
|
|
||||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||||
|
|
||||||
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
|
|
||||||
|
|
||||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
|
||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv1.cancel)
|
self.assertRaises(BudgetError, jv.cancel)
|
||||||
|
|
||||||
budget.load_from_db()
|
budget.load_from_db()
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
def test_monthly_budget_against_group_cost_center(self):
|
def test_monthly_budget_against_group_cost_center(self):
|
||||||
set_total_expense_zero("2013-02-28", "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
set_total_expense_zero("2013-02-28", "cost_center", "_Test Cost Center 2 - _TC")
|
set_total_expense_zero(nowdate(), "cost_center", "_Test Cost Center 2 - _TC")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
|
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date="2013-02-28")
|
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -231,7 +223,7 @@ class TestBudget(unittest.TestCase):
|
|||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, cost_center, posting_date="2013-02-28")
|
"_Test Bank - _TC", 40000, cost_center, posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -246,12 +238,14 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
|
|||||||
else:
|
else:
|
||||||
budget_against = budget_against_CC or "_Test Cost Center - _TC"
|
budget_against = budget_against_CC or "_Test Cost Center - _TC"
|
||||||
|
|
||||||
|
fiscal_year = get_fiscal_year(nowdate())[0]
|
||||||
|
|
||||||
args = frappe._dict({
|
args = frappe._dict({
|
||||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"monthly_end_date": posting_date,
|
"monthly_end_date": posting_date,
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"fiscal_year": "_Test Fiscal Year 2013",
|
"fiscal_year": fiscal_year,
|
||||||
"budget_against_field": budget_against_field,
|
"budget_against_field": budget_against_field,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -263,10 +257,10 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
|
|||||||
if existing_expense:
|
if existing_expense:
|
||||||
if budget_against_field == "cost_center":
|
if budget_against_field == "cost_center":
|
||||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||||
elif budget_against_field == "project":
|
elif budget_against_field == "project":
|
||||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date="2013-02-28")
|
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
|
||||||
|
|
||||||
def make_budget(**args):
|
def make_budget(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
@ -274,10 +268,13 @@ def make_budget(**args):
|
|||||||
budget_against=args.budget_against
|
budget_against=args.budget_against
|
||||||
cost_center=args.cost_center
|
cost_center=args.cost_center
|
||||||
|
|
||||||
|
fiscal_year = get_fiscal_year(nowdate())[0]
|
||||||
|
|
||||||
if budget_against == "Project":
|
if budget_against == "Project":
|
||||||
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
|
project_name = "{0}%".format("_Test Project/" + fiscal_year)
|
||||||
|
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", project_name)})
|
||||||
else:
|
else:
|
||||||
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/_Test Fiscal Year 2013")
|
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
|
||||||
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
|
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
|
||||||
for d in budget_list:
|
for d in budget_list:
|
||||||
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
|
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
|
||||||
@ -290,8 +287,10 @@ def make_budget(**args):
|
|||||||
else:
|
else:
|
||||||
budget.cost_center =cost_center or "_Test Cost Center - _TC"
|
budget.cost_center =cost_center or "_Test Cost Center - _TC"
|
||||||
|
|
||||||
|
monthly_distribution = frappe.get_doc("Monthly Distribution", "_Test Distribution")
|
||||||
|
monthly_distribution.fiscal_year = fiscal_year
|
||||||
|
|
||||||
budget.fiscal_year = "_Test Fiscal Year 2013"
|
budget.fiscal_year = fiscal_year
|
||||||
budget.monthly_distribution = "_Test Distribution"
|
budget.monthly_distribution = "_Test Distribution"
|
||||||
budget.company = "_Test Company"
|
budget.company = "_Test Company"
|
||||||
budget.applicable_on_booking_actual_expenses = 1
|
budget.applicable_on_booking_actual_expenses = 1
|
||||||
@ -300,7 +299,7 @@ def make_budget(**args):
|
|||||||
budget.budget_against = budget_against
|
budget.budget_against = budget_against
|
||||||
budget.append("accounts", {
|
budget.append("accounts", {
|
||||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||||
"budget_amount": 100000
|
"budget_amount": 200000
|
||||||
})
|
})
|
||||||
|
|
||||||
if args.applicable_on_material_request:
|
if args.applicable_on_material_request:
|
||||||
|
|||||||
@ -18,7 +18,7 @@ frappe.ui.form.on('Cost Center', {
|
|||||||
},
|
},
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
if (!frm.is_new()) {
|
if (!frm.is_new()) {
|
||||||
frm.add_custom_button(__('Update Cost Center Number'), function () {
|
frm.add_custom_button(__('Update Cost Center Name / Number'), function () {
|
||||||
frm.trigger("update_cost_center_number");
|
frm.trigger("update_cost_center_number");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -47,35 +47,45 @@ frappe.ui.form.on('Cost Center', {
|
|||||||
},
|
},
|
||||||
update_cost_center_number: function(frm) {
|
update_cost_center_number: function(frm) {
|
||||||
var d = new frappe.ui.Dialog({
|
var d = new frappe.ui.Dialog({
|
||||||
title: __('Update Cost Center Number'),
|
title: __('Update Cost Center Name / Number'),
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
"label": 'Cost Center Number',
|
"label": "Cost Center Name",
|
||||||
|
"fieldname": "cost_center_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"reqd": 1,
|
||||||
|
"default": frm.doc.cost_center_name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Cost Center Number",
|
||||||
"fieldname": "cost_center_number",
|
"fieldname": "cost_center_number",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"default": frm.doc.cost_center_number
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
var data = d.get_values();
|
var data = d.get_values();
|
||||||
if(data.cost_center_number === frm.doc.cost_center_number) {
|
if(data.cost_center_name === frm.doc.cost_center_name && data.cost_center_number === frm.doc.cost_center_number) {
|
||||||
d.hide();
|
d.hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
frappe.dom.freeze();
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.utils.update_number_field",
|
method: "erpnext.accounts.utils.update_cost_center",
|
||||||
args: {
|
args: {
|
||||||
doctype_name: frm.doc.doctype,
|
docname: frm.doc.name,
|
||||||
name: frm.doc.name,
|
cost_center_name: data.cost_center_name,
|
||||||
field_name: d.fields[0].fieldname,
|
cost_center_number: data.cost_center_number,
|
||||||
number_value: data.cost_center_number,
|
|
||||||
company: frm.doc.company
|
company: frm.doc.company
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
frappe.dom.unfreeze();
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
frappe.set_route("Form", "Cost Center", r.message);
|
frappe.set_route("Form", "Cost Center", r.message);
|
||||||
} else {
|
} else {
|
||||||
|
me.frm.set_value("cost_center_name", data.cost_center_name);
|
||||||
me.frm.set_value("cost_center_number", data.cost_center_number);
|
me.frm.set_value("cost_center_number", data.cost_center_number);
|
||||||
}
|
}
|
||||||
d.hide();
|
d.hide();
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
"actions": [],
|
"actions": [],
|
||||||
"allow_copy": 1,
|
"allow_copy": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
|
||||||
"creation": "2013-01-23 19:57:17",
|
"creation": "2013-01-23 19:57:17",
|
||||||
"description": "Track separate Income and Expense for product verticals or divisions.",
|
"description": "Track separate Income and Expense for product verticals or divisions.",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -126,7 +125,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-18 17:59:04.321637",
|
"modified": "2020-04-29 16:09:30.025214",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Cost Center",
|
"name": "Cost Center",
|
||||||
|
|||||||
@ -30,7 +30,8 @@
|
|||||||
"company",
|
"company",
|
||||||
"finance_book",
|
"finance_book",
|
||||||
"to_rename",
|
"to_rename",
|
||||||
"due_date"
|
"due_date",
|
||||||
|
"is_cancelled"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -245,12 +246,18 @@
|
|||||||
"fieldname": "due_date",
|
"fieldname": "due_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Due Date"
|
"label": "Due Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "is_cancelled",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Cancelled"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-list",
|
"icon": "fa fa-list",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"modified": "2020-03-28 16:22:33.766994",
|
"modified": "2020-04-07 16:22:33.766994",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "GL Entry",
|
"name": "GL Entry",
|
||||||
|
|||||||
@ -30,23 +30,20 @@ class GLEntry(Document):
|
|||||||
self.pl_must_have_cost_center()
|
self.pl_must_have_cost_center()
|
||||||
self.validate_cost_center()
|
self.validate_cost_center()
|
||||||
|
|
||||||
if not self.flags.from_repost:
|
self.check_pl_account()
|
||||||
self.check_pl_account()
|
self.validate_party()
|
||||||
self.validate_party()
|
self.validate_currency()
|
||||||
self.validate_currency()
|
|
||||||
|
|
||||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
||||||
if not from_repost:
|
self.validate_account_details(adv_adj)
|
||||||
self.validate_account_details(adv_adj)
|
self.validate_dimensions_for_pl_and_bs()
|
||||||
self.validate_dimensions_for_pl_and_bs()
|
|
||||||
check_freezing_date(self.posting_date, adv_adj)
|
|
||||||
|
|
||||||
validate_frozen_account(self.account, adv_adj)
|
validate_frozen_account(self.account, adv_adj)
|
||||||
validate_balance_type(self.account, adv_adj)
|
validate_balance_type(self.account, adv_adj)
|
||||||
|
|
||||||
# Update outstanding amt on against voucher
|
# Update outstanding amt on against voucher
|
||||||
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
|
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
|
||||||
and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
|
and self.against_voucher and update_outstanding == 'Yes':
|
||||||
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
|
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
|
||||||
self.against_voucher)
|
self.against_voucher)
|
||||||
|
|
||||||
@ -159,7 +156,6 @@ class GLEntry(Document):
|
|||||||
if self.party_type and self.party:
|
if self.party_type and self.party:
|
||||||
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
|
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
|
||||||
|
|
||||||
|
|
||||||
def validate_and_set_fiscal_year(self):
|
def validate_and_set_fiscal_year(self):
|
||||||
if not self.fiscal_year:
|
if not self.fiscal_year:
|
||||||
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
||||||
@ -176,19 +172,6 @@ def validate_balance_type(account, adv_adj=False):
|
|||||||
(balance_must_be=="Credit" and flt(balance) > 0):
|
(balance_must_be=="Credit" and flt(balance) > 0):
|
||||||
frappe.throw(_("Balance for Account {0} must always be {1}").format(account, _(balance_must_be)))
|
frappe.throw(_("Balance for Account {0} must always be {1}").format(account, _(balance_must_be)))
|
||||||
|
|
||||||
def check_freezing_date(posting_date, adv_adj=False):
|
|
||||||
"""
|
|
||||||
Nobody can do GL Entries where posting date is before freezing date
|
|
||||||
except authorized person
|
|
||||||
"""
|
|
||||||
if not adv_adj:
|
|
||||||
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
|
|
||||||
if acc_frozen_upto:
|
|
||||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
|
|
||||||
if getdate(posting_date) <= getdate(acc_frozen_upto) \
|
|
||||||
and not frozen_accounts_modifier in frappe.get_roles():
|
|
||||||
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
|
|
||||||
|
|
||||||
def update_outstanding_amt(account, party_type, party, against_voucher_type, against_voucher, on_cancel=False):
|
def update_outstanding_amt(account, party_type, party, against_voucher_type, against_voucher, on_cancel=False):
|
||||||
if party_type and party:
|
if party_type and party:
|
||||||
party_condition = " and party_type={0} and party={1}"\
|
party_condition = " and party_type={0} and party={1}"\
|
||||||
|
|||||||
@ -57,6 +57,7 @@ class JournalEntry(AccountsController):
|
|||||||
from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
|
from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
|
||||||
unlink_ref_doc_from_payment_entries(self)
|
unlink_ref_doc_from_payment_entries(self)
|
||||||
unlink_ref_doc_from_salary_slip(self.name)
|
unlink_ref_doc_from_salary_slip(self.name)
|
||||||
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
self.make_gl_entries(1)
|
self.make_gl_entries(1)
|
||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
self.update_expense_claim()
|
self.update_expense_claim()
|
||||||
@ -594,7 +595,7 @@ class JournalEntry(AccountsController):
|
|||||||
for d in self.accounts:
|
for d in self.accounts:
|
||||||
if d.reference_type=="Expense Claim" and d.reference_name:
|
if d.reference_type=="Expense Claim" and d.reference_name:
|
||||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||||
update_reimbursed_amount(doc)
|
update_reimbursed_amount(doc, jv=self.name)
|
||||||
|
|
||||||
|
|
||||||
def validate_expense_claim(self):
|
def validate_expense_claim(self):
|
||||||
|
|||||||
@ -75,6 +75,7 @@ class PaymentEntry(AccountsController):
|
|||||||
self.set_status()
|
self.set_status()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
self.setup_party_account_field()
|
self.setup_party_account_field()
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
self.update_outstanding_amounts()
|
self.update_outstanding_amounts()
|
||||||
@ -571,7 +572,7 @@ class PaymentEntry(AccountsController):
|
|||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
if d.reference_doctype=="Expense Claim" and d.reference_name:
|
if d.reference_doctype=="Expense Claim" and d.reference_name:
|
||||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||||
update_reimbursed_amount(doc)
|
update_reimbursed_amount(doc, self.name)
|
||||||
|
|
||||||
def on_recurring(self, reference_doc, auto_repeat_doc):
|
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||||
self.reference_no = reference_doc.name
|
self.reference_no = reference_doc.name
|
||||||
|
|||||||
@ -35,8 +35,6 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
|
|
||||||
pe.cancel()
|
pe.cancel()
|
||||||
|
|
||||||
self.assertFalse(self.get_gle(pe.name))
|
|
||||||
|
|
||||||
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
|
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
|
||||||
self.assertEqual(so_advance_paid, 0)
|
self.assertEqual(so_advance_paid, 0)
|
||||||
|
|
||||||
@ -124,7 +122,6 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
self.assertEqual(outstanding_amount, 0)
|
self.assertEqual(outstanding_amount, 0)
|
||||||
|
|
||||||
pe.cancel()
|
pe.cancel()
|
||||||
self.assertFalse(self.get_gle(pe.name))
|
|
||||||
|
|
||||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||||
self.assertEqual(outstanding_amount, 100)
|
self.assertEqual(outstanding_amount, 100)
|
||||||
@ -381,7 +378,6 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
self.assertEqual(outstanding_amount, 0)
|
self.assertEqual(outstanding_amount, 0)
|
||||||
|
|
||||||
pe3.cancel()
|
pe3.cancel()
|
||||||
self.assertFalse(self.get_gle(pe3.name))
|
|
||||||
|
|
||||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
|
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
|
||||||
self.assertEqual(outstanding_amount, -100)
|
self.assertEqual(outstanding_amount, -100)
|
||||||
|
|||||||
@ -326,7 +326,7 @@ def make_payment_request(**args):
|
|||||||
"reference_doctype": args.dt,
|
"reference_doctype": args.dt,
|
||||||
"reference_name": args.dn,
|
"reference_name": args.dn,
|
||||||
"party_type": args.get("party_type") or "Customer",
|
"party_type": args.get("party_type") or "Customer",
|
||||||
"party": args.get("party") or ref_doc.customer,
|
"party": args.get("party") or ref_doc.get("customer"),
|
||||||
"bank_account": bank_account
|
"bank_account": bank_account
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ def make_payment_entry(docname):
|
|||||||
|
|
||||||
def update_payment_req_status(doc, method):
|
def update_payment_req_status(doc, method):
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
|
||||||
|
|
||||||
for ref in doc.references:
|
for ref in doc.references:
|
||||||
payment_request_name = frappe.db.get_value("Payment Request",
|
payment_request_name = frappe.db.get_value("Payment Request",
|
||||||
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
|
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
|
||||||
@ -430,7 +430,7 @@ def update_payment_req_status(doc, method):
|
|||||||
ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
|
ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
|
||||||
pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
|
pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
|
||||||
status = pay_req_doc.status
|
status = pay_req_doc.status
|
||||||
|
|
||||||
if status != "Paid" and not ref_details.outstanding_amount:
|
if status != "Paid" and not ref_details.outstanding_amount:
|
||||||
status = 'Paid'
|
status = 'Paid'
|
||||||
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
|
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ frappe.ui.form.on('Period Closing Voucher', {
|
|||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
|
if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
|
||||||
},
|
},
|
||||||
|
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.set_query("closing_account_head", function() {
|
frm.set_query("closing_account_head", function() {
|
||||||
return {
|
return {
|
||||||
@ -18,9 +18,9 @@ frappe.ui.form.on('Period Closing Voucher', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
if(frm.doc.docstatus==1) {
|
if(frm.doc.docstatus > 0) {
|
||||||
frm.add_custom_button(__('Ledger'), function() {
|
frm.add_custom_button(__('Ledger'), function() {
|
||||||
frappe.route_options = {
|
frappe.route_options = {
|
||||||
"voucher_no": frm.doc.name,
|
"voucher_no": frm.doc.name,
|
||||||
@ -33,5 +33,5 @@ frappe.ui.form.on('Period Closing Voucher', {
|
|||||||
}, "fa fa-table");
|
}, "fa fa-table");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@ -17,8 +17,9 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
frappe.db.sql("""delete from `tabGL Entry`
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name)
|
from erpnext.accounts.general_ledger import make_reverse_gl_entries
|
||||||
|
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name, cancel=True)
|
||||||
|
|
||||||
def validate_account_head(self):
|
def validate_account_head(self):
|
||||||
closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
|
closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
|
||||||
|
|||||||
@ -261,12 +261,25 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
price_list: this.frm.doc.buying_price_list
|
price_list: this.frm.doc.buying_price_list
|
||||||
}, function() {
|
}, function() {
|
||||||
me.apply_pricing_rule();
|
me.apply_pricing_rule();
|
||||||
|
|
||||||
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
|
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
|
||||||
|
me.frm.doc.tax_withholding_category = me.frm.supplier_tds;
|
||||||
me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
|
me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
|
||||||
|
me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
apply_tds: function(frm) {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
if (!me.frm.doc.apply_tds) {
|
||||||
|
me.frm.set_value("tax_withholding_category", '');
|
||||||
|
me.frm.set_df_property("tax_withholding_category", "hidden", 1);
|
||||||
|
} else {
|
||||||
|
me.frm.set_value("tax_withholding_category", me.frm.supplier_tds);
|
||||||
|
me.frm.set_df_property("tax_withholding_category", "hidden", 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
credit_to: function() {
|
credit_to: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.credit_to) {
|
if(this.frm.doc.credit_to) {
|
||||||
@ -369,11 +382,6 @@ function hide_fields(doc) {
|
|||||||
cur_frm.refresh_fields();
|
cur_frm.refresh_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.update_stock = function(doc, dt, dn) {
|
|
||||||
hide_fields(doc, dt, dn);
|
|
||||||
this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: [
|
filters: [
|
||||||
@ -515,5 +523,10 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
erpnext.buying.get_default_bom(frm);
|
erpnext.buying.get_default_bom(frm);
|
||||||
}
|
}
|
||||||
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
|
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
|
||||||
|
},
|
||||||
|
|
||||||
|
update_stock: function(frm) {
|
||||||
|
hide_fields(frm.doc);
|
||||||
|
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"supplier_name",
|
"supplier_name",
|
||||||
"tax_id",
|
"tax_id",
|
||||||
"due_date",
|
"due_date",
|
||||||
|
"tax_withholding_category",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"company",
|
"company",
|
||||||
"posting_date",
|
"posting_date",
|
||||||
@ -1294,13 +1295,21 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Internal Supplier",
|
"label": "Is Internal Supplier",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "tax_withholding_category",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Tax Withholding Category",
|
||||||
|
"options": "Tax Withholding Category",
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 204,
|
"idx": 204,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-17 13:05:25.199832",
|
"modified": "2020-04-18 13:05:25.199832",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from erpnext.accounts.party import get_party_account, get_due_date
|
|||||||
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
|
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
|
||||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
|
||||||
from erpnext.stock import get_warehouse_account_map
|
from erpnext.stock import get_warehouse_account_map
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, make_reverse_gl_entries
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||||
from erpnext.buying.utils import check_on_hold_or_closed_status
|
from erpnext.buying.utils import check_on_hold_or_closed_status
|
||||||
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
|
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
|
||||||
@ -382,7 +382,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
self.update_project()
|
self.update_project()
|
||||||
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
def make_gl_entries(self, gl_entries=None):
|
||||||
if not self.grand_total:
|
if not self.grand_total:
|
||||||
return
|
return
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
@ -391,21 +391,17 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if gl_entries:
|
if gl_entries:
|
||||||
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
|
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
|
||||||
|
|
||||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
if self.docstatus == 1:
|
||||||
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
|
make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
|
||||||
|
elif self.docstatus == 2:
|
||||||
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
if update_outstanding == "No":
|
if update_outstanding == "No":
|
||||||
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
|
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
|
||||||
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
||||||
|
|
||||||
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) and self.auto_accounting_for_stock:
|
|
||||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
|
||||||
items, warehouses = self.get_items_and_warehouses()
|
|
||||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
|
||||||
warehouses, items, company = self.company)
|
|
||||||
|
|
||||||
elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
|
elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
|
||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
||||||
@ -934,6 +930,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
frappe.db.set(self, 'status', 'Cancelled')
|
frappe.db.set(self, 'status', 'Cancelled')
|
||||||
|
|
||||||
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||||
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
|
|
||||||
def update_project(self):
|
def update_project(self):
|
||||||
project_list = []
|
project_list = []
|
||||||
@ -1002,7 +999,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if not self.apply_tds:
|
if not self.apply_tds:
|
||||||
return
|
return
|
||||||
|
|
||||||
tax_withholding_details = get_party_tax_withholding_details(self)
|
tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
|
||||||
|
|
||||||
if not tax_withholding_details:
|
if not tax_withholding_details:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -138,13 +138,12 @@
|
|||||||
"row_id": 7
|
"row_id": 7
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"posting_date": "2013-02-03",
|
|
||||||
"supplier": "_Test Supplier",
|
"supplier": "_Test Supplier",
|
||||||
"supplier_name": "_Test Supplier"
|
"supplier_name": "_Test Supplier"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"bill_no": "NA",
|
"bill_no": "NA",
|
||||||
"buying_price_list": "_Test Price List",
|
"buying_price_list": "_Test Price List",
|
||||||
@ -204,7 +203,6 @@
|
|||||||
"tax_amount": 150.0
|
"tax_amount": 150.0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"posting_date": "2013-02-03",
|
|
||||||
"supplier": "_Test Supplier",
|
"supplier": "_Test Supplier",
|
||||||
"supplier_name": "_Test Supplier"
|
"supplier_name": "_Test Supplier"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "hash",
|
"autoname": "hash",
|
||||||
"creation": "2013-05-21 16:16:04",
|
"creation": "2013-05-21 16:16:04",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -14,11 +15,11 @@
|
|||||||
"col_break1",
|
"col_break1",
|
||||||
"account_head",
|
"account_head",
|
||||||
"description",
|
"description",
|
||||||
|
"section_break_10",
|
||||||
|
"rate",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
"section_break_10",
|
|
||||||
"rate",
|
|
||||||
"section_break_9",
|
"section_break_9",
|
||||||
"tax_amount",
|
"tax_amount",
|
||||||
"tax_amount_after_discount_amount",
|
"tax_amount_after_discount_amount",
|
||||||
@ -27,8 +28,7 @@
|
|||||||
"base_tax_amount",
|
"base_tax_amount",
|
||||||
"base_total",
|
"base_total",
|
||||||
"base_tax_amount_after_discount_amount",
|
"base_tax_amount_after_discount_amount",
|
||||||
"item_wise_tax_detail",
|
"item_wise_tax_detail"
|
||||||
"parenttype"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -53,6 +53,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
|
"default": "On Net Total",
|
||||||
"fieldname": "charge_type",
|
"fieldname": "charge_type",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@ -196,15 +197,6 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "parenttype",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1,
|
|
||||||
"label": "Parenttype",
|
|
||||||
"oldfieldname": "parenttype",
|
|
||||||
"oldfieldtype": "Data",
|
|
||||||
"print_hide": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "accounting_dimensions_section",
|
"fieldname": "accounting_dimensions_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@ -217,11 +209,14 @@
|
|||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-05-25 23:08:38.281025",
|
"links": [],
|
||||||
|
"modified": "2020-03-12 14:53:47.679439",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Taxes and Charges",
|
"name": "Purchase Taxes and Charges",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@ -26,16 +26,24 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
||||||
|
|
||||||
frm.add_custom_button('E-Way Bill JSON', () => {
|
frm.add_custom_button('E-Way Bill JSON', () => {
|
||||||
var w = window.open(
|
frappe.call({
|
||||||
frappe.urllib.get_full_url(
|
method: 'erpnext.regional.india.utils.generate_ewb_json',
|
||||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
args: {
|
||||||
+ "dt=" + encodeURIComponent(frm.doc.doctype)
|
'dt': frm.doc.doctype,
|
||||||
+ "&dn=" + encodeURIComponent(frm.doc.name)
|
'dn': [frm.doc.name]
|
||||||
)
|
},
|
||||||
);
|
callback: function(r) {
|
||||||
if (!w) {
|
if (r.message) {
|
||||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
const args = {
|
||||||
}
|
cmd: 'erpnext.regional.india.utils.download_ewb_json',
|
||||||
|
data: r.message,
|
||||||
|
docname: frm.doc.name
|
||||||
|
};
|
||||||
|
open_url_post(frappe.request.url, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}, __("Create"));
|
}, __("Create"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,17 +16,23 @@ frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var w = window.open(
|
frappe.call({
|
||||||
frappe.urllib.get_full_url(
|
method: 'erpnext.regional.india.utils.generate_ewb_json',
|
||||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
args: {
|
||||||
+ "dt=" + encodeURIComponent(doclist.doctype)
|
'dt': doclist.doctype,
|
||||||
+ "&dn=" + encodeURIComponent(docnames)
|
'dn': docnames
|
||||||
)
|
},
|
||||||
);
|
callback: function(r) {
|
||||||
if (!w) {
|
if (r.message) {
|
||||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
const args = {
|
||||||
}
|
cmd: 'erpnext.regional.india.utils.download_ewb_json',
|
||||||
|
data: r.message,
|
||||||
|
docname: docnames
|
||||||
|
};
|
||||||
|
open_url_post(frappe.request.url, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
|
doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
|
||||||
|
|||||||
@ -345,7 +345,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
|
|
||||||
set_dynamic_labels: function() {
|
set_dynamic_labels: function() {
|
||||||
this._super();
|
this._super();
|
||||||
this.hide_fields(this.frm.doc);
|
this.frm.events.hide_fields(this.frm)
|
||||||
},
|
},
|
||||||
|
|
||||||
items_on_form_rendered: function() {
|
items_on_form_rendered: function() {
|
||||||
@ -404,7 +404,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
if(r.message && r.message.print_format) {
|
if(r.message && r.message.print_format) {
|
||||||
me.frm.pos_print_format = r.message.print_format;
|
me.frm.pos_print_format = r.message.print_format;
|
||||||
}
|
}
|
||||||
me.frm.script_manager.trigger("update_stock");
|
me.frm.trigger("update_stock");
|
||||||
if(me.frm.doc.taxes_and_charges) {
|
if(me.frm.doc.taxes_and_charges) {
|
||||||
me.frm.script_manager.trigger("taxes_and_charges");
|
me.frm.script_manager.trigger("taxes_and_charges");
|
||||||
}
|
}
|
||||||
@ -446,35 +446,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
// for backward compatibility: combine new and previous states
|
// for backward compatibility: combine new and previous states
|
||||||
$.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
|
$.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
|
||||||
|
|
||||||
// Hide Fields
|
|
||||||
// ------------
|
|
||||||
cur_frm.cscript.hide_fields = function(doc) {
|
|
||||||
var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
|
|
||||||
'advances', 'from_date', 'to_date'];
|
|
||||||
|
|
||||||
if(cint(doc.is_pos) == 1) {
|
|
||||||
hide_field(parent_fields);
|
|
||||||
} else {
|
|
||||||
for (var i in parent_fields) {
|
|
||||||
var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
|
|
||||||
if(!docfield.hidden) unhide_field(parent_fields[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// India related fields
|
|
||||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
|
||||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
|
||||||
|
|
||||||
this.frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
|
|
||||||
|
|
||||||
cur_frm.refresh_fields();
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.update_stock = function(doc, dt, dn) {
|
|
||||||
cur_frm.cscript.hide_fields(doc, dt, dn);
|
|
||||||
this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript['Make Delivery Note'] = function() {
|
cur_frm.cscript['Make Delivery Note'] = function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_delivery_note",
|
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_delivery_note",
|
||||||
@ -587,7 +558,9 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
frm.set_query("account_for_change_amount", function() {
|
frm.set_query("account_for_change_amount", function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
account_type: ['in', ["Cash", "Bank"]]
|
account_type: ['in', ["Cash", "Bank"]],
|
||||||
|
company: frm.doc.company,
|
||||||
|
is_group: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -668,7 +641,8 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
frm.fields_dict["loyalty_redemption_account"].get_query = function() {
|
frm.fields_dict["loyalty_redemption_account"].get_query = function() {
|
||||||
return {
|
return {
|
||||||
filters:{
|
filters:{
|
||||||
"company": frm.doc.company
|
"company": frm.doc.company,
|
||||||
|
"is_group": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -677,7 +651,8 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
frm.fields_dict["loyalty_redemption_cost_center"].get_query = function() {
|
frm.fields_dict["loyalty_redemption_cost_center"].get_query = function() {
|
||||||
return {
|
return {
|
||||||
filters:{
|
filters:{
|
||||||
"company": frm.doc.company
|
"company": frm.doc.company,
|
||||||
|
"is_group": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -715,6 +690,12 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
frm.redemption_conversion_factor = null;
|
frm.redemption_conversion_factor = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
update_stock: function(frm, dt, dn) {
|
||||||
|
frm.events.hide_fields(frm);
|
||||||
|
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock);
|
||||||
|
frm.trigger('reset_posting_time');
|
||||||
|
},
|
||||||
|
|
||||||
redeem_loyalty_points: function(frm) {
|
redeem_loyalty_points: function(frm) {
|
||||||
frm.events.get_loyalty_details(frm);
|
frm.events.get_loyalty_details(frm);
|
||||||
},
|
},
|
||||||
@ -738,6 +719,29 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hide_fields: function(frm) {
|
||||||
|
let doc = frm.doc;
|
||||||
|
var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
|
||||||
|
'advances', 'from_date', 'to_date'];
|
||||||
|
|
||||||
|
if(cint(doc.is_pos) == 1) {
|
||||||
|
hide_field(parent_fields);
|
||||||
|
} else {
|
||||||
|
for (var i in parent_fields) {
|
||||||
|
var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
|
||||||
|
if(!docfield.hidden) unhide_field(parent_fields[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// India related fields
|
||||||
|
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||||
|
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||||
|
|
||||||
|
frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
|
||||||
|
|
||||||
|
frm.refresh_fields();
|
||||||
|
},
|
||||||
|
|
||||||
get_loyalty_details: function(frm) {
|
get_loyalty_details: function(frm) {
|
||||||
if (frm.doc.customer && frm.doc.redeem_loyalty_points) {
|
if (frm.doc.customer && frm.doc.redeem_loyalty_points) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
|
|||||||
@ -149,9 +149,9 @@
|
|||||||
"edit_printing_settings",
|
"edit_printing_settings",
|
||||||
"letter_head",
|
"letter_head",
|
||||||
"group_same_items",
|
"group_same_items",
|
||||||
"language",
|
|
||||||
"column_break_84",
|
|
||||||
"select_print_heading",
|
"select_print_heading",
|
||||||
|
"column_break_84",
|
||||||
|
"language",
|
||||||
"more_information",
|
"more_information",
|
||||||
"inter_company_invoice_reference",
|
"inter_company_invoice_reference",
|
||||||
"is_internal_customer",
|
"is_internal_customer",
|
||||||
@ -1579,7 +1579,7 @@
|
|||||||
"idx": 181,
|
"idx": 181,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-17 12:38:41.435728",
|
"modified": "2020-04-29 13:37:09.355300",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import frappe.defaults
|
|||||||
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
|
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
from erpnext.accounts.party import get_party_account, get_due_date
|
from erpnext.accounts.party import get_party_account, get_due_date
|
||||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from erpnext.accounts.doctype.sales_invoice.pos import update_multi_mode_option
|
from erpnext.accounts.doctype.sales_invoice.pos import update_multi_mode_option
|
||||||
|
|
||||||
@ -282,6 +281,8 @@ class SalesInvoice(SellingController):
|
|||||||
if "Healthcare" in active_domains:
|
if "Healthcare" in active_domains:
|
||||||
manage_invoice_submit_cancel(self, "on_cancel")
|
manage_invoice_submit_cancel(self, "on_cancel")
|
||||||
|
|
||||||
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
|
|
||||||
def update_status_updater_args(self):
|
def update_status_updater_args(self):
|
||||||
if cint(self.update_stock):
|
if cint(self.update_stock):
|
||||||
self.status_updater.append({
|
self.status_updater.append({
|
||||||
@ -717,7 +718,9 @@ class SalesInvoice(SellingController):
|
|||||||
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
|
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
|
||||||
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
|
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
def make_gl_entries(self, gl_entries=None):
|
||||||
|
from erpnext.accounts.general_ledger import make_reverse_gl_entries
|
||||||
|
|
||||||
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
gl_entries = self.get_gl_entries()
|
gl_entries = self.get_gl_entries()
|
||||||
@ -729,23 +732,19 @@ class SalesInvoice(SellingController):
|
|||||||
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account or
|
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account or
|
||||||
cint(self.redeem_loyalty_points)) else "Yes"
|
cint(self.redeem_loyalty_points)) else "Yes"
|
||||||
|
|
||||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
if self.docstatus == 1:
|
||||||
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
|
make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
|
||||||
|
elif self.docstatus == 2:
|
||||||
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
if update_outstanding == "No":
|
if update_outstanding == "No":
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||||
update_outstanding_amt(self.debit_to, "Customer", self.customer,
|
update_outstanding_amt(self.debit_to, "Customer", self.customer,
|
||||||
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
||||||
|
|
||||||
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) \
|
|
||||||
and cint(auto_accounting_for_stock):
|
|
||||||
items, warehouses = self.get_items_and_warehouses()
|
|
||||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
|
||||||
warehouses, items, company = self.company)
|
|
||||||
elif self.docstatus == 2 and cint(self.update_stock) \
|
elif self.docstatus == 2 and cint(self.update_stock) \
|
||||||
and cint(auto_accounting_for_stock):
|
and cint(auto_accounting_for_stock):
|
||||||
from erpnext.accounts.general_ledger import delete_gl_entries
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
from erpnext.accounts.general_ledger import merge_similar_entries
|
from erpnext.accounts.general_ledger import merge_similar_entries
|
||||||
|
|||||||
@ -364,7 +364,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
gle = frappe.db.sql("""select * from `tabGL Entry`
|
gle = frappe.db.sql("""select * from `tabGL Entry`
|
||||||
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
||||||
|
|
||||||
self.assertFalse(gle)
|
self.assertTrue(gle)
|
||||||
|
|
||||||
def test_tax_calculation_with_multiple_items(self):
|
def test_tax_calculation_with_multiple_items(self):
|
||||||
si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
|
si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
|
||||||
@ -678,14 +678,15 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
gle = frappe.db.sql("""select * from `tabGL Entry`
|
gle = frappe.db.sql("""select * from `tabGL Entry`
|
||||||
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
||||||
|
|
||||||
self.assertFalse(gle)
|
self.assertTrue(gle)
|
||||||
|
|
||||||
def test_pos_gl_entry_with_perpetual_inventory(self):
|
def test_pos_gl_entry_with_perpetual_inventory(self):
|
||||||
make_pos_profile()
|
make_pos_profile()
|
||||||
|
|
||||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
||||||
|
|
||||||
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
|
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
|
||||||
|
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
|
||||||
|
|
||||||
pos.is_pos = 1
|
pos.is_pos = 1
|
||||||
pos.update_stock = 1
|
pos.update_stock = 1
|
||||||
@ -766,9 +767,13 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
def test_pos_change_amount(self):
|
def test_pos_change_amount(self):
|
||||||
make_pos_profile()
|
make_pos_profile()
|
||||||
|
|
||||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
|
||||||
|
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
|
||||||
|
|
||||||
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
|
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
|
||||||
|
debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
|
||||||
|
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
|
||||||
|
cost_center = "Main - TCP1", do_not_save=True)
|
||||||
|
|
||||||
pos.is_pos = 1
|
pos.is_pos = 1
|
||||||
pos.update_stock = 1
|
pos.update_stock = 1
|
||||||
@ -787,8 +792,15 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
|
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
|
||||||
|
|
||||||
pos_profile = make_pos_profile()
|
pos_profile = make_pos_profile()
|
||||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
|
||||||
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
|
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
|
||||||
|
item_code= "_Test FG Item",
|
||||||
|
warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
|
||||||
|
|
||||||
|
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
|
||||||
|
debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
|
||||||
|
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
|
||||||
|
cost_center = "Main - TCP1", do_not_save=True)
|
||||||
|
|
||||||
pos.is_pos = 1
|
pos.is_pos = 1
|
||||||
pos.update_stock = 1
|
pos.update_stock = 1
|
||||||
@ -891,11 +903,9 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
gle = frappe.db.sql("""select * from `tabGL Entry`
|
gle = frappe.db.sql("""select * from `tabGL Entry`
|
||||||
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
||||||
|
|
||||||
self.assertFalse(gle)
|
self.assertTrue(gle)
|
||||||
|
|
||||||
|
|
||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
si.delete()
|
|
||||||
|
|
||||||
def test_pos_si_without_payment(self):
|
def test_pos_si_without_payment(self):
|
||||||
set_perpetual_inventory()
|
set_perpetual_inventory()
|
||||||
@ -1012,9 +1022,6 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
si.cancel()
|
si.cancel()
|
||||||
|
|
||||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
|
|
||||||
where reference_name=%s""", si.name))
|
|
||||||
|
|
||||||
def test_serialized(self):
|
def test_serialized(self):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
@ -1230,7 +1237,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
gle = frappe.db.sql("""select name from `tabGL Entry`
|
gle = frappe.db.sql("""select name from `tabGL Entry`
|
||||||
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
||||||
|
|
||||||
self.assertFalse(gle)
|
self.assertTrue(gle)
|
||||||
|
|
||||||
def test_invalid_currency(self):
|
def test_invalid_currency(self):
|
||||||
# Customer currency = USD
|
# Customer currency = USD
|
||||||
@ -1892,7 +1899,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
data = get_ewb_data("Sales Invoice", si.name)
|
data = get_ewb_data("Sales Invoice", [si.name])
|
||||||
|
|
||||||
self.assertEqual(data['version'], '1.0.1118')
|
self.assertEqual(data['version'], '1.0.1118')
|
||||||
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
||||||
|
|||||||
@ -6,23 +6,42 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt, getdate
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
class TaxWithholdingCategory(Document):
|
class TaxWithholdingCategory(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_party_tax_withholding_details(ref_doc):
|
def get_party_tax_withholding_details(ref_doc, tax_withholding_category=None):
|
||||||
tax_withholding_category = frappe.db.get_value('Supplier', ref_doc.supplier, 'tax_withholding_category')
|
|
||||||
|
pan_no = ''
|
||||||
|
suppliers = []
|
||||||
|
|
||||||
|
if not tax_withholding_category:
|
||||||
|
tax_withholding_category, pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, ['tax_withholding_category', 'pan'])
|
||||||
|
|
||||||
if not tax_withholding_category:
|
if not tax_withholding_category:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not pan_no:
|
||||||
|
pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, 'pan')
|
||||||
|
|
||||||
|
# Get others suppliers with the same PAN No
|
||||||
|
if pan_no:
|
||||||
|
suppliers = [d.name for d in frappe.get_all('Supplier', fields=['name'], filters={'pan': pan_no})]
|
||||||
|
|
||||||
|
if not suppliers:
|
||||||
|
suppliers.append(ref_doc.supplier)
|
||||||
|
|
||||||
fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
|
fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
|
||||||
tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
|
tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
|
||||||
if not tax_details:
|
if not tax_details:
|
||||||
frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
|
frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
|
||||||
.format(tax_withholding_category, ref_doc.company))
|
.format(tax_withholding_category, ref_doc.company))
|
||||||
tds_amount = get_tds_amount(ref_doc, tax_details, fy)
|
|
||||||
|
tds_amount = get_tds_amount(suppliers, ref_doc.net_total, ref_doc.company,
|
||||||
|
tax_details, fy, ref_doc.posting_date, pan_no)
|
||||||
|
|
||||||
tax_row = get_tax_row(tax_details, tds_amount)
|
tax_row = get_tax_row(tax_details, tds_amount)
|
||||||
|
|
||||||
return tax_row
|
return tax_row
|
||||||
@ -51,6 +70,7 @@ def get_tax_withholding_rates(tax_withholding, fiscal_year):
|
|||||||
frappe.throw(_("No Tax Withholding data found for the current Fiscal Year."))
|
frappe.throw(_("No Tax Withholding data found for the current Fiscal Year."))
|
||||||
|
|
||||||
def get_tax_row(tax_details, tds_amount):
|
def get_tax_row(tax_details, tds_amount):
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"category": "Total",
|
"category": "Total",
|
||||||
"add_deduct_tax": "Deduct",
|
"add_deduct_tax": "Deduct",
|
||||||
@ -60,25 +80,36 @@ def get_tax_row(tax_details, tds_amount):
|
|||||||
"tax_amount": tds_amount
|
"tax_amount": tds_amount
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_details, posting_date, pan_no=None):
|
||||||
fiscal_year, year_start_date, year_end_date = fiscal_year_details
|
fiscal_year, year_start_date, year_end_date = fiscal_year_details
|
||||||
tds_amount = 0
|
tds_amount = 0
|
||||||
tds_deducted = 0
|
tds_deducted = 0
|
||||||
|
|
||||||
def _get_tds(amount):
|
def _get_tds(amount, rate):
|
||||||
if amount <= 0:
|
if amount <= 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return amount * tax_details.rate / 100
|
return amount * rate / 100
|
||||||
|
|
||||||
|
ldc_name = frappe.db.get_value('Lower Deduction Certificate',
|
||||||
|
{
|
||||||
|
'pan_no': pan_no,
|
||||||
|
'fiscal_year': fiscal_year
|
||||||
|
}, 'name')
|
||||||
|
ldc = ''
|
||||||
|
|
||||||
|
if ldc_name:
|
||||||
|
ldc = frappe.get_doc('Lower Deduction Certificate', ldc_name)
|
||||||
|
|
||||||
entries = frappe.db.sql("""
|
entries = frappe.db.sql("""
|
||||||
select voucher_no, credit
|
select voucher_no, credit
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where party=%s and fiscal_year=%s and credit > 0
|
where company = %s and
|
||||||
""", (ref_doc.supplier, fiscal_year), as_dict=1)
|
party in %s and fiscal_year=%s and credit > 0
|
||||||
|
""", (company, tuple(suppliers), fiscal_year), as_dict=1)
|
||||||
|
|
||||||
vouchers = [d.voucher_no for d in entries]
|
vouchers = [d.voucher_no for d in entries]
|
||||||
advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
|
advance_vouchers = get_advance_vouchers(suppliers, fiscal_year=fiscal_year, company=company)
|
||||||
|
|
||||||
tds_vouchers = vouchers + advance_vouchers
|
tds_vouchers = vouchers + advance_vouchers
|
||||||
|
|
||||||
@ -93,7 +124,20 @@ def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
|||||||
tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
|
tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
|
||||||
|
|
||||||
if tds_deducted:
|
if tds_deducted:
|
||||||
tds_amount = _get_tds(ref_doc.net_total)
|
if ldc:
|
||||||
|
limit_consumed = frappe.db.get_value('Purchase Invoice',
|
||||||
|
{
|
||||||
|
'supplier': ('in', suppliers),
|
||||||
|
'apply_tds': 1,
|
||||||
|
'docstatus': 1
|
||||||
|
}, 'sum(net_total)')
|
||||||
|
|
||||||
|
if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total,
|
||||||
|
ldc.certificate_limit):
|
||||||
|
|
||||||
|
tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
|
||||||
|
else:
|
||||||
|
tds_amount = _get_tds(net_total, tax_details.rate)
|
||||||
else:
|
else:
|
||||||
supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
|
supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
|
||||||
fields = ['sum(net_amount)'],
|
fields = ['sum(net_amount)'],
|
||||||
@ -106,43 +150,79 @@ def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
|||||||
fields = ['sum(credit_in_account_currency)'],
|
fields = ['sum(credit_in_account_currency)'],
|
||||||
filters = {
|
filters = {
|
||||||
'parent': ('in', vouchers), 'docstatus': 1,
|
'parent': ('in', vouchers), 'docstatus': 1,
|
||||||
'party': ref_doc.supplier,
|
'party': ('in', suppliers),
|
||||||
'reference_type': ('not in', ['Purchase Invoice'])
|
'reference_type': ('not in', ['Purchase Invoice'])
|
||||||
}, as_list=1)
|
}, as_list=1)
|
||||||
|
|
||||||
supplier_credit_amount += (jv_supplier_credit_amt[0][0]
|
supplier_credit_amount += (jv_supplier_credit_amt[0][0]
|
||||||
if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
|
if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
|
||||||
|
|
||||||
supplier_credit_amount += ref_doc.net_total
|
supplier_credit_amount += net_total
|
||||||
|
|
||||||
debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date)
|
debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
|
||||||
supplier_credit_amount -= debit_note_amount
|
supplier_credit_amount -= debit_note_amount
|
||||||
|
|
||||||
if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
|
if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
|
||||||
or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
|
or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
|
||||||
tds_amount = _get_tds(supplier_credit_amount)
|
|
||||||
|
if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,
|
||||||
|
ldc.certificate_limit):
|
||||||
|
tds_amount = get_ltds_amount(supplier_credit_amount, 0, ldc.certificate_limit, ldc.rate,
|
||||||
|
tax_details)
|
||||||
|
else:
|
||||||
|
tds_amount = _get_tds(supplier_credit_amount, tax_details.rate)
|
||||||
|
|
||||||
return tds_amount
|
return tds_amount
|
||||||
|
|
||||||
def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=None, to_date=None):
|
def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=None, to_date=None):
|
||||||
condition = "fiscal_year=%s" % fiscal_year
|
condition = "fiscal_year=%s" % fiscal_year
|
||||||
|
|
||||||
|
if company:
|
||||||
|
condition += "and company =%s" % (company)
|
||||||
if from_date and to_date:
|
if from_date and to_date:
|
||||||
condition = "company=%s and posting_date between %s and %s" % (company, from_date, to_date)
|
condition += "and posting_date between %s and %s" % (company, from_date, to_date)
|
||||||
|
|
||||||
|
## Appending the same supplier again if length of suppliers list is 1
|
||||||
|
## since tuple of single element list contains None, For example ('Test Supplier 1', )
|
||||||
|
## and the below query fails
|
||||||
|
if len(suppliers) == 1:
|
||||||
|
suppliers.append(suppliers[0])
|
||||||
|
|
||||||
return frappe.db.sql_list("""
|
return frappe.db.sql_list("""
|
||||||
select distinct voucher_no
|
select distinct voucher_no
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where party=%s and %s and debit > 0
|
where party in %s and %s and debit > 0
|
||||||
""", (supplier, condition)) or []
|
""", (tuple(suppliers), condition)) or []
|
||||||
|
|
||||||
def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
|
def get_debit_note_amount(suppliers, year_start_date, year_end_date, company=None):
|
||||||
condition = ""
|
condition = "and 1=1"
|
||||||
if company:
|
if company:
|
||||||
condition = " and company=%s " % company
|
condition = " and company=%s " % company
|
||||||
|
|
||||||
|
if len(suppliers) == 1:
|
||||||
|
suppliers.append(suppliers[0])
|
||||||
|
|
||||||
return flt(frappe.db.sql("""
|
return flt(frappe.db.sql("""
|
||||||
select abs(sum(net_total))
|
select abs(sum(net_total))
|
||||||
from `tabPurchase Invoice`
|
from `tabPurchase Invoice`
|
||||||
where supplier=%s %s and is_return=1 and docstatus=1
|
where supplier in %s and is_return=1 and docstatus=1
|
||||||
and posting_date between %s and %s
|
and posting_date between %s and %s %s
|
||||||
""", (supplier, condition, year_start_date, year_end_date)))
|
""", (tuple(suppliers), year_start_date, year_end_date, condition)))
|
||||||
|
|
||||||
|
def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
|
||||||
|
if current_amount < (certificate_limit - deducted_amount):
|
||||||
|
return current_amount * rate/100
|
||||||
|
else:
|
||||||
|
ltds_amount = (certificate_limit - deducted_amount)
|
||||||
|
tds_amount = current_amount - ltds_amount
|
||||||
|
|
||||||
|
return ltds_amount * rate/100 + tds_amount * tax_details.rate/100
|
||||||
|
|
||||||
|
def is_valid_certificate(valid_from, valid_upto, posting_date, deducted_amount, current_amount, certificate_limit):
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
if ((getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and
|
||||||
|
certificate_limit > deducted_amount):
|
||||||
|
valid = True
|
||||||
|
|
||||||
|
return valid
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.utils import flt, cstr, cint, comma_and
|
from frappe.utils import flt, cstr, cint, comma_and, today, getdate, formatdate, now
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.accounts.utils import get_stock_and_account_balance
|
from erpnext.accounts.utils import get_stock_and_account_balance
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
@ -15,17 +15,17 @@ class ClosedAccountingPeriod(frappe.ValidationError): pass
|
|||||||
class StockAccountInvalidTransaction(frappe.ValidationError): pass
|
class StockAccountInvalidTransaction(frappe.ValidationError): pass
|
||||||
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
|
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
|
||||||
|
|
||||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
|
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
|
||||||
if gl_map:
|
if gl_map:
|
||||||
if not cancel:
|
if not cancel:
|
||||||
validate_accounting_period(gl_map)
|
validate_accounting_period(gl_map)
|
||||||
gl_map = process_gl_map(gl_map, merge_entries)
|
gl_map = process_gl_map(gl_map, merge_entries)
|
||||||
if gl_map and len(gl_map) > 1:
|
if gl_map and len(gl_map) > 1:
|
||||||
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
|
save_entries(gl_map, adv_adj, update_outstanding)
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
|
frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
|
||||||
else:
|
else:
|
||||||
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||||
|
|
||||||
def validate_accounting_period(gl_map):
|
def validate_accounting_period(gl_map):
|
||||||
accounting_periods = frappe.db.sql(""" SELECT
|
accounting_periods = frappe.db.sql(""" SELECT
|
||||||
@ -119,33 +119,36 @@ def check_if_in_list(gle, gl_map, dimensions=None):
|
|||||||
if same_head:
|
if same_head:
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
|
def save_entries(gl_map, adv_adj, update_outstanding):
|
||||||
if not from_repost:
|
validate_cwip_accounts(gl_map)
|
||||||
validate_cwip_accounts(gl_map)
|
|
||||||
|
|
||||||
round_off_debit_credit(gl_map)
|
round_off_debit_credit(gl_map)
|
||||||
|
|
||||||
|
if gl_map:
|
||||||
|
check_freezing_date(gl_map[0]["posting_date"], adv_adj)
|
||||||
|
|
||||||
for entry in gl_map:
|
for entry in gl_map:
|
||||||
make_entry(entry, adv_adj, update_outstanding, from_repost)
|
make_entry(entry, adv_adj, update_outstanding)
|
||||||
|
|
||||||
# check against budget
|
# check against budget
|
||||||
if not from_repost:
|
validate_expense_against_budget(entry)
|
||||||
validate_expense_against_budget(entry)
|
|
||||||
|
|
||||||
if not from_repost:
|
validate_account_for_perpetual_inventory(gl_map)
|
||||||
validate_account_for_perpetual_inventory(gl_map)
|
|
||||||
|
|
||||||
|
|
||||||
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
def make_entry(args, adv_adj, update_outstanding):
|
||||||
gle = frappe.new_doc("GL Entry")
|
gle = frappe.new_doc("GL Entry")
|
||||||
gle.update(args)
|
gle.update(args)
|
||||||
gle.flags.ignore_permissions = 1
|
gle.flags.ignore_permissions = 1
|
||||||
gle.flags.from_repost = from_repost
|
|
||||||
gle.validate()
|
gle.validate()
|
||||||
gle.db_insert()
|
gle.db_insert()
|
||||||
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
|
gle.run_method("on_update_with_args", adv_adj, update_outstanding)
|
||||||
gle.flags.ignore_validate = True
|
gle.flags.ignore_validate = True
|
||||||
gle.submit()
|
gle.submit()
|
||||||
|
|
||||||
|
# check against budget
|
||||||
|
validate_expense_against_budget(args)
|
||||||
|
|
||||||
def validate_account_for_perpetual_inventory(gl_map):
|
def validate_account_for_perpetual_inventory(gl_map):
|
||||||
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
|
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
|
||||||
account_list = [gl_entries.account for gl_entries in gl_map]
|
account_list = [gl_entries.account for gl_entries in gl_map]
|
||||||
@ -169,33 +172,33 @@ def validate_account_for_perpetual_inventory(gl_map):
|
|||||||
.format(account), StockAccountInvalidTransaction)
|
.format(account), StockAccountInvalidTransaction)
|
||||||
|
|
||||||
# This has been comment for a temporary, will add this code again on release of immutable ledger
|
# This has been comment for a temporary, will add this code again on release of immutable ledger
|
||||||
# elif account_bal != stock_bal:
|
elif account_bal != stock_bal:
|
||||||
# precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||||
# currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
|
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
|
||||||
|
|
||||||
# diff = flt(stock_bal - account_bal, precision)
|
diff = flt(stock_bal - account_bal, precision)
|
||||||
# error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
|
error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
|
||||||
# stock_bal, account_bal, frappe.bold(account))
|
stock_bal, account_bal, frappe.bold(account))
|
||||||
# error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
|
error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
|
||||||
# stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
|
stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
|
||||||
|
|
||||||
# db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
|
db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
|
||||||
# db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
|
db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
|
||||||
|
|
||||||
# journal_entry_args = {
|
journal_entry_args = {
|
||||||
# 'accounts':[
|
'accounts':[
|
||||||
# {'account': account, db_or_cr_warehouse_account : abs(diff)},
|
{'account': account, db_or_cr_warehouse_account : abs(diff)},
|
||||||
# {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
|
{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
|
||||||
# }
|
}
|
||||||
|
|
||||||
# frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
||||||
# raise_exception=StockValueAndAccountBalanceOutOfSync,
|
raise_exception=StockValueAndAccountBalanceOutOfSync,
|
||||||
# title=_('Values Out Of Sync'),
|
title=_('Values Out Of Sync'),
|
||||||
# primary_action={
|
primary_action={
|
||||||
# 'label': _('Make Journal Entry'),
|
'label': _('Make Journal Entry'),
|
||||||
# 'client_action': 'erpnext.route_to_adjustment_jv',
|
'client_action': 'erpnext.route_to_adjustment_jv',
|
||||||
# 'args': journal_entry_args
|
'args': journal_entry_args
|
||||||
# })
|
})
|
||||||
|
|
||||||
def validate_cwip_accounts(gl_map):
|
def validate_cwip_accounts(gl_map):
|
||||||
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
|
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
|
||||||
@ -282,31 +285,64 @@ def get_round_off_account_and_cost_center(company):
|
|||||||
|
|
||||||
return round_off_account, round_off_cost_center
|
return round_off_account, round_off_cost_center
|
||||||
|
|
||||||
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
def make_reverse_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
||||||
adv_adj=False, update_outstanding="Yes"):
|
adv_adj=False, update_outstanding="Yes"):
|
||||||
|
"""
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import validate_balance_type, \
|
Get original gl entries of the voucher
|
||||||
check_freezing_date, update_outstanding_amt, validate_frozen_account
|
and make reverse gl entries by swapping debit and credit
|
||||||
|
"""
|
||||||
|
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
gl_entries = frappe.db.sql("""
|
gl_entries = frappe.get_all("GL Entry",
|
||||||
select account, posting_date, party_type, party, cost_center, fiscal_year,voucher_type,
|
fields = ["*"],
|
||||||
voucher_no, against_voucher_type, against_voucher, cost_center, company
|
filters = {
|
||||||
from `tabGL Entry`
|
"voucher_type": voucher_type,
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
|
"voucher_no": voucher_no
|
||||||
|
})
|
||||||
|
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
|
set_as_cancel(gl_entries[0]['voucher_type'], gl_entries[0]['voucher_no'])
|
||||||
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
||||||
|
|
||||||
frappe.db.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
|
for entry in gl_entries:
|
||||||
(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
|
entry['name'] = None
|
||||||
|
debit = entry.get('debit', 0)
|
||||||
|
credit = entry.get('credit', 0)
|
||||||
|
|
||||||
for entry in gl_entries:
|
debit_in_account_currency = entry.get('debit_in_account_currency', 0)
|
||||||
validate_frozen_account(entry["account"], adv_adj)
|
credit_in_account_currency = entry.get('credit_in_account_currency', 0)
|
||||||
validate_balance_type(entry["account"], adv_adj)
|
|
||||||
if not adv_adj:
|
|
||||||
validate_expense_against_budget(entry)
|
|
||||||
|
|
||||||
if entry.get("against_voucher") and update_outstanding == 'Yes' and not adv_adj:
|
entry['debit'] = credit
|
||||||
update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
|
entry['credit'] = debit
|
||||||
entry.get("against_voucher"), on_cancel=True)
|
entry['debit_in_account_currency'] = credit_in_account_currency
|
||||||
|
entry['credit_in_account_currency'] = debit_in_account_currency
|
||||||
|
|
||||||
|
entry['remarks'] = "On cancellation of " + entry['voucher_no']
|
||||||
|
entry['is_cancelled'] = 1
|
||||||
|
entry['posting_date'] = today()
|
||||||
|
|
||||||
|
if entry['debit'] or entry['credit']:
|
||||||
|
make_entry(entry, adv_adj, "Yes")
|
||||||
|
|
||||||
|
|
||||||
|
def check_freezing_date(posting_date, adv_adj=False):
|
||||||
|
"""
|
||||||
|
Nobody can do GL Entries where posting date is before freezing date
|
||||||
|
except authorized person
|
||||||
|
"""
|
||||||
|
if not adv_adj:
|
||||||
|
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
|
||||||
|
if acc_frozen_upto:
|
||||||
|
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
|
||||||
|
if getdate(posting_date) <= getdate(acc_frozen_upto) \
|
||||||
|
and not frozen_accounts_modifier in frappe.get_roles():
|
||||||
|
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
|
||||||
|
|
||||||
|
def set_as_cancel(voucher_type, voucher_no):
|
||||||
|
"""
|
||||||
|
Set is_cancelled=1 in all original gl entries for the voucher
|
||||||
|
"""
|
||||||
|
frappe.db.sql("""update `tabGL Entry` set is_cancelled = 1,
|
||||||
|
modified=%s, modified_by=%s
|
||||||
|
where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
|
||||||
|
(now(), frappe.session.user, voucher_type, voucher_no))
|
||||||
|
|||||||
@ -84,6 +84,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
|
|||||||
|
|
||||||
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
||||||
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
|
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
|
||||||
|
company_currency = get_company_currency(filters)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
data.extend(income or [])
|
data.extend(income or [])
|
||||||
@ -93,7 +94,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
|||||||
|
|
||||||
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
|
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
|
||||||
|
|
||||||
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
|
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
|
||||||
|
|
||||||
return data, None, chart, report_summary
|
return data, None, chart, report_summary
|
||||||
|
|
||||||
|
|||||||
@ -154,8 +154,12 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
{
|
{
|
||||||
"fieldname": "include_default_book_entries",
|
"fieldname": "include_default_book_entries",
|
||||||
"label": __("Include Default Book Entries"),
|
"label": __("Include Default Book Entries"),
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check"
|
||||||
"default": 1
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "show_cancelled_entries",
|
||||||
|
"label": __("Show Cancelled Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -188,6 +188,9 @@ def get_conditions(filters):
|
|||||||
else:
|
else:
|
||||||
conditions.append("finance_book in (%(finance_book)s)")
|
conditions.append("finance_book in (%(finance_book)s)")
|
||||||
|
|
||||||
|
if not filters.get("show_cancelled_entries"):
|
||||||
|
conditions.append("is_cancelled = 0")
|
||||||
|
|
||||||
from frappe.desk.reportview import build_match_conditions
|
from frappe.desk.reportview import build_match_conditions
|
||||||
match_conditions = build_match_conditions("GL Entry")
|
match_conditions = build_match_conditions("GL Entry")
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,12 @@ def execute(filters=None):
|
|||||||
})
|
})
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
|
# to avoid error eg: gross_income[0] : list index out of range
|
||||||
|
if not gross_income:
|
||||||
|
gross_income = [{}]
|
||||||
|
if not gross_expense:
|
||||||
|
gross_expense = [{}]
|
||||||
|
|
||||||
data.append({
|
data.append({
|
||||||
"account_name": "'" + _("Included in Gross Profit") + "'",
|
"account_name": "'" + _("Included in Gross Profit") + "'",
|
||||||
"account": "'" + _("Included in Gross Profit") + "'"
|
"account": "'" + _("Included in Gross Profit") + "'"
|
||||||
|
|||||||
@ -55,27 +55,27 @@ def get_columns(group_wise_columns, filters):
|
|||||||
columns = []
|
columns = []
|
||||||
column_map = frappe._dict({
|
column_map = frappe._dict({
|
||||||
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||||
"posting_date": _("Posting Date") + ":Date",
|
"posting_date": _("Posting Date") + ":Date:100",
|
||||||
"posting_time": _("Posting Time"),
|
"posting_time": _("Posting Time") + ":Data:100",
|
||||||
"item_code": _("Item Code") + ":Link/Item",
|
"item_code": _("Item Code") + ":Link/Item:100",
|
||||||
"item_name": _("Item Name"),
|
"item_name": _("Item Name") + ":Data:100",
|
||||||
"item_group": _("Item Group") + ":Link/Item Group",
|
"item_group": _("Item Group") + ":Link/Item Group:100",
|
||||||
"brand": _("Brand"),
|
"brand": _("Brand") + ":Link/Brand:100",
|
||||||
"description": _("Description"),
|
"description": _("Description") +":Data:100",
|
||||||
"warehouse": _("Warehouse") + ":Link/Warehouse",
|
"warehouse": _("Warehouse") + ":Link/Warehouse:100",
|
||||||
"qty": _("Qty") + ":Float",
|
"qty": _("Qty") + ":Float:80",
|
||||||
"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
|
"base_rate": _("Avg. Selling Rate") + ":Currency/currency:100",
|
||||||
"buying_rate": _("Valuation Rate") + ":Currency/currency",
|
"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
|
||||||
"base_amount": _("Selling Amount") + ":Currency/currency",
|
"base_amount": _("Selling Amount") + ":Currency/currency:100",
|
||||||
"buying_amount": _("Buying Amount") + ":Currency/currency",
|
"buying_amount": _("Buying Amount") + ":Currency/currency:100",
|
||||||
"gross_profit": _("Gross Profit") + ":Currency/currency",
|
"gross_profit": _("Gross Profit") + ":Currency/currency:100",
|
||||||
"gross_profit_percent": _("Gross Profit %") + ":Percent",
|
"gross_profit_percent": _("Gross Profit %") + ":Percent:100",
|
||||||
"project": _("Project") + ":Link/Project",
|
"project": _("Project") + ":Link/Project:100",
|
||||||
"sales_person": _("Sales person"),
|
"sales_person": _("Sales person"),
|
||||||
"allocated_amount": _("Allocated Amount") + ":Currency/currency",
|
"allocated_amount": _("Allocated Amount") + ":Currency/currency:100",
|
||||||
"customer": _("Customer") + ":Link/Customer",
|
"customer": _("Customer") + ":Link/Customer:100",
|
||||||
"customer_group": _("Customer Group") + ":Link/Customer Group",
|
"customer_group": _("Customer Group") + ":Link/Customer Group:100",
|
||||||
"territory": _("Territory") + ":Link/Territory"
|
"territory": _("Territory") + ":Link/Territory:100"
|
||||||
})
|
})
|
||||||
|
|
||||||
for col in group_wise_columns.get(scrub(filters.group_by)):
|
for col in group_wise_columns.get(scrub(filters.group_by)):
|
||||||
@ -85,7 +85,8 @@ def get_columns(group_wise_columns, filters):
|
|||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"label" : _("Currency"),
|
"label" : _("Currency"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Currency"
|
"options": "Currency",
|
||||||
|
"hidden": 1
|
||||||
})
|
})
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
@ -277,7 +278,7 @@ class GrossProfitGenerator(object):
|
|||||||
from `tabPurchase Invoice Item` a
|
from `tabPurchase Invoice Item` a
|
||||||
where a.item_code = %s and a.docstatus=1
|
where a.item_code = %s and a.docstatus=1
|
||||||
and modified <= %s
|
and modified <= %s
|
||||||
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
|
order by a.modified desc limit 1""", (item_code, self.filters.to_date))
|
||||||
else:
|
else:
|
||||||
last_purchase_rate = frappe.db.sql("""
|
last_purchase_rate = frappe.db.sql("""
|
||||||
select (a.base_rate / a.conversion_factor)
|
select (a.base_rate / a.conversion_factor)
|
||||||
|
|||||||
@ -102,7 +102,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
if filters.get('group_by'):
|
if filters.get('group_by') and item_list:
|
||||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||||
data.append(total_row)
|
data.append(total_row)
|
||||||
|
|||||||
@ -111,7 +111,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
if filters.get('group_by'):
|
if filters.get('group_by') and item_list:
|
||||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||||
data.append(total_row)
|
data.append(total_row)
|
||||||
|
|||||||
@ -44,9 +44,14 @@ def get_result(filters):
|
|||||||
out = []
|
out = []
|
||||||
for supplier in filters.supplier:
|
for supplier in filters.supplier:
|
||||||
tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category)
|
tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category)
|
||||||
rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year][0]
|
rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year]
|
||||||
|
|
||||||
|
if rate:
|
||||||
|
rate = rate[0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
account = [d.account for d in tds.accounts if d.company == filters.company][0]
|
account = [d.account for d in tds.accounts if d.company == filters.company][0]
|
||||||
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
account = []
|
account = []
|
||||||
total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account,
|
total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account,
|
||||||
@ -76,7 +81,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
|
|||||||
supplier_credit_amount = flt(sum([d.credit for d in entries]))
|
supplier_credit_amount = flt(sum([d.credit for d in entries]))
|
||||||
|
|
||||||
vouchers = [d.voucher_no for d in entries]
|
vouchers = [d.voucher_no for d in entries]
|
||||||
vouchers += get_advance_vouchers(supplier, company=company,
|
vouchers += get_advance_vouchers([supplier], company=company,
|
||||||
from_date=from_date, to_date=to_date)
|
from_date=from_date, to_date=to_date)
|
||||||
|
|
||||||
tds_deducted = 0
|
tds_deducted = 0
|
||||||
@ -89,7 +94,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
|
|||||||
""".format(', '.join(["'%s'" % d for d in vouchers])),
|
""".format(', '.join(["'%s'" % d for d in vouchers])),
|
||||||
(account, from_date, to_date, company))[0][0])
|
(account, from_date, to_date, company))[0][0])
|
||||||
|
|
||||||
debit_note_amount = get_debit_note_amount(supplier, from_date, to_date, company=company)
|
debit_note_amount = get_debit_note_amount([supplier], from_date, to_date, company=company)
|
||||||
|
|
||||||
total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount
|
total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount
|
||||||
|
|
||||||
|
|||||||
@ -817,48 +817,37 @@ def create_payment_gateway_account(gateway):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_number_field(doctype_name, name, field_name, number_value, company):
|
def update_cost_center(docname, cost_center_name, cost_center_number, company):
|
||||||
'''
|
'''
|
||||||
doctype_name = Name of the DocType
|
|
||||||
name = Docname being referred
|
|
||||||
field_name = Name of the field thats holding the 'number' attribute
|
|
||||||
number_value = Numeric value entered in field_name
|
|
||||||
|
|
||||||
Stores the number entered in the dialog to the DocType's field.
|
|
||||||
|
|
||||||
Renames the document by adding the number as a prefix to the current name and updates
|
Renames the document by adding the number as a prefix to the current name and updates
|
||||||
all transaction where it was present.
|
all transaction where it was present.
|
||||||
'''
|
'''
|
||||||
doc_title = frappe.db.get_value(doctype_name, name, frappe.scrub(doctype_name)+"_name")
|
validate_field_number("Cost Center", docname, cost_center_number, company, "cost_center_number")
|
||||||
|
|
||||||
validate_field_number(doctype_name, name, number_value, company, field_name)
|
if cost_center_number:
|
||||||
|
frappe.db.set_value("Cost Center", docname, "cost_center_number", cost_center_number.strip())
|
||||||
|
else:
|
||||||
|
frappe.db.set_value("Cost Center", docname, "cost_center_number", "")
|
||||||
|
|
||||||
frappe.db.set_value(doctype_name, name, field_name, number_value)
|
frappe.db.set_value("Cost Center", docname, "cost_center_name", cost_center_name.strip())
|
||||||
|
|
||||||
if doc_title[0].isdigit():
|
new_name = get_autoname_with_number(cost_center_number, cost_center_name, docname, company)
|
||||||
separator = " - " if " - " in doc_title else " "
|
if docname != new_name:
|
||||||
doc_title = doc_title.split(separator, 1)[1]
|
frappe.rename_doc("Cost Center", docname, new_name, force=1)
|
||||||
|
|
||||||
frappe.db.set_value(doctype_name, name, frappe.scrub(doctype_name)+"_name", doc_title)
|
|
||||||
|
|
||||||
new_name = get_autoname_with_number(number_value, doc_title, name, company)
|
|
||||||
|
|
||||||
if name != new_name:
|
|
||||||
frappe.rename_doc(doctype_name, name, new_name)
|
|
||||||
return new_name
|
return new_name
|
||||||
|
|
||||||
def validate_field_number(doctype_name, name, number_value, company, field_name):
|
def validate_field_number(doctype_name, docname, number_value, company, field_name):
|
||||||
''' Validate if the number entered isn't already assigned to some other document. '''
|
''' Validate if the number entered isn't already assigned to some other document. '''
|
||||||
if number_value:
|
if number_value:
|
||||||
|
filters = {field_name: number_value, "name": ["!=", docname]}
|
||||||
if company:
|
if company:
|
||||||
doctype_with_same_number = frappe.db.get_value(doctype_name,
|
filters["company"] = company
|
||||||
{field_name: number_value, "company": company, "name": ["!=", name]})
|
|
||||||
else:
|
doctype_with_same_number = frappe.db.get_value(doctype_name, filters)
|
||||||
doctype_with_same_number = frappe.db.get_value(doctype_name,
|
|
||||||
{field_name: number_value, "name": ["!=", name]})
|
|
||||||
if doctype_with_same_number:
|
if doctype_with_same_number:
|
||||||
frappe.throw(_("{0} Number {1} already used in account {2}")
|
frappe.throw(_("{0} Number {1} is already used in {2} {3}")
|
||||||
.format(doctype_name, number_value, doctype_with_same_number))
|
.format(doctype_name, number_value, doctype_name.lower(), doctype_with_same_number))
|
||||||
|
|
||||||
def get_autoname_with_number(number_value, doc_title, name, company):
|
def get_autoname_with_number(number_value, doc_title, name, company):
|
||||||
''' append title with prefix as number and suffix as company's abbreviation separated by '-' '''
|
''' append title with prefix as number and suffix as company's abbreviation separated by '-' '''
|
||||||
@ -897,4 +886,60 @@ def get_stock_accounts(company):
|
|||||||
return frappe.get_all("Account", filters = {
|
return frappe.get_all("Account", filters = {
|
||||||
"account_type": "Stock",
|
"account_type": "Stock",
|
||||||
"company": company
|
"company": company
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||||
|
warehouse_account=None, company=None):
|
||||||
|
def _delete_gl_entries(voucher_type, voucher_no):
|
||||||
|
frappe.db.sql("""delete from `tabGL Entry`
|
||||||
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
|
if not warehouse_account:
|
||||||
|
warehouse_account = get_warehouse_account_map(company)
|
||||||
|
|
||||||
|
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
||||||
|
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
||||||
|
|
||||||
|
for voucher_type, voucher_no in future_stock_vouchers:
|
||||||
|
existing_gle = gle.get((voucher_type, voucher_no), [])
|
||||||
|
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
||||||
|
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
||||||
|
if expected_gle:
|
||||||
|
if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
|
||||||
|
_delete_gl_entries(voucher_type, voucher_no)
|
||||||
|
voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True)
|
||||||
|
else:
|
||||||
|
_delete_gl_entries(voucher_type, voucher_no)
|
||||||
|
|
||||||
|
def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
|
||||||
|
future_stock_vouchers = []
|
||||||
|
|
||||||
|
values = []
|
||||||
|
condition = ""
|
||||||
|
if for_items:
|
||||||
|
condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
|
||||||
|
values += for_items
|
||||||
|
|
||||||
|
if for_warehouses:
|
||||||
|
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
|
||||||
|
values += for_warehouses
|
||||||
|
|
||||||
|
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||||
|
from `tabStock Ledger Entry` sle
|
||||||
|
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
|
||||||
|
order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
|
||||||
|
tuple([posting_date, posting_time] + values), as_dict=True):
|
||||||
|
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
||||||
|
|
||||||
|
return future_stock_vouchers
|
||||||
|
|
||||||
|
def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
|
||||||
|
gl_entries = {}
|
||||||
|
if future_stock_vouchers:
|
||||||
|
for d in frappe.db.sql("""select * from `tabGL Entry`
|
||||||
|
where posting_date >= %s and voucher_no in (%s)""" %
|
||||||
|
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
|
||||||
|
tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
|
||||||
|
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
||||||
|
|
||||||
|
return gl_entries
|
||||||
@ -11,7 +11,7 @@ from frappe.model.document import Document
|
|||||||
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
||||||
from erpnext.assets.doctype.asset.depreciation \
|
from erpnext.assets.doctype.asset.depreciation \
|
||||||
import get_disposal_account_and_cost_center, get_depreciation_accounts
|
import get_disposal_account_and_cost_center, get_depreciation_accounts
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
|
|
||||||
@ -41,7 +41,8 @@ class Asset(AccountsController):
|
|||||||
self.validate_cancellation()
|
self.validate_cancellation()
|
||||||
self.delete_depreciation_entries()
|
self.delete_depreciation_entries()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
delete_gl_entries(voucher_type='Asset', voucher_no=self.name)
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
|
make_reverse_gl_entries(voucher_type='Asset', voucher_no=self.name)
|
||||||
self.db_set('booked_fixed_asset', 0)
|
self.db_set('booked_fixed_asset', 0)
|
||||||
|
|
||||||
def validate_asset_and_reference(self):
|
def validate_asset_and_reference(self):
|
||||||
|
|||||||
@ -66,9 +66,6 @@ class TestAsset(unittest.TestCase):
|
|||||||
pr.cancel()
|
pr.cancel()
|
||||||
self.assertEqual(asset.docstatus, 2)
|
self.assertEqual(asset.docstatus, 2)
|
||||||
|
|
||||||
self.assertFalse(frappe.db.get_value("GL Entry",
|
|
||||||
{"voucher_type": "Purchase Invoice", "voucher_no": pi.name}))
|
|
||||||
|
|
||||||
def test_is_fixed_asset_set(self):
|
def test_is_fixed_asset_set(self):
|
||||||
asset = create_asset(is_existing_asset = 1)
|
asset = create_asset(is_existing_asset = 1)
|
||||||
doc = frappe.new_doc('Purchase Invoice')
|
doc = frappe.new_doc('Purchase Invoice')
|
||||||
|
|||||||
@ -27,15 +27,6 @@ frappe.ui.form.on("Purchase Order", {
|
|||||||
frm.set_indicator_formatter('item_code',
|
frm.set_indicator_formatter('item_code',
|
||||||
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
||||||
|
|
||||||
frm.set_query("blanket_order", "items", function() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
"company": frm.doc.company,
|
|
||||||
"docstatus": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
frm.set_query("expense_account", "items", function() {
|
frm.set_query("expense_account", "items", function() {
|
||||||
return {
|
return {
|
||||||
query: "erpnext.controllers.queries.get_expense_account",
|
query: "erpnext.controllers.queries.get_expense_account",
|
||||||
@ -365,9 +356,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
||||||
source_doctype: "Material Request",
|
source_doctype: "Material Request",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {},
|
||||||
company: me.frm.doc.company
|
|
||||||
},
|
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
@ -384,7 +373,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
source_doctype: "Supplier Quotation",
|
source_doctype: "Supplier Quotation",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company
|
supplier: me.frm.doc.supplier
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
|
|||||||
@ -54,11 +54,6 @@
|
|||||||
"items_section",
|
"items_section",
|
||||||
"scan_barcode",
|
"scan_barcode",
|
||||||
"items",
|
"items",
|
||||||
"section_break_48",
|
|
||||||
"pricing_rules",
|
|
||||||
"raw_material_details",
|
|
||||||
"set_reserve_warehouse",
|
|
||||||
"supplied_items",
|
|
||||||
"sb_last_purchase",
|
"sb_last_purchase",
|
||||||
"total_qty",
|
"total_qty",
|
||||||
"base_total",
|
"base_total",
|
||||||
@ -67,6 +62,11 @@
|
|||||||
"total_net_weight",
|
"total_net_weight",
|
||||||
"total",
|
"total",
|
||||||
"net_total",
|
"net_total",
|
||||||
|
"section_break_48",
|
||||||
|
"pricing_rules",
|
||||||
|
"raw_material_details",
|
||||||
|
"set_reserve_warehouse",
|
||||||
|
"supplied_items",
|
||||||
"taxes_section",
|
"taxes_section",
|
||||||
"tax_category",
|
"tax_category",
|
||||||
"column_break_50",
|
"column_break_50",
|
||||||
@ -105,23 +105,25 @@
|
|||||||
"payment_schedule_section",
|
"payment_schedule_section",
|
||||||
"payment_terms_template",
|
"payment_terms_template",
|
||||||
"payment_schedule",
|
"payment_schedule",
|
||||||
|
"tracking_section",
|
||||||
|
"per_billed",
|
||||||
|
"column_break_75",
|
||||||
|
"per_received",
|
||||||
"terms_section_break",
|
"terms_section_break",
|
||||||
"tc_name",
|
"tc_name",
|
||||||
"terms",
|
"terms",
|
||||||
"more_info",
|
"more_info",
|
||||||
"status",
|
"status",
|
||||||
"ref_sq",
|
"ref_sq",
|
||||||
|
"column_break_74",
|
||||||
"party_account_currency",
|
"party_account_currency",
|
||||||
"inter_company_order_reference",
|
"inter_company_order_reference",
|
||||||
"column_break_74",
|
|
||||||
"per_received",
|
|
||||||
"per_billed",
|
|
||||||
"column_break5",
|
"column_break5",
|
||||||
"letter_head",
|
"letter_head",
|
||||||
"select_print_heading",
|
"select_print_heading",
|
||||||
"column_break_86",
|
"column_break_86",
|
||||||
"group_same_items",
|
|
||||||
"language",
|
"language",
|
||||||
|
"group_same_items",
|
||||||
"subscription_section",
|
"subscription_section",
|
||||||
"from_date",
|
"from_date",
|
||||||
"to_date",
|
"to_date",
|
||||||
@ -220,7 +222,7 @@
|
|||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "schedule_date",
|
"fieldname": "schedule_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Reqd By Date"
|
"label": "Required By"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
@ -432,6 +434,7 @@
|
|||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "Sets 'Warehouse' in each row of the Items table.",
|
||||||
"fieldname": "set_warehouse",
|
"fieldname": "set_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Set Target Warehouse",
|
"label": "Set Target Warehouse",
|
||||||
@ -827,6 +830,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"collapsible": 1,
|
||||||
"fieldname": "payment_schedule_section",
|
"fieldname": "payment_schedule_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Payment Terms"
|
"label": "Payment Terms"
|
||||||
@ -917,7 +921,8 @@
|
|||||||
"fieldname": "inter_company_order_reference",
|
"fieldname": "inter_company_order_reference",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Inter Company Order Reference",
|
"label": "Inter Company Order Reference",
|
||||||
"options": "Sales Order"
|
"options": "Sales Order",
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_74",
|
"fieldname": "column_break_74",
|
||||||
@ -930,8 +935,6 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "% Received",
|
"label": "% Received",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "per_received",
|
|
||||||
"oldfieldtype": "Currency",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -942,8 +945,6 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "% Billed",
|
"label": "% Billed",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "per_billed",
|
|
||||||
"oldfieldtype": "Currency",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -998,6 +999,7 @@
|
|||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"collapsible": 1,
|
||||||
"fieldname": "subscription_section",
|
"fieldname": "subscription_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Subscription Section"
|
"label": "Subscription Section"
|
||||||
@ -1050,13 +1052,23 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Set Reserve Warehouse",
|
"label": "Set Reserve Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "tracking_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Tracking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_75",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-17 13:04:28.185197",
|
"modified": "2020-04-24 12:13:14.186280",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
|||||||
@ -18,10 +18,6 @@
|
|||||||
"col_break1",
|
"col_break1",
|
||||||
"image",
|
"image",
|
||||||
"image_view",
|
"image_view",
|
||||||
"manufacture_details",
|
|
||||||
"manufacturer",
|
|
||||||
"column_break_14",
|
|
||||||
"manufacturer_part_no",
|
|
||||||
"quantity_and_rate",
|
"quantity_and_rate",
|
||||||
"qty",
|
"qty",
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
@ -44,7 +40,6 @@
|
|||||||
"base_amount",
|
"base_amount",
|
||||||
"pricing_rules",
|
"pricing_rules",
|
||||||
"is_free_item",
|
"is_free_item",
|
||||||
"is_fixed_asset",
|
|
||||||
"section_break_29",
|
"section_break_29",
|
||||||
"net_rate",
|
"net_rate",
|
||||||
"net_amount",
|
"net_amount",
|
||||||
@ -52,11 +47,6 @@
|
|||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
"billed_amt",
|
"billed_amt",
|
||||||
"item_weight_details",
|
|
||||||
"weight_per_unit",
|
|
||||||
"total_weight",
|
|
||||||
"column_break_40",
|
|
||||||
"weight_uom",
|
|
||||||
"warehouse_and_reference",
|
"warehouse_and_reference",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"delivered_by_supplier",
|
"delivered_by_supplier",
|
||||||
@ -80,20 +70,31 @@
|
|||||||
"column_break_60",
|
"column_break_60",
|
||||||
"received_qty",
|
"received_qty",
|
||||||
"returned_qty",
|
"returned_qty",
|
||||||
|
"manufacture_details",
|
||||||
|
"manufacturer",
|
||||||
|
"column_break_14",
|
||||||
|
"manufacturer_part_no",
|
||||||
|
"more_info_section_break",
|
||||||
|
"is_fixed_asset",
|
||||||
|
"item_tax_rate",
|
||||||
"accounting_details",
|
"accounting_details",
|
||||||
"expense_account",
|
"expense_account",
|
||||||
"column_break_68",
|
"column_break_68",
|
||||||
|
"item_weight_details",
|
||||||
|
"weight_per_unit",
|
||||||
|
"total_weight",
|
||||||
|
"column_break_40",
|
||||||
|
"weight_uom",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
"section_break_72",
|
"section_break_72",
|
||||||
"page_break",
|
"page_break"
|
||||||
"item_tax_rate"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"columns": 3,
|
"columns": 2,
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@ -133,7 +134,7 @@
|
|||||||
"fieldname": "schedule_date",
|
"fieldname": "schedule_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Reqd By Date",
|
"label": "Required By",
|
||||||
"oldfieldname": "schedule_date",
|
"oldfieldname": "schedule_date",
|
||||||
"oldfieldtype": "Date",
|
"oldfieldtype": "Date",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@ -216,15 +217,16 @@
|
|||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"columns": 1,
|
||||||
"fieldname": "uom",
|
"fieldname": "uom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
"label": "UOM",
|
"label": "UOM",
|
||||||
"oldfieldname": "uom",
|
"oldfieldname": "uom",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "UOM",
|
"options": "UOM",
|
||||||
"print_width": "100px",
|
"print_width": "100px",
|
||||||
"reqd": 1,
|
"reqd": 1
|
||||||
"width": "100px"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "conversion_factor",
|
"fieldname": "conversion_factor",
|
||||||
@ -685,6 +687,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"collapsible": 1,
|
||||||
"fieldname": "manufacture_details",
|
"fieldname": "manufacture_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Manufacture"
|
"label": "Manufacture"
|
||||||
@ -717,12 +720,17 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Fixed Asset",
|
"label": "Is Fixed Asset",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "more_info_section_break",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "More Information"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-07 18:35:17.558928",
|
"modified": "2020-04-21 11:55:58.643393",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
|||||||
@ -1,20 +1,26 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2013-02-22 01:27:42",
|
"creation": "2013-02-22 01:27:42",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"main_item_code",
|
"main_item_code",
|
||||||
"rm_item_code",
|
|
||||||
"required_qty",
|
|
||||||
"supplied_qty",
|
|
||||||
"rate",
|
|
||||||
"amount",
|
|
||||||
"column_break_6",
|
|
||||||
"bom_detail_no",
|
"bom_detail_no",
|
||||||
"reference_name",
|
|
||||||
"conversion_factor",
|
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
"reserve_warehouse"
|
"conversion_factor",
|
||||||
|
"column_break_6",
|
||||||
|
"rm_item_code",
|
||||||
|
"reference_name",
|
||||||
|
"reserve_warehouse",
|
||||||
|
"section_break2",
|
||||||
|
"rate",
|
||||||
|
"col_break2",
|
||||||
|
"amount",
|
||||||
|
"section_break1",
|
||||||
|
"required_qty",
|
||||||
|
"col_break1",
|
||||||
|
"supplied_qty"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -120,15 +126,34 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Supplied Qty",
|
"label": "Supplied Qty",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break1",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "col_break1",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break2",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "col_break2",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_toolbar": 1,
|
"hide_toolbar": 1,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-08-20 13:37:32.702068",
|
"links": [],
|
||||||
|
"modified": "2020-03-12 15:43:53.862897",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item Supplied",
|
"name": "Purchase Order Item Supplied",
|
||||||
"owner": "dhanalekshmi@webnotestech.com",
|
"owner": "dhanalekshmi@webnotestech.com",
|
||||||
"permissions": []
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
}
|
}
|
||||||
@ -23,15 +23,11 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Payments'),
|
'label': _('Payments'),
|
||||||
'items': ['Payment Entry']
|
'items': ['Payment Entry', 'Bank Account']
|
||||||
},
|
|
||||||
{
|
|
||||||
'label': _('Bank'),
|
|
||||||
'items': ['Bank Account']
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Pricing'),
|
'label': _('Pricing'),
|
||||||
'items': ['Pricing Rule']
|
'items': ['Pricing Rule']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,19 +141,18 @@ def get_conditions(filters):
|
|||||||
conditions = ""
|
conditions = ""
|
||||||
|
|
||||||
if filters.get("company"):
|
if filters.get("company"):
|
||||||
conditions += " AND company=%s"% frappe.db.escape(filters.get('company'))
|
conditions += " AND par.company=%s" % frappe.db.escape(filters.get('company'))
|
||||||
|
|
||||||
if filters.get("cost_center") or filters.get("project"):
|
if filters.get("cost_center") or filters.get("project"):
|
||||||
conditions += """
|
conditions += """
|
||||||
AND (cost_center=%s
|
AND (child.`cost_center`=%s OR child.`project`=%s)
|
||||||
OR project=%s)
|
""" % (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
|
||||||
"""% (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
|
|
||||||
|
|
||||||
if filters.get("from_date"):
|
if filters.get("from_date"):
|
||||||
conditions += " AND transaction_date>=%s"% filters.get('from_date')
|
conditions += " AND par.transaction_date>='%s'" % filters.get('from_date')
|
||||||
|
|
||||||
if filters.get("to_date"):
|
if filters.get("to_date"):
|
||||||
conditions += " AND transaction_date<=%s"% filters.get('to_date')
|
conditions += " AND par.transaction_date<='%s'" % filters.get('to_date')
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
@ -162,7 +161,6 @@ def get_data(filters):
|
|||||||
mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions)
|
mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions)
|
||||||
pr_records = get_mapped_pr_records()
|
pr_records = get_mapped_pr_records()
|
||||||
pi_records = get_mapped_pi_records()
|
pi_records = get_mapped_pi_records()
|
||||||
print(pi_records)
|
|
||||||
|
|
||||||
procurement_record=[]
|
procurement_record=[]
|
||||||
if procurement_record_against_mr:
|
if procurement_record_against_mr:
|
||||||
@ -198,16 +196,16 @@ def get_mapped_mr_details(conditions):
|
|||||||
mr_records = {}
|
mr_records = {}
|
||||||
mr_details = frappe.db.sql("""
|
mr_details = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
mr.transaction_date,
|
par.transaction_date,
|
||||||
mr.per_ordered,
|
par.per_ordered,
|
||||||
mr_item.name,
|
child.name,
|
||||||
mr_item.parent,
|
child.parent,
|
||||||
mr_item.amount
|
child.amount
|
||||||
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
|
FROM `tabMaterial Request` par, `tabMaterial Request Item` child
|
||||||
WHERE
|
WHERE
|
||||||
mr.per_ordered>=0
|
par.per_ordered>=0
|
||||||
AND mr.name=mr_item.parent
|
AND par.name=child.parent
|
||||||
AND mr.docstatus=1
|
AND par.docstatus=1
|
||||||
{conditions}
|
{conditions}
|
||||||
""".format(conditions=conditions), as_dict=1) #nosec
|
""".format(conditions=conditions), as_dict=1) #nosec
|
||||||
|
|
||||||
@ -254,29 +252,29 @@ def get_mapped_pr_records():
|
|||||||
def get_po_entries(conditions):
|
def get_po_entries(conditions):
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
po_item.name,
|
child.name,
|
||||||
po_item.parent,
|
child.parent,
|
||||||
po_item.cost_center,
|
child.cost_center,
|
||||||
po_item.project,
|
child.project,
|
||||||
po_item.warehouse,
|
child.warehouse,
|
||||||
po_item.material_request,
|
child.material_request,
|
||||||
po_item.material_request_item,
|
child.material_request_item,
|
||||||
po_item.description,
|
child.description,
|
||||||
po_item.stock_uom,
|
child.stock_uom,
|
||||||
po_item.qty,
|
child.qty,
|
||||||
po_item.amount,
|
child.amount,
|
||||||
po_item.base_amount,
|
child.base_amount,
|
||||||
po_item.schedule_date,
|
child.schedule_date,
|
||||||
po.transaction_date,
|
par.transaction_date,
|
||||||
po.supplier,
|
par.supplier,
|
||||||
po.status,
|
par.status,
|
||||||
po.owner
|
par.owner
|
||||||
FROM `tabPurchase Order` po, `tabPurchase Order Item` po_item
|
FROM `tabPurchase Order` par, `tabPurchase Order Item` child
|
||||||
WHERE
|
WHERE
|
||||||
po.docstatus = 1
|
par.docstatus = 1
|
||||||
AND po.name = po_item.parent
|
AND par.name = child.parent
|
||||||
AND po.status not in ("Closed","Completed","Cancelled")
|
AND par.status not in ("Closed","Completed","Cancelled")
|
||||||
{conditions}
|
{conditions}
|
||||||
GROUP BY
|
GROUP BY
|
||||||
po.name,po_item.item_code
|
par.name, child.item_code
|
||||||
""".format(conditions=conditions), as_dict=1) #nosec
|
""".format(conditions=conditions), as_dict=1) #nosec
|
||||||
@ -170,6 +170,10 @@ def get_data():
|
|||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Payroll Period",
|
"name": "Payroll Period",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Income Tax Slab",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Salary Component",
|
"name": "Salary Component",
|
||||||
@ -209,6 +213,10 @@ def get_data():
|
|||||||
"name": "Employee Tax Exemption Proof Submission",
|
"name": "Employee Tax Exemption Proof Submission",
|
||||||
"dependencies": ["Employee"]
|
"dependencies": ["Employee"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Employee Other Income",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Employee Benefit Application",
|
"name": "Employee Benefit Application",
|
||||||
|
|||||||
@ -664,23 +664,26 @@ class AccountsController(TransactionBase):
|
|||||||
def set_total_advance_paid(self):
|
def set_total_advance_paid(self):
|
||||||
if self.doctype == "Sales Order":
|
if self.doctype == "Sales Order":
|
||||||
dr_or_cr = "credit_in_account_currency"
|
dr_or_cr = "credit_in_account_currency"
|
||||||
|
rev_dr_or_cr = "debit_in_account_currency"
|
||||||
party = self.customer
|
party = self.customer
|
||||||
else:
|
else:
|
||||||
dr_or_cr = "debit_in_account_currency"
|
dr_or_cr = "debit_in_account_currency"
|
||||||
|
rev_dr_or_cr = "credit_in_account_currency"
|
||||||
party = self.supplier
|
party = self.supplier
|
||||||
|
|
||||||
advance = frappe.db.sql("""
|
advance = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
account_currency, sum({dr_or_cr}) as amount
|
account_currency, sum({dr_or_cr}) - sum({rev_dr_cr}) as amount
|
||||||
from
|
from
|
||||||
`tabGL Entry`
|
`tabGL Entry`
|
||||||
where
|
where
|
||||||
against_voucher_type = %s and against_voucher = %s and party=%s
|
against_voucher_type = %s and against_voucher = %s and party=%s
|
||||||
and docstatus = 1
|
and docstatus = 1
|
||||||
""".format(dr_or_cr=dr_or_cr), (self.doctype, self.name, party), as_dict=1)
|
""".format(dr_or_cr=dr_or_cr, rev_dr_cr=rev_dr_or_cr), (self.doctype, self.name, party), as_dict=1) #nosec
|
||||||
|
|
||||||
if advance:
|
if advance:
|
||||||
advance = advance[0]
|
advance = advance[0]
|
||||||
|
|
||||||
advance_paid = flt(advance.amount, self.precision("advance_paid"))
|
advance_paid = flt(advance.amount, self.precision("advance_paid"))
|
||||||
formatted_advance_paid = fmt_money(advance_paid, precision=self.precision("advance_paid"),
|
formatted_advance_paid = fmt_money(advance_paid, precision=self.precision("advance_paid"),
|
||||||
currency=advance.account_currency)
|
currency=advance.account_currency)
|
||||||
|
|||||||
@ -371,6 +371,19 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
fields = ["name", "parent_account"],
|
fields = ["name", "parent_account"],
|
||||||
limit_start=start, limit_page_length=page_len, as_list=True)
|
limit_start=start, limit_page_length=page_len, as_list=True)
|
||||||
|
|
||||||
|
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
|
||||||
|
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
|
||||||
|
where
|
||||||
|
boi.parent = bo.name
|
||||||
|
and boi.item_code = {item_code}
|
||||||
|
and bo.blanket_order_type = '{blanket_order_type}'
|
||||||
|
and bo.company = {company}
|
||||||
|
and bo.docstatus = 1"""
|
||||||
|
.format(item_code = frappe.db.escape(filters.get("item")),
|
||||||
|
blanket_order_type = filters.get("blanket_order_type"),
|
||||||
|
company = frappe.db.escape(filters.get("company"))
|
||||||
|
))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
|||||||
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, flt, cstr
|
from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate
|
||||||
from frappe import _
|
from frappe import _
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries, process_gl_map
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
from erpnext.stock import get_warehouse_account_map
|
from erpnext.stock import get_warehouse_account_map
|
||||||
@ -23,9 +23,9 @@ class StockController(AccountsController):
|
|||||||
self.validate_serialized_batch()
|
self.validate_serialized_batch()
|
||||||
self.validate_customer_provided_item()
|
self.validate_customer_provided_item()
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
def make_gl_entries(self, gl_entries=None):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
if cint(erpnext.is_perpetual_inventory_enabled(self.company)):
|
if cint(erpnext.is_perpetual_inventory_enabled(self.company)):
|
||||||
warehouse_account = get_warehouse_account_map(self.company)
|
warehouse_account = get_warehouse_account_map(self.company)
|
||||||
@ -33,16 +33,12 @@ class StockController(AccountsController):
|
|||||||
if self.docstatus==1:
|
if self.docstatus==1:
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
gl_entries = self.get_gl_entries(warehouse_account)
|
gl_entries = self.get_gl_entries(warehouse_account)
|
||||||
make_gl_entries(gl_entries, from_repost=from_repost)
|
make_gl_entries(gl_entries)
|
||||||
|
|
||||||
if (repost_future_gle or self.flags.repost_future_gle):
|
|
||||||
items, warehouses = self.get_items_and_warehouses()
|
|
||||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
|
|
||||||
warehouse_account, company=self.company)
|
|
||||||
elif self.doctype in ['Purchase Receipt', 'Purchase Invoice'] and self.docstatus == 1:
|
elif self.doctype in ['Purchase Receipt', 'Purchase Invoice'] and self.docstatus == 1:
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
gl_entries = self.get_asset_gl_entry(gl_entries)
|
gl_entries = self.get_asset_gl_entry(gl_entries)
|
||||||
make_gl_entries(gl_entries, from_repost=from_repost)
|
make_gl_entries(gl_entries)
|
||||||
|
|
||||||
def validate_serialized_batch(self):
|
def validate_serialized_batch(self):
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
@ -55,6 +51,13 @@ class StockController(AccountsController):
|
|||||||
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
||||||
.format(d.idx, serial_no_data.name, d.batch_no))
|
.format(d.idx, serial_no_data.name, d.batch_no))
|
||||||
|
|
||||||
|
if d.qty > 0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
|
||||||
|
expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
|
||||||
|
|
||||||
|
if expiry_date and getdate(expiry_date) < getdate(self.posting_date):
|
||||||
|
frappe.throw(_("Row #{0}: The batch {1} has already expired.")
|
||||||
|
.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
||||||
default_cost_center=None):
|
default_cost_center=None):
|
||||||
|
|
||||||
@ -267,21 +270,21 @@ class StockController(AccountsController):
|
|||||||
"batch_no": cstr(d.get("batch_no")).strip(),
|
"batch_no": cstr(d.get("batch_no")).strip(),
|
||||||
"serial_no": d.get("serial_no"),
|
"serial_no": d.get("serial_no"),
|
||||||
"project": d.get("project") or self.get('project'),
|
"project": d.get("project") or self.get('project'),
|
||||||
"is_cancelled": self.docstatus==2 and "Yes" or "No"
|
"is_cancelled": 1 if self.docstatus==2 else 0
|
||||||
})
|
})
|
||||||
|
|
||||||
sl_dict.update(args)
|
sl_dict.update(args)
|
||||||
return sl_dict
|
return sl_dict
|
||||||
|
|
||||||
def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False,
|
def make_sl_entries(self, sl_entries, allow_negative_stock=False,
|
||||||
via_landed_cost_voucher=False):
|
via_landed_cost_voucher=False):
|
||||||
from erpnext.stock.stock_ledger import make_sl_entries
|
from erpnext.stock.stock_ledger import make_sl_entries
|
||||||
make_sl_entries(sl_entries, is_amended, allow_negative_stock, via_landed_cost_voucher)
|
make_sl_entries(sl_entries, allow_negative_stock, via_landed_cost_voucher)
|
||||||
|
|
||||||
def make_gl_entries_on_cancel(self, repost_future_gle=True):
|
def make_gl_entries_on_cancel(self):
|
||||||
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
|
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
|
||||||
and voucher_no=%s""", (self.doctype, self.name)):
|
and voucher_no=%s""", (self.doctype, self.name)):
|
||||||
self.make_gl_entries(repost_future_gle=repost_future_gle)
|
self.make_gl_entries()
|
||||||
|
|
||||||
def get_serialized_items(self):
|
def get_serialized_items(self):
|
||||||
serialized_items = []
|
serialized_items = []
|
||||||
@ -384,29 +387,6 @@ class StockController(AccountsController):
|
|||||||
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
|
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
|
||||||
d.allow_zero_valuation_rate = 1
|
d.allow_zero_valuation_rate = 1
|
||||||
|
|
||||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
|
||||||
warehouse_account=None, company=None):
|
|
||||||
def _delete_gl_entries(voucher_type, voucher_no):
|
|
||||||
frappe.db.sql("""delete from `tabGL Entry`
|
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
|
||||||
|
|
||||||
if not warehouse_account:
|
|
||||||
warehouse_account = get_warehouse_account_map(company)
|
|
||||||
|
|
||||||
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
|
||||||
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
|
||||||
|
|
||||||
for voucher_type, voucher_no in future_stock_vouchers:
|
|
||||||
existing_gle = gle.get((voucher_type, voucher_no), [])
|
|
||||||
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
|
||||||
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
|
||||||
if expected_gle:
|
|
||||||
if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
|
|
||||||
_delete_gl_entries(voucher_type, voucher_no)
|
|
||||||
voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True)
|
|
||||||
else:
|
|
||||||
_delete_gl_entries(voucher_type, voucher_no)
|
|
||||||
|
|
||||||
def compare_existing_and_expected_gle(existing_gle, expected_gle):
|
def compare_existing_and_expected_gle(existing_gle, expected_gle):
|
||||||
matched = True
|
matched = True
|
||||||
for entry in expected_gle:
|
for entry in expected_gle:
|
||||||
@ -423,36 +403,3 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle):
|
|||||||
matched = False
|
matched = False
|
||||||
break
|
break
|
||||||
return matched
|
return matched
|
||||||
|
|
||||||
def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
|
|
||||||
future_stock_vouchers = []
|
|
||||||
|
|
||||||
values = []
|
|
||||||
condition = ""
|
|
||||||
if for_items:
|
|
||||||
condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
|
|
||||||
values += for_items
|
|
||||||
|
|
||||||
if for_warehouses:
|
|
||||||
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
|
|
||||||
values += for_warehouses
|
|
||||||
|
|
||||||
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
|
||||||
from `tabStock Ledger Entry` sle
|
|
||||||
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
|
|
||||||
order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
|
|
||||||
tuple([posting_date, posting_time] + values), as_dict=True):
|
|
||||||
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
|
||||||
|
|
||||||
return future_stock_vouchers
|
|
||||||
|
|
||||||
def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
|
|
||||||
gl_entries = {}
|
|
||||||
if future_stock_vouchers:
|
|
||||||
for d in frappe.db.sql("""select * from `tabGL Entry`
|
|
||||||
where posting_date >= %s and voucher_no in (%s)""" %
|
|
||||||
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
|
|
||||||
tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
|
|
||||||
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
|
||||||
|
|
||||||
return gl_entries
|
|
||||||
|
|||||||
@ -12,13 +12,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Settings",
|
"label": "Maintenance",
|
||||||
"links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]"
|
"links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Maintenance",
|
"label": "Campaign",
|
||||||
"links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
|
"links": "[\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create and Schedule social media posts\",\n \"label\": \"Social Media Post\",\n \"name\": \"Social Media Post\",\n \"type\": \"doctype\"\n }\n]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Settings",
|
||||||
|
"links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Twitter Settings\",\n \"name\": \"Twitter Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"LinkedIn Settings\",\n \"name\": \"LinkedIn Settings\",\n \"type\": \"doctype\"\n }\n]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
@ -33,7 +38,7 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "CRM",
|
"label": "CRM",
|
||||||
"modified": "2020-04-01 11:28:51.219999",
|
"modified": "2020-04-27 22:32:26.682911",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "CRM",
|
"name": "CRM",
|
||||||
@ -42,7 +47,7 @@
|
|||||||
"pin_to_top": 0,
|
"pin_to_top": 0,
|
||||||
"shortcuts": [
|
"shortcuts": [
|
||||||
{
|
{
|
||||||
"format": "Open",
|
"format": "{} Open",
|
||||||
"label": "Lead",
|
"label": "Lead",
|
||||||
"link_to": "Lead",
|
"link_to": "Lead",
|
||||||
"stats_filter": "{\"status\":\"Open\"}",
|
"stats_filter": "{\"status\":\"Open\"}",
|
||||||
|
|||||||
@ -16,23 +16,27 @@ frappe.ui.form.on('Twitter Settings', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
refresh: function(frm){
|
refresh: function(frm){
|
||||||
let msg,color;
|
let msg, color, flag=false;
|
||||||
if (frm.doc.session_status == "Active"){
|
if (frm.doc.session_status == "Active"){
|
||||||
msg = __("Session Active");
|
msg = __("Session Active");
|
||||||
color = 'green';
|
color = 'green';
|
||||||
|
flag = true;
|
||||||
}
|
}
|
||||||
else {
|
else if(frm.doc.consumer_key && frm.doc.consumer_secret) {
|
||||||
msg = __("Session Not Active. Save doc to login.");
|
msg = __("Session Not Active. Save doc to login.");
|
||||||
color = 'red';
|
color = 'red';
|
||||||
|
flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.dashboard.set_headline_alert(
|
if (flag){
|
||||||
`<div class="row">
|
frm.dashboard.set_headline_alert(
|
||||||
<div class="col-xs-12">
|
`<div class="row">
|
||||||
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
|
<div class="col-xs-12">
|
||||||
</div>
|
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
|
||||||
</div>`
|
</div>
|
||||||
);
|
</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
login: function(frm){
|
login: function(frm){
|
||||||
if (frm.doc.consumer_key && frm.doc.consumer_secret){
|
if (frm.doc.consumer_key && frm.doc.consumer_secret){
|
||||||
|
|||||||
24
erpnext/crm/utils.py
Normal file
24
erpnext/crm/utils.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def update_lead_phone_numbers(contact, method):
|
||||||
|
if contact.phone_nos:
|
||||||
|
contact_lead = contact.get_link_for("Lead")
|
||||||
|
if contact_lead:
|
||||||
|
phone = mobile_no = contact.phone_nos[0].phone
|
||||||
|
|
||||||
|
if len(contact.phone_nos) > 1:
|
||||||
|
# get the default phone number
|
||||||
|
primary_phones = [phone_doc.phone for phone_doc in contact.phone_nos if phone_doc.is_primary_phone]
|
||||||
|
if primary_phones:
|
||||||
|
phone = primary_phones[0]
|
||||||
|
|
||||||
|
# get the default mobile number
|
||||||
|
primary_mobile_nos = [phone_doc.phone for phone_doc in contact.phone_nos if phone_doc.is_primary_mobile_no]
|
||||||
|
if primary_mobile_nos:
|
||||||
|
mobile_no = primary_mobile_nos[0]
|
||||||
|
|
||||||
|
lead = frappe.get_doc("Lead", contact_lead)
|
||||||
|
lead.phone = phone
|
||||||
|
lead.mobile_no = mobile_no
|
||||||
|
lead.save()
|
||||||
@ -112,6 +112,8 @@ frappe.ui.form.on("Fees", {
|
|||||||
args: {
|
args: {
|
||||||
"dt": frm.doc.doctype,
|
"dt": frm.doc.doctype,
|
||||||
"dn": frm.doc.name,
|
"dn": frm.doc.name,
|
||||||
|
"party_type": "Student",
|
||||||
|
"party": frm.doc.student,
|
||||||
"recipient_id": frm.doc.student_email
|
"recipient_id": frm.doc.student_email
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from frappe.utils import money_in_words
|
|||||||
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
|
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
|
||||||
from frappe.utils.csvutils import getlink
|
from frappe.utils.csvutils import getlink
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.general_ledger import delete_gl_entries
|
from erpnext.accounts.general_ledger import make_reverse_gl_entries
|
||||||
|
|
||||||
|
|
||||||
class Fees(AccountsController):
|
class Fees(AccountsController):
|
||||||
@ -75,12 +75,14 @@ class Fees(AccountsController):
|
|||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
if self.send_payment_request and self.student_email:
|
if self.send_payment_request and self.student_email:
|
||||||
pr = make_payment_request(dt="Fees", dn=self.name, recipient_id=self.student_email,
|
pr = make_payment_request(party_type="Student", party=self.student, dt="Fees",
|
||||||
|
dn=self.name, recipient_id=self.student_email,
|
||||||
submit_doc=True, use_dummy_message=True)
|
submit_doc=True, use_dummy_message=True)
|
||||||
frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
|
frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
|
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name, cancel=True)
|
||||||
# frappe.db.set(self, 'status', 'Cancelled')
|
# frappe.db.set(self, 'status', 'Cancelled')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,9 @@ def get_data():
|
|||||||
'heatmap': True,
|
'heatmap': True,
|
||||||
'heatmap_message': _('This is based on the attendance of this Student'),
|
'heatmap_message': _('This is based on the attendance of this Student'),
|
||||||
'fieldname': 'student',
|
'fieldname': 'student',
|
||||||
|
'non_standard_fieldnames': {
|
||||||
|
'Bank Account': 'party'
|
||||||
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'label': _('Admission'),
|
'label': _('Admission'),
|
||||||
@ -29,7 +32,7 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Fee'),
|
'label': _('Fee'),
|
||||||
'items': ['Fees']
|
'items': ['Fees', 'Bank Account']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,6 +80,7 @@ frappe.ui.form.on('Clinical Procedure', {
|
|||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'complete_procedure',
|
method: 'complete_procedure',
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
|
freeze: true,
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
@ -87,8 +88,8 @@ frappe.ui.form.on('Clinical Procedure', {
|
|||||||
['<a class="bold" href="#Form/Stock Entry/'+ r.message + '">' + r.message + '</a>']),
|
['<a class="bold" href="#Form/Stock Entry/'+ r.message + '">' + r.message + '</a>']),
|
||||||
indicator: 'green'
|
indicator: 'green'
|
||||||
});
|
});
|
||||||
frm.reload_doc();
|
|
||||||
}
|
}
|
||||||
|
frm.reload_doc();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -111,9 +112,10 @@ frappe.ui.form.on('Clinical Procedure', {
|
|||||||
frappe.call({
|
frappe.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: 'make_material_receipt',
|
method: 'make_material_receipt',
|
||||||
|
freeze: true,
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (!r.exc) {
|
if (!r.exc) {
|
||||||
cur_frm.reload_doc();
|
frm.reload_doc();
|
||||||
let doclist = frappe.model.sync(r.message);
|
let doclist = frappe.model.sync(r.message);
|
||||||
frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
|
frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
|
||||||
}
|
}
|
||||||
@ -122,7 +124,7 @@ frappe.ui.form.on('Clinical Procedure', {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cur_frm.reload_doc();
|
frm.reload_doc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,7 +87,8 @@ class ClinicalProcedure(Document):
|
|||||||
else:
|
else:
|
||||||
frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found'))
|
frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found'))
|
||||||
|
|
||||||
frappe.db.set_value('Clinical Procedure', self.name, 'status', 'Completed')
|
self.db_set('status', 'Completed')
|
||||||
|
|
||||||
if self.consume_stock and self.items:
|
if self.consume_stock and self.items:
|
||||||
return stock_entry
|
return stock_entry
|
||||||
|
|
||||||
@ -245,9 +246,9 @@ def make_procedure(source_name, target_doc=None):
|
|||||||
|
|
||||||
|
|
||||||
def insert_clinical_procedure_to_medical_record(doc):
|
def insert_clinical_procedure_to_medical_record(doc):
|
||||||
subject = cstr(doc.procedure_template)
|
subject = frappe.bold(_("Clinical Procedure conducted: ")) + cstr(doc.procedure_template) + "<br>"
|
||||||
if doc.practitioner:
|
if doc.practitioner:
|
||||||
subject += ' ' + doc.practitioner
|
subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
|
||||||
if subject and doc.notes:
|
if subject and doc.notes:
|
||||||
subject += '<br/>' + doc.notes
|
subject += '<br/>' + doc.notes
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,8 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
|
|
||||||
this.exercise_cards = $('<div class="exercise-cards"></div>').appendTo(this.wrapper);
|
this.exercise_cards = $('<div class="exercise-cards"></div>').appendTo(this.wrapper);
|
||||||
|
|
||||||
|
this.row = $('<div class="exercise-row"></div>').appendTo(this.wrapper);
|
||||||
|
|
||||||
let me = this;
|
let me = this;
|
||||||
|
|
||||||
this.exercise_toolbar.find(".btn-add")
|
this.exercise_toolbar.find(".btn-add")
|
||||||
@ -32,7 +34,7 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
me.show_add_card_dialog(frm);
|
me.show_add_card_dialog(frm);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (frm.doc.steps_table.length > 0) {
|
if (frm.doc.steps_table && frm.doc.steps_table.length > 0) {
|
||||||
this.make_cards(frm);
|
this.make_cards(frm);
|
||||||
this.make_buttons(frm);
|
this.make_buttons(frm);
|
||||||
}
|
}
|
||||||
@ -41,7 +43,6 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
make_cards: function(frm) {
|
make_cards: function(frm) {
|
||||||
var me = this;
|
var me = this;
|
||||||
$(me.exercise_cards).empty();
|
$(me.exercise_cards).empty();
|
||||||
this.row = $('<div class="exercise-row"></div>').appendTo(me.exercise_cards);
|
|
||||||
|
|
||||||
$.each(frm.doc.steps_table, function(i, step) {
|
$.each(frm.doc.steps_table, function(i, step) {
|
||||||
$(repl(`
|
$(repl(`
|
||||||
@ -78,6 +79,7 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
frm.doc.steps_table.pop(id);
|
frm.doc.steps_table.pop(id);
|
||||||
frm.refresh_field('steps_table');
|
frm.refresh_field('steps_table');
|
||||||
$('#col-'+id).remove();
|
$('#col-'+id).remove();
|
||||||
|
frm.dirty();
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -106,7 +108,10 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
],
|
],
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
let data = d.get_values();
|
let data = d.get_values();
|
||||||
let i = frm.doc.steps_table.length;
|
let i = 0;
|
||||||
|
if (frm.doc.steps_table) {
|
||||||
|
i = frm.doc.steps_table.length;
|
||||||
|
}
|
||||||
$(repl(`
|
$(repl(`
|
||||||
<div class="exercise-col col-sm-4" id="%(col_id)s">
|
<div class="exercise-col col-sm-4" id="%(col_id)s">
|
||||||
<div class="card h-100 exercise-card" id="%(card_id)s">
|
<div class="card h-100 exercise-card" id="%(card_id)s">
|
||||||
@ -165,9 +170,10 @@ erpnext.ExerciseEditor = Class.extend({
|
|||||||
frm.doc.steps_table[id].image = data.image;
|
frm.doc.steps_table[id].image = data.image;
|
||||||
frm.doc.steps_table[id].description = data.step_description;
|
frm.doc.steps_table[id].description = data.step_description;
|
||||||
refresh_field('steps_table');
|
refresh_field('steps_table');
|
||||||
|
frm.dirty();
|
||||||
new_dialog.hide();
|
new_dialog.hide();
|
||||||
},
|
},
|
||||||
primary_action_label: __("Save"),
|
primary_action_label: __("Edit"),
|
||||||
});
|
});
|
||||||
|
|
||||||
new_dialog.set_values({
|
new_dialog.set_values({
|
||||||
|
|||||||
@ -288,23 +288,23 @@ def insert_lab_test_to_medical_record(doc):
|
|||||||
table_row = False
|
table_row = False
|
||||||
subject = cstr(doc.lab_test_name)
|
subject = cstr(doc.lab_test_name)
|
||||||
if doc.practitioner:
|
if doc.practitioner:
|
||||||
subject += " "+ doc.practitioner
|
subject += frappe.bold(_("Healthcare Practitioner: "))+ doc.practitioner + "<br>"
|
||||||
if doc.normal_test_items:
|
if doc.normal_test_items:
|
||||||
item = doc.normal_test_items[0]
|
item = doc.normal_test_items[0]
|
||||||
comment = ""
|
comment = ""
|
||||||
if item.lab_test_comment:
|
if item.lab_test_comment:
|
||||||
comment = str(item.lab_test_comment)
|
comment = str(item.lab_test_comment)
|
||||||
table_row = item.lab_test_name
|
table_row = frappe.bold(_("Lab Test Conducted: ")) + item.lab_test_name
|
||||||
|
|
||||||
if item.lab_test_event:
|
if item.lab_test_event:
|
||||||
table_row += " " + item.lab_test_event
|
table_row += frappe.bold(_("Lab Test Event: ")) + item.lab_test_event
|
||||||
|
|
||||||
if item.result_value:
|
if item.result_value:
|
||||||
table_row += " " + item.result_value
|
table_row += " " + frappe.bold(_("Lab Test Result: ")) + item.result_value
|
||||||
|
|
||||||
if item.normal_range:
|
if item.normal_range:
|
||||||
table_row += " normal_range("+item.normal_range+")"
|
table_row += " " + _("Normal Range:") + item.normal_range
|
||||||
table_row += " "+comment
|
table_row += " " + comment
|
||||||
|
|
||||||
elif doc.special_test_items:
|
elif doc.special_test_items:
|
||||||
item = doc.special_test_items[0]
|
item = doc.special_test_items[0]
|
||||||
@ -316,12 +316,12 @@ def insert_lab_test_to_medical_record(doc):
|
|||||||
item = doc.sensitivity_test_items[0]
|
item = doc.sensitivity_test_items[0]
|
||||||
|
|
||||||
if item.antibiotic and item.antibiotic_sensitivity:
|
if item.antibiotic and item.antibiotic_sensitivity:
|
||||||
table_row = item.antibiotic +" "+ item.antibiotic_sensitivity
|
table_row = item.antibiotic + " " + item.antibiotic_sensitivity
|
||||||
|
|
||||||
if table_row:
|
if table_row:
|
||||||
subject += "<br/>"+table_row
|
subject += "<br>" + table_row
|
||||||
if doc.lab_test_comment:
|
if doc.lab_test_comment:
|
||||||
subject += "<br/>"+ cstr(doc.lab_test_comment)
|
subject += "<br>" + cstr(doc.lab_test_comment)
|
||||||
|
|
||||||
medical_record = frappe.new_doc("Patient Medical Record")
|
medical_record = frappe.new_doc("Patient Medical Record")
|
||||||
medical_record.patient = doc.patient
|
medical_record.patient = doc.patient
|
||||||
|
|||||||
@ -18,6 +18,9 @@ class PatientEncounter(Document):
|
|||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
insert_encounter_to_medical_record(self)
|
insert_encounter_to_medical_record(self)
|
||||||
|
|
||||||
|
def on_submit(self):
|
||||||
|
update_encounter_medical_record(self)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
if self.appointment:
|
if self.appointment:
|
||||||
frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open')
|
frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open')
|
||||||
@ -66,22 +69,26 @@ def delete_medical_record(encounter):
|
|||||||
frappe.db.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name)
|
frappe.db.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name)
|
||||||
|
|
||||||
def set_subject_field(encounter):
|
def set_subject_field(encounter):
|
||||||
subject = encounter.practitioner + '\n'
|
subject = frappe.bold(_('Healthcare Practitioner: ')) + encounter.practitioner + '<br>'
|
||||||
if encounter.symptoms:
|
if encounter.symptoms:
|
||||||
subject += _('Symptoms: ') + cstr(encounter.symptoms) + '\n'
|
subject += frappe.bold(_('Symptoms: ')) + '<br>'
|
||||||
|
for entry in encounter.symptoms:
|
||||||
|
subject += cstr(entry.complaint) + '<br>'
|
||||||
else:
|
else:
|
||||||
subject += _('No Symptoms') + '\n'
|
subject += frappe.bold(_('No Symptoms')) + '<br>'
|
||||||
|
|
||||||
if encounter.diagnosis:
|
if encounter.diagnosis:
|
||||||
subject += _('Diagnosis: ') + cstr(encounter.diagnosis) + '\n'
|
subject += frappe.bold(_('Diagnosis: ')) + '<br>'
|
||||||
|
for entry in encounter.diagnosis:
|
||||||
|
subject += cstr(entry.diagnosis) + '<br>'
|
||||||
else:
|
else:
|
||||||
subject += _('No Diagnosis') + '\n'
|
subject += frappe.bold(_('No Diagnosis')) + '<br>'
|
||||||
|
|
||||||
if encounter.drug_prescription:
|
if encounter.drug_prescription:
|
||||||
subject += '\n' + _('Drug(s) Prescribed.')
|
subject += '<br>' + _('Drug(s) Prescribed.')
|
||||||
if encounter.lab_test_prescription:
|
if encounter.lab_test_prescription:
|
||||||
subject += '\n' + _('Test(s) Prescribed.')
|
subject += '<br>' + _('Test(s) Prescribed.')
|
||||||
if encounter.procedure_prescription:
|
if encounter.procedure_prescription:
|
||||||
subject += '\n' + _('Procedure(s) Prescribed.')
|
subject += '<br>' + _('Procedure(s) Prescribed.')
|
||||||
|
|
||||||
return subject
|
return subject
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "subject",
|
"fieldname": "subject",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Text Editor",
|
||||||
"ignore_xss_filter": 1,
|
"ignore_xss_filter": 1,
|
||||||
"label": "Subject"
|
"label": "Subject"
|
||||||
},
|
},
|
||||||
@ -125,7 +125,7 @@
|
|||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-23 19:26:59.308383",
|
"modified": "2020-04-29 12:26:57.679402",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Healthcare",
|
"module": "Healthcare",
|
||||||
"name": "Patient Medical Record",
|
"name": "Patient Medical Record",
|
||||||
|
|||||||
@ -21,8 +21,14 @@ class TherapyPlan(Document):
|
|||||||
self.status = 'Completed'
|
self.status = 'Completed'
|
||||||
|
|
||||||
def set_totals(self):
|
def set_totals(self):
|
||||||
total_sessions = sum([int(d.no_of_sessions) for d in self.get('therapy_plan_details')])
|
total_sessions = 0
|
||||||
total_sessions_completed = sum([int(d.sessions_completed) for d in self.get('therapy_plan_details')])
|
total_sessions_completed = 0
|
||||||
|
for entry in self.therapy_plan_details:
|
||||||
|
if entry.no_of_sessions:
|
||||||
|
total_sessions += entry.no_of_sessions
|
||||||
|
if entry.sessions_completed:
|
||||||
|
total_sessions_completed += entry.sessions_completed
|
||||||
|
|
||||||
self.db_set('total_sessions', total_sessions)
|
self.db_set('total_sessions', total_sessions)
|
||||||
self.db_set('total_sessions_completed', total_sessions_completed)
|
self.db_set('total_sessions_completed', total_sessions_completed)
|
||||||
|
|
||||||
|
|||||||
@ -13,23 +13,92 @@ frappe.ui.form.on('Therapy Session', {
|
|||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
if (!frm.doc.__islocal) {
|
if (!frm.doc.__islocal) {
|
||||||
let target = 0;
|
frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue');
|
||||||
let completed = 0;
|
frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]),
|
||||||
$.each(frm.doc.exercises, function(_i, e) {
|
(frm.doc.total_counts_completed < frm.doc.total_counts_targeted) ? 'orange' : 'green');
|
||||||
target += e.counts_target;
|
|
||||||
completed += e.counts_completed;
|
|
||||||
});
|
|
||||||
frm.dashboard.add_indicator(__('Counts Targetted: {0}', [target]), 'blue');
|
|
||||||
frm.dashboard.add_indicator(__('Counts Completed: {0}', [completed]), (completed < target) ? 'orange' : 'green');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.docstatus === 1) {
|
if (frm.doc.docstatus === 1) {
|
||||||
frm.add_custom_button(__('Patient Assessment'),function() {
|
frm.add_custom_button(__('Patient Assessment'), function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: 'erpnext.healthcare.doctype.patient_assessment.patient_assessment.create_patient_assessment',
|
method: 'erpnext.healthcare.doctype.patient_assessment.patient_assessment.create_patient_assessment',
|
||||||
frm: frm,
|
frm: frm,
|
||||||
})
|
})
|
||||||
}, 'Create');
|
}, 'Create');
|
||||||
|
|
||||||
|
frm.add_custom_button(__('Sales Invoice'), function() {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
|
||||||
|
frm: frm,
|
||||||
|
})
|
||||||
|
}, 'Create');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
patient: function(frm) {
|
||||||
|
if (frm.doc.patient) {
|
||||||
|
frappe.call({
|
||||||
|
'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
|
||||||
|
args: {
|
||||||
|
patient: frm.doc.patient
|
||||||
|
},
|
||||||
|
callback: function (data) {
|
||||||
|
let age = '';
|
||||||
|
if (data.message.dob) {
|
||||||
|
age = calculate_age(data.message.dob);
|
||||||
|
} else if (data.message.age) {
|
||||||
|
age = data.message.age;
|
||||||
|
if (data.message.age_as_on) {
|
||||||
|
age = __('{0} as on {1}', [age, data.message.age_as_on]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frm.set_value('patient_age', age);
|
||||||
|
frm.set_value('gender', data.message.sex);
|
||||||
|
frm.set_value('patient_name', data.message.patient_name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
frm.set_value('patient_age', '');
|
||||||
|
frm.set_value('gender', '');
|
||||||
|
frm.set_value('patient_name', '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
appointment: function(frm) {
|
||||||
|
if (frm.doc.appointment) {
|
||||||
|
frappe.call({
|
||||||
|
'method': 'frappe.client.get',
|
||||||
|
args: {
|
||||||
|
doctype: 'Patient Appointment',
|
||||||
|
name: frm.doc.appointment
|
||||||
|
},
|
||||||
|
callback: function(data) {
|
||||||
|
let values = {
|
||||||
|
'patient':data.message.patient,
|
||||||
|
'therapy_type': data.message.therapy_type,
|
||||||
|
'therapy_plan': data.message.therapy_plan,
|
||||||
|
'practitioner': data.message.practitioner,
|
||||||
|
'department': data.message.department,
|
||||||
|
'start_date': data.message.appointment_date,
|
||||||
|
'start_time': data.message.appointment_time,
|
||||||
|
'service_unit': data.message.service_unit,
|
||||||
|
'company': data.message.company
|
||||||
|
};
|
||||||
|
frm.set_value(values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let values = {
|
||||||
|
'patient': '',
|
||||||
|
'therapy_type': '',
|
||||||
|
'therapy_plan': '',
|
||||||
|
'practitioner': '',
|
||||||
|
'department': '',
|
||||||
|
'start_date': '',
|
||||||
|
'start_time': '',
|
||||||
|
'service_unit': '',
|
||||||
|
};
|
||||||
|
frm.set_value(values);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -44,6 +113,8 @@ frappe.ui.form.on('Therapy Session', {
|
|||||||
callback: function(data) {
|
callback: function(data) {
|
||||||
frm.set_value('duration', data.message.default_duration);
|
frm.set_value('duration', data.message.default_duration);
|
||||||
frm.set_value('rate', data.message.rate);
|
frm.set_value('rate', data.message.rate);
|
||||||
|
frm.set_value('service_unit', data.message.healthcare_service_unit);
|
||||||
|
frm.set_value('department', data.message.medical_department);
|
||||||
frm.doc.exercises = [];
|
frm.doc.exercises = [];
|
||||||
$.each(data.message.exercises, function(_i, e) {
|
$.each(data.message.exercises, function(_i, e) {
|
||||||
let exercise = frm.add_child('exercises');
|
let exercise = frm.add_child('exercises');
|
||||||
|
|||||||
@ -9,9 +9,11 @@
|
|||||||
"naming_series",
|
"naming_series",
|
||||||
"appointment",
|
"appointment",
|
||||||
"patient",
|
"patient",
|
||||||
|
"patient_name",
|
||||||
"patient_age",
|
"patient_age",
|
||||||
"gender",
|
"gender",
|
||||||
"column_break_5",
|
"column_break_5",
|
||||||
|
"company",
|
||||||
"therapy_plan",
|
"therapy_plan",
|
||||||
"therapy_type",
|
"therapy_type",
|
||||||
"practitioner",
|
"practitioner",
|
||||||
@ -20,7 +22,6 @@
|
|||||||
"duration",
|
"duration",
|
||||||
"rate",
|
"rate",
|
||||||
"location",
|
"location",
|
||||||
"company",
|
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"service_unit",
|
"service_unit",
|
||||||
"start_date",
|
"start_date",
|
||||||
@ -28,6 +29,10 @@
|
|||||||
"invoiced",
|
"invoiced",
|
||||||
"exercises_section",
|
"exercises_section",
|
||||||
"exercises",
|
"exercises",
|
||||||
|
"section_break_23",
|
||||||
|
"total_counts_targeted",
|
||||||
|
"column_break_25",
|
||||||
|
"total_counts_completed",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -159,7 +164,8 @@
|
|||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"options": "Company"
|
"options": "Company",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -173,11 +179,38 @@
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Patient Age",
|
"label": "Patient Age",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_counts_targeted",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Total Counts Targeted",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_counts_completed",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Total Counts Completed",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_23",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_25",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "patient.patient_name",
|
||||||
|
"fieldname": "patient_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Patient Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-21 13:16:46.378798",
|
"modified": "2020-04-29 16:49:16.286006",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Healthcare",
|
"module": "Healthcare",
|
||||||
"name": "Therapy Session",
|
"name": "Therapy Session",
|
||||||
|
|||||||
@ -6,10 +6,17 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import cstr, getdate
|
||||||
|
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
|
||||||
|
|
||||||
class TherapySession(Document):
|
class TherapySession(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.set_total_counts()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.update_sessions_count_in_therapy_plan()
|
self.update_sessions_count_in_therapy_plan()
|
||||||
|
insert_session_medical_record(self)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.update_sessions_count_in_therapy_plan(on_cancel=True)
|
self.update_sessions_count_in_therapy_plan(on_cancel=True)
|
||||||
@ -24,6 +31,18 @@ class TherapySession(Document):
|
|||||||
entry.sessions_completed += 1
|
entry.sessions_completed += 1
|
||||||
therapy_plan.save()
|
therapy_plan.save()
|
||||||
|
|
||||||
|
def set_total_counts(self):
|
||||||
|
target_total = 0
|
||||||
|
counts_completed = 0
|
||||||
|
for entry in self.exercises:
|
||||||
|
if entry.counts_target:
|
||||||
|
target_total += entry.counts_target
|
||||||
|
if entry.counts_completed:
|
||||||
|
counts_completed += entry.counts_completed
|
||||||
|
|
||||||
|
self.db_set('total_counts_targeted', target_total)
|
||||||
|
self.db_set('total_counts_completed', counts_completed)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_therapy_session(source_name, target_doc=None):
|
def create_therapy_session(source_name, target_doc=None):
|
||||||
@ -52,4 +71,62 @@ def create_therapy_session(source_name, target_doc=None):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def invoice_therapy_session(source_name, target_doc=None):
|
||||||
|
def set_missing_values(source, target):
|
||||||
|
target.customer = frappe.db.get_value('Patient', source.patient, 'customer')
|
||||||
|
target.due_date = getdate()
|
||||||
|
target.debit_to = get_receivable_account(source.company)
|
||||||
|
item = target.append('items', {})
|
||||||
|
item = get_therapy_item(source, item)
|
||||||
|
target.set_missing_values(for_validate=True)
|
||||||
|
|
||||||
|
doc = get_mapped_doc('Therapy Session', source_name, {
|
||||||
|
'Therapy Session': {
|
||||||
|
'doctype': 'Sales Invoice',
|
||||||
|
'field_map': [
|
||||||
|
['patient', 'patient'],
|
||||||
|
['referring_practitioner', 'practitioner'],
|
||||||
|
['company', 'company'],
|
||||||
|
['due_date', 'start_date']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def get_therapy_item(therapy, item):
|
||||||
|
item.item_code = frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item')
|
||||||
|
item.description = _('Therapy Session Charges: {0}').format(therapy.practitioner)
|
||||||
|
item.income_account = get_income_account(therapy.practitioner, therapy.company)
|
||||||
|
item.cost_center = frappe.get_cached_value('Company', therapy.company, 'cost_center')
|
||||||
|
item.rate = therapy.rate
|
||||||
|
item.amount = therapy.rate
|
||||||
|
item.qty = 1
|
||||||
|
item.reference_dt = 'Therapy Session'
|
||||||
|
item.reference_dn = therapy.name
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
def insert_session_medical_record(doc):
|
||||||
|
subject = frappe.bold(_('Therapy: ')) + cstr(doc.therapy_type) + '<br>'
|
||||||
|
if doc.therapy_plan:
|
||||||
|
subject += frappe.bold(_('Therapy Plan: ')) + cstr(doc.therapy_plan) + '<br>'
|
||||||
|
if doc.practitioner:
|
||||||
|
subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
|
||||||
|
subject += frappe.bold(_('Total Counts Targeted: ')) + cstr(doc.total_counts_targeted) + '<br>'
|
||||||
|
subject += frappe.bold(_('Total Counts Completed: ')) + cstr(doc.total_counts_completed) + '<br>'
|
||||||
|
|
||||||
|
medical_record = frappe.new_doc('Patient Medical Record')
|
||||||
|
medical_record.patient = doc.patient
|
||||||
|
medical_record.subject = subject
|
||||||
|
medical_record.status = 'Open'
|
||||||
|
medical_record.communication_date = doc.start_date
|
||||||
|
medical_record.reference_doctype = 'Therapy Session'
|
||||||
|
medical_record.reference_name = doc.name
|
||||||
|
medical_record.reference_owner = doc.owner
|
||||||
|
medical_record.save(ignore_permissions=True)
|
||||||
@ -35,17 +35,17 @@ def delete_vital_signs_from_medical_record(doc):
|
|||||||
|
|
||||||
def set_subject_field(doc):
|
def set_subject_field(doc):
|
||||||
subject = ''
|
subject = ''
|
||||||
if(doc.temperature):
|
if doc.temperature:
|
||||||
subject += _('Temperature: ') + '\n'+ cstr(doc.temperature) + '. '
|
subject += frappe.bold(_('Temperature: ')) + cstr(doc.temperature) + '<br>'
|
||||||
if(doc.pulse):
|
if doc.pulse:
|
||||||
subject += _('Pulse: ') + '\n' + cstr(doc.pulse) + '. '
|
subject += frappe.bold(_('Pulse: ')) + cstr(doc.pulse) + '<br>'
|
||||||
if(doc.respiratory_rate):
|
if doc.respiratory_rate:
|
||||||
subject += _('Respiratory Rate: ') + '\n' + cstr(doc.respiratory_rate) + '. '
|
subject += frappe.bold(_('Respiratory Rate: ')) + cstr(doc.respiratory_rate) + '<br>'
|
||||||
if(doc.bp):
|
if doc.bp:
|
||||||
subject += _('BP: ') + '\n' + cstr(doc.bp) + '. '
|
subject += frappe.bold(_('BP: ')) + cstr(doc.bp) + '<br>'
|
||||||
if(doc.bmi):
|
if doc.bmi:
|
||||||
subject += _('BMI: ') + '\n' + cstr(doc.bmi) + '. '
|
subject += frappe.bold(_('BMI: ')) + cstr(doc.bmi) + '<br>'
|
||||||
if(doc.nutrition_note):
|
if doc.nutrition_note:
|
||||||
subject += _('Note: ') + '\n' + cstr(doc.nutrition_note) + '. '
|
subject += frappe.bold(_('Note: ')) + cstr(doc.nutrition_note) + '<br>'
|
||||||
|
|
||||||
return subject
|
return subject
|
||||||
|
|||||||
@ -43,7 +43,7 @@ def validate_customer_created(patient):
|
|||||||
|
|
||||||
def get_fee_validity(patient_appointments):
|
def get_fee_validity(patient_appointments):
|
||||||
if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
|
if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
|
||||||
return
|
return []
|
||||||
|
|
||||||
items_to_invoice = []
|
items_to_invoice = []
|
||||||
for appointment in patient_appointments:
|
for appointment in patient_appointments:
|
||||||
@ -110,7 +110,7 @@ def get_lab_tests_to_invoice(patient):
|
|||||||
filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1}
|
filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1}
|
||||||
)
|
)
|
||||||
for lab_test in lab_tests:
|
for lab_test in lab_tests:
|
||||||
item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.lab_test_code, ['item', 'is_billable'])
|
item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.template, ['item', 'is_billable'])
|
||||||
if is_billable:
|
if is_billable:
|
||||||
lab_tests_to_invoice.append({
|
lab_tests_to_invoice.append({
|
||||||
'reference_type': 'Lab Test',
|
'reference_type': 'Lab Test',
|
||||||
|
|||||||
@ -250,7 +250,8 @@ doc_events = {
|
|||||||
},
|
},
|
||||||
"Contact": {
|
"Contact": {
|
||||||
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
|
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
|
||||||
"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
|
"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information",
|
||||||
|
"validate": "erpnext.crm.utils.update_lead_phone_numbers"
|
||||||
},
|
},
|
||||||
"Lead": {
|
"Lead": {
|
||||||
"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
|
"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
|
||||||
@ -537,4 +538,4 @@ global_search_doctypes = {
|
|||||||
{'doctype': 'Hotel Room Package', 'index': 3},
|
{'doctype': 'Hotel Room Package', 'index': 3},
|
||||||
{'doctype': 'Hotel Room Type', 'index': 4}
|
{'doctype': 'Hotel Room Type', 'index': 4}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Payroll",
|
"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 \"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\": \"Income Tax Slab\",\n \"name\": \"Income Tax Slab\",\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]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -73,7 +73,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Employee Tax and Benefits",
|
"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]"
|
"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 \"Payroll Period\"\n ],\n \"label\": \"Employee Other Income\",\n \"name\": \"Employee Other Income\",\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",
|
"category": "Modules",
|
||||||
@ -88,7 +88,7 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "HR",
|
"label": "HR",
|
||||||
"modified": "2020-04-01 11:28:50.860012",
|
"modified": "2020-04-29 20:29:22.114309",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR",
|
"name": "HR",
|
||||||
|
|||||||
@ -87,11 +87,12 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.status==\"On Leave\"",
|
"depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
|
||||||
"fieldname": "leave_type",
|
"fieldname": "leave_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Leave Type",
|
"label": "Leave Type",
|
||||||
|
"mandatory_depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
|
||||||
"oldfieldname": "leave_type",
|
"oldfieldname": "leave_type",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Leave Type"
|
"options": "Leave Type"
|
||||||
@ -100,6 +101,7 @@
|
|||||||
"fieldname": "leave_application",
|
"fieldname": "leave_application",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Leave Application",
|
"label": "Leave Application",
|
||||||
|
"no_copy": 1,
|
||||||
"options": "Leave Application",
|
"options": "Leave Application",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -175,7 +177,8 @@
|
|||||||
"icon": "fa fa-ok",
|
"icon": "fa fa-ok",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2020-02-19 14:25:32.945842",
|
"links": [],
|
||||||
|
"modified": "2020-04-11 11:40:14.319496",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
|
|||||||
@ -7,33 +7,15 @@ import frappe
|
|||||||
from frappe.utils import getdate, nowdate
|
from frappe.utils import getdate, nowdate
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cstr, get_datetime, get_datetime_str
|
from frappe.utils import cstr, get_datetime, formatdate
|
||||||
from frappe.utils import update_progress_bar
|
|
||||||
|
|
||||||
class Attendance(Document):
|
class Attendance(Document):
|
||||||
def validate_duplicate_record(self):
|
def validate(self):
|
||||||
res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and attendance_date = %s
|
from erpnext.controllers.status_updater import validate_status
|
||||||
and name != %s and docstatus != 2""",
|
validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
|
||||||
(self.employee, getdate(self.attendance_date), self.name))
|
self.validate_attendance_date()
|
||||||
if res:
|
self.validate_duplicate_record()
|
||||||
frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
|
self.check_leave_record()
|
||||||
|
|
||||||
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_attendance_date(self):
|
def validate_attendance_date(self):
|
||||||
date_of_joining = frappe.db.get_value("Employee", self.employee, "date_of_joining")
|
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):
|
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"))
|
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):
|
def validate_employee(self):
|
||||||
emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
|
emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
|
||||||
self.employee)
|
self.employee)
|
||||||
if not emp:
|
if not emp:
|
||||||
frappe.throw(_("Employee {0} is not active or does not exist").format(self.employee))
|
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()
|
@frappe.whitelist()
|
||||||
def get_events(start, end, filters=None):
|
def get_events(start, end, filters=None):
|
||||||
events = []
|
events = []
|
||||||
@ -90,18 +105,20 @@ def add_attendance(events, start, end, conditions=None):
|
|||||||
if e not in events:
|
if e not in events:
|
||||||
events.append(e)
|
events.append(e)
|
||||||
|
|
||||||
def mark_attendance(employee, attendance_date, status, shift=None):
|
def mark_attendance(employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False):
|
||||||
employee_doc = frappe.get_doc('Employee', employee)
|
|
||||||
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
|
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',
|
'doctype': 'Attendance',
|
||||||
'employee': employee,
|
'employee': employee,
|
||||||
'attendance_date': attendance_date,
|
'attendance_date': attendance_date,
|
||||||
'status': status,
|
'status': status,
|
||||||
'company': employee_doc.company,
|
'company': company,
|
||||||
'shift': shift
|
'shift': shift,
|
||||||
}
|
'leave_type': leave_type
|
||||||
attendance = frappe.get_doc(doc_dict).insert()
|
})
|
||||||
|
attendance.flags.ignore_validate = ignore_validate
|
||||||
|
attendance.insert()
|
||||||
attendance.submit()
|
attendance.submit()
|
||||||
return attendance.name
|
return attendance.name
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,9 @@ def get_data():
|
|||||||
'heatmap': True,
|
'heatmap': True,
|
||||||
'heatmap_message': _('This is based on the attendance of this Employee'),
|
'heatmap_message': _('This is based on the attendance of this Employee'),
|
||||||
'fieldname': 'employee',
|
'fieldname': 'employee',
|
||||||
|
'non_standard_fieldnames': {
|
||||||
|
'Bank Account': 'party'
|
||||||
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'label': _('Leave and Attendance'),
|
'label': _('Leave and Attendance'),
|
||||||
@ -33,7 +36,7 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Payroll'),
|
'label': _('Payroll'),
|
||||||
'items': ['Salary Structure Assignment', 'Salary Slip', 'Additional Salary', 'Timesheet','Employee Incentive', 'Retention Bonus']
|
'items': ['Salary Structure Assignment', 'Salary Slip', 'Additional Salary', 'Timesheet','Employee Incentive', 'Retention Bonus', 'Bank Account']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Training'),
|
'label': _('Training'),
|
||||||
|
|||||||
@ -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,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
"allow_import": 1,
|
||||||
"allow_guest_to_view": 0,
|
"allow_rename": 1,
|
||||||
"allow_import": 1,
|
"autoname": "HR-TAX-DEC-.YYYY.-.#####",
|
||||||
"allow_rename": 1,
|
"creation": "2018-04-13 16:53:36.175504",
|
||||||
"autoname": "HR-TAX-DEC-.YYYY.-.#####",
|
"doctype": "DocType",
|
||||||
"beta": 0,
|
"editable_grid": 1,
|
||||||
"creation": "2018-04-13 16:53:36.175504",
|
"engine": "InnoDB",
|
||||||
"custom": 0,
|
"field_order": [
|
||||||
"docstatus": 0,
|
"employee",
|
||||||
"doctype": "DocType",
|
"employee_name",
|
||||||
"document_type": "",
|
"department",
|
||||||
"editable_grid": 1,
|
"column_break_2",
|
||||||
"engine": "InnoDB",
|
"payroll_period",
|
||||||
|
"company",
|
||||||
|
"amended_from",
|
||||||
|
"section_break_8",
|
||||||
|
"declarations",
|
||||||
|
"section_break_10",
|
||||||
|
"total_declared_amount",
|
||||||
|
"column_break_12",
|
||||||
|
"total_exemption_amount"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "employee",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Employee",
|
||||||
"collapsible": 0,
|
"options": "Employee",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fetch_from": "employee.employee_name",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "employee_name",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Data",
|
||||||
"bold": 0,
|
"label": "Employee Name",
|
||||||
"collapsible": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fetch_from": "employee.department",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "department",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Department",
|
||||||
"collapsible": 0,
|
"options": "Department",
|
||||||
"columns": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "column_break_2",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "payroll_period",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Payroll Period",
|
||||||
"collapsible": 0,
|
"options": "Payroll Period",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fetch_from": "employee.company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "company",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Company",
|
||||||
"collapsible": 0,
|
"options": "Company"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "amended_from",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Amended From",
|
||||||
"bold": 0,
|
"no_copy": 1,
|
||||||
"collapsible": 0,
|
"options": "Employee Tax Exemption Declaration",
|
||||||
"columns": 0,
|
"print_hide": 1,
|
||||||
"fetch_if_empty": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "section_break_8",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "declarations",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Table",
|
||||||
"allow_on_submit": 0,
|
"label": "Declarations",
|
||||||
"bold": 0,
|
"options": "Employee Tax Exemption Declaration Category"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "section_break_10",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "total_declared_amount",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Currency",
|
||||||
"allow_on_submit": 0,
|
"label": "Total Declared Amount",
|
||||||
"bold": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "column_break_12",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "total_exemption_amount",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Currency",
|
||||||
"allow_on_submit": 0,
|
"label": "Total Exemption Amount",
|
||||||
"bold": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"is_submittable": 1,
|
||||||
"hide_heading": 0,
|
"links": [],
|
||||||
"hide_toolbar": 0,
|
"modified": "2020-03-18 14:56:25.625717",
|
||||||
"idx": 0,
|
"modified_by": "Administrator",
|
||||||
"image_view": 0,
|
"module": "HR",
|
||||||
"in_create": 0,
|
"name": "Employee Tax Exemption Declaration",
|
||||||
"is_submittable": 1,
|
"owner": "Administrator",
|
||||||
"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",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "System Manager",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "HR Manager",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "HR Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "HR User",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "HR User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "Employee",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "Employee",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
"sort_field": "modified",
|
||||||
"read_only": 0,
|
"sort_order": "DESC",
|
||||||
"read_only_onload": 0,
|
"track_changes": 1
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@ -8,31 +8,17 @@ from frappe.model.document import Document
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.model.mapper import get_mapped_doc
|
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
|
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
|
||||||
|
calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
|
||||||
class DuplicateDeclarationError(frappe.ValidationError): pass
|
|
||||||
|
|
||||||
class EmployeeTaxExemptionDeclaration(Document):
|
class EmployeeTaxExemptionDeclaration(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
validate_tax_declaration(self.declarations)
|
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_declared_amount()
|
||||||
self.set_total_exemption_amount()
|
self.set_total_exemption_amount()
|
||||||
self.calculate_hra_exemption()
|
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):
|
def set_total_declared_amount(self):
|
||||||
self.total_declared_amount = 0.0
|
self.total_declared_amount = 0.0
|
||||||
for d in self.declarations:
|
for d in self.declarations:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
import unittest
|
import unittest
|
||||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
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):
|
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@ -21,8 +21,6 @@
|
|||||||
"total_actual_amount",
|
"total_actual_amount",
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"exemption_amount",
|
"exemption_amount",
|
||||||
"other_incomes_section",
|
|
||||||
"income_from_other_sources",
|
|
||||||
"attachment_section",
|
"attachment_section",
|
||||||
"attachments",
|
"attachments",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
@ -111,16 +109,6 @@
|
|||||||
"label": "Total Exemption Amount",
|
"label": "Total Exemption Amount",
|
||||||
"read_only": 1
|
"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",
|
"fieldname": "attachment_section",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
@ -142,7 +130,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-02 19:02:15.398486",
|
"modified": "2020-03-18 14:55:51.420016",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Tax Exemption Proof Submission",
|
"name": "Employee Tax Exemption Proof Submission",
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
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):
|
class EmployeeTaxExemptionProofSubmission(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -15,6 +16,7 @@ class EmployeeTaxExemptionProofSubmission(Document):
|
|||||||
self.set_total_actual_amount()
|
self.set_total_actual_amount()
|
||||||
self.set_total_exemption_amount()
|
self.set_total_exemption_amount()
|
||||||
self.calculate_hra_exemption()
|
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):
|
def set_total_actual_amount(self):
|
||||||
self.total_actual_amount = flt(self.get("house_rent_payment_amount"))
|
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.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
|
||||||
self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
|
self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
|
||||||
self.monthly_house_rent = hra_exemption["monthly_house_rent"]
|
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;
|
||||||
}
|
}
|
||||||
return frappe.call({
|
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: {
|
args: {
|
||||||
"expense_claim_type": d.expense_type,
|
"expense_claim_type": d.expense_type,
|
||||||
"company": doc.company
|
"company": doc.company
|
||||||
@ -25,6 +25,7 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
d.default_account = r.message.account;
|
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
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _
|
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 frappe.model.document import Document
|
||||||
from erpnext.hr.utils import set_employee_name
|
from erpnext.hr.utils import set_employee_name
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
@ -76,6 +76,7 @@ class ExpenseClaim(AccountsController):
|
|||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.update_task_and_project()
|
self.update_task_and_project()
|
||||||
|
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
|
||||||
if self.payable_account:
|
if self.payable_account:
|
||||||
self.make_gl_entries(cancel=True)
|
self.make_gl_entries(cancel=True)
|
||||||
|
|
||||||
@ -192,7 +193,8 @@ class ExpenseClaim(AccountsController):
|
|||||||
def validate_account_details(self):
|
def validate_account_details(self):
|
||||||
for data in self.expenses:
|
for data in self.expenses:
|
||||||
if not data.cost_center:
|
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 self.is_paid:
|
||||||
if not self.mode_of_payment:
|
if not self.mode_of_payment:
|
||||||
@ -259,10 +261,17 @@ class ExpenseClaim(AccountsController):
|
|||||||
if not expense.default_account or not validate:
|
if not expense.default_account or not validate:
|
||||||
expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"]
|
expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"]
|
||||||
|
|
||||||
def update_reimbursed_amount(doc):
|
def update_reimbursed_amount(doc, jv=None):
|
||||||
amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) as amt
|
|
||||||
|
condition = ""
|
||||||
|
|
||||||
|
if jv:
|
||||||
|
condition += "and voucher_no = '{0}'".format(jv)
|
||||||
|
|
||||||
|
amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) - ifnull(sum(credit_in_account_currency), 0)as amt
|
||||||
from `tabGL Entry` where against_voucher_type = 'Expense Claim' and against_voucher = %s
|
from `tabGL Entry` where against_voucher_type = 'Expense Claim' and against_voucher = %s
|
||||||
and party = %s """, (doc.name, doc.employee) ,as_dict=1)[0].amt
|
and party = %s {condition}""".format(condition=condition), #nosec
|
||||||
|
(doc.name, doc.employee) ,as_dict=1)[0].amt
|
||||||
|
|
||||||
doc.total_amount_reimbursed = amt
|
doc.total_amount_reimbursed = amt
|
||||||
frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt)
|
frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt)
|
||||||
@ -308,13 +317,23 @@ def make_bank_entry(dt, dn):
|
|||||||
|
|
||||||
return je.as_dict()
|
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()
|
@frappe.whitelist()
|
||||||
def get_expense_claim_account(expense_claim_type, company):
|
def get_expense_claim_account(expense_claim_type, company):
|
||||||
account = frappe.db.get_value("Expense Claim Account",
|
account = frappe.db.get_value("Expense Claim Account",
|
||||||
{"parent": expense_claim_type, "company": company}, "default_account")
|
{"parent": expense_claim_type, "company": company}, "default_account")
|
||||||
if not account:
|
if not account:
|
||||||
frappe.throw(_("Please set default account in Expense Claim Type {0}")
|
frappe.throw(_("Set the default account for the {0} {1}")
|
||||||
.format(expense_claim_type))
|
.format(frappe.bold("Expense Claim Type"), get_link_to_form("Expense Claim Type", expense_claim_type)))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"account": account
|
"account": account
|
||||||
|
|||||||
@ -13,10 +13,12 @@
|
|||||||
"stop_birthday_reminders",
|
"stop_birthday_reminders",
|
||||||
"expense_approver_mandatory_in_expense_claim",
|
"expense_approver_mandatory_in_expense_claim",
|
||||||
"payroll_settings",
|
"payroll_settings",
|
||||||
|
"payroll_based_on",
|
||||||
|
"max_working_hours_against_timesheet",
|
||||||
"include_holidays_in_total_working_days",
|
"include_holidays_in_total_working_days",
|
||||||
"disable_rounded_total",
|
"disable_rounded_total",
|
||||||
"max_working_hours_against_timesheet",
|
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
|
"daily_wages_fraction_for_half_day",
|
||||||
"email_salary_slip_to_employee",
|
"email_salary_slip_to_employee",
|
||||||
"encrypt_salary_slips_in_emails",
|
"encrypt_salary_slips_in_emails",
|
||||||
"password_policy",
|
"password_policy",
|
||||||
@ -184,13 +186,27 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Role Allowed to Create Backdated Leave Application",
|
"label": "Role Allowed to Create Backdated Leave Application",
|
||||||
"options": "Role"
|
"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",
|
"icon": "fa fa-cog",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-01-06 18:46:30.189815",
|
"modified": "2020-04-13 21:20:59.382394",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR Settings",
|
"name": "HR Settings",
|
||||||
|
|||||||
@ -15,6 +15,9 @@ class HRSettings(Document):
|
|||||||
self.set_naming_series()
|
self.set_naming_series()
|
||||||
self.validate_password_policy()
|
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):
|
def set_naming_series(self):
|
||||||
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
|
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
|
||||||
set_by_naming_series("Employee", "employee_number",
|
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', {
|
||||||
|
|
||||||
|
});
|
||||||
152
erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
Normal file
152
erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
{
|
||||||
|
"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,
|
||||||
|
"collapsible_depends_on": "other_taxes_and_charges",
|
||||||
|
"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-29 15:08:21.436120",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Income Tax Slab",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"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,
|
||||||
|
"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,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"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
|
||||||
@ -30,16 +30,16 @@ class LeaveAllocation(Document):
|
|||||||
def validate_leave_allocation_days(self):
|
def validate_leave_allocation_days(self):
|
||||||
company = frappe.db.get_value("Employee", self.employee, "company")
|
company = frappe.db.get_value("Employee", self.employee, "company")
|
||||||
leave_period = get_leave_period(self.from_date, self.to_date, 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:
|
if max_leaves_allowed > 0:
|
||||||
leave_allocated = 0
|
leave_allocated = 0
|
||||||
if leave_period:
|
if leave_period:
|
||||||
leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
|
leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
|
||||||
leave_period[0].from_date, leave_period[0].to_date)
|
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:
|
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")
|
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):
|
def on_submit(self):
|
||||||
self.create_leave_ledger_entry()
|
self.create_leave_ledger_entry()
|
||||||
|
|||||||
@ -374,7 +374,8 @@ class LeaveApplication(Document):
|
|||||||
leaves=self.total_leave_days * -1,
|
leaves=self.total_leave_days * -1,
|
||||||
from_date=self.from_date,
|
from_date=self.from_date,
|
||||||
to_date=self.to_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)
|
create_leave_ledger_entry(self, args, submit)
|
||||||
|
|
||||||
@ -384,7 +385,9 @@ class LeaveApplication(Document):
|
|||||||
from_date=self.from_date,
|
from_date=self.from_date,
|
||||||
to_date=expiry_date,
|
to_date=expiry_date,
|
||||||
leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
|
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)
|
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
|
return expiry[0]['to_date'] if expiry else None
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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
|
number_of_days = 0
|
||||||
if cint(half_day) == 1:
|
if cint(half_day) == 1:
|
||||||
if from_date == to_date:
|
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
|
number_of_days = date_diff(to_date, from_date) + 1
|
||||||
|
|
||||||
if not frappe.db.get_value("Leave Type", leave_type, "include_holiday"):
|
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
|
return number_of_days
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@ -575,7 +578,7 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
|
|||||||
{'name': leave_entry.transaction_name}, ['half_day_date'])
|
{'name': leave_entry.transaction_name}, ['half_day_date'])
|
||||||
|
|
||||||
leave_days += get_number_of_leave_days(employee, leave_type,
|
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
|
return leave_days
|
||||||
|
|
||||||
@ -589,7 +592,7 @@ 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("""
|
return frappe.db.sql("""
|
||||||
SELECT
|
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
|
is_carry_forward, is_expired
|
||||||
FROM `tabLeave Ledger Entry`
|
FROM `tabLeave Ledger Entry`
|
||||||
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
||||||
@ -607,9 +610,10 @@ def get_leave_entries(employee, leave_type, from_date, to_date):
|
|||||||
}, as_dict=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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'''
|
'''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
|
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
|
where h1.parent = h2.name and h1.holiday_date between %s and %s
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2019-05-09 15:47:39.760406",
|
"creation": "2019-05-09 15:47:39.760406",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
@ -12,6 +13,7 @@
|
|||||||
"column_break_7",
|
"column_break_7",
|
||||||
"from_date",
|
"from_date",
|
||||||
"to_date",
|
"to_date",
|
||||||
|
"holiday_list",
|
||||||
"is_carry_forward",
|
"is_carry_forward",
|
||||||
"is_expired",
|
"is_expired",
|
||||||
"is_lwp",
|
"is_lwp",
|
||||||
@ -98,11 +100,18 @@
|
|||||||
"fieldname": "is_lwp",
|
"fieldname": "is_lwp",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Leave Without Pay"
|
"label": "Is Leave Without Pay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "holiday_list",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Holiday List",
|
||||||
|
"options": "Holiday List"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-08-20 14:40:04.130799",
|
"links": [],
|
||||||
|
"modified": "2020-02-27 14:40:10.502605",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Ledger Entry",
|
"name": "Leave Ledger Entry",
|
||||||
|
|||||||
@ -1,401 +1,102 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
"allow_import": 1,
|
||||||
"allow_guest_to_view": 0,
|
"autoname": "Prompt",
|
||||||
"allow_import": 1,
|
"creation": "2018-04-13 15:18:53.698553",
|
||||||
"allow_rename": 0,
|
"doctype": "DocType",
|
||||||
"autoname": "Prompt",
|
"editable_grid": 1,
|
||||||
"beta": 0,
|
"engine": "InnoDB",
|
||||||
"creation": "2018-04-13 15:18:53.698553",
|
"field_order": [
|
||||||
"custom": 0,
|
"company",
|
||||||
"docstatus": 0,
|
"column_break_2",
|
||||||
"doctype": "DocType",
|
"start_date",
|
||||||
"document_type": "",
|
"end_date",
|
||||||
"editable_grid": 1,
|
"section_break_5",
|
||||||
"engine": "InnoDB",
|
"periods"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Company",
|
||||||
"collapsible": 0,
|
"options": "Company",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "column_break_2",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "start_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "Start Date",
|
||||||
"bold": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "end_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "End Date",
|
||||||
"bold": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "section_break_5",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break",
|
||||||
"allow_on_submit": 0,
|
"hidden": 1,
|
||||||
"bold": 0,
|
"label": "Payroll Periods"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "periods",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Table",
|
||||||
"allow_on_submit": 0,
|
"label": "Payroll Periods",
|
||||||
"bold": 0,
|
"options": "Payroll Period Date"
|
||||||
"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
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_heading": 0,
|
"modified": "2020-03-18 18:13:23.859980",
|
||||||
"hide_toolbar": 0,
|
"modified_by": "Administrator",
|
||||||
"idx": 0,
|
"module": "HR",
|
||||||
"image_view": 0,
|
"name": "Payroll Period",
|
||||||
"in_create": 0,
|
"owner": "Administrator",
|
||||||
"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",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"delete": 1,
|
||||||
"create": 1,
|
"email": 1,
|
||||||
"delete": 1,
|
"export": 1,
|
||||||
"email": 1,
|
"print": 1,
|
||||||
"export": 1,
|
"read": 1,
|
||||||
"if_owner": 0,
|
"report": 1,
|
||||||
"import": 0,
|
"role": "System Manager",
|
||||||
"permlevel": 0,
|
"share": 1,
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"delete": 1,
|
||||||
"create": 1,
|
"email": 1,
|
||||||
"delete": 1,
|
"export": 1,
|
||||||
"email": 1,
|
"print": 1,
|
||||||
"export": 1,
|
"read": 1,
|
||||||
"if_owner": 0,
|
"report": 1,
|
||||||
"import": 0,
|
"role": "HR Manager",
|
||||||
"permlevel": 0,
|
"share": 1,
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "HR Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"delete": 1,
|
||||||
"create": 1,
|
"email": 1,
|
||||||
"delete": 1,
|
"export": 1,
|
||||||
"email": 1,
|
"print": 1,
|
||||||
"export": 1,
|
"read": 1,
|
||||||
"if_owner": 0,
|
"report": 1,
|
||||||
"import": 0,
|
"role": "HR User",
|
||||||
"permlevel": 0,
|
"share": 1,
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "HR User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
"sort_field": "modified",
|
||||||
"read_only": 0,
|
"sort_order": "DESC",
|
||||||
"read_only_onload": 0,
|
"track_changes": 1
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@ -45,8 +45,9 @@ class PayrollPeriod(Document):
|
|||||||
+ _(") for {0}").format(self.company)
|
+ _(") for {0}").format(self.company)
|
||||||
frappe.throw(msg)
|
frappe.throw(msg)
|
||||||
|
|
||||||
def get_payroll_period_days(start_date, end_date, employee):
|
def get_payroll_period_days(start_date, end_date, employee, company=None):
|
||||||
company = frappe.db.get_value("Employee", employee, "company")
|
if not company:
|
||||||
|
company = frappe.db.get_value("Employee", employee, "company")
|
||||||
payroll_period = frappe.db.sql("""
|
payroll_period = frappe.db.sql("""
|
||||||
select name, start_date, end_date
|
select name, start_date, end_date
|
||||||
from `tabPayroll Period`
|
from `tabPayroll Period`
|
||||||
|
|||||||
@ -1,264 +1,263 @@
|
|||||||
{
|
{
|
||||||
"allow_import": 1,
|
"actions": [],
|
||||||
"allow_rename": 1,
|
"allow_import": 1,
|
||||||
"autoname": "field:salary_component",
|
"allow_rename": 1,
|
||||||
"creation": "2016-06-30 15:42:43.631931",
|
"autoname": "field:salary_component",
|
||||||
"doctype": "DocType",
|
"creation": "2016-06-30 15:42:43.631931",
|
||||||
"document_type": "Setup",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"document_type": "Setup",
|
||||||
"engine": "InnoDB",
|
"editable_grid": 1,
|
||||||
"field_order": [
|
"engine": "InnoDB",
|
||||||
"salary_component",
|
"field_order": [
|
||||||
"salary_component_abbr",
|
"salary_component",
|
||||||
"type",
|
"salary_component_abbr",
|
||||||
"description",
|
"type",
|
||||||
"column_break_4",
|
"description",
|
||||||
"is_payable",
|
"column_break_4",
|
||||||
"depends_on_payment_days",
|
"depends_on_payment_days",
|
||||||
"is_tax_applicable",
|
"is_tax_applicable",
|
||||||
"deduct_full_tax_on_selected_payroll_date",
|
"deduct_full_tax_on_selected_payroll_date",
|
||||||
"round_to_the_nearest_integer",
|
"variable_based_on_taxable_salary",
|
||||||
"statistical_component",
|
"exempted_from_income_tax",
|
||||||
"do_not_include_in_total",
|
"round_to_the_nearest_integer",
|
||||||
"disabled",
|
"statistical_component",
|
||||||
"flexible_benefits",
|
"do_not_include_in_total",
|
||||||
"is_flexible_benefit",
|
"disabled",
|
||||||
"max_benefit_amount",
|
"flexible_benefits",
|
||||||
"column_break_9",
|
"is_flexible_benefit",
|
||||||
"pay_against_benefit_claim",
|
"max_benefit_amount",
|
||||||
"only_tax_impact",
|
"column_break_9",
|
||||||
"create_separate_payment_entry_against_benefit_claim",
|
"pay_against_benefit_claim",
|
||||||
"section_break_11",
|
"only_tax_impact",
|
||||||
"variable_based_on_taxable_salary",
|
"create_separate_payment_entry_against_benefit_claim",
|
||||||
"section_break_5",
|
"section_break_5",
|
||||||
"accounts",
|
"accounts",
|
||||||
"condition_and_formula",
|
"condition_and_formula",
|
||||||
"condition",
|
"condition",
|
||||||
"amount",
|
"amount",
|
||||||
"amount_based_on_formula",
|
"amount_based_on_formula",
|
||||||
"formula",
|
"formula",
|
||||||
"column_break_28",
|
"column_break_28",
|
||||||
"help"
|
"help"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldname": "salary_component",
|
"fieldname": "salary_component",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Name",
|
"label": "Name",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "salary_component_abbr",
|
"fieldname": "salary_component_abbr",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Abbr",
|
"label": "Abbr",
|
||||||
"print_width": "120px",
|
"print_width": "120px",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"width": "120px"
|
"width": "120px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "type",
|
"fieldname": "type",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Type",
|
"label": "Type",
|
||||||
"options": "Earning\nDeduction",
|
"options": "Earning\nDeduction",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"depends_on": "eval:doc.type == \"Earning\"",
|
"depends_on": "eval:doc.type == \"Earning\"",
|
||||||
"fieldname": "is_tax_applicable",
|
"fieldname": "is_tax_applicable",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Tax Applicable"
|
"label": "Is Tax Applicable"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"fieldname": "is_payable",
|
"fieldname": "depends_on_payment_days",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Payable"
|
"label": "Depends on Payment Days",
|
||||||
},
|
"print_hide": 1
|
||||||
{
|
},
|
||||||
"default": "1",
|
{
|
||||||
"fieldname": "depends_on_payment_days",
|
"default": "0",
|
||||||
"fieldtype": "Check",
|
"fieldname": "do_not_include_in_total",
|
||||||
"label": "Depends on Payment Days",
|
"fieldtype": "Check",
|
||||||
"print_hide": 1
|
"label": "Do Not Include in Total"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "do_not_include_in_total",
|
"depends_on": "eval:doc.is_tax_applicable && doc.type=='Earning'",
|
||||||
"fieldtype": "Check",
|
"fieldname": "deduct_full_tax_on_selected_payroll_date",
|
||||||
"label": "Do Not Include in Total"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Deduct Full Tax on Selected Payroll Date"
|
||||||
{
|
},
|
||||||
"default": "0",
|
{
|
||||||
"depends_on": "is_tax_applicable",
|
"fieldname": "column_break_4",
|
||||||
"fieldname": "deduct_full_tax_on_selected_payroll_date",
|
"fieldtype": "Column Break"
|
||||||
"fieldtype": "Check",
|
},
|
||||||
"label": "Deduct Full Tax on Selected Payroll Date"
|
{
|
||||||
},
|
"default": "0",
|
||||||
{
|
"fieldname": "disabled",
|
||||||
"fieldname": "column_break_4",
|
"fieldtype": "Check",
|
||||||
"fieldtype": "Column Break"
|
"label": "Disabled"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"fieldname": "description",
|
||||||
"fieldname": "disabled",
|
"fieldtype": "Small Text",
|
||||||
"fieldtype": "Check",
|
"in_list_view": 1,
|
||||||
"label": "Disabled"
|
"label": "Description"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "description",
|
"default": "0",
|
||||||
"fieldtype": "Small Text",
|
"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. ",
|
||||||
"in_list_view": 1,
|
"fieldname": "statistical_component",
|
||||||
"label": "Description"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Statistical Component"
|
||||||
{
|
},
|
||||||
"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. ",
|
"depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
|
||||||
"fieldname": "statistical_component",
|
"fieldname": "flexible_benefits",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Section Break",
|
||||||
"label": "Statistical Component"
|
"label": "Flexible Benefits"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
|
"default": "0",
|
||||||
"fieldname": "flexible_benefits",
|
"fieldname": "is_flexible_benefit",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Check",
|
||||||
"label": "Flexible Benefits"
|
"label": "Is Flexible Benefit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"depends_on": "is_flexible_benefit",
|
||||||
"fieldname": "is_flexible_benefit",
|
"fieldname": "max_benefit_amount",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Currency",
|
||||||
"label": "Is Flexible Benefit"
|
"label": "Max Benefit Amount (Yearly)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "is_flexible_benefit",
|
"fieldname": "column_break_9",
|
||||||
"fieldname": "max_benefit_amount",
|
"fieldtype": "Column Break"
|
||||||
"fieldtype": "Currency",
|
},
|
||||||
"label": "Max Benefit Amount (Yearly)"
|
{
|
||||||
},
|
"default": "0",
|
||||||
{
|
"depends_on": "is_flexible_benefit",
|
||||||
"fieldname": "column_break_9",
|
"fieldname": "pay_against_benefit_claim",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Pay Against Benefit Claim"
|
||||||
{
|
},
|
||||||
"default": "0",
|
{
|
||||||
"depends_on": "is_flexible_benefit",
|
"default": "0",
|
||||||
"fieldname": "pay_against_benefit_claim",
|
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
|
||||||
"fieldtype": "Check",
|
"fieldname": "only_tax_impact",
|
||||||
"label": "Pay Against Benefit Claim"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
|
||||||
{
|
},
|
||||||
"default": "0",
|
{
|
||||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
|
"default": "0",
|
||||||
"fieldname": "only_tax_impact",
|
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
|
||||||
"fieldtype": "Check",
|
"fieldname": "create_separate_payment_entry_against_benefit_claim",
|
||||||
"label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Create Separate Payment Entry Against Benefit Claim"
|
||||||
{
|
},
|
||||||
"default": "0",
|
{
|
||||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
|
"default": "0",
|
||||||
"fieldname": "create_separate_payment_entry_against_benefit_claim",
|
"depends_on": "eval:doc.type == \"Deduction\"",
|
||||||
"fieldtype": "Check",
|
"fieldname": "variable_based_on_taxable_salary",
|
||||||
"label": "Create Separate Payment Entry Against Benefit Claim"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Variable Based On Taxable Salary"
|
||||||
{
|
},
|
||||||
"depends_on": "eval:doc.type=='Deduction'",
|
{
|
||||||
"fieldname": "section_break_11",
|
"depends_on": "eval:doc.statistical_component != 1",
|
||||||
"fieldtype": "Section Break"
|
"fieldname": "section_break_5",
|
||||||
},
|
"fieldtype": "Section Break",
|
||||||
{
|
"label": "Accounts"
|
||||||
"default": "0",
|
},
|
||||||
"fieldname": "variable_based_on_taxable_salary",
|
{
|
||||||
"fieldtype": "Check",
|
"fieldname": "accounts",
|
||||||
"label": "Variable Based On Taxable Salary"
|
"fieldtype": "Table",
|
||||||
},
|
"label": "Accounts",
|
||||||
{
|
"options": "Salary Component Account"
|
||||||
"depends_on": "eval:doc.statistical_component != 1",
|
},
|
||||||
"fieldname": "section_break_5",
|
{
|
||||||
"fieldtype": "Section Break",
|
"collapsible": 1,
|
||||||
"label": "Accounts"
|
"depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
|
||||||
},
|
"fieldname": "condition_and_formula",
|
||||||
{
|
"fieldtype": "Section Break",
|
||||||
"fieldname": "accounts",
|
"label": "Condition and Formula"
|
||||||
"fieldtype": "Table",
|
},
|
||||||
"label": "Accounts",
|
{
|
||||||
"options": "Salary Component Account"
|
"fieldname": "condition",
|
||||||
},
|
"fieldtype": "Code",
|
||||||
{
|
"label": "Condition"
|
||||||
"collapsible": 1,
|
},
|
||||||
"depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
|
{
|
||||||
"fieldname": "condition_and_formula",
|
"default": "0",
|
||||||
"fieldtype": "Section Break",
|
"fieldname": "amount_based_on_formula",
|
||||||
"label": "Condition and Formula"
|
"fieldtype": "Check",
|
||||||
},
|
"label": "Amount based on formula"
|
||||||
{
|
},
|
||||||
"fieldname": "condition",
|
{
|
||||||
"fieldtype": "Code",
|
"depends_on": "amount_based_on_formula",
|
||||||
"label": "Condition"
|
"fieldname": "formula",
|
||||||
},
|
"fieldtype": "Code",
|
||||||
{
|
"label": "Formula"
|
||||||
"default": "0",
|
},
|
||||||
"fieldname": "amount_based_on_formula",
|
{
|
||||||
"fieldtype": "Check",
|
"depends_on": "eval:doc.amount_based_on_formula!==1",
|
||||||
"label": "Amount based on formula"
|
"fieldname": "amount",
|
||||||
},
|
"fieldtype": "Currency",
|
||||||
{
|
"label": "Amount"
|
||||||
"depends_on": "amount_based_on_formula",
|
},
|
||||||
"fieldname": "formula",
|
{
|
||||||
"fieldtype": "Code",
|
"fieldname": "column_break_28",
|
||||||
"label": "Formula"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.amount_based_on_formula!==1",
|
"fieldname": "help",
|
||||||
"fieldname": "amount",
|
"fieldtype": "HTML",
|
||||||
"fieldtype": "Currency",
|
"label": "Help",
|
||||||
"label": "Amount"
|
"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>"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_28",
|
"default": "0",
|
||||||
"fieldtype": "Column Break"
|
"fieldname": "round_to_the_nearest_integer",
|
||||||
},
|
"fieldtype": "Check",
|
||||||
{
|
"label": "Round to the Nearest Integer"
|
||||||
"fieldname": "help",
|
},
|
||||||
"fieldtype": "HTML",
|
{
|
||||||
"label": "Help",
|
"default": "0",
|
||||||
"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>"
|
"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 without any declaration or proof submission.",
|
||||||
{
|
"fieldname": "exempted_from_income_tax",
|
||||||
"default": "0",
|
"fieldtype": "Check",
|
||||||
"fieldname": "round_to_the_nearest_integer",
|
"label": "Exempted from Income Tax"
|
||||||
"fieldtype": "Check",
|
}
|
||||||
"label": "Round to the Nearest Integer"
|
],
|
||||||
}
|
"icon": "fa fa-flag",
|
||||||
],
|
"links": [],
|
||||||
"icon": "fa fa-flag",
|
"modified": "2020-04-28 15:46:45.252945",
|
||||||
"modified": "2019-06-05 11:34:14.231228",
|
"modified_by": "Administrator",
|
||||||
"modified_by": "Administrator",
|
"module": "HR",
|
||||||
"module": "HR",
|
"name": "Salary Component",
|
||||||
"name": "Salary Component",
|
"owner": "Administrator",
|
||||||
"owner": "Administrator",
|
"permissions": [
|
||||||
"permissions": [
|
{
|
||||||
{
|
"create": 1,
|
||||||
"create": 1,
|
"delete": 1,
|
||||||
"delete": 1,
|
"email": 1,
|
||||||
"email": 1,
|
"export": 1,
|
||||||
"export": 1,
|
"print": 1,
|
||||||
"print": 1,
|
"read": 1,
|
||||||
"read": 1,
|
"report": 1,
|
||||||
"report": 1,
|
"role": "HR User",
|
||||||
"role": "HR User",
|
"share": 1,
|
||||||
"share": 1,
|
"write": 1
|
||||||
"write": 1
|
},
|
||||||
},
|
{
|
||||||
{
|
"read": 1,
|
||||||
"read": 1,
|
"role": "Employee"
|
||||||
"role": "Employee"
|
}
|
||||||
}
|
],
|
||||||
],
|
"sort_field": "modified",
|
||||||
"sort_field": "modified",
|
"sort_order": "DESC"
|
||||||
"sort_order": "DESC"
|
}
|
||||||
}
|
|
||||||
@ -3,14 +3,12 @@
|
|||||||
"doctype": "Salary Component",
|
"doctype": "Salary Component",
|
||||||
"salary_component": "_Test Basic Salary",
|
"salary_component": "_Test Basic Salary",
|
||||||
"type": "Earning",
|
"type": "Earning",
|
||||||
"is_payable": 1,
|
|
||||||
"is_tax_applicable": 1
|
"is_tax_applicable": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Salary Component",
|
"doctype": "Salary Component",
|
||||||
"salary_component": "_Test Allowance",
|
"salary_component": "_Test Allowance",
|
||||||
"type": "Earning",
|
"type": "Earning",
|
||||||
"is_payable": 1,
|
|
||||||
"is_tax_applicable": 1
|
"is_tax_applicable": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -27,14 +25,12 @@
|
|||||||
"doctype": "Salary Component",
|
"doctype": "Salary Component",
|
||||||
"salary_component": "Basic",
|
"salary_component": "Basic",
|
||||||
"type": "Earning",
|
"type": "Earning",
|
||||||
"is_payable": 1,
|
|
||||||
"is_tax_applicable": 1
|
"is_tax_applicable": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Salary Component",
|
"doctype": "Salary Component",
|
||||||
"salary_component": "Leave Encashment",
|
"salary_component": "Leave Encashment",
|
||||||
"type": "Earning",
|
"type": "Earning",
|
||||||
"is_payable": 1,
|
|
||||||
"is_tax_applicable": 1
|
"is_tax_applicable": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -18,6 +18,5 @@ def create_salary_component(component_name, **args):
|
|||||||
"doctype": "Salary Component",
|
"doctype": "Salary Component",
|
||||||
"salary_component": component_name,
|
"salary_component": component_name,
|
||||||
"type": args.get("type") or "Earning",
|
"type": args.get("type") or "Earning",
|
||||||
"is_payable": args.get("is_payable") or 1,
|
|
||||||
"is_tax_applicable": args.get("is_tax_applicable") or 1
|
"is_tax_applicable": args.get("is_tax_applicable") or 1
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"deduct_full_tax_on_selected_payroll_date",
|
"deduct_full_tax_on_selected_payroll_date",
|
||||||
"depends_on_payment_days",
|
"depends_on_payment_days",
|
||||||
"is_tax_applicable",
|
"is_tax_applicable",
|
||||||
|
"exempted_from_income_tax",
|
||||||
"is_flexible_benefit",
|
"is_flexible_benefit",
|
||||||
"variable_based_on_taxable_salary",
|
"variable_based_on_taxable_salary",
|
||||||
"section_break_2",
|
"section_break_2",
|
||||||
@ -62,6 +63,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "eval:doc.parentfield=='earnings'",
|
||||||
"fetch_from": "salary_component.is_tax_applicable",
|
"fetch_from": "salary_component.is_tax_applicable",
|
||||||
"fieldname": "is_tax_applicable",
|
"fieldname": "is_tax_applicable",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -71,6 +73,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "eval:doc.parentfield=='earnings'",
|
||||||
"fetch_from": "salary_component.is_flexible_benefit",
|
"fetch_from": "salary_component.is_flexible_benefit",
|
||||||
"fieldname": "is_flexible_benefit",
|
"fieldname": "is_flexible_benefit",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -80,6 +83,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "eval:doc.parentfield=='deductions'",
|
||||||
"fetch_from": "salary_component.variable_based_on_taxable_salary",
|
"fetch_from": "salary_component.variable_based_on_taxable_salary",
|
||||||
"fieldname": "variable_based_on_taxable_salary",
|
"fieldname": "variable_based_on_taxable_salary",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -187,11 +191,20 @@
|
|||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"label": "Condition and Formula Help",
|
"label": "Condition and Formula Help",
|
||||||
"options": "<h3>Condition and Formula 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>"
|
"options": "<h3>Condition and Formula 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",
|
||||||
|
"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,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-31 17:15:25.646689",
|
"modified": "2020-04-24 20:00:16.475295",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Salary Detail",
|
"name": "Salary Detail",
|
||||||
|
|||||||
@ -51,7 +51,7 @@ frappe.ui.form.on("Salary Slip", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
end_date: function(frm) {
|
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){
|
set_end_date: function(frm){
|
||||||
@ -86,7 +86,7 @@ frappe.ui.form.on("Salary Slip", {
|
|||||||
|
|
||||||
salary_slip_based_on_timesheet: function(frm) {
|
salary_slip_based_on_timesheet: function(frm) {
|
||||||
frm.trigger("toggle_fields");
|
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) {
|
payroll_frequency: function(frm) {
|
||||||
@ -95,15 +95,14 @@ frappe.ui.form.on("Salary Slip", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
employee: function(frm) {
|
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){
|
leave_without_pay: function(frm){
|
||||||
if (frm.doc.employee && frm.doc.start_date && frm.doc.end_date) {
|
if (frm.doc.employee && frm.doc.start_date && frm.doc.end_date) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
method: 'process_salary_based_on_leave',
|
method: 'process_salary_based_on_working_days',
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
args: {"lwp": frm.doc.leave_without_pay},
|
|
||||||
callback: function(r, rt) {
|
callback: function(r, rt) {
|
||||||
frm.refresh();
|
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(['hourly_wages', 'timesheets'], cint(frm.doc.salary_slip_based_on_timesheet)===1);
|
||||||
|
|
||||||
frm.toggle_display(['payment_days', 'total_working_days', 'leave_without_pay'],
|
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({
|
return frappe.call({
|
||||||
method: 'get_emp_and_leave_details',
|
method: 'get_emp_and_working_day_details',
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
callback: function(r, rt) {
|
callback: function(r, rt) {
|
||||||
frm.refresh();
|
frm.refresh();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user