fix: Subcontracting Receipt GL Entries (backport #31918) (#32124)

fix: Subcontracting Receipt GL Entries
This commit is contained in:
Sagar Sharma
2022-09-08 11:18:00 +05:30
committed by GitHub
parent 9b6dd7e71f
commit f2ab220ce3
8 changed files with 311 additions and 46 deletions

View File

@@ -510,7 +510,7 @@ def create_subcontracting_order(**args):
for item in sco.items:
item.include_exploded_items = args.get("include_exploded_items", 1)
if args.get("warehouse"):
if args.warehouse:
for item in sco.items:
item.warehouse = args.warehouse
else:

View File

@@ -5,6 +5,8 @@ import frappe
from frappe import _
from frappe.utils import cint, flt, getdate, nowdate
import erpnext
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.subcontracting_controller import SubcontractingController
@@ -225,6 +227,137 @@ class SubcontractingReceipt(SubcontractingController):
if status:
frappe.db.set_value("Subcontracting Receipt", self.name, "status", status, update_modified)
def get_gl_entries(self, warehouse_account=None):
from erpnext.accounts.general_ledger import process_gl_map
gl_entries = []
self.make_item_gl_entries(gl_entries, warehouse_account)
return process_gl_map(gl_entries)
def make_item_gl_entries(self, gl_entries, warehouse_account=None):
if erpnext.is_perpetual_inventory_enabled(self.company):
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
warehouse_with_no_account = []
for item in self.items:
if flt(item.rate) and flt(item.qty):
if warehouse_account.get(item.warehouse):
stock_value_diff = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Subcontracting Receipt",
"voucher_no": self.name,
"voucher_detail_no": item.name,
"warehouse": item.warehouse,
"is_cancelled": 0,
},
"stock_value_difference",
)
warehouse_account_name = warehouse_account[item.warehouse]["account"]
warehouse_account_currency = warehouse_account[item.warehouse]["account_currency"]
supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
"account_currency"
)
remarks = self.get("remarks") or _("Accounting Entry for Stock")
# FG Warehouse Account (Debit)
self.add_gl_entry(
gl_entries=gl_entries,
account=warehouse_account_name,
cost_center=item.cost_center,
debit=stock_value_diff,
credit=0.0,
remarks=remarks,
against_account=stock_rbnb,
account_currency=warehouse_account_currency,
item=item,
)
# Supplier Warehouse Account (Credit)
if flt(item.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
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=warehouse_account_name,
account_currency=supplier_warehouse_account_currency,
item=item,
)
# Expense Account (Credit)
if flt(item.service_cost_per_qty):
self.add_gl_entry(
gl_entries=gl_entries,
account=item.expense_account,
cost_center=item.cost_center,
debit=0.0,
credit=flt(item.service_cost_per_qty) * flt(item.qty),
remarks=remarks,
against_account=warehouse_account_name,
account_currency=get_account_currency(item.expense_account),
item=item,
)
# Loss Account (Credit)
divisional_loss = flt(item.amount - stock_value_diff, item.precision("amount"))
if divisional_loss:
if self.is_return:
loss_account = expenses_included_in_valuation
else:
loss_account = item.expense_account
self.add_gl_entry(
gl_entries=gl_entries,
account=loss_account,
cost_center=item.cost_center,
debit=divisional_loss,
credit=0.0,
remarks=remarks,
against_account=warehouse_account_name,
account_currency=get_account_currency(loss_account),
project=item.project,
item=item,
)
elif (
item.warehouse not in warehouse_with_no_account
or item.rejected_warehouse not in warehouse_with_no_account
):
warehouse_with_no_account.append(item.warehouse)
# Additional Costs Expense Accounts (Credit)
for row in self.additional_costs:
credit_amount = (
flt(row.base_amount)
if (row.base_amount or row.account_currency != self.company_currency)
else flt(row.amount)
)
self.add_gl_entry(
gl_entries=gl_entries,
account=row.expense_account,
cost_center=self.cost_center or self.get_company_default("cost_center"),
debit=0.0,
credit=credit_amount,
remarks=remarks,
against_account=None,
)
if warehouse_with_no_account:
frappe.msgprint(
_("No accounting entries for the following warehouses")
+ ": \n"
+ "\n".join(warehouse_with_no_account)
)
@frappe.whitelist()
def make_subcontract_return(source_name, target_doc=None):

View File

@@ -6,8 +6,10 @@ import copy
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import flt
from frappe.utils import cint, flt
import erpnext
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.controllers.tests.test_subcontracting_controller import (
get_rm_items,
@@ -22,6 +24,7 @@ from erpnext.controllers.tests.test_subcontracting_controller import (
set_backflush_based_on,
)
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
make_subcontracting_receipt,
@@ -366,6 +369,103 @@ class TestSubcontractingReceipt(FrappeTestCase):
args = frappe._dict(scr_name=scr1.name, qty=-15)
self.assertRaises(OverAllowanceError, make_return_subcontracting_receipt, **args)
def test_subcontracting_receipt_no_gl_entry(self):
sco = get_subcontracting_order()
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.append(
"additional_costs",
{
"expense_account": "Expenses Included In Valuation - _TC",
"description": "Test Additional Costs",
"amount": 100,
},
)
scr.save()
scr.submit()
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Subcontracting Receipt",
"voucher_no": scr.name,
"item_code": "Subcontracted Item SA7",
"warehouse": "_Test Warehouse - _TC",
},
"stock_value_difference",
)
# Service Cost(100 * 10) + Raw Materials Cost(50 * 10) + Additional Costs(100) = 1600
self.assertEqual(stock_value_difference, 1600)
self.assertFalse(get_gl_entries("Subcontracting Receipt", scr.name))
def test_subcontracting_receipt_gl_entry(self):
sco = get_subcontracting_order(
company="_Test Company with perpetual inventory",
warehouse="Stores - TCP1",
supplier_warehouse="Work In Progress - TCP1",
)
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)
additional_costs_expense_account = "Expenses Included In Valuation - TCP1"
scr.append(
"additional_costs",
{
"expense_account": additional_costs_expense_account,
"description": "Test Additional Costs",
"amount": 100,
"base_amount": 100,
},
)
scr.save()
scr.submit()
self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(scr.company)), 1)
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)
supplier_warehouse_ac = get_inventory_account(scr.company, scr.supplier_warehouse)
expense_account = scr.items[0].expense_account
if fg_warehouse_ac == supplier_warehouse_ac:
expected_values = {
fg_warehouse_ac: [2100.0, 1000.0], # FG Amount (D), RM Cost (C)
expense_account: [0.0, 1000.0], # Service Cost (C)
additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C)
}
else:
expected_values = {
fg_warehouse_ac: [2100.0, 0.0], # FG Amount (D)
supplier_warehouse_ac: [0.0, 1000.0], # RM Cost (C)
expense_account: [0.0, 1000.0], # Service Cost (C)
additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C)
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
scr.reload()
scr.cancel()
self.assertTrue(get_gl_entries("Subcontracting Receipt", scr.name))
def make_return_subcontracting_receipt(**args):
args = frappe._dict(args)