fix: Opening accounting entry for stock entry (#17710)
* fix: Opening accounting entry for stock entry * test: Add test case for opening stock entry gle * fix: validate expense account for opening stock entry * fix: validate expense account for opening stock reco
This commit is contained in:
@@ -80,7 +80,7 @@ class StockController(AccountsController):
|
|||||||
"cost_center": item_row.cost_center,
|
"cost_center": item_row.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||||
"debit": flt(sle.stock_value_difference, 2),
|
"debit": flt(sle.stock_value_difference, 2),
|
||||||
"is_opening": item_row.get("is_opening"),
|
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
|
||||||
}, warehouse_account[sle.warehouse]["account_currency"]))
|
}, warehouse_account[sle.warehouse]["account_currency"]))
|
||||||
|
|
||||||
# to target warehouse / expense account
|
# to target warehouse / expense account
|
||||||
@@ -91,7 +91,7 @@ class StockController(AccountsController):
|
|||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||||
"credit": flt(sle.stock_value_difference, 2),
|
"credit": flt(sle.stock_value_difference, 2),
|
||||||
"project": item_row.get("project") or self.get("project"),
|
"project": item_row.get("project") or self.get("project"),
|
||||||
"is_opening": item_row.get("is_opening")
|
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No"
|
||||||
}))
|
}))
|
||||||
elif sle.warehouse not in warehouse_with_no_account:
|
elif sle.warehouse not in warehouse_with_no_account:
|
||||||
warehouse_with_no_account.append(sle.warehouse)
|
warehouse_with_no_account.append(sle.warehouse)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@ from erpnext.stock.doctype.item.item import get_item_defaults
|
|||||||
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, add_additional_cost
|
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, add_additional_cost
|
||||||
from erpnext.stock.utils import get_bin
|
from erpnext.stock.utils import get_bin
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
|
||||||
|
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ class StockEntry(StockController):
|
|||||||
self.validate_batch()
|
self.validate_batch()
|
||||||
self.validate_inspection()
|
self.validate_inspection()
|
||||||
self.validate_fg_completed_qty()
|
self.validate_fg_completed_qty()
|
||||||
|
self.validate_difference_account()
|
||||||
self.set_job_card_data()
|
self.set_job_card_data()
|
||||||
|
|
||||||
if not self.from_bom:
|
if not self.from_bom:
|
||||||
@@ -215,7 +217,18 @@ class StockEntry(StockController):
|
|||||||
production_item = frappe.get_value('Work Order', self.work_order, 'production_item')
|
production_item = frappe.get_value('Work Order', self.work_order, 'production_item')
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
if item.item_code == production_item and item.qty != self.fg_completed_qty:
|
if item.item_code == production_item and item.qty != self.fg_completed_qty:
|
||||||
frappe.throw(_("Finished product quantity <b>{0}</b> and For Quantity <b>{1}</b> cannot be different").format(item.qty, self.fg_completed_qty))
|
frappe.throw(_("Finished product quantity <b>{0}</b> and For Quantity <b>{1}</b> cannot be different")
|
||||||
|
.format(item.qty, self.fg_completed_qty))
|
||||||
|
|
||||||
|
def validate_difference_account(self):
|
||||||
|
if not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
|
||||||
|
return
|
||||||
|
|
||||||
|
for d in self.get("items"):
|
||||||
|
if not d.expense_account:
|
||||||
|
frappe.throw(_("Please enter Difference Account"))
|
||||||
|
elif self.is_opening == "Yes" and frappe.db.get_value("Account", d.expense_account, "report_type") == "Profit and Loss":
|
||||||
|
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Entry is an Opening Entry"), OpeningEntryAccountError)
|
||||||
|
|
||||||
def validate_warehouse(self):
|
def validate_warehouse(self):
|
||||||
"""perform various (sometimes conditional) validations on warehouse"""
|
"""perform various (sometimes conditional) validations on warehouse"""
|
||||||
|
|||||||
@@ -89,10 +89,11 @@ def make_stock_entry(**args):
|
|||||||
s.purchase_receipt_no = args.purchase_receipt_no
|
s.purchase_receipt_no = args.purchase_receipt_no
|
||||||
s.delivery_note_no = args.delivery_note_no
|
s.delivery_note_no = args.delivery_note_no
|
||||||
s.sales_invoice_no = args.sales_invoice_no
|
s.sales_invoice_no = args.sales_invoice_no
|
||||||
|
s.is_opening = args.is_opening or "No"
|
||||||
if not args.cost_center:
|
if not args.cost_center:
|
||||||
args.cost_center = frappe.get_value('Company', s.company, 'cost_center')
|
args.cost_center = frappe.get_value('Company', s.company, 'cost_center')
|
||||||
|
|
||||||
if not args.expense_account:
|
if not args.expense_account and s.is_opening == "No":
|
||||||
args.expense_account = frappe.get_value('Company', s.company, 'stock_adjustment_account')
|
args.expense_account = frappe.get_value('Company', s.company, 'stock_adjustment_account')
|
||||||
|
|
||||||
# We can find out the serial number using the batch source document
|
# We can find out the serial number using the batch source document
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import frappe, unittest
|
|||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.utils import flt, nowdate, nowtime
|
from frappe.utils import flt, nowdate, nowtime
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import *
|
from erpnext.stock.doctype.serial_no.serial_no import *
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
|
from erpnext import set_perpetual_inventory
|
||||||
import set_perpetual_inventory
|
|
||||||
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
|
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
|
||||||
from erpnext.stock.stock_ledger import get_previous_sle
|
from erpnext.stock.stock_ledger import get_previous_sle
|
||||||
from frappe.permissions import add_user_permission, remove_user_permission
|
from frappe.permissions import add_user_permission, remove_user_permission
|
||||||
@@ -16,6 +15,7 @@ from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make
|
|||||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse
|
from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse
|
||||||
|
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
|
||||||
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
@@ -720,6 +720,22 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
for d in stock_entry.get('items'):
|
for d in stock_entry.get('items'):
|
||||||
self.assertEqual(item_quantity.get(d.item_code), d.qty)
|
self.assertEqual(item_quantity.get(d.item_code), d.qty)
|
||||||
|
|
||||||
|
def test_gle_for_opening_stock_entry(self):
|
||||||
|
set_perpetual_inventory(1)
|
||||||
|
|
||||||
|
mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
|
||||||
|
qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC", is_opening="Yes", do_not_save=True)
|
||||||
|
|
||||||
|
self.assertRaises(OpeningEntryAccountError, mr.save)
|
||||||
|
|
||||||
|
mr.items[0].expense_account = "Temporary Opening - _TC"
|
||||||
|
mr.save()
|
||||||
|
mr.submit()
|
||||||
|
|
||||||
|
is_opening = frappe.db.get_value("GL Entry",
|
||||||
|
filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening")
|
||||||
|
self.assertEqual(is_opening, "Yes")
|
||||||
|
|
||||||
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
||||||
se = frappe.copy_doc(test_records[0])
|
se = frappe.copy_doc(test_records[0])
|
||||||
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
||||||
|
|||||||
@@ -238,8 +238,8 @@ class StockReconciliation(StockController):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not self.expense_account:
|
if not self.expense_account:
|
||||||
msgprint(_("Please enter Expense Account"), raise_exception=1)
|
frappe.throw(_("Please enter Expense Account"))
|
||||||
elif not frappe.db.sql("""select name from `tabStock Ledger Entry` limit 1"""):
|
elif self.purpose == "Opening Stock" or not frappe.db.sql("""select name from `tabStock Ledger Entry` limit 1"""):
|
||||||
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
||||||
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user