mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-16 16:15:02 +00:00
Merge pull request #49757 from rohitwaghchaure/subcontracting-receipt-service-expense-account
feat: service expense account in the subcontracting receipt
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user