Merge pull request #49757 from rohitwaghchaure/subcontracting-receipt-service-expense-account

feat: service expense account in the subcontracting receipt
This commit is contained in:
rohitwaghchaure
2025-09-26 21:12:26 +05:30
committed by GitHub
5 changed files with 151 additions and 11 deletions

View File

@@ -1308,6 +1308,7 @@ def make_subcontracted_items():
"Subcontracted Item SA7": {},
"Subcontracted Item SA8": {},
"Subcontracted Item SA9": {"stock_uom": "Litre"},
"Subcontracted Item SA10": {},
}
for item, properties in sub_contracted_items.items():
@@ -1329,6 +1330,7 @@ def make_raw_materials():
"Subcontracted SRM Item 5": {"has_serial_no": 1, "serial_no_series": "SRIID.####"},
"Subcontracted SRM Item 8": {},
"Subcontracted SRM Item 9": {"stock_uom": "Litre"},
"Subcontracted SRM Item 10": {},
}
for item, properties in raw_materials.items():
@@ -1357,6 +1359,7 @@ def make_service_items():
"Subcontracted Service Item 7": {},
"Subcontracted Service Item 8": {},
"Subcontracted Service Item 9": {},
"Subcontracted Service Item 10": {},
}
for item, properties in service_items.items():
@@ -1381,6 +1384,7 @@ def make_bom_for_subcontracted_items():
"Subcontracted Item SA6": ["Subcontracted SRM Item 3"],
"Subcontracted Item SA7": ["Subcontracted SRM Item 1"],
"Subcontracted Item SA8": ["Subcontracted SRM Item 8"],
"Subcontracted Item SA10": ["Subcontracted SRM Item 10"],
}
for item_code, raw_materials in boms.items():

View File

@@ -117,7 +117,13 @@ class SubcontractingReceipt(SubcontractingController):
self.validate_items_qty()
self.set_items_bom()
self.set_items_cost_center()
self.set_items_expense_account()
if self.company:
default_expense_account = self.get_company_default(
"default_expense_account", ignore_validation=True
)
self.set_service_expense_account(default_expense_account)
self.set_expense_account_for_subcontracted_items(default_expense_account)
def validate(self):
self.reset_supplied_items()
@@ -205,6 +211,39 @@ class SubcontractingReceipt(SubcontractingController):
doc = frappe.get_doc("Job Card", row.job_card)
doc.set_manufactured_qty()
def set_service_expense_account(self, default_expense_account):
for row in self.get("items"):
if not row.service_expense_account and row.purchase_order_item:
service_item = frappe.db.get_value(
"Purchase Order Item", row.purchase_order_item, "item_code"
)
if service_item:
if default := (
get_item_defaults(service_item, self.company)
or get_item_group_defaults(service_item, self.company)
or get_brand_defaults(service_item, self.company)
):
if service_expense_account := default.get("expense_account"):
row.service_expense_account = service_expense_account
if not row.service_expense_account:
row.service_expense_account = default_expense_account
def set_expense_account_for_subcontracted_items(self, default_expense_account):
for row in self.get("items"):
if not row.expense_account:
if default := (
get_item_defaults(row.item_code, self.company)
or get_item_group_defaults(row.item_code, self.company)
or get_brand_defaults(row.item_code, self.company)
):
if expense_account := default.get("expense_account"):
row.expense_account = expense_account
if not row.expense_account:
row.expense_account = default_expense_account
def get_manufactured_qty(self, job_card):
table = frappe.qb.DocType("Subcontracting Receipt Item")
query = (
@@ -262,14 +301,6 @@ class SubcontractingReceipt(SubcontractingController):
self.company,
)
def set_items_expense_account(self):
if self.company:
expense_account = self.get_company_default("default_expense_account", ignore_validation=True)
for item in self.items:
if not item.expense_account:
item.expense_account = expense_account
def set_supplied_items_expense_account(self):
for item in self.supplied_items:
if not item.expense_account:
@@ -625,13 +656,17 @@ class SubcontractingReceipt(SubcontractingController):
project=item.project,
item=item,
)
service_cost = flt(
item.service_cost_per_qty, item.precision("service_cost_per_qty")
) * flt(item.qty, item.precision("qty"))
# Expense Account (Credit)
self.add_gl_entry(
gl_entries=gl_entries,
account=item.expense_account,
cost_center=item.cost_center,
debit=0.0,
credit=stock_value_diff,
credit=flt(stock_value_diff) - service_cost,
remarks=remarks,
against_account=accepted_warehouse_account,
account_currency=get_account_currency(item.expense_account),
@@ -639,6 +674,21 @@ class SubcontractingReceipt(SubcontractingController):
item=item,
)
service_account = item.service_expense_account or item.expense_account
# Expense Account (Credit)
self.add_gl_entry(
gl_entries=gl_entries,
account=service_account,
cost_center=item.cost_center,
debit=0.0,
credit=service_cost,
remarks=remarks,
against_account=accepted_warehouse_account,
account_currency=get_account_currency(service_account),
project=item.project,
item=item,
)
if flt(item.rm_supp_cost) and supplier_warehouse_account:
for rm_item in supplied_items_details.get(item.name):
# Supplier Warehouse Account (Credit)

