diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
index 8961167f018..3003c68196e 100644
--- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
+++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
@@ -25,7 +25,8 @@
"in_list_view": 1,
"label": "Type",
"options": "DocType",
- "reqd": 1
+ "reqd": 1,
+ "search_index": 1
},
{
"columns": 2,
@@ -35,7 +36,8 @@
"in_list_view": 1,
"label": "Name",
"options": "reference_doctype",
- "reqd": 1
+ "reqd": 1,
+ "search_index": 1
},
{
"fieldname": "due_date",
@@ -104,7 +106,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-09-26 17:06:55.597389",
+ "modified": "2022-12-12 12:31:44.919895",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",
@@ -113,5 +115,6 @@
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index ed46d85e3a4..e2b015bf021 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -256,7 +256,7 @@ def apply_pricing_rule(args, doc=None):
for item in item_list:
args_copy = copy.deepcopy(args)
args_copy.update(item)
- data = get_pricing_rule_for_item(args_copy, item.get("price_list_rate"), doc=doc)
+ data = get_pricing_rule_for_item(args_copy, doc=doc)
out.append(data)
if (
@@ -293,7 +293,7 @@ def update_pricing_rule_uom(pricing_rule, args):
pricing_rule.uom = row.uom
-def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
+def get_pricing_rule_for_item(args, doc=None, for_validate=False):
from erpnext.accounts.doctype.pricing_rule.utils import (
get_applied_pricing_rules,
get_pricing_rule_items,
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 79c7c12b413..7f8cc4c63e0 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -997,7 +997,7 @@ def make_pricing_rule(**args):
"apply_on": args.apply_on or "Item Code",
"applicable_for": args.applicable_for,
"selling": args.selling or 0,
- "currency": "USD",
+ "currency": "INR",
"apply_discount_on_rate": args.apply_discount_on_rate or 0,
"buying": args.buying or 0,
"min_qty": args.min_qty or 0.0,
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 35eed49da70..ab1d7385f78 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -244,6 +244,17 @@ def get_other_conditions(conditions, values, args):
and ifnull(`tabPricing Rule`.valid_upto, '2500-12-31')"""
values["transaction_date"] = args.get("transaction_date")
+ if args.get("doctype") in [
+ "Quotation",
+ "Sales Order",
+ "Delivery Note",
+ "Sales Invoice",
+ "POS Invoice",
+ ]:
+ conditions += """ and ifnull(`tabPricing Rule`.selling, 0) = 1"""
+ else:
+ conditions += """ and ifnull(`tabPricing Rule`.buying, 0) = 1"""
+
return conditions
@@ -663,7 +674,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
item_details.free_item_data.append(free_item_data_args)
-def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
+def apply_pricing_rule_for_free_items(doc, pricing_rule_args):
if pricing_rule_args:
items = tuple((d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item)
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 330e442a808..6c8f4bb6fe9 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -533,12 +533,13 @@ def get_accounts(root_type, companies):
],
filters={"company": company, "root_type": root_type},
):
- if account.account_name not in added_accounts:
+ if account.account_number:
+ account_key = account.account_number + "-" + account.account_name
+ else:
+ account_key = account.account_name
+
+ if account_key not in added_accounts:
accounts.append(account)
- if account.account_number:
- account_key = account.account_number + "-" + account.account_name
- else:
- account_key = account.account_name
added_accounts.append(account_key)
return accounts
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index ba8d3072283..ba733c2d185 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -234,8 +234,11 @@ def modify_report_columns(doctype, field, column):
if field in ["item_tax_rate", "base_net_amount"]:
return None
- if doctype == "GL Entry" and field in ["debit", "credit"]:
- column.update({"label": _("Amount"), "fieldname": "amount"})
+ if doctype == "GL Entry":
+ if field in ["debit", "credit"]:
+ column.update({"label": _("Amount"), "fieldname": "amount"})
+ elif field == "voucher_type":
+ column.update({"fieldtype": "Data", "options": ""})
if field == "taxes_and_charges":
column.update({"label": _("Taxes and Charges Template")})
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 7e542197407..7791b117444 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -136,6 +136,10 @@ frappe.ui.form.on('Asset', {
}, __("Manage"));
}
+ if (frm.doc.depr_entry_posting_status === "Failed") {
+ frm.trigger("set_depr_posting_failure_alert");
+ }
+
frm.trigger("setup_chart");
}
@@ -146,6 +150,19 @@ frappe.ui.form.on('Asset', {
}
},
+ set_depr_posting_failure_alert: function (frm) {
+ const alert = `
+
+
+
+ Failed to post depreciation entries
+
+
+
`;
+
+ frm.dashboard.set_headline_alert(alert);
+ },
+
toggle_reference_doc: function(frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
frm.set_df_property('purchase_invoice', 'read_only', 1);
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index f0505ff9835..8b6af47b049 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -70,6 +70,7 @@
"column_break_51",
"purchase_receipt_amount",
"default_finance_book",
+ "depr_entry_posting_status",
"amended_from"
],
"fields": [
@@ -488,6 +489,16 @@
"fieldtype": "Int",
"label": "Asset Quantity",
"read_only_depends_on": "eval:!doc.is_existing_asset"
+ },
+ {
+ "fieldname": "depr_entry_posting_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Depreciation Entry Posting Status",
+ "no_copy": 1,
+ "options": "\nSuccessful\nFailed",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 72,
@@ -510,7 +521,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2022-07-20 10:15:12.887372",
+ "modified": "2022-12-05 16:21:30.024060",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 97941706aa8..c6daccc9728 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -5,6 +5,8 @@
import frappe
from frappe import _
from frappe.utils import add_months, cint, flt, getdate, nowdate, today
+from frappe.utils.data import get_link_to_form
+from frappe.utils.user import get_users_with_role
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
@@ -12,7 +14,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
-def post_depreciation_entries(date=None, commit=True):
+def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
if not cint(
frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")
@@ -21,10 +23,22 @@ def post_depreciation_entries(date=None, commit=True):
if not date:
date = today()
- for asset in get_depreciable_assets(date):
- make_depreciation_entry(asset, date)
- if commit:
+
+ failed_asset_names = []
+
+ for asset_name in get_depreciable_assets(date):
+ try:
+ make_depreciation_entry(asset_name, date)
frappe.db.commit()
+ except Exception as e:
+ frappe.db.rollback()
+ failed_asset_names.append(asset_name)
+
+ if failed_asset_names:
+ set_depr_entry_posting_status_for_failed_assets(failed_asset_names)
+ notify_depr_entry_posting_error(failed_asset_names)
+
+ frappe.db.commit()
def get_depreciable_assets(date):
@@ -123,6 +137,8 @@ def make_depreciation_entry(asset_name, date=None):
finance_books.value_after_depreciation -= d.depreciation_amount
finance_books.db_update()
+ frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful")
+
asset.set_status()
return asset
@@ -186,6 +202,42 @@ def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation
return credit_account, debit_account
+def set_depr_entry_posting_status_for_failed_assets(failed_asset_names):
+ for asset_name in failed_asset_names:
+ frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Failed")
+
+
+def notify_depr_entry_posting_error(failed_asset_names):
+ recipients = get_users_with_role("Accounts Manager")
+
+ if not recipients:
+ recipients = get_users_with_role("System Manager")
+
+ subject = _("Error while posting depreciation entries")
+
+ asset_links = get_comma_separated_asset_links(failed_asset_names)
+
+ message = (
+ _("Hi,")
+ + "
"
+ + _("The following assets have failed to post depreciation entries: {0}").format(asset_links)
+ + "."
+ )
+
+ frappe.sendmail(recipients=recipients, subject=subject, message=message)
+
+
+def get_comma_separated_asset_links(asset_names):
+ asset_links = []
+
+ for asset_name in asset_names:
+ asset_links.append(get_link_to_form("Asset", asset_name))
+
+ asset_links = ", ".join(asset_links)
+
+ return asset_links
+
+
@frappe.whitelist()
def scrap_asset(asset_name):
asset = frappe.get_doc("Asset", asset_name)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index baed310adb9..5a31ca0e2d7 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -1478,6 +1478,7 @@ def create_asset(**args):
"asset_owner": args.asset_owner or "Company",
"is_existing_asset": args.is_existing_asset or 1,
"asset_quantity": args.get("asset_quantity") or 1,
+ "depr_entry_posting_status": args.depr_entry_posting_status or "",
}
)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 5a051e3bafc..334a2d806d6 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -197,7 +197,7 @@ class AccountsController(TransactionBase):
validate_einvoice_fields(self)
- if self.doctype != "Material Request":
+ if self.doctype != "Material Request" and not self.ignore_pricing_rule:
apply_pricing_rule_on_transaction(self)
def before_cancel(self):
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 6e7d2b33c28..bf077282bf8 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -349,7 +349,7 @@ class StatusUpdater(Document):
def warn_about_bypassing_with_role(self, item, qty_or_amount, role):
action = _("Over Receipt/Delivery") if qty_or_amount == "qty" else _("Overbilling")
- msg = _("{} of {} {} ignored for item {} because you have {} role.").format(
+ msg = _("{0} of {1} {2} ignored for item {3} because you have {4} role.").format(
action,
_(item["target_ref_field"].title()),
frappe.bold(item["reduce_by"]),
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
index 1e1b4356008..cdf1541f888 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
@@ -4,7 +4,7 @@
import frappe
from frappe import _
-from frappe.query_builder.functions import Floor, Sum
+from frappe.query_builder.functions import Sum
from pypika.terms import ExistsCriterion
@@ -58,9 +58,9 @@ def get_bom_stock(filters):
bom_item.description,
bom_item.stock_qty,
bom_item.stock_uom,
- bom_item.stock_qty * qty_to_produce / bom.quantity,
- Sum(bin.actual_qty).as_("actual_qty"),
- Sum(Floor(bin.actual_qty / (bom_item.stock_qty * qty_to_produce / bom.quantity))),
+ (bom_item.stock_qty / bom.quantity) * qty_to_produce,
+ Sum(bin.actual_qty),
+ Sum(bin.actual_qty) / (bom_item.stock_qty / bom.quantity),
)
.where((bom_item.parent == filters.get("bom")) & (bom_item.parenttype == "BOM"))
.groupby(bom_item.item_code)
diff --git a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
index 16c25ce7e6d..109d9ab656b 100644
--- a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
+++ b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
@@ -49,7 +49,7 @@ class ProductionPlanReport(object):
parent.bom_no,
parent.fg_warehouse.as_("warehouse"),
)
- .where(parent.status.notin(["Completed", "Stopped"]))
+ .where(parent.status.notin(["Completed", "Stopped", "Closed"]))
)
if order_by == "Planned Start Date":
@@ -79,10 +79,11 @@ class ProductionPlanReport(object):
query = query.where(child.parent.isin(self.filters.docnames))
if doctype == "Sales Order":
- query = query.select(
- child.delivery_date,
- parent.base_grand_total,
- ).where((child.stock_qty > child.produced_qty) & (parent.per_delivered < 100.0))
+ query = query.select(child.delivery_date, parent.base_grand_total,).where(
+ (child.stock_qty > child.produced_qty)
+ & (parent.per_delivered < 100.0)
+ & (parent.status.notin(["Completed", "Closed"]))
+ )
if order_by == "Delivery Date":
query = query.orderby(child.delivery_date, order=Order.asc)
@@ -91,7 +92,9 @@ class ProductionPlanReport(object):
elif doctype == "Material Request":
query = query.select(child.schedule_date,).where(
- (parent.per_ordered < 100) & (parent.material_request_type == "Manufacture")
+ (parent.per_ordered < 100)
+ & (parent.material_request_type == "Manufacture")
+ & (parent.status != "Stopped")
)
if order_by == "Required Date":
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 74810005ed9..1f8a5e39f25 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -58,7 +58,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
if (
in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype)
- && this.frm.doc.s_pos
+ && this.frm.doc.is_pos
&& this.frm.doc.is_return
) {
this.set_total_amount_to_default_mop();
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 46ac80895cf..58d8de24993 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1130,10 +1130,13 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
qty(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
- item.pricing_rules = ''
- this.conversion_factor(doc, cdt, cdn, true);
- this.calculate_stock_uom_rate(doc, cdt, cdn);
- this.apply_pricing_rule(item, true);
+ // item.pricing_rules = ''
+ frappe.run_serially([
+ () => this.remove_pricing_rule(item),
+ () => this.conversion_factor(doc, cdt, cdn, true),
+ () => this.calculate_stock_uom_rate(doc, cdt, cdn),
+ () => this.apply_pricing_rule(item, true)
+ ]);
}
calculate_stock_uom_rate(doc, cdt, cdn) {
@@ -1357,16 +1360,21 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
var item_list = [];
$.each(this.frm.doc["items"] || [], function(i, d) {
- if (d.item_code && !d.is_free_item) {
- item_list.push({
- "doctype": d.doctype,
- "name": d.name,
- "item_code": d.item_code,
- "pricing_rules": d.pricing_rules,
- "parenttype": d.parenttype,
- "parent": d.parent,
- "price_list_rate": d.price_list_rate
- })
+ if (d.item_code) {
+ if (d.is_free_item) {
+ // Simply remove free items
+ me.frm.get_field("items").grid.grid_rows[i].remove();
+ } else {
+ item_list.push({
+ "doctype": d.doctype,
+ "name": d.name,
+ "item_code": d.item_code,
+ "pricing_rules": d.pricing_rules,
+ "parenttype": d.parenttype,
+ "parent": d.parent,
+ "price_list_rate": d.price_list_rate
+ })
+ }
}
});
return this.frm.call({
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index d0eb3774e26..60c33567bef 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -6,7 +6,7 @@ import json
import frappe
import frappe.defaults
-from frappe import _, msgprint
+from frappe import _, msgprint, qb
from frappe.contacts.address_and_contact import (
delete_contact_and_address,
load_address_and_contact,
@@ -732,12 +732,15 @@ def make_address(args, is_primary_address=1):
@frappe.validate_and_sanitize_search_inputs
def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, filters):
customer = filters.get("customer")
- return frappe.db.sql(
- """
- select `tabContact`.name from `tabContact`, `tabDynamic Link`
- where `tabContact`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
- and `tabDynamic Link`.link_doctype = 'Customer'
- and `tabContact`.name like %(txt)s
- """,
- {"customer": customer, "txt": "%%%s%%" % txt},
+
+ con = qb.DocType("Contact")
+ dlink = qb.DocType("Dynamic Link")
+
+ return (
+ qb.from_(con)
+ .join(dlink)
+ .on(con.name == dlink.parent)
+ .select(con.name, con.full_name, con.email_id)
+ .where((dlink.link_name == customer) & (con.name.like(f"%{txt}%")))
+ .run()
)
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 6f0b381fc16..b151dd5e79c 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -30,6 +30,24 @@ class TestQuotation(FrappeTestCase):
self.assertTrue(sales_order.get("payment_schedule"))
+ def test_maintain_rate_in_sales_cycle_is_enforced(self):
+ from erpnext.selling.doctype.quotation.quotation import make_sales_order
+
+ maintain_rate = frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")
+ frappe.db.set_single_value("Selling Settings", "maintain_same_sales_rate", 1)
+
+ quotation = frappe.copy_doc(test_records[0])
+ quotation.transaction_date = nowdate()
+ quotation.valid_till = add_months(quotation.transaction_date, 1)
+ quotation.insert()
+ quotation.submit()
+
+ sales_order = make_sales_order(quotation.name)
+ sales_order.items[0].rate = 1
+ self.assertRaises(frappe.ValidationError, sales_order.save)
+
+ frappe.db.set_single_value("Selling Settings", "maintain_same_sales_rate", maintain_rate)
+
def test_make_sales_order_with_different_currency(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 78e2370878f..0013c95032f 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -194,7 +194,7 @@ class SalesOrder(SellingController):
)
if cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")):
- self.validate_rate_with_reference_doc([["Quotation", "prev_docname", "quotation_item"]])
+ self.validate_rate_with_reference_doc([["Quotation", "prevdoc_docname", "quotation_item"]])
def update_enquiry_status(self, prevdoc, flag):
enq = frappe.db.sql(
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index ace2e29c2b4..5c4b57813d3 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -12,7 +12,10 @@ def get_data():
"Auto Repeat": "reference_document",
"Maintenance Visit": "prevdoc_docname",
},
- "internal_links": {"Quotation": ["items", "prevdoc_docname"]},
+ "internal_links": {
+ "Quotation": ["items", "prevdoc_docname"],
+ "Material Request": ["items", "material_request"],
+ },
"transactions": [
{
"label": _("Fulfillment"),
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 411176b70af..95bbf84616b 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -152,7 +152,7 @@ def get_parent_item_groups(item_group_name, from_item=False):
if from_item and frappe.request.environ.get("HTTP_REFERER"):
# base page after 'Home' will vary on Item page
- last_page = frappe.request.environ["HTTP_REFERER"].split("/")[-1]
+ last_page = frappe.request.environ["HTTP_REFERER"].split("/")[-1].split("?")[0]
if last_page and last_page in ("shop-by-category", "all-products"):
base_nav_page_title = " ".join(last_page.split("-")).title()
base_nav_page = {"name": _(base_nav_page_title), "route": "/" + last_page}
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 108611c09bf..31dccf6944d 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -113,7 +113,7 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
if args.get(key) is None:
args[key] = value
- data = get_pricing_rule_for_item(args, out.price_list_rate, doc, for_validate=for_validate)
+ data = get_pricing_rule_for_item(args, doc=doc, for_validate=for_validate)
out.update(data)
@@ -1305,7 +1305,7 @@ def apply_price_list_on_item(args):
item_doc = frappe.db.get_value("Item", args.item_code, ["name", "variant_of"], as_dict=1)
item_details = get_price_list_rate(args, item_doc)
- item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
+ item_details.update(get_pricing_rule_for_item(args))
return item_details
diff --git a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py
index 81700099fa4..d364b577a26 100644
--- a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py
+++ b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py
@@ -45,7 +45,7 @@ def get_warehouses(report_filters: StockBalanceFilter):
return frappe.get_all(
"Warehouse",
fields=["name", "parent_warehouse", "is_group"],
- filters={"company": report_filters.company, "disabled": 0},
+ filters={"company": report_filters.company},
order_by="lft",
)
@@ -55,9 +55,10 @@ def get_data(filters: StockBalanceFilter):
warehouses = get_warehouses(filters)
for warehouse in warehouses:
- warehouse["stock_balance"] = warehouse_balance.get(warehouse.name, 0)
+ warehouse.stock_balance = warehouse_balance.get(warehouse.name, 0) or 0.0
update_indent(warehouses)
+ set_balance_in_parent(warehouses)
return warehouses
@@ -69,13 +70,26 @@ def update_indent(warehouses):
warehouse.indent = indent
for child in warehouses:
if child.parent_warehouse == warehouse.name:
- warehouse.stock_balance += child.stock_balance
add_indent(child, indent + 1)
if warehouse.is_group:
add_indent(warehouse, warehouse.indent or 0)
+def set_balance_in_parent(warehouses):
+ # sort warehouses by indent in descending order
+ warehouses = sorted(warehouses, key=lambda x: x.get("indent", 0), reverse=1)
+
+ for warehouse in warehouses:
+
+ def update_balance(warehouse, balance):
+ for parent in warehouses:
+ if warehouse.parent_warehouse == parent.name:
+ parent.stock_balance += balance
+
+ update_balance(warehouse, warehouse.stock_balance)
+
+
def get_columns():
return [
{
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index ec9c50247fa..a401983d2ad 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -9916,3 +9916,4 @@ Cost and Freight,Kosten und Fracht,
Delivered at Place,Geliefert benannter Ort,
Delivered at Place Unloaded,Geliefert benannter Ort entladen,
Delivered Duty Paid,Geliefert verzollt,
+{0} of {1} {2} ignored for item {3} because you have {4} role,"{0} von Artikel {3} mit {1} {2} wurde ignoriert, weil Sie die Rolle {4} haben."
diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py
index 04ee0b3b1eb..afe9654e8ea 100644
--- a/erpnext/utilities/product.py
+++ b/erpnext/utilities/product.py
@@ -110,6 +110,7 @@ def get_price(item_code, price_list, customer_group, company, qty=1):
"conversion_rate": 1,
"for_shopping_cart": True,
"currency": frappe.db.get_value("Price List", price_list, "currency"),
+ "doctype": "Quotation",
}
)