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:
ruthra kumar
2024-09-18 11:40:02 +05:30
committed by GitHub
2 changed files with 84 additions and 32 deletions

View File

@@ -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,

View File

@@ -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):