refactor: move warehouse defaults from Stock Settings to Company

Default Warehouse and Sample Retention Warehouse were global singles, so every
consumer had to re-check that the warehouse belonged to the transaction's
company before using it. Both now live on Company, under a new Warehouse
Defaults section that also collects the warehouse fields Company already had.

The company check moves to Company.validate_warehouses, which also rejects
group warehouses for all seven fields — a group or cross-company value there
already failed at SLE time, this just surfaces it at the source.

New companies get their Stores warehouse as Default Warehouse via
create_default_warehouses, replacing the setup-wizard and test-fixture code
that seeded the global.
This commit is contained in:
Mihir Kandoi
2026-07-28 19:29:18 +05:30
parent 2f07dfc474
commit 26613d258e
23 changed files with 177 additions and 158 deletions

View File

@@ -911,8 +911,8 @@ class SellingController(StockController):
if self.get("is_return"):
return
sample_retention_warehouse = frappe.db.get_single_value(
"Stock Settings", "sample_retention_warehouse"
sample_retention_warehouse = frappe.get_cached_value(
"Company", self.company, "sample_retention_warehouse"
)
if not sample_retention_warehouse:
return

View File

@@ -504,3 +504,4 @@ execute:frappe.db.set_single_value("Stock Settings", "use_inline_serial_batch_ed
erpnext.patches.v16_0.recalculate_bins_for_production_plan_items
erpnext.patches.v16_0.rename_ar_ap_ageing_filter
erpnext.patches.v16_0.fix_subcontracting_titles
erpnext.patches.v16_0.move_warehouse_defaults_to_company

View File

@@ -0,0 +1,20 @@
import frappe
import frappe.defaults
FIELDS = ("default_warehouse", "sample_retention_warehouse")
def execute():
"""Move the global warehouse defaults from Stock Settings onto the Company that owns them."""
settings = frappe.db.get_singles_dict("Stock Settings")
warehouses = {field: settings.get(field) for field in FIELDS if settings.get(field)}
if not warehouses:
return
for field, warehouse in warehouses.items():
company = frappe.db.get_value("Warehouse", warehouse, "company")
if company:
frappe.db.set_value("Company", company, field, warehouse)
frappe.db.delete("Singles", {"doctype": "Stock Settings", "field": ("in", FIELDS)})
frappe.defaults.clear_default("default_warehouse")

View File

@@ -935,8 +935,8 @@ class TestSalesOrder(ERPNextTestSuite):
self.assertEqual(so.taxes[0].tax_amount, 10)
self.assertEqual(so.taxes[0].total, 110)
old_stock_settings_value = frappe.db.get_single_value("Stock Settings", "default_warehouse")
frappe.db.set_single_value("Stock Settings", "default_warehouse", "_Test Warehouse - _TC")
old_default_warehouse = frappe.db.get_value("Company", "_Test Company", "default_warehouse")
frappe.db.set_value("Company", "_Test Company", "default_warehouse", "_Test Warehouse - _TC")
items = json.dumps(
[
@@ -974,7 +974,7 @@ class TestSalesOrder(ERPNextTestSuite):
so.delete()
new_item_with_tax.delete()
frappe.get_doc("Item Tax Template", "Test Update Items Template - _TC").delete()
frappe.db.set_single_value("Stock Settings", "default_warehouse", old_stock_settings_value)
frappe.db.set_value("Company", "_Test Company", "default_warehouse", old_default_warehouse)
def test_warehouse_user(self):
test_user = create_user("test_so_warehouse_user@example.com", "Sales User", "Stock User")

View File

@@ -3,6 +3,17 @@
frappe.provide("erpnext.company");
// Static filters (is_group / disabled / warehouse_type) live in the fields' link_filters.
const WAREHOUSE_DEFAULT_FIELDS = [
"default_warehouse",
"sample_retention_warehouse",
"default_in_transit_warehouse",
"default_warehouse_for_sales_return",
"default_wip_warehouse",
"default_fg_warehouse",
"default_scrap_warehouse",
];
frappe.ui.form.on("Company", {
onload: function (frm) {
if (frm.doc.__islocal && frm.doc.parent_company) {
@@ -51,23 +62,10 @@ frappe.ui.form.on("Company", {
return { filters: { buying: 1 } };
});
frm.set_query("default_in_transit_warehouse", function () {
return {
filters: {
warehouse_type: "Transit",
is_group: 0,
company: frm.doc.company_name,
},
};
});
frm.set_query("default_warehouse_for_sales_return", function () {
return {
filters: {
company: frm.doc.name,
is_group: 0,
},
};
WAREHOUSE_DEFAULT_FIELDS.forEach((fieldname) => {
frm.set_query(fieldname, function (doc) {
return { filters: { company: doc.name } };
});
});
frm.set_query("default_letter_head", function () {

View File

@@ -112,7 +112,6 @@
"column_break_goals",
"default_selling_terms",
"default_sales_contact",
"default_warehouse_for_sales_return",
"credit_limit",
"transactions_annual_history",
"purchase_expense_section",
@@ -140,10 +139,14 @@
"stock_delivered_but_not_billed",
"disable_sdbnb_in_sr",
"default_provisional_account",
"default_in_transit_warehouse",
"manufacturing_section",
"default_operating_cost_account",
"column_break_9prc",
"warehouse_defaults_section",
"default_warehouse",
"sample_retention_warehouse",
"default_in_transit_warehouse",
"column_break_ware",
"default_warehouse_for_sales_return",
"default_wip_warehouse",
"default_fg_warehouse",
"default_scrap_warehouse",
@@ -278,6 +281,7 @@
"fieldname": "default_warehouse_for_sales_return",
"fieldtype": "Link",
"label": "Default Warehouse for Sales Return",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
@@ -734,8 +738,33 @@
"fieldname": "default_in_transit_warehouse",
"fieldtype": "Link",
"label": "Default In-Transit Warehouse",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0],[\"Warehouse\",\"warehouse_type\",\"=\",\"Transit\"]]",
"options": "Warehouse"
},
{
"fieldname": "warehouse_defaults_section",
"fieldtype": "Section Break",
"label": "Warehouse Defaults"
},
{
"fieldname": "default_warehouse",
"fieldtype": "Link",
"label": "Default Warehouse",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"documentation_url": "https://docs.frappe.io/erpnext/retain-sample-stock",
"fieldname": "sample_retention_warehouse",
"fieldtype": "Link",
"label": "Sample Retention Warehouse",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "column_break_ware",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "unrealized_profit_loss_account",
@@ -997,27 +1026,23 @@
"fieldname": "default_wip_warehouse",
"fieldtype": "Link",
"label": " Default Work In Progress Warehouse ",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "default_fg_warehouse",
"fieldtype": "Link",
"label": "Default Finished Goods Warehouse",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "default_scrap_warehouse",
"fieldtype": "Link",
"label": "Default Scrap Warehouse",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"link_filters": "[[\"Warehouse\",\"is_group\",\"=\",0],[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "column_break_9prc",
"fieldtype": "Column Break"
},
{
"fieldname": "default_sales_contact",
"fieldtype": "Link",

View File

@@ -89,6 +89,7 @@ class Company(NestedSet):
default_sales_contact: DF.Link | None
default_scrap_warehouse: DF.Link | None
default_selling_terms: DF.Link | None
default_warehouse: DF.Link | None
default_warehouse_for_sales_return: DF.Link | None
default_wip_warehouse: DF.Link | None
depreciation_cost_center: DF.Link | None
@@ -128,6 +129,7 @@ class Company(NestedSet):
round_off_cost_center: DF.Link | None
round_off_for_opening: DF.Link | None
sales_monthly_history: DF.SmallText | None
sample_retention_warehouse: DF.Link | None
series_for_depreciation_entry: DF.Data | None
service_expense_account: DF.Link | None
stock_adjustment_account: DF.Link | None
@@ -187,6 +189,7 @@ class Company(NestedSet):
self.validate_parent_company()
self.set_reporting_currency()
self.validate_inventory_account_settings()
self.validate_warehouses()
self.cant_change_valuation_method()
self.validate_pending_reposts(old_doc)
self.validate_sdbnb_configuration()
@@ -299,6 +302,42 @@ class Company(NestedSet):
title=_("Cannot Change Inventory Account Setting"),
)
def validate_warehouses(self):
for fieldname in (
"default_warehouse",
"sample_retention_warehouse",
"default_in_transit_warehouse",
"default_warehouse_for_sales_return",
"default_wip_warehouse",
"default_fg_warehouse",
"default_scrap_warehouse",
):
warehouse = self.get(fieldname)
if not warehouse:
continue
details = frappe.db.get_value("Warehouse", warehouse, ["is_group", "company"], as_dict=True)
if not details:
continue
label = _(self.meta.get_label(fieldname))
if details.is_group:
frappe.throw(
_(
"Group Warehouses cannot be used in transactions. Please change the value of {0}"
).format(bold(label)),
title=_("Incorrect Warehouse"),
)
if details.company != self.name:
frappe.throw(
_("{0} {1} does not belong to company {2}").format(
bold(label), bold(warehouse), bold(self.name)
),
title=_("Incorrect Warehouse"),
)
def validate_abbr(self):
if not self.abbr:
self.abbr = "".join(c[0] for c in self.company_name.split()).upper()
@@ -482,6 +521,11 @@ class Company(NestedSet):
if wh_detail["is_group"]:
parent_warehouse = warehouse.name
if not self.default_warehouse:
stores = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores"), "company": self.name})
if stores:
self.db_set("default_warehouse", stores)
def create_default_accounts(self):
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts

View File

@@ -196,7 +196,7 @@ const COMPANY_DEFAULTS_TO_VF = {
};
const FIELD_DEFAULT_SOURCE = {
default_warehouse: "Stock Settings",
default_warehouse: "Company",
default_inventory_account: "Company",
buying_cost_center: "Company",
selling_cost_center: "Company",

View File

@@ -104,17 +104,15 @@ def get_company_resolved_defaults(company: str) -> dict:
"""
Returns effective default values for a company by checking:
1. Company document
2. Stock Settings (for warehouse fallback)
3. Accounts Settings (for deferred account fallbacks)
2. Accounts Settings (for deferred account fallbacks)
"""
if not company:
return {}
company_doc = frappe.get_cached_doc("Company", company)
default_warehouse = frappe.db.get_single_value("Stock Settings", "default_warehouse")
return {
"default_warehouse": default_warehouse,
"default_warehouse": company_doc.get("default_warehouse"),
"default_inventory_account": company_doc.get("default_inventory_account"),
"buying_cost_center": company_doc.get("cost_center"),
"selling_cost_center": company_doc.get("cost_center"),

View File

@@ -30,7 +30,6 @@ def set_default_settings(args):
stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO"
stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores")})
stock_settings.stock_uom = "Nos"
stock_settings.auto_indent = 1
stock_settings.auto_insert_price_list_rate_if_missing = 1

View File

@@ -534,7 +534,6 @@ def update_stock_settings():
stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO"
stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores")})
stock_settings.stock_uom = "Nos"
stock_settings.auto_indent = 1
stock_settings.auto_insert_price_list_rate_if_missing = 1

View File

@@ -321,13 +321,11 @@ class Item(Document):
for default in self.item_defaults or [
frappe._dict({"company": frappe.defaults.get_defaults().company})
]:
default_warehouse = default.default_warehouse or frappe.get_single_value(
"Stock Settings", "default_warehouse"
)
if default_warehouse:
warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
default_warehouse = default.default_warehouse
if not default_warehouse and default.company:
default_warehouse = frappe.get_cached_value("Company", default.company, "default_warehouse")
if not default_warehouse or warehouse_company != default.company:
if not default_warehouse:
default_warehouse = frappe.db.get_value(
"Warehouse", {"warehouse_name": _("Stores"), "company": default.company}
)
@@ -389,8 +387,10 @@ class Item(Document):
)
def validate_retain_sample(self):
if self.retain_sample and not frappe.get_single_value("Stock Settings", "sample_retention_warehouse"):
frappe.throw(_("Please select Sample Retention Warehouse in Stock Settings first"))
if self.retain_sample and not frappe.db.exists(
"Company", {"sample_retention_warehouse": ("is", "set")}
):
frappe.throw(_("Please select Sample Retention Warehouse in Company first"))
if self.retain_sample and not self.has_batch_no:
frappe.throw(
_(
@@ -1770,11 +1770,8 @@ def get_default_warehouse_for_opening_stock(item, company: str, warehouse: str |
if default.company == company and default.default_warehouse:
return default.default_warehouse
settings_warehouse = frappe.get_single_value("Stock Settings", "default_warehouse")
if settings_warehouse:
warehouse_company = frappe.db.get_value("Warehouse", settings_warehouse, "company")
if warehouse_company == company:
return settings_warehouse
if company_warehouse := frappe.get_cached_value("Company", company, "default_warehouse"):
return company_warehouse
stores_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores"), "company": company})
@@ -1783,7 +1780,7 @@ def get_default_warehouse_for_opening_stock(item, company: str, warehouse: str |
frappe.throw(
_(
"No warehouse found for company {0}. Please set a Default Warehouse in Item Defaults or Stock Settings."
"No warehouse found for company {0}. Please set a Default Warehouse in Item Defaults or Company."
).format(frappe.bold(company))
)

View File

@@ -976,10 +976,8 @@ class TestItem(ERPNextTestSuite):
)
self.consume_item_code_with_differet_stock_transactions(item_code=item.name)
@ERPNextTestSuite.change_settings(
"Stock Settings", {"sample_retention_warehouse": "_Test Warehouse - _TC"}
)
def test_retain_sample(self):
frappe.db.set_value("Company", "_Test Company", "sample_retention_warehouse", "_Test Warehouse - _TC")
item = make_item("_TestRetainSample", {"has_batch_no": 1, "retain_sample": 1, "sample_quantity": 1})
self.assertEqual(item.has_batch_no, 1)

View File

@@ -461,6 +461,7 @@ var validate_sample_quantity = function (frm, cdt, cdn) {
item_code: d.item_code,
sample_quantity: d.sample_quantity,
qty: d.qty,
company: frm.doc.company,
},
callback: (r) => {
frappe.model.set_value(cdt, cdn, "sample_quantity", r.message);

View File

@@ -1178,7 +1178,7 @@ def ceil_qty_if_uom_has_whole_number(qty, stock_uom):
def move_sample_to_retention_warehouse(company: str, items: str | list):
items = frappe.parse_json(items)
retention_warehouse = frappe.get_single_value("Stock Settings", "sample_retention_warehouse")
retention_warehouse = frappe.get_cached_value("Company", company, "sample_retention_warehouse")
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.company = company
stock_entry.purpose = "Material Transfer"
@@ -1195,7 +1195,7 @@ def move_sample_to_retention_warehouse(company: str, items: str | list):
def _process_sample_item(stock_entry, item, retention_warehouse):
warehouse = item.get("t_warehouse") or item.get("warehouse")
sabb = _duplicate_sample_bundle(item, warehouse)
total_qty, sabe_list = _collect_sample_batches(sabb, item, warehouse)
total_qty, sabe_list = _collect_sample_batches(sabb, item, warehouse, stock_entry.company)
if total_qty:
_append_sample_entry(stock_entry, sabb, item, warehouse, retention_warehouse, total_qty, sabe_list)
@@ -1212,21 +1212,22 @@ def _duplicate_sample_bundle(item, warehouse):
).duplicate_package()
def _collect_sample_batches(sabb, item, warehouse):
def _collect_sample_batches(sabb, item, warehouse, company):
batches = get_batch_nos(item.get("serial_and_batch_bundle"))
sabe_list, total_qty = [], 0
for batch_no in batches.keys():
qty, entries = _process_sample_batch(sabb, item, warehouse, batch_no)
qty, entries = _process_sample_batch(sabb, item, warehouse, batch_no, company)
total_qty += qty
sabe_list.extend(entries)
return total_qty, sabe_list
def _process_sample_batch(sabb, item, warehouse, batch_no):
def _process_sample_batch(sabb, item, warehouse, batch_no, company):
sample_quantity = validate_sample_quantity(
item.get("item_code"),
item.get("sample_quantity"),
item.get("transfer_qty") or item.get("qty"),
company,
batch_no,
)
sabe = next(entry for entry in sabb.entries if entry.batch_no == batch_no)
@@ -1270,18 +1271,21 @@ def _append_sample_entry(stock_entry, sabb, item, warehouse, retention_warehouse
@frappe.whitelist()
def validate_sample_quantity(item_code: str, sample_quantity: int, qty: float, batch_no: str | None = None):
def validate_sample_quantity(
item_code: str, sample_quantity: int, qty: float, company: str, batch_no: str | None = None
):
from erpnext.stock.doctype.batch.batch import get_batch_qty
if cint(qty) < cint(sample_quantity):
frappe.throw(
_("Sample quantity {0} cannot be more than received quantity {1}").format(sample_quantity, qty)
)
return _adjust_sample_quantity(item_code, sample_quantity, batch_no, get_batch_qty)
retention_warehouse = frappe.get_cached_value("Company", company, "sample_retention_warehouse")
return _adjust_sample_quantity(item_code, sample_quantity, batch_no, get_batch_qty, retention_warehouse)
def _adjust_sample_quantity(item_code, sample_quantity, batch_no, get_batch_qty):
retention_warehouse = frappe.get_single_value("Stock Settings", "sample_retention_warehouse")
def _adjust_sample_quantity(item_code, sample_quantity, batch_no, get_batch_qty, retention_warehouse):
retainted_qty = get_batch_qty(batch_no, retention_warehouse, item_code) if batch_no else 0
max_retain_qty = frappe.get_value("Item", item_code, "sample_quantity")
if retainted_qty >= max_retain_qty:

View File

@@ -65,30 +65,25 @@ frappe.ui.form.on("Stock Entry", {
};
});
frappe.db.get_value(
"Stock Settings",
{ name: "Stock Settings" },
"sample_retention_warehouse",
(r) => {
if (r.sample_retention_warehouse) {
let filters = [
["Warehouse", "company", "=", frm.doc.company],
["Warehouse", "is_group", "=", 0],
["Warehouse", "name", "!=", r.sample_retention_warehouse],
];
frm.set_query("from_warehouse", function () {
return {
filters: filters,
};
});
frm.set_query("s_warehouse", "items", function () {
return {
filters: filters,
};
});
}
frappe.db.get_value("Company", frm.doc.company, "sample_retention_warehouse", (r) => {
if (r.sample_retention_warehouse) {
let filters = [
["Warehouse", "company", "=", frm.doc.company],
["Warehouse", "is_group", "=", 0],
["Warehouse", "name", "!=", r.sample_retention_warehouse],
];
frm.set_query("from_warehouse", function () {
return {
filters: filters,
};
});
frm.set_query("s_warehouse", "items", function () {
return {
filters: filters,
};
});
}
);
});
frm.set_query("batch_no", "items", function (doc, cdt, cdn) {
let item = locals[cdt][cdn];
@@ -1173,6 +1168,7 @@ var validate_sample_quantity = function (frm, cdt, cdn) {
item_code: d.item_code,
sample_quantity: d.sample_quantity,
qty: d.transfer_qty,
company: frm.doc.company,
},
callback: (r) => {
frappe.model.set_value(cdt, cdn, "sample_quantity", r.message);

View File

@@ -2868,14 +2868,14 @@ class TestStockEntry(ERPNextTestSuite):
self.assertRaises(frappe.ValidationError, se.save)
@ERPNextTestSuite.change_settings(
"Stock Settings", {"sample_retention_warehouse": "_Test Warehouse 1 - _TC"}
)
def test_sample_retention_stock_entry(self):
from erpnext.stock.doctype.stock_entry.services.manufacturing import (
move_sample_to_retention_warehouse,
)
frappe.db.set_value(
"Company", "_Test Company", "sample_retention_warehouse", "_Test Warehouse 1 - _TC"
)
warehouse = "_Test Warehouse - _TC"
retain_sample_item = make_item(
"Retain Sample Item",
@@ -3222,19 +3222,19 @@ class TestStockEntryCoverage(ERPNextTestSuite):
# ── validate_sample_quantity ───────────────────────────────────────────────
@ERPNextTestSuite.change_settings(
"Stock Settings", {"sample_retention_warehouse": "_Test Warehouse 1 - _TC"}
)
def test_validate_sample_quantity_raises_when_sample_exceeds_received_qty(self):
from erpnext.stock.doctype.stock_entry.services.manufacturing import (
validate_sample_quantity,
)
frappe.db.set_value(
"Company", "_Test Company", "sample_retention_warehouse", "_Test Warehouse 1 - _TC"
)
item = make_item(
"_Sample Qty Excess Item",
{"is_stock_item": 1, "retain_sample": 1, "sample_quantity": 2},
)
self.assertRaises(frappe.ValidationError, validate_sample_quantity, item.name, 10, 5)
self.assertRaises(frappe.ValidationError, validate_sample_quantity, item.name, 10, 5, "_Test Company")
# ── get_expired_batches ────────────────────────────────────────────────────

View File

@@ -3,17 +3,6 @@
frappe.ui.form.on("Stock Settings", {
refresh: function (frm) {
let filters = function () {
return {
filters: {
is_group: 0,
},
};
};
frm.set_query("default_warehouse", filters);
frm.set_query("sample_retention_warehouse", filters);
if (!frm.naming_controller) frm.naming_controller = new frappe.ui.NamingSeriesController(frm);
const item_display = frm.doc.item_naming_by === "Naming Series";
const serial_and_batch_naming_display =

View File

@@ -23,9 +23,6 @@
"allow_to_edit_stock_uom_qty_for_purchase",
"allow_to_edit_stock_uom_qty_for_stock_entry",
"allow_uom_with_conversion_rate_defined_in_item",
"warehouse_defaults_section",
"default_warehouse",
"sample_retention_warehouse",
"stock_validations_tab",
"negative_stock_section",
"allow_negative_stock",
@@ -113,19 +110,6 @@
"label": "Default Stock UOM",
"options": "UOM"
},
{
"fieldname": "default_warehouse",
"fieldtype": "Link",
"label": "Default Warehouse",
"options": "Warehouse"
},
{
"documentation_url": "https://docs.frappe.io/erpnext/retain-sample-stock",
"fieldname": "sample_retention_warehouse",
"fieldtype": "Link",
"label": "Sample Retention Warehouse",
"options": "Warehouse"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
@@ -527,11 +511,6 @@
"fieldtype": "Check",
"label": "Activate Serial / Batch No for Item"
},
{
"fieldname": "warehouse_defaults_section",
"fieldtype": "Section Break",
"label": "Warehouse Defaults"
},
{
"fieldname": "internal_transfer_rules_section",
"fieldtype": "Section Break",

View File

@@ -41,7 +41,6 @@ class StockSettings(Document):
auto_reserve_stock: DF.Check
auto_reserve_stock_for_sales_order_on_purchase: DF.Check
clean_description_html: DF.Check
default_warehouse: DF.Link | None
disable_serial_no_and_batch_selector: DF.Check
do_not_update_serial_batch_on_creation_of_auto_bundle: DF.Check
do_not_use_batchwise_valuation: DF.Check
@@ -57,7 +56,6 @@ class StockSettings(Document):
reorder_email_notify: DF.Check
role_allowed_to_create_edit_back_dated_transactions: DF.Link | None
role_allowed_to_over_deliver_receive: DF.Link | None
sample_retention_warehouse: DF.Link | None
set_serial_and_batch_bundle_naming_based_on_naming_series: DF.Check
show_barcode_field: DF.Check
stock_auth_role: DF.Link | None
@@ -79,7 +77,6 @@ class StockSettings(Document):
"item_group",
"stock_uom",
"allow_negative_stock",
"default_warehouse",
"set_qty_in_transactions_based_on_serial_no_input",
"use_serial_batch_fields",
"enable_serial_and_batch_no_for_item",
@@ -104,7 +101,6 @@ class StockSettings(Document):
validate_fields_for_doctype=False,
)
self.validate_warehouses()
self.validate_serial_and_batch_no_settings()
self.cant_change_valuation_method()
self.validate_clean_description_html()
@@ -150,17 +146,6 @@ class StockSettings(Document):
)
)
def validate_warehouses(self):
warehouse_fields = ["default_warehouse", "sample_retention_warehouse"]
for field in warehouse_fields:
if frappe.db.get_value("Warehouse", self.get(field), "is_group"):
frappe.throw(
_(
"Group Warehouses cannot be used in transactions. Please change the value of {0}"
).format(frappe.bold(self.meta.get_field(field).label)),
title=_("Incorrect Warehouse"),
)
def cant_change_valuation_method(self):
doc_before_save = self.get_doc_before_save()
if not doc_before_save:

View File

@@ -15,18 +15,10 @@
"setting_field": "clean_description_html",
"settings_doctype": "Stock Settings"
},
{
"setting_field": "default_warehouse",
"settings_doctype": "Stock Settings"
},
{
"setting_field": "valuation_method",
"settings_doctype": "Stock Settings"
},
{
"setting_field": "sample_retention_warehouse",
"settings_doctype": "Stock Settings"
},
{
"setting_field": "selling_price_list",
"settings_doctype": "Selling Settings"

View File

@@ -650,13 +650,8 @@ def get_item_warehouse_(ctx: ItemDetailsCtx, item, overwrite_warehouse, defaults
else:
warehouse = ctx.warehouse
if not warehouse:
default_warehouse = frappe.get_single_value("Stock Settings", "default_warehouse")
if (
default_warehouse
and frappe.get_cached_value("Warehouse", default_warehouse, "company") == ctx.company
):
return default_warehouse
if not warehouse and ctx.company:
return frappe.get_cached_value("Company", ctx.company, "default_warehouse")
return warehouse

View File

@@ -246,7 +246,6 @@ class BootStrapTestData:
stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO"
stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores")})
stock_settings.stock_uom = "Nos"
stock_settings.auto_indent = 1
stock_settings.auto_insert_price_list_rate_if_missing = 1