mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-23 15:09:20 +00:00
Merge pull request #43266 from frappe/mergify/bp/version-15-hotfix/pr-43216
fix: get cost center allocation percentage only from the applicable allocation (backport #43216)
This commit is contained in:
@@ -22,8 +22,10 @@ class TestCostCenterAllocation(unittest.TestCase):
|
|||||||
cost_centers = [
|
cost_centers = [
|
||||||
"Main Cost Center 1",
|
"Main Cost Center 1",
|
||||||
"Main Cost Center 2",
|
"Main Cost Center 2",
|
||||||
|
"Main Cost Center 3",
|
||||||
"Sub Cost Center 1",
|
"Sub Cost Center 1",
|
||||||
"Sub Cost Center 2",
|
"Sub Cost Center 2",
|
||||||
|
"Sub Cost Center 3",
|
||||||
]
|
]
|
||||||
for cc in cost_centers:
|
for cc in cost_centers:
|
||||||
create_cost_center(cost_center_name=cc, company="_Test Company")
|
create_cost_center(cost_center_name=cc, company="_Test Company")
|
||||||
@@ -36,7 +38,7 @@ class TestCostCenterAllocation(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
jv = make_journal_entry(
|
jv = make_journal_entry(
|
||||||
"_Test Cash - _TC", "Sales - _TC", 100, cost_center="Main Cost Center 1 - _TC", submit=True
|
"Cash - _TC", "Sales - _TC", 100, cost_center="Main Cost Center 1 - _TC", submit=True
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_values = [["Sub Cost Center 1 - _TC", 0.0, 60], ["Sub Cost Center 2 - _TC", 0.0, 40]]
|
expected_values = [["Sub Cost Center 1 - _TC", 0.0, 60], ["Sub Cost Center 2 - _TC", 0.0, 40]]
|
||||||
@@ -120,7 +122,7 @@ class TestCostCenterAllocation(unittest.TestCase):
|
|||||||
def test_valid_from_based_on_existing_gle(self):
|
def test_valid_from_based_on_existing_gle(self):
|
||||||
# GLE posted against Sub Cost Center 1 on today
|
# GLE posted against Sub Cost Center 1 on today
|
||||||
jv = make_journal_entry(
|
jv = make_journal_entry(
|
||||||
"_Test Cash - _TC",
|
"Cash - _TC",
|
||||||
"Sales - _TC",
|
"Sales - _TC",
|
||||||
100,
|
100,
|
||||||
cost_center="Main Cost Center 1 - _TC",
|
cost_center="Main Cost Center 1 - _TC",
|
||||||
@@ -141,6 +143,53 @@ class TestCostCenterAllocation(unittest.TestCase):
|
|||||||
|
|
||||||
jv.cancel()
|
jv.cancel()
|
||||||
|
|
||||||
|
def test_multiple_cost_center_allocation_on_same_main_cost_center(self):
|
||||||
|
coa1 = create_cost_center_allocation(
|
||||||
|
"_Test Company",
|
||||||
|
"Main Cost Center 3 - _TC",
|
||||||
|
{"Sub Cost Center 1 - _TC": 30, "Sub Cost Center 2 - _TC": 30, "Sub Cost Center 3 - _TC": 40},
|
||||||
|
valid_from=add_days(today(), -5),
|
||||||
|
)
|
||||||
|
|
||||||
|
coa2 = create_cost_center_allocation(
|
||||||
|
"_Test Company",
|
||||||
|
"Main Cost Center 3 - _TC",
|
||||||
|
{"Sub Cost Center 1 - _TC": 50, "Sub Cost Center 2 - _TC": 50},
|
||||||
|
valid_from=add_days(today(), -1),
|
||||||
|
)
|
||||||
|
|
||||||
|
jv = make_journal_entry(
|
||||||
|
"Cash - _TC",
|
||||||
|
"Sales - _TC",
|
||||||
|
100,
|
||||||
|
cost_center="Main Cost Center 3 - _TC",
|
||||||
|
posting_date=today(),
|
||||||
|
submit=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_values = {"Sub Cost Center 1 - _TC": 50, "Sub Cost Center 2 - _TC": 50}
|
||||||
|
|
||||||
|
gle = frappe.qb.DocType("GL Entry")
|
||||||
|
gl_entries = (
|
||||||
|
frappe.qb.from_(gle)
|
||||||
|
.select(gle.cost_center, gle.debit, gle.credit)
|
||||||
|
.where(gle.voucher_type == "Journal Entry")
|
||||||
|
.where(gle.voucher_no == jv.name)
|
||||||
|
.where(gle.account == "Sales - _TC")
|
||||||
|
.orderby(gle.cost_center)
|
||||||
|
).run(as_dict=1)
|
||||||
|
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
|
for gle in gl_entries:
|
||||||
|
self.assertTrue(gle.cost_center in expected_values)
|
||||||
|
self.assertEqual(gle.debit, 0)
|
||||||
|
self.assertEqual(gle.credit, expected_values[gle.cost_center])
|
||||||
|
|
||||||
|
coa1.cancel()
|
||||||
|
coa2.cancel()
|
||||||
|
jv.cancel()
|
||||||
|
|
||||||
|
|
||||||
def create_cost_center_allocation(
|
def create_cost_center_allocation(
|
||||||
company,
|
company,
|
||||||
|
|||||||
@@ -179,50 +179,53 @@ def process_gl_map(gl_map, merge_entries=True, precision=None):
|
|||||||
|
|
||||||
|
|
||||||
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
|
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
|
||||||
cost_center_allocation = get_cost_center_allocation_data(gl_map[0]["company"], gl_map[0]["posting_date"])
|
|
||||||
if not cost_center_allocation:
|
|
||||||
return gl_map
|
|
||||||
|
|
||||||
new_gl_map = []
|
new_gl_map = []
|
||||||
for d in gl_map:
|
for d in gl_map:
|
||||||
cost_center = d.get("cost_center")
|
cost_center = d.get("cost_center")
|
||||||
|
|
||||||
# Validate budget against main cost center
|
# Validate budget against main cost center
|
||||||
validate_expense_against_budget(d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision))
|
validate_expense_against_budget(d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision))
|
||||||
|
cost_center_allocation = get_cost_center_allocation_data(
|
||||||
if cost_center and cost_center_allocation.get(cost_center):
|
gl_map[0]["company"], gl_map[0]["posting_date"], cost_center
|
||||||
for sub_cost_center, percentage in cost_center_allocation.get(cost_center, {}).items():
|
)
|
||||||
gle = copy.deepcopy(d)
|
if not cost_center_allocation:
|
||||||
gle.cost_center = sub_cost_center
|
|
||||||
for field in ("debit", "credit", "debit_in_account_currency", "credit_in_account_currency"):
|
|
||||||
gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
|
|
||||||
new_gl_map.append(gle)
|
|
||||||
else:
|
|
||||||
new_gl_map.append(d)
|
new_gl_map.append(d)
|
||||||
|
continue
|
||||||
|
|
||||||
|
for sub_cost_center, percentage in cost_center_allocation:
|
||||||
|
gle = copy.deepcopy(d)
|
||||||
|
gle.cost_center = sub_cost_center
|
||||||
|
for field in ("debit", "credit", "debit_in_account_currency", "credit_in_account_currency"):
|
||||||
|
gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
|
||||||
|
new_gl_map.append(gle)
|
||||||
|
|
||||||
return new_gl_map
|
return new_gl_map
|
||||||
|
|
||||||
|
|
||||||
def get_cost_center_allocation_data(company, posting_date):
|
def get_cost_center_allocation_data(company, posting_date, cost_center):
|
||||||
par = frappe.qb.DocType("Cost Center Allocation")
|
cost_center_allocation = frappe.db.get_value(
|
||||||
child = frappe.qb.DocType("Cost Center Allocation Percentage")
|
"Cost Center Allocation",
|
||||||
|
{
|
||||||
|
"docstatus": 1,
|
||||||
|
"company": company,
|
||||||
|
"valid_from": ("<=", posting_date),
|
||||||
|
"main_cost_center": cost_center,
|
||||||
|
},
|
||||||
|
pluck="name",
|
||||||
|
order_by="valid_from desc",
|
||||||
|
)
|
||||||
|
|
||||||
records = (
|
if not cost_center_allocation:
|
||||||
frappe.qb.from_(par)
|
return []
|
||||||
.inner_join(child)
|
|
||||||
.on(par.name == child.parent)
|
|
||||||
.select(par.main_cost_center, child.cost_center, child.percentage)
|
|
||||||
.where(par.docstatus == 1)
|
|
||||||
.where(par.company == company)
|
|
||||||
.where(par.valid_from <= posting_date)
|
|
||||||
.orderby(par.valid_from, order=frappe.qb.desc)
|
|
||||||
).run(as_dict=True)
|
|
||||||
|
|
||||||
cc_allocation = frappe._dict()
|
records = frappe.db.get_all(
|
||||||
for d in records:
|
"Cost Center Allocation Percentage",
|
||||||
cc_allocation.setdefault(d.main_cost_center, frappe._dict()).setdefault(d.cost_center, d.percentage)
|
{"parent": cost_center_allocation},
|
||||||
|
["cost_center", "percentage"],
|
||||||
|
as_list=True,
|
||||||
|
)
|
||||||
|
|
||||||
return cc_allocation
|
return records
|
||||||
|
|
||||||
|
|
||||||
def merge_similar_entries(gl_map, precision=None):
|
def merge_similar_entries(gl_map, precision=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user