fix: use Stock Reconciliation for opening stock entry

This commit is contained in:
khushi8112
2026-05-14 03:28:07 +05:30
parent 60f528b531
commit e602cad39a
2 changed files with 79 additions and 72 deletions

View File

@@ -883,6 +883,29 @@ $.extend(erpnext.item, {
},
show_opening_stock_dialog: function (frm) {
const has_serial = cint(frm.doc.has_serial_no);
const has_batch = cint(frm.doc.has_batch_no);
if (has_serial || has_batch) {
const default_company = frappe.defaults.get_default("company");
const row = (frm.doc.item_defaults || []).find((d) => d.company === default_company);
const default_warehouse = (row && row.default_warehouse) || "";
frappe.route_options = {
purpose: "Opening Stock",
company: default_company,
};
frappe.new_doc("Stock Reconciliation", null, (doc) => {
const child = doc.items[0];
frappe.model.set_value(child.doctype, child.name, "item_code", frm.doc.name);
if (default_warehouse) {
frappe.model.set_value(child.doctype, child.name, "warehouse", default_warehouse);
}
});
return;
}
const companies = (frm.doc.item_defaults || []).map((d) => d.company).filter(Boolean);
if (!companies.length) {
@@ -901,9 +924,6 @@ $.extend(erpnext.item, {
return (row && row.default_warehouse) || "";
};
const has_serial = cint(frm.doc.has_serial_no);
const has_batch = cint(frm.doc.has_batch_no);
const fields = [
{
label: __("Company"),
@@ -950,51 +970,10 @@ $.extend(erpnext.item, {
},
];
if (has_serial) {
fields.push(
{ fieldtype: "Section Break", label: __("Serial / Batch") },
{
label: __("Serial No Series"),
fieldname: "serial_no_series",
fieldtype: "Data",
default: frm.doc.serial_no_series || "",
reqd: 1,
description: __(
"Example: SN-.YYYY.-.#####. - One serial number will be created per unit of qty."
),
}
);
}
if (has_batch) {
if (!has_serial) {
fields.push({ fieldtype: "Section Break", label: __("Serial Nos / Batches") });
}
fields.push(
{
label: __("Automatically Create New Batch"),
fieldname: "create_new_batch",
fieldtype: "Check",
default: 1,
read_only: 1,
},
{
label: __("Batch Number Series"),
fieldname: "batch_number_series",
fieldtype: "Data",
default: frm.doc.batch_number_series || "",
reqd: 1,
description: __(
"Example: BATCH-.YYYY.-.#####. - A new batch will be auto-created from this series."
),
}
);
}
const dialog = new frappe.ui.Dialog({
title: __("Set Opening Stock"),
title: __("Add Opening Stock"),
fields: fields,
primary_action_label: __("Create Stock Entry"),
primary_action_label: __("Save"),
primary_action: function (values) {
frappe.call({
method: "erpnext.stock.doctype.item.item.make_opening_stock_entry",
@@ -1004,9 +983,6 @@ $.extend(erpnext.item, {
qty: values.qty,
valuation_rate: values.valuation_rate || 0,
warehouse: values.warehouse || null,
serial_no_series: values.serial_no_series || null,
create_new_batch: values.create_new_batch ? 1 : 0,
batch_number_series: values.batch_number_series || null,
},
freeze: true,
freeze_message: __("Creating Opening Stock Entry..."),
@@ -1022,6 +998,25 @@ $.extend(erpnext.item, {
dialog.set_value("warehouse", get_warehouse_for_company(companies[0]));
dialog.show();
dialog.add_custom_action(__("Edit Full Form"), function () {
const default_company = frappe.defaults.get_default("company");
const row = (frm.doc.item_defaults || []).find((d) => d.company === default_company);
frappe.route_options = {
purpose: "Opening Stock",
company: default_company,
};
frappe.new_doc("Stock Reconciliation", null, (doc) => {
const child = doc.items[0];
frappe.model.set_value(child.doctype, child.name, "item_code", frm.doc.name);
if (row && row.default_warehouse) {
frappe.model.set_value(child.doctype, child.name, "warehouse", row.default_warehouse);
}
});
dialog.hide();
});
},
weight_to_validate: function (frm) {

View File

@@ -312,9 +312,6 @@ class Item(Document):
if self.valuation_rate is None and not self.is_customer_provided_item:
frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
# default warehouse, or Stores
for default in self.item_defaults or [
frappe._dict({"company": frappe.defaults.get_defaults().company})
]:
@@ -329,39 +326,54 @@ class Item(Document):
"Warehouse", {"warehouse_name": _("Stores"), "company": default.company}
)
if default_warehouse:
stock_entry = make_stock_entry(
item_code=self.name,
target=default_warehouse,
qty=self.opening_stock,
rate=self.valuation_rate,
company=default.company,
posting_date=getdate(),
posting_time=nowtime(),
do_not_save=True,
opening_account = frappe.db.get_value(
"Account",
{"company": default.company, "account_type": "Temporary", "is_group": 0},
"name",
)
if not opening_account:
frappe.throw(
_(
"Please set a Temporary Opening account for company {0} to create an Opening Stock entry."
).format(frappe.bold(default.company))
)
if self.valuation_rate == 0:
for item in stock_entry.items:
item.allow_zero_valuation_rate = 1
if default_warehouse:
stock_reco = frappe.get_doc(
{
"doctype": "Stock Reconciliation",
"purpose": "Opening Stock",
"company": default.company,
"expense_account": opening_account,
"items": [
{
"item_code": self.name,
"warehouse": default_warehouse,
"qty": self.opening_stock,
"valuation_rate": self.valuation_rate,
"allow_zero_valuation_rate": 1 if flt(self.valuation_rate) == 0 else 0,
}
],
}
)
stock_entry.insert()
stock_entry.submit()
stock_entry.load_from_db()
stock_entry.add_comment("Comment", _("Opening Stock"))
stock_reco.insert()
stock_reco.submit()
stock_reco.add_comment("Comment", _("Opening Stock"))
stock_entry_link = frappe.utils.get_link_to_form("Stock Entry", stock_entry.name)
stock_reco_link = frappe.utils.get_link_to_form("Stock Reconciliation", stock_reco.name)
if self.valuation_rate == 0:
frappe.msgprint(
_("Opening Stock entry created with zero valuation rate: {0}").format(
stock_entry_link
stock_reco_link
),
indicator="orange",
alert=True,
)
else:
frappe.msgprint(
_("Opening Stock entry created: {0}").format(stock_entry_link),
_("Opening Stock entry created: {0}").format(stock_reco_link),
indicator="green",
alert=True,
)