diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 48beb5e287ce..98f3a60a0357 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -33,7 +33,7 @@ ) from erpnext.accounts.party import get_due_date, get_party_account from erpnext.accounts.utils import get_account_currency, get_fiscal_year -from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled +from erpnext.assets.doctype.asset.asset import is_cwip_accounting_enabled from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.accounts_controller import validate_account_head @@ -281,9 +281,6 @@ def set_expense_account(self, for_validate=False): # in case of auto inventory accounting, # expense account is always "Stock Received But Not Billed" for a stock item # except opening entry, drop-ship entry and fixed asset items - if item.item_code: - asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category") - if ( auto_accounting_for_stock and item.item_code in stock_items @@ -350,22 +347,26 @@ def set_expense_account(self, for_validate=False): frappe.msgprint(msg, title=_("Expense Head Changed")) item.expense_account = stock_not_billed_account - - elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category): + elif item.is_fixed_asset and item.pr_detail: + if not asset_received_but_not_billed: + asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") + item.expense_account = asset_received_but_not_billed + elif item.is_fixed_asset: + account_type = ( + "capital_work_in_progress_account" + if is_cwip_accounting_enabled(item.asset_category) + else "fixed_asset_account" + ) asset_category_account = get_asset_category_account( - "fixed_asset_account", item=item.item_code, company=self.company + account_type, item=item.item_code, company=self.company ) if not asset_category_account: - form_link = get_link_to_form("Asset Category", asset_category) + form_link = get_link_to_form("Asset Category", item.asset_category) throw( _("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company), title=_("Missing Account"), ) item.expense_account = asset_category_account - elif item.is_fixed_asset and item.pr_detail: - if not asset_received_but_not_billed: - asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") - item.expense_account = asset_received_but_not_billed elif not item.expense_account and for_validate: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) @@ -584,12 +585,12 @@ def make_gl_entries(self, gl_entries=None, from_repost=False): def get_gl_entries(self, warehouse_account=None): self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company) + self.asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") + if self.auto_accounting_for_stock: self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed") - self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") else: self.stock_received_but_not_billed = None - self.expenses_included_in_valuation = None self.negative_expense_to_be_booked = 0.0 gl_entries = [] @@ -598,9 +599,6 @@ def get_gl_entries(self, warehouse_account=None): self.make_item_gl_entries(gl_entries) self.make_precision_loss_gl_entry(gl_entries) - if self.check_asset_cwip_enabled(): - self.get_asset_gl_entry(gl_entries) - self.make_tax_gl_entries(gl_entries) self.make_internal_transfer_gl_entries(gl_entries) @@ -702,7 +700,11 @@ def make_item_gl_entries(self, gl_entries): if item.item_code: asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category") - if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items: + if ( + self.update_stock + and self.auto_accounting_for_stock + and (item.item_code in stock_items or item.is_fixed_asset) + ): # warehouse account warehouse_debit_amount = self.make_stock_adjustment_entry( gl_entries, item, voucher_wise_stock_value, account_currency @@ -817,9 +819,7 @@ def make_item_gl_entries(self, gl_entries): ) ) - elif not item.is_fixed_asset or ( - item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category) - ): + else: expense_account = ( item.expense_account if (not item.enable_deferred_expense or self.is_return) @@ -912,40 +912,6 @@ def make_item_gl_entries(self, gl_entries): ) ) - # If asset is bought through this document and not linked to PR - if self.update_stock and item.landed_cost_voucher_amount: - expenses_included_in_asset_valuation = self.get_company_default( - "expenses_included_in_asset_valuation" - ) - # Amount added through landed-cost-voucher - gl_entries.append( - self.get_gl_dict( - { - "account": expenses_included_in_asset_valuation, - "against": expense_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) - ) - - gl_entries.append( - self.get_gl_dict( - { - "account": expense_account, - "against": expenses_included_in_asset_valuation, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) - ) - # update gross amount of asset bought through this document assets = frappe.db.get_all( "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code} @@ -970,11 +936,16 @@ def make_item_gl_entries(self, gl_entries): (item.purchase_receipt, valuation_tax_accounts), ) + stock_rbnb = ( + self.asset_received_but_not_billed + if item.is_fixed_asset + else self.stock_received_but_not_billed + ) if not negative_expense_booked_in_pr: gl_entries.append( self.get_gl_dict( { - "account": self.stock_received_but_not_billed, + "account": stock_rbnb, "against": self.supplier, "debit": flt(item.item_tax_amount, item.precision("item_tax_amount")), "remarks": self.remarks or _("Accounting Entry for Stock"), @@ -989,6 +960,7 @@ def make_item_gl_entries(self, gl_entries): item.item_tax_amount, item.precision("item_tax_amount") ) +<<<<<<< HEAD def get_asset_gl_entry(self, gl_entries): arbnb_account = None eiiav_account = None @@ -1139,6 +1111,14 @@ def get_asset_gl_entry(self, gl_entries): frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)) return gl_entries +======= + assets = frappe.db.get_all( + "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code} + ) + for asset in assets: + frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate)) + frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)) +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) def make_stock_adjustment_entry( self, gl_entries, item, voucher_wise_stock_value, account_currency diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 4272218de644..5a41336b2f62 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2498,12 +2498,6 @@ def test_inter_company_transaction_without_default_warehouse(self): "stock_received_but_not_billed", "Stock Received But Not Billed - _TC1", ) - frappe.db.set_value( - "Company", - "_Test Company 1", - "expenses_included_in_valuation", - "Expenses Included In Valuation - _TC1", - ) # begin test si = create_sales_invoice( diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index d4967785ba08..70a847061476 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -41,7 +41,7 @@ def make_gl_entries( from_repost=from_repost, ) save_entries(gl_map, adv_adj, update_outstanding, from_repost) - # Post GL Map proccess there may no be any GL Entries + # Post GL Map process there may no be any GL Entries elif gl_map: frappe.throw( _( diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 04adca459522..0e30a17f470a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -194,6 +194,7 @@ def test_purchase_of_grouped_asset(self): def test_is_fixed_asset_set(self): asset = create_asset(is_existing_asset=1) doc = frappe.new_doc("Purchase Invoice") + doc.company = "_Test Company" doc.supplier = "_Test Supplier" doc.append("items", {"item_code": "Macbook Pro", "qty": 1, "asset": asset.name}) @@ -534,7 +535,7 @@ def test_expense_head(self): self.assertEqual("Asset Received But Not Billed - _TC", doc.items[0].expense_account) - # CWIP: Capital Work In Progress + # Capital Work In Progress def test_cwip_accounting(self): pr = make_purchase_receipt( item_code="Macbook Pro", qty=1, rate=5000, do_not_submit=True, location="Test Location" @@ -567,7 +568,8 @@ def test_cwip_accounting(self): pr.submit() expected_gle = ( - ("Asset Received But Not Billed - _TC", 0.0, 5250.0), + ("_Test Account Shipping Charges - _TC", 0.0, 250.0), + ("Asset Received But Not Billed - _TC", 0.0, 5000.0), ("CWIP Account - _TC", 5250.0, 0.0), ) @@ -586,9 +588,8 @@ def test_cwip_accounting(self): expected_gle = ( ("_Test Account Service Tax - _TC", 250.0, 0.0), ("_Test Account Shipping Charges - _TC", 250.0, 0.0), - ("Asset Received But Not Billed - _TC", 5250.0, 0.0), + ("Asset Received But Not Billed - _TC", 5000.0, 0.0), ("Creditors - _TC", 0.0, 5500.0), - ("Expenses Included In Asset Valuation - _TC", 0.0, 250.0), ) pi_gle = frappe.db.sql( diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 961697c0ac23..c5b26c0c2680 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -558,7 +558,10 @@ def update_item(obj, target, source_parent): "material_request_item": "material_request_item", "sales_order": "sales_order", "sales_order_item": "sales_order_item", +<<<<<<< HEAD "wip_composite_asset": "wip_composite_asset", +======= +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) }, "postprocess": update_item, "condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index e48c01b77fc8..4d646836d664 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -62,9 +62,12 @@ def make_gl_entries(self, gl_entries=None, from_repost=False): ) ) + is_asset_pr = any(d.get("is_fixed_asset") for d in self.get("items")) + if ( cint(erpnext.is_perpetual_inventory_enabled(self.company)) or provisional_accounting_for_non_stock_items + or is_asset_pr ): warehouse_account = get_warehouse_account_map(self.company) @@ -73,12 +76,15 @@ def make_gl_entries(self, gl_entries=None, from_repost=False): gl_entries = self.get_gl_entries(warehouse_account) make_gl_entries(gl_entries, from_repost=from_repost) +<<<<<<< HEAD elif self.doctype in ["Purchase Receipt", "Purchase Invoice"] and self.docstatus == 1: gl_entries = [] gl_entries = self.get_asset_gl_entry(gl_entries) update_regional_gl_entries(gl_entries, self) make_gl_entries(gl_entries, from_repost=from_repost) +======= +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) def validate_serialized_batch(self): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 023166849dbf..229f8853fff0 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -1196,12 +1196,12 @@ def get_children(parent=None, is_root=False, **filters): def add_additional_cost(stock_entry, work_order): # Add non stock items cost in the additional cost stock_entry.additional_costs = [] - expenses_included_in_valuation = frappe.get_cached_value( - "Company", work_order.company, "expenses_included_in_valuation" + default_expense_account = frappe.get_cached_value( + "Company", work_order.company, "default_expense_account" ) - add_non_stock_items_cost(stock_entry, work_order, expenses_included_in_valuation) - add_operations_cost(stock_entry, work_order, expenses_included_in_valuation) + add_non_stock_items_cost(stock_entry, work_order, default_expense_account) + add_operations_cost(stock_entry, work_order, default_expense_account) def add_non_stock_items_cost(stock_entry, work_order, expense_account): diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py deleted file mode 100644 index 9588e026d34c..000000000000 --- a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py +++ /dev/null @@ -1,42 +0,0 @@ -import frappe - - -def execute(): - frappe.reload_doctype("Landed Cost Taxes and Charges") - - company_account_map = frappe._dict( - frappe.db.sql( - """ - SELECT name, expenses_included_in_valuation from `tabCompany` - """ - ) - ) - - for company, account in company_account_map.items(): - frappe.db.sql( - """ - UPDATE - `tabLanded Cost Taxes and Charges` t, `tabLanded Cost Voucher` l - SET - t.expense_account = %s - WHERE - l.docstatus = 1 - AND l.company = %s - AND t.parent = l.name - """, - (account, company), - ) - - frappe.db.sql( - """ - UPDATE - `tabLanded Cost Taxes and Charges` t, `tabStock Entry` s - SET - t.expense_account = %s - WHERE - s.docstatus = 1 - AND s.company = %s - AND t.parent = s.name - """, - (account, company), - ) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 15944a56f0e2..1bd469b9567d 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -221,7 +221,6 @@ erpnext.company.setup_queries = function(frm) { ["cost_center", {}], ["round_off_cost_center", {}], ["depreciation_cost_center", {}], - ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}], ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}], ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}], ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}], @@ -236,8 +235,6 @@ erpnext.company.setup_queries = function(frm) { $.each([ ["stock_adjustment_account", {"root_type": "Expense", "account_type": "Stock Adjustment"}], - ["expenses_included_in_valuation", - {"root_type": "Expense", "account_type": "Expenses Included in Valuation"}], ["stock_received_but_not_billed", {"root_type": "Liability", "account_type": "Stock Received But Not Billed"}], ["service_received_but_not_billed", diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 24d7da45b841..6a142aa19d36 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -65,6 +65,7 @@ "payment_terms", "cost_center", "default_finance_book", +<<<<<<< HEAD "advance_payments_section", "book_advance_payments_in_separate_party_account", "column_break_fwcf", @@ -76,11 +77,21 @@ "submit_err_jv", "budget_detail", "exception_budget_approver_role", +======= + "auto_accounting_for_stock_settings", + "enable_perpetual_inventory", + "enable_provisional_accounting_for_non_stock_items", + "default_inventory_account", + "stock_adjustment_account", + "default_in_transit_warehouse", + "column_break_32", + "stock_received_but_not_billed", + "default_provisional_account", +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) "fixed_asset_defaults", "accumulated_depreciation_account", "depreciation_expense_account", "series_for_depreciation_entry", - "expenses_included_in_asset_valuation", "column_break_40", "disposal_account", "depreciation_cost_center", @@ -469,14 +480,6 @@ "no_copy": 1, "options": "Account" }, - { - "fieldname": "expenses_included_in_valuation", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Expenses Included In Valuation", - "no_copy": 1, - "options": "Account" - }, { "fieldname": "accumulated_depreciation_account", "fieldtype": "Link", @@ -496,12 +499,6 @@ "fieldtype": "Data", "label": "Series for Asset Depreciation Entry (Journal Entry)" }, - { - "fieldname": "expenses_included_in_asset_valuation", - "fieldtype": "Link", - "label": "Expenses Included In Asset Valuation", - "options": "Account" - }, { "fieldname": "column_break_40", "fieldtype": "Column Break" @@ -782,7 +779,11 @@ "image_field": "company_logo", "is_tree": 1, "links": [], +<<<<<<< HEAD "modified": "2023-09-10 21:53:13.860791", +======= + "modified": "2023-10-23 10:19:24.322898", +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) "modified_by": "Administrator", "module": "Setup", "name": "Company", diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index b05696ad9696..3413702c5aae 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -92,7 +92,6 @@ def validate_default_accounts(self): ["Default Income Account", "default_income_account"], ["Stock Received But Not Billed Account", "stock_received_but_not_billed"], ["Stock Adjustment Account", "stock_adjustment_account"], - ["Expense Included In Valuation Account", "expenses_included_in_valuation"], ] for account in accounts: @@ -384,7 +383,6 @@ def set_default_accounts(self): "depreciation_expense_account": "Depreciation", "capital_work_in_progress_account": "Capital Work in Progress", "asset_received_but_not_billed": "Asset Received But Not Billed", - "expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation", "default_expense_account": "Cost of Goods Sold", } @@ -394,7 +392,6 @@ def set_default_accounts(self): "stock_received_but_not_billed": "Stock Received But Not Billed", "default_inventory_account": "Stock", "stock_adjustment_account": "Stock Adjustment", - "expenses_included_in_valuation": "Expenses Included In Valuation", } ) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index aedf29ccccda..7c934dc5b780 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -13,7 +13,6 @@ import erpnext from erpnext.accounts.utils import get_account_currency from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled -from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.buying_controller import BuyingController from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_transaction @@ -144,8 +143,8 @@ def validate_cwip_accounts(self): if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category): # check cwip accounts before making auto assets # Improves UX by not giving messages of "Assets Created" before throwing error of not finding arbnb account - arbnb_account = self.get_company_default("asset_received_but_not_billed") - cwip_account = get_asset_account( + self.get_company_default("asset_received_but_not_billed") + get_asset_account( "capital_work_in_progress_account", asset_category=item.asset_category, company=self.company ) break @@ -314,8 +313,11 @@ def get_gl_entries(self, warehouse_account=None): self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account) self.make_tax_gl_entries(gl_entries) +<<<<<<< HEAD self.get_asset_gl_entry(gl_entries) update_regional_gl_entries(gl_entries, self) +======= +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) return process_gl_map(gl_entries) @@ -324,14 +326,6 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): get_purchase_document_details, ) - stock_rbnb = None - if erpnext.is_perpetual_inventory_enabled(self.company): - stock_rbnb = self.get_company_default("stock_received_but_not_billed") - landed_cost_entries = get_item_account_wise_additional_cost(self.name) - expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") - - warehouse_with_no_account = [] - stock_items = self.get_stock_items() provisional_accounting_for_non_stock_items = cint( frappe.db.get_value( "Company", self.company, "enable_provisional_accounting_for_non_stock_items" @@ -340,28 +334,256 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): exchange_rate_map, net_rate_map = get_purchase_document_details(self) + def validate_account(account_type): + frappe.throw(_("{0} account not found while submitting purchase receipt").format(account_type)) + + def make_item_asset_inward_gl_entry(item, stock_value_diff, stock_asset_account_name): + account_currency = get_account_currency(stock_asset_account_name) + + if not stock_asset_account_name: + validate_account("Asset or warehouse account") + + self.add_gl_entry( + gl_entries=gl_entries, + account=stock_asset_account_name, + cost_center=d.cost_center, + debit=stock_value_diff, + credit=0.0, + remarks=remarks, + against_account=stock_asset_rbnb, + account_currency=account_currency, + item=item, + ) + + def make_stock_received_but_not_billed_entry(item): + account = ( + warehouse_account[item.from_warehouse]["account"] if item.from_warehouse else stock_asset_rbnb + ) + account_currency = get_account_currency(account) + + # GL Entry for from warehouse or Stock Received but not billed + # Intentionally passed negative debit amount to avoid incorrect GL Entry validation + credit_amount = ( + flt(item.base_net_amount, item.precision("base_net_amount")) + if account_currency == self.company_currency + else flt(item.net_amount, item.precision("net_amount")) + ) + + outgoing_amount = item.base_net_amount + if self.is_internal_transfer() and item.valuation_rate: + outgoing_amount = abs(get_stock_value_difference(self.name, item.name, item.from_warehouse)) + credit_amount = outgoing_amount + + if credit_amount: + if not account: + validate_account("Stock or Asset Received But Not Billed") + + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=item.cost_center, + debit=-1 * flt(outgoing_amount, item.precision("base_net_amount")), + credit=0.0, + remarks=remarks, + against_account=stock_asset_account_name, + debit_in_account_currency=-1 * flt(outgoing_amount, item.precision("base_net_amount")), + account_currency=account_currency, + item=item, + ) + + # check if the exchange rate has changed + if d.get("purchase_invoice"): + if ( + exchange_rate_map[item.purchase_invoice] + and self.conversion_rate != exchange_rate_map[item.purchase_invoice] + and item.net_rate == net_rate_map[item.purchase_invoice_item] + ): + + discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * ( + exchange_rate_map[item.purchase_invoice] - self.conversion_rate + ) + + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=item.cost_center, + debit=0.0, + credit=discrepancy_caused_by_exchange_rate_difference, + remarks=remarks, + against_account=self.supplier, + debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=account_currency, + item=item, + ) + + self.add_gl_entry( + gl_entries=gl_entries, + account=self.get_company_default("exchange_gain_loss_account"), + cost_center=d.cost_center, + debit=discrepancy_caused_by_exchange_rate_difference, + credit=0.0, + remarks=remarks, + against_account=self.supplier, + debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=account_currency, + item=item, + ) + + return outgoing_amount + + def make_landed_cost_gl_entries(item): + # Amount added through landed-cost-voucher + if item.landed_cost_voucher_amount and landed_cost_entries: + if (item.item_code, item.name) in landed_cost_entries: + for account, amount in landed_cost_entries[(item.item_code, item.name)].items(): + account_currency = get_account_currency(account) + credit_amount = ( + flt(amount["base_amount"]) + if (amount["base_amount"] or account_currency != self.company_currency) + else flt(amount["amount"]) + ) + + if not account: + validate_account("Landed Cost Account") + + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=item.cost_center, + debit=0.0, + credit=credit_amount, + remarks=remarks, + against_account=stock_asset_account_name, + credit_in_account_currency=flt(amount["amount"]), + account_currency=account_currency, + project=item.project, + item=item, + ) + + def make_rate_difference_entry(item): + if item.rate_difference_with_purchase_invoice and stock_asset_rbnb: + account_currency = get_account_currency(stock_asset_rbnb) + self.add_gl_entry( + gl_entries=gl_entries, + account=stock_asset_rbnb, + cost_center=item.cost_center, + debit=0.0, + credit=flt(item.rate_difference_with_purchase_invoice), + remarks=_("Adjustment based on Purchase Invoice rate"), + against_account=stock_asset_account_name, + account_currency=account_currency, + project=item.project, + item=item, + ) + + def make_sub_contracting_gl_entries(item): + # sub-contracting warehouse + 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=stock_asset_account_name, + account_currency=supplier_warehouse_account_currency, + item=item, + ) + + def make_divisional_loss_gl_entry(item, outgoing_amount): + if item.is_fixed_asset: + return + + # divisional loss adjustment + valuation_amount_as_per_doc = ( + flt(outgoing_amount, d.precision("base_net_amount")) + + flt(item.landed_cost_voucher_amount) + + flt(item.rm_supp_cost) + + flt(item.item_tax_amount) + + flt(item.rate_difference_with_purchase_invoice) + ) + + divisional_loss = flt( + valuation_amount_as_per_doc - flt(stock_value_diff), item.precision("base_net_amount") + ) + + if divisional_loss: + loss_account = ( + self.get_company_default("default_expense_account", ignore_validation=True) + or stock_asset_rbnb + ) + + cost_center = item.cost_center or frappe.get_cached_value( + "Company", self.company, "cost_center" + ) + account_currency = get_account_currency(loss_account) + self.add_gl_entry( + gl_entries=gl_entries, + account=loss_account, + cost_center=cost_center, + debit=divisional_loss, + credit=0.0, + remarks=remarks, + against_account=stock_asset_account_name, + account_currency=account_currency, + project=item.project, + item=item, + ) + + stock_items = self.get_stock_items() + warehouse_with_no_account = [] + for d in self.get("items"): - if d.item_code in stock_items and flt(d.qty) and (flt(d.valuation_rate) or self.is_return): - if warehouse_account.get(d.warehouse): - stock_value_diff = frappe.db.get_value( - "Stock Ledger Entry", - { - "voucher_type": "Purchase Receipt", - "voucher_no": self.name, - "voucher_detail_no": d.name, - "warehouse": d.warehouse, - "is_cancelled": 0, - }, - "stock_value_difference", + if ( + provisional_accounting_for_non_stock_items + and d.item_code not in stock_items + and flt(d.qty) + and d.get("provisional_expense_account") + and not d.is_fixed_asset + ): + self.add_provisional_gl_entry( + d, gl_entries, self.posting_date, d.get("provisional_expense_account") + ) + elif flt(d.qty) and (flt(d.valuation_rate) or self.is_return): + is_asset_pr = any(d.is_fixed_asset for d in self.get("items")) + remarks = self.get("remarks") or _("Accounting Entry for {0}").format( + "Asset" if is_asset_pr else "Stock" + ) + + if not (erpnext.is_perpetual_inventory_enabled(self.company) or is_asset_pr): + return + + stock_asset_rbnb = ( + self.get_company_default("asset_received_but_not_billed") + if is_asset_pr + else self.get_company_default("stock_received_but_not_billed") + ) + landed_cost_entries = get_item_account_wise_additional_cost(self.name) + + if d.is_fixed_asset: + account_type = ( + "capital_work_in_progress_account" + if is_cwip_accounting_enabled(d.asset_category) + else "fixed_asset_account" ) - warehouse_account_name = warehouse_account[d.warehouse]["account"] - warehouse_account_currency = warehouse_account[d.warehouse]["account_currency"] + stock_asset_account_name = get_asset_account( + account_type, asset_category=d.asset_category, company=self.company + ) + + stock_value_diff = ( + flt(d.net_amount) + + flt(d.item_tax_amount / self.conversion_rate) + + flt(d.landed_cost_voucher_amount) + ) + elif warehouse_account.get(d.warehouse): + stock_value_diff = get_stock_value_difference(self.name, d.name, d.warehouse) + stock_asset_account_name = warehouse_account[d.warehouse]["account"] 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") # If PR is sub-contracted and fg item rate is zero # in that case if account for source and target warehouse are same, @@ -369,10 +591,11 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): if ( flt(stock_value_diff) == flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse) - and warehouse_account_name == supplier_warehouse_account + and stock_asset_account_name == supplier_warehouse_account ): continue +<<<<<<< HEAD self.add_gl_entry( gl_entries=gl_entries, account=warehouse_account_name, @@ -566,16 +789,23 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): d.rejected_warehouse and d.rejected_warehouse not in warehouse_with_no_account ): warehouse_with_no_account.append(d.warehouse or d.rejected_warehouse) +======= + if (flt(d.valuation_rate) or self.is_return or d.is_fixed_asset) and flt(d.qty): + make_item_asset_inward_gl_entry(d, stock_value_diff, stock_asset_account_name) + outgoing_amount = make_stock_received_but_not_billed_entry(d) + make_landed_cost_gl_entries(d) + make_rate_difference_entry(d) + make_sub_contracting_gl_entries(d) + make_divisional_loss_gl_entry(d, outgoing_amount) +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) elif ( - d.item_code not in stock_items - and not d.is_fixed_asset - and flt(d.qty) - and provisional_accounting_for_non_stock_items - and d.get("provisional_expense_account") + d.warehouse not in warehouse_with_no_account + or d.rejected_warehouse not in warehouse_with_no_account ): - self.add_provisional_gl_entry( - d, gl_entries, self.posting_date, d.get("provisional_expense_account") - ) + warehouse_with_no_account.append(d.warehouse) + + if d.is_fixed_asset: + self.update_assets(d, d.valuation_rate) if warehouse_with_no_account: frappe.msgprint( @@ -588,8 +818,8 @@ def add_provisional_gl_entry( self, item, gl_entries, posting_date, provisional_account, reverse=0 ): credit_currency = get_account_currency(provisional_account) - debit_currency = get_account_currency(item.expense_account) expense_account = item.expense_account + debit_currency = get_account_currency(item.expense_account) remarks = self.get("remarks") or _("Accounting Entry for Service") multiplication_factor = 1 @@ -630,11 +860,8 @@ def add_provisional_gl_entry( ) def make_tax_gl_entries(self, gl_entries): - - if erpnext.is_perpetual_inventory_enabled(self.company): - expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") - negative_expense_to_be_booked = sum([flt(d.item_tax_amount) for d in self.get("items")]) + is_asset_pr = any(d.is_fixed_asset for d in self.get("items")) # Cost center-wise amount breakup for other charges included for valuation valuation_tax = {} for tax in self.get("taxes"): @@ -654,26 +881,26 @@ def make_tax_gl_entries(self, gl_entries): if negative_expense_to_be_booked and valuation_tax: # Backward compatibility: - # If expenses_included_in_valuation account has been credited in against PI # and charges added via Landed Cost Voucher, # post valuation related charges on "Stock Received But Not Billed" - # introduced in 2014 for backward compatibility of expenses already booked in expenses_included_in_valuation account - - negative_expense_booked_in_pi = frappe.db.sql( - """select name from `tabPurchase Invoice Item` pi - where docstatus = 1 and purchase_receipt=%s - and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' - and voucher_no=pi.parent and account=%s)""", - (self.name, expenses_included_in_valuation), - ) - against_account = ", ".join([d.account for d in gl_entries if flt(d.debit) > 0]) total_valuation_amount = sum(valuation_tax.values()) amount_including_divisional_loss = negative_expense_to_be_booked - stock_rbnb = self.get_company_default("stock_received_but_not_billed") + stock_rbnb = ( + self.get("asset_received_but_not_billed") + if is_asset_pr + else self.get_company_default("stock_received_but_not_billed") + ) i = 1 for tax in self.get("taxes"): if valuation_tax.get(tax.name): + negative_expense_booked_in_pi = frappe.db.sql( + """select name from `tabPurchase Invoice Item` pi + where docstatus = 1 and purchase_receipt=%s + and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' + and voucher_no=pi.parent and account=%s)""", + (self.name, tax.account_head), + ) if negative_expense_booked_in_pi: account = stock_rbnb @@ -701,103 +928,6 @@ def make_tax_gl_entries(self, gl_entries): i += 1 - def get_asset_gl_entry(self, gl_entries): - for item in self.get("items"): - if item.is_fixed_asset: - if is_cwip_accounting_enabled(item.asset_category): - self.add_asset_gl_entries(item, gl_entries) - if flt(item.landed_cost_voucher_amount): - self.add_lcv_gl_entries(item, gl_entries) - # update assets gross amount by its valuation rate - # valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item - self.update_assets(item, item.valuation_rate) - return gl_entries - - def add_asset_gl_entries(self, item, gl_entries): - arbnb_account = self.get_company_default("asset_received_but_not_billed") - # This returns category's cwip account if not then fallback to company's default cwip account - cwip_account = get_asset_account( - "capital_work_in_progress_account", asset_category=item.asset_category, company=self.company - ) - - asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate) - base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) - remarks = self.get("remarks") or _("Accounting Entry for Asset") - - cwip_account_currency = get_account_currency(cwip_account) - # debit cwip account - debit_in_account_currency = ( - base_asset_amount if cwip_account_currency == self.company_currency else asset_amount - ) - - self.add_gl_entry( - gl_entries=gl_entries, - account=cwip_account, - cost_center=item.cost_center, - debit=base_asset_amount, - credit=0.0, - remarks=remarks, - against_account=arbnb_account, - debit_in_account_currency=debit_in_account_currency, - item=item, - ) - - asset_rbnb_currency = get_account_currency(arbnb_account) - # credit arbnb account - credit_in_account_currency = ( - base_asset_amount if asset_rbnb_currency == self.company_currency else asset_amount - ) - - self.add_gl_entry( - gl_entries=gl_entries, - account=arbnb_account, - cost_center=item.cost_center, - debit=0.0, - credit=base_asset_amount, - remarks=remarks, - against_account=cwip_account, - credit_in_account_currency=credit_in_account_currency, - item=item, - ) - - def add_lcv_gl_entries(self, item, gl_entries): - expenses_included_in_asset_valuation = self.get_company_default( - "expenses_included_in_asset_valuation" - ) - if not is_cwip_accounting_enabled(item.asset_category): - asset_account = get_asset_category_account( - asset_category=item.asset_category, fieldname="fixed_asset_account", company=self.company - ) - else: - # This returns company's default cwip account - asset_account = get_asset_account("capital_work_in_progress_account", company=self.company) - - remarks = self.get("remarks") or _("Accounting Entry for Stock") - - self.add_gl_entry( - gl_entries=gl_entries, - account=expenses_included_in_asset_valuation, - cost_center=item.cost_center, - debit=0.0, - credit=flt(item.landed_cost_voucher_amount), - remarks=remarks, - against_account=asset_account, - project=item.project, - item=item, - ) - - self.add_gl_entry( - gl_entries=gl_entries, - account=asset_account, - cost_center=item.cost_center, - debit=flt(item.landed_cost_voucher_amount), - credit=0.0, - remarks=remarks, - against_account=expenses_included_in_asset_valuation, - project=item.project, - item=item, - ) - def update_assets(self, item, valuation_rate): assets = frappe.db.get_all( "Asset", filters={"purchase_receipt": self.name, "item_code": item.item_code} @@ -869,7 +999,25 @@ def reserve_stock_for_sales_order(self): ) +<<<<<<< HEAD def update_billed_amount_based_on_po(po_details, update_modified=True, pr_doc=None): +======= +def get_stock_value_difference(voucher_no, voucher_detail_no, warehouse): + return frappe.db.get_value( + "Stock Ledger Entry", + { + "voucher_type": "Purchase Receipt", + "voucher_no": voucher_no, + "voucher_detail_no": voucher_detail_no, + "warehouse": warehouse, + "is_cancelled": 0, + }, + "stock_value_difference", + ) + + +def update_billed_amount_based_on_po(po_details, update_modified=True): +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) po_billed_amt_details = get_billed_amount_against_po(po_details) # Get all Purchase Receipt Item rows against the Purchase Order Items diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index ce2e5d7f8404..459e8e8037f5 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1091,7 +1091,11 @@ "idx": 1, "istable": 1, "links": [], +<<<<<<< HEAD "modified": "2023-11-14 18:38:15.251994", +======= + "modified": "2023-10-19 10:50:58.071735", +>>>>>>> 80774e2da1 (fix: GL Entries for receiving non CWIP assets using Purchase Receipt (#37660)) "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index f8675f338ed7..b640983a09d6 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -449,9 +449,7 @@ def test_repack_with_additional_costs(self): repack.posting_date = nowdate() repack.posting_time = nowtime() - expenses_included_in_valuation = frappe.get_value( - "Company", company, "expenses_included_in_valuation" - ) + default_expense_account = frappe.get_value("Company", company, "default_expense_account") items = get_multiple_items() repack.items = [] @@ -462,12 +460,12 @@ def test_repack_with_additional_costs(self): "additional_costs", [ { - "expense_account": expenses_included_in_valuation, + "expense_account": default_expense_account, "description": "Actual Operating Cost", "amount": 1000, }, { - "expense_account": expenses_included_in_valuation, + "expense_account": default_expense_account, "description": "Additional Operating Cost", "amount": 200, }, @@ -506,9 +504,7 @@ def test_repack_with_additional_costs(self): self.check_gl_entries( "Stock Entry", repack.name, - sorted( - [[stock_in_hand_account, 1200, 0.0], ["Expenses Included In Valuation - TCP1", 0.0, 1200.0]] - ), + sorted([[stock_in_hand_account, 1200, 0.0], ["Cost of Goods Sold - TCP1", 0.0, 1200.0]]), ) def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle): diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index fee3f1b4821d..8d705aa97dfd 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -412,7 +412,6 @@ def get_gl_entries(self, warehouse_account=None): def make_item_gl_entries(self, gl_entries, warehouse_account=None): 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 = [] @@ -484,10 +483,7 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): 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 + loss_account = item.expense_account self.add_gl_entry( gl_entries=gl_entries,