diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 300f7a774eb..73474f2afe5 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -10,6 +10,10 @@ import erpnext from erpnext.accounts.utils import get_account_currency from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.subcontracting_controller import SubcontractingController +from erpnext.setup.doctype.brand.brand import get_brand_defaults +from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults +from erpnext.stock.doctype.item.item import get_item_defaults +from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account from erpnext.stock.stock_ledger import get_valuation_rate @@ -140,6 +144,9 @@ class SubcontractingReceipt(SubcontractingController): self.reset_default_field_value("rejected_warehouse", "items", "rejected_warehouse") self.get_current_stock() + self.set_supplied_items_expense_account() + self.set_supplied_items_cost_center() + def on_submit(self): self.validate_closed_subcontracting_order() self.validate_available_qty_for_consumption() @@ -224,6 +231,17 @@ class SubcontractingReceipt(SubcontractingController): if not item.cost_center: item.cost_center = cost_center + def set_supplied_items_cost_center(self): + for item in self.supplied_items: + if not item.cost_center: + item.cost_center = get_default_cost_center( + {"project": self.project}, + get_item_defaults(item.rm_item_code, self.company), + get_item_group_defaults(item.rm_item_code, self.company), + get_brand_defaults(item.rm_item_code, self.company), + self.company, + ) + def set_items_expense_account(self): if self.company: expense_account = self.get_company_default("default_expense_account", ignore_validation=True) @@ -232,6 +250,22 @@ class SubcontractingReceipt(SubcontractingController): 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: + item.expense_account = get_default_expense_account( + frappe._dict( + { + "expense_account": self.get_company_default( + "default_expense_account", ignore_validation=True + ) + } + ), + get_item_defaults(item.rm_item_code, self.company), + get_item_group_defaults(item.rm_item_code, self.company), + get_brand_defaults(item.rm_item_code, self.company), + ) + def reset_supplied_items(self): if ( frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on") @@ -519,6 +553,18 @@ class SubcontractingReceipt(SubcontractingController): def make_item_gl_entries(self, gl_entries, warehouse_account=None): warehouse_with_no_account = [] + supplied_items_details = frappe._dict() + for item in self.supplied_items: + supplied_items_details.setdefault(item.reference_name, []).append( + frappe._dict( + { + "amount": item.amount, + "expense_account": item.expense_account, + "cost_center": item.cost_center, + } + ) + ) + for item in self.items: if flt(item.rate) and flt(item.qty): if warehouse_account.get(item.warehouse): @@ -568,32 +614,33 @@ class SubcontractingReceipt(SubcontractingController): ) if flt(item.rm_supp_cost) and supplier_warehouse_account: - # Supplier Warehouse Account (Credit) - self.add_gl_entry( - gl_entries=gl_entries, - account=supplier_warehouse_account, - cost_center=item.cost_center, - debit=0.0, - credit=flt(item.rm_supp_cost), - remarks=remarks, - against_account=item.expense_account, - account_currency=get_account_currency(supplier_warehouse_account), - project=item.project, - item=item, - ) - # Expense Account (Debit) - self.add_gl_entry( - gl_entries=gl_entries, - account=item.expense_account, - cost_center=item.cost_center, - debit=flt(item.rm_supp_cost), - credit=0.0, - remarks=remarks, - against_account=supplier_warehouse_account, - account_currency=get_account_currency(item.expense_account), - project=item.project, - item=item, - ) + for rm_item in supplied_items_details.get(item.name): + # Supplier Warehouse Account (Credit) + self.add_gl_entry( + gl_entries=gl_entries, + account=supplier_warehouse_account, + cost_center=rm_item.cost_center, + debit=0.0, + credit=flt(rm_item.amount), + remarks=remarks, + against_account=rm_item.expense_account, + account_currency=get_account_currency(supplier_warehouse_account), + project=item.project, + item=item, + ) + # Expense Account (Debit) + self.add_gl_entry( + gl_entries=gl_entries, + account=rm_item.expense_account, + cost_center=rm_item.cost_center, + debit=flt(rm_item.amount), + credit=0.0, + remarks=remarks, + against_account=supplier_warehouse_account, + account_currency=get_account_currency(item.expense_account), + project=item.project, + item=item, + ) # Expense Account (Debit) if item.additional_cost_per_qty: diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index b5d190f7736..55e950856bc 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -372,6 +372,56 @@ class TestSubcontractingReceipt(FrappeTestCase): self.assertTrue(get_gl_entries("Subcontracting Receipt", scr.name)) frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1) + @change_settings("Stock Settings", {"use_serial_batch_fields": 0}) + def test_subcontracting_receipt_gl_entry_with_different_rm_expense_accounts(self): + service_items = [ + { + "warehouse": "Stores - TCP1", + "item_code": "Subcontracted Service Item 7", + "qty": 10, + "rate": 100, + "fg_item": "Subcontracted Item SA4", + "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.save() + scr.supplied_items[1].expense_account = "_Test Write Off - TCP1" + scr.save() + scr.submit() + + for item in scr.supplied_items: + self.assertTrue(item.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: [4000, 3000], + expense_account: [2000, 4000], + "_Test Write Off - TCP1": [1000, 0], + } + + for gle in gl_entries: + self.assertEqual(expected_values[gle.account][0], gle.debit) + self.assertEqual(expected_values[gle.account][1], gle.credit) + @change_settings("Stock Settings", {"use_serial_batch_fields": 0}) def test_subcontracting_receipt_with_zero_service_cost(self): warehouse = "Stores - TCP1" diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json index e1927a5467a..ce3494e879d 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json @@ -33,7 +33,11 @@ "section_break_zwnh", "serial_no", "column_break_qibi", - "batch_no" + "batch_no", + "accounting_details_section", + "expense_account", + "accounting_dimensions_section", + "cost_center" ], "fields": [ { @@ -103,7 +107,7 @@ { "fieldname": "stock_uom", "fieldtype": "Link", - "label": "Stock Uom", + "label": "Stock UOM", "options": "UOM", "read_only": 1 }, @@ -231,18 +235,43 @@ "fieldname": "add_serial_batch_bundle", "fieldtype": "Button", "label": "Add Serial / Batch Bundle" + }, + { + "fieldname": "accounting_details_section", + "fieldtype": "Section Break", + "label": "Accounting Details" + }, + { + "fieldname": "expense_account", + "fieldtype": "Link", + "label": "Expense Account", + "options": "Account" + }, + { + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))", + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center", + "print_hide": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2024-03-30 10:26:27.237371", + "modified": "2025-05-27 12:33:58.772638", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Supplied Item", "naming_rule": "Autoincrement", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [], diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py index 8f09197aa83..1c6ae80969a 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py @@ -20,8 +20,10 @@ class SubcontractingReceiptSuppliedItem(Document): bom_detail_no: DF.Data | None consumed_qty: DF.Float conversion_factor: DF.Float + cost_center: DF.Link | None current_stock: DF.Float description: DF.TextEditor | None + expense_account: DF.Link | None item_name: DF.Data | None main_item_code: DF.Link | None parent: DF.Data