Merge pull request #31918 from s-aga-r/fix/subcontracting-receipt/gl-entries
fix: Subcontracting Receipt GL Entries
This commit is contained in:
commit
72d5366e96
@ -700,6 +700,47 @@ class StockController(AccountsController):
|
||||
else:
|
||||
create_repost_item_valuation_entry(args)
|
||||
|
||||
def add_gl_entry(
|
||||
self,
|
||||
gl_entries,
|
||||
account,
|
||||
cost_center,
|
||||
debit,
|
||||
credit,
|
||||
remarks,
|
||||
against_account,
|
||||
debit_in_account_currency=None,
|
||||
credit_in_account_currency=None,
|
||||
account_currency=None,
|
||||
project=None,
|
||||
voucher_detail_no=None,
|
||||
item=None,
|
||||
posting_date=None,
|
||||
):
|
||||
|
||||
gl_entry = {
|
||||
"account": account,
|
||||
"cost_center": cost_center,
|
||||
"debit": debit,
|
||||
"credit": credit,
|
||||
"against": against_account,
|
||||
"remarks": remarks,
|
||||
}
|
||||
|
||||
if voucher_detail_no:
|
||||
gl_entry.update({"voucher_detail_no": voucher_detail_no})
|
||||
|
||||
if debit_in_account_currency:
|
||||
gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
|
||||
|
||||
if credit_in_account_currency:
|
||||
gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
|
||||
|
||||
if posting_date:
|
||||
gl_entry.update({"posting_date": posting_date})
|
||||
|
||||
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
|
||||
|
||||
|
||||
def repost_required_for_queue(doc: StockController) -> bool:
|
||||
"""check if stock document contains repeated item-warehouse with queue based valuation.
|
||||
|
@ -897,7 +897,7 @@ def make_stock_transfer_entry(**args):
|
||||
"item_name": row.item_code,
|
||||
"rate": row.rate or 100,
|
||||
"stock_uom": row.stock_uom or "Nos",
|
||||
"warehouse": row.warehuose or "_Test Warehouse - _TC",
|
||||
"warehouse": row.warehouse or "_Test Warehouse - _TC",
|
||||
}
|
||||
|
||||
item_details = args.itemwise_details.get(row.item_code)
|
||||
@ -1031,9 +1031,9 @@ def get_subcontracting_order(**args):
|
||||
if not args.service_items:
|
||||
service_items = [
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 7",
|
||||
"qty": 5,
|
||||
"qty": 10,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA7",
|
||||
"fg_item_qty": 10,
|
||||
@ -1046,6 +1046,7 @@ def get_subcontracting_order(**args):
|
||||
rm_items=service_items,
|
||||
is_subcontracted=1,
|
||||
supplier_warehouse=args.supplier_warehouse or "_Test Warehouse 1 - _TC",
|
||||
company=args.company,
|
||||
)
|
||||
|
||||
return create_subcontracting_order(po_name=po.name, **args)
|
||||
|
@ -312,4 +312,5 @@ erpnext.patches.v13_0.fix_number_and_frequency_for_monthly_depreciation
|
||||
erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
|
||||
erpnext.patches.v14_0.fix_crm_no_of_employees
|
||||
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
||||
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
||||
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
||||
|
@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison import (
|
||||
get_data,
|
||||
)
|
||||
|
||||
|
||||
def execute():
|
||||
data = []
|
||||
|
||||
for company in frappe.db.get_list("Company", pluck="name"):
|
||||
data += get_data(
|
||||
frappe._dict(
|
||||
{
|
||||
"company": company,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if data:
|
||||
for d in data:
|
||||
if d and d.get("voucher_type") == "Subcontracting Receipt":
|
||||
doc = frappe.new_doc("Repost Item Valuation")
|
||||
doc.voucher_type = d.get("voucher_type")
|
||||
doc.voucher_no = d.get("voucher_no")
|
||||
doc.save()
|
||||
doc.submit()
|
@ -631,47 +631,6 @@ class PurchaseReceipt(BuyingController):
|
||||
|
||||
i += 1
|
||||
|
||||
def add_gl_entry(
|
||||
self,
|
||||
gl_entries,
|
||||
account,
|
||||
cost_center,
|
||||
debit,
|
||||
credit,
|
||||
remarks,
|
||||
against_account,
|
||||
debit_in_account_currency=None,
|
||||
credit_in_account_currency=None,
|
||||
account_currency=None,
|
||||
project=None,
|
||||
voucher_detail_no=None,
|
||||
item=None,
|
||||
posting_date=None,
|
||||
):
|
||||
|
||||
gl_entry = {
|
||||
"account": account,
|
||||
"cost_center": cost_center,
|
||||
"debit": debit,
|
||||
"credit": credit,
|
||||
"against": against_account,
|
||||
"remarks": remarks,
|
||||
}
|
||||
|
||||
if voucher_detail_no:
|
||||
gl_entry.update({"voucher_detail_no": voucher_detail_no})
|
||||
|
||||
if debit_in_account_currency:
|
||||
gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
|
||||
|
||||
if credit_in_account_currency:
|
||||
gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
|
||||
|
||||
if posting_date:
|
||||
gl_entry.update({"posting_date": posting_date})
|
||||
|
||||
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
|
||||
|
||||
def get_asset_gl_entry(self, gl_entries):
|
||||
for item in self.get("items"):
|
||||
if item.is_fixed_asset:
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user