View File

@@ -421,6 +421,79 @@ class TestSubcontractingReceipt(IntegrationTestCase):
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
def test_subcontracting_receipt_for_service_expense_account(self):
service_expense_account = (
frappe.get_doc(
{
"doctype": "Account",
"account_name": "_Test Service Expense",
"account_type": "Expense Account",
"company": "_Test Company with perpetual inventory",
"is_group": 0,
"parent_account": "Indirect Expenses - TCP1",
}
)
.insert(ignore_if_duplicate=True)
.name
)
service_item_doc = frappe.get_doc("Item", "Subcontracted Service Item 10")
service_item_doc.append(
"item_defaults",
{
"company": "_Test Company with perpetual inventory",
"expense_account": service_expense_account,
"default_warehouse": "Stores - TCP1",
},
)
service_item_doc.save()
service_items = [
{
"warehouse": "Stores - TCP1",
"item_code": "Subcontracted Service Item 10",
"qty": 10,
"rate": 100,
"fg_item": "Subcontracted Item SA10",
"fg_item_qty": 10,
},
]
sco = get_subcontracting_order(
company="_Test Company with perpetual inventory",
warehouse="Stores - TCP1",
supplier_warehouse="Work In Progress - TCP1",
service_items=service_items,
)
rm_items = get_rm_items(sco.supplied_items)
itemwise_details = make_stock_in_entry(rm_items=rm_items)
make_stock_transfer_entry(
sco_no=sco.name,
rm_items=rm_items,
itemwise_details=copy.deepcopy(itemwise_details),
)
scr = make_subcontracting_receipt(sco.name)
scr.submit()
for item in scr.items:
self.assertEqual(item.service_expense_account, service_expense_account)
gl_entries = get_gl_entries("Subcontracting Receipt", scr.name)
self.assertTrue(gl_entries)
fg_warehouse_ac = get_inventory_account(scr.company, scr.items[0].warehouse)
expense_account = scr.items[0].expense_account
expected_values = {
fg_warehouse_ac: [2000, 1000],
expense_account: [1000, 1000],
service_expense_account: [0, 1000],
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
@IntegrationTestCase.change_settings("Stock Settings", {"use_serial_batch_fields": 0})
def test_subcontracting_receipt_with_zero_service_cost(self):
warehouse = "Stores - TCP1"

View File

@@ -66,6 +66,8 @@
"manufacturer_part_no",
"accounting_details_section",
"expense_account",
"column_break_exht",
"service_expense_account",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
@@ -597,13 +599,23 @@
"label": "Landed Cost Voucher Amount",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "column_break_exht",
"fieldtype": "Column Break"
},
{
"fieldname": "service_expense_account",
"fieldtype": "Link",
"label": "Service Expense Account",
"options": "Account"
}
],
"grid_page_length": 50,
"idx": 1,
"istable": 1,
"links": [],
"modified": "2025-06-11 08:45:18.903036",
"modified": "2025-09-26 12:00:38.877638",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Receipt Item",

View File

@@ -56,6 +56,7 @@ class SubcontractingReceiptItem(Document):
serial_and_batch_bundle: DF.Link | None
serial_no: DF.SmallText | None
service_cost_per_qty: DF.Currency
service_expense_account: DF.Link | None
stock_uom: DF.Link
subcontracting_order: DF.Link | None
subcontracting_order_item: DF.Data | None