Repository: frappe/erpnext
Pull request: fix: accounting dimensions required while creating POS Profile
**Issue:**
<img width="957" alt="image" src="https://github.com/frappe/erpnext/assets/65544983/e2c20632-3b56-4668-8d97-a53fd4ba4e29">
When closing a POS whilst having a Accounting Dimension mandatory for either P&L or BS, we get the above error.
<img width="1366" alt="image" src="https://github.com/frappe/erpnext/assets/65544983/0ce763bd-2734-424d-92cd-e8053210a327">

**Solution:**
The accounting dimensions which are enabled and mandatory for either  P&L or BS, are now required while creating a POS Profile.
These values from POS Profile are then fetched while closing POS hence removing the error.

**Result:**
We are now able to close POS without any issue. 


Problem statement:
POS Invoice merging doesn't pick the default accounting dimensions set in Accounting Dimension, or on the POS Profile
### Information about bug

1. Create an Accounting Dimension, e.g. Department
2. Tick Mandatory For Profit and Loss Account
3. Set Default Dimension value in the Dimension Defaults
4. In addition or as an alternative, set the Default Dimension value in the POS Profile, under Accounting Dimensions
5. Create a POS Invoice in POS, then close shift to merge the POS invoices into sales invoices
6. Alternatively create a sales invoice in POS Awesome, and try to submit it

- In 5 and 6 above, each scenario raises, Accounting Dimension is required for 'Profit and Loss Account' XXX

### Module

selling

### Version

ERPNext: v14.31.2 (HEAD)
Frappe Framework: v14.41.0 (HEAD)

### Installation method

FrappeCloud

### Relevant log output / Stack trace / Full Error Message.

```shell
request.js:457 Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 94, in application
    response = frappe.api.handle()
  File "apps/frappe/frappe/api.py", line 54, in handle
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 47, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1619, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/desk/form/save.py", line 28, in savedocs
    doc.save()
  File "apps/frappe/frappe/model/document.py", line 305, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 356, in _save
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1085, in run_post_save_methods
    self.run_method("on_submit")
  File "apps/frappe/frappe/model/document.py", line 914, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1267, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1249, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 911, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py", line 93, in on_submit
    consolidate_pos_invoices(closing_entry=self)
  File "apps/erpnext/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py", line 346, in consolidate_pos_invoices
    create_merge_logs(invoice_by_customer, closing_entry)
  File "apps/erpnext/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py", line 431, in create_merge_logs
    merge_log.submit()
  File "apps/frappe/frappe/model/document.py", line 1005, in submit
    return self._submit()
  File "apps/frappe/frappe/model/document.py", line 984, in _submit
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 305, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 356, in _save
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1085, in run_post_save_methods
    self.run_method("on_submit")
  File "apps/frappe/frappe/model/document.py", line 914, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1267, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1249, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 911, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py", line 96, in on_submit
    sales_invoice = self.process_merging_into_sales_invoice(sales)
  File "apps/erpnext/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py", line 120, in process_merging_into_sales_invoice
    sales_invoice.submit()
  File "apps/frappe/frappe/model/document.py", line 1005, in submit
    return self._submit()
  File "apps/frappe/frappe/model/document.py", line 984, in _submit
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 305, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 356, in _save
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1085, in run_post_save_methods
    self.run_method("on_submit")
  File "apps/frappe/frappe/model/document.py", line 914, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1267, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1249, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 911, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py", line 269, in on_submit
    self.make_gl_entries()
  File "apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py", line 1043, in make_gl_entries
    make_gl_entries(
  File "apps/erpnext/erpnext/accounts/general_ledger.py", line 42, in make_gl_entries
    save_entries(gl_map, adv_adj, update_outstanding, from_repost)
  File "apps/erpnext/erpnext/accounts/general_ledger.py", line 305, in save_entries
    make_entry(entry, adv_adj, update_outstanding, from_repost)
  File "apps/erpnext/erpnext/accounts/general_ledger.py", line 316, in make_entry
    gle.submit()
  File "apps/frappe/frappe/model/document.py", line 1005, in submit
    return self._submit()
  File "apps/frappe/frappe/model/document.py", line 984, in _submit
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 305, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 327, in _save
    return self.insert()
  File "apps/frappe/frappe/model/document.py", line 285, in insert
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1084, in run_post_save_methods
    self.run_method("on_update")
  File "apps/frappe/frappe/model/document.py", line 914, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1267, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1249, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 911, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py", line 56, in on_update
    self.validate_dimensions_for_pl_and_bs()
  File "apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py", line 141, in validate_dimensions_for_pl_and_bs
    frappe.throw(
  File "apps/frappe/frappe/__init__.py", line 533, in throw
    msgprint(
  File "apps/frappe/frappe/__init__.py", line 501, in msgprint
    _raise_exception()
  File "apps/frappe/frappe/__init__.py", line 450, in _raise_exception
    raise raise_exception(msg)
frappe.exceptions.ValidationError: Accounting Dimension <b>Department</b> is required for 'Profit and Loss' account 4110 - Sales - VFL.
```

Hints from issue discussion:

Commit message: chore: code cleanup

Patch to review:
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index cfe5e6e80092..3a2c3cbeeb10 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -265,20 +265,21 @@ def get_dimension_with_children(doctype, dimensions):
 
 @frappe.whitelist()
 def get_dimensions(with_cost_center_and_project=False):
-	dimension_filters = frappe.db.sql(
-		"""
-		SELECT label, fieldname, document_type
-		FROM `tabAccounting Dimension`
-		WHERE disabled = 0
-	""",
-		as_dict=1,
-	)
 
-	default_dimensions = frappe.db.sql(
-		"""SELECT p.fieldname, c.company, c.default_dimension
-		FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
-		WHERE c.parent = p.name""",
-		as_dict=1,
+	c = frappe.qb.DocType("Accounting Dimension Detail")
+	p = frappe.qb.DocType("Accounting Dimension")
+	dimension_filters = (
+		frappe.qb.from_(p)
+		.select(p.label, p.fieldname, p.document_type)
+		.where(p.disabled == 0)
+		.run(as_dict=1)
+	)
+	default_dimensions = (
+		frappe.qb.from_(c)
+		.inner_join(p)
+		.on(c.parent == p.name)
+		.select(p.fieldname, c.company, c.default_dimension)
+		.run(as_dict=1)
 	)
 
 	if isinstance(with_cost_center_and_project, str):
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index d8cbcc141bda..e3a4e2be16d6 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -12,6 +12,10 @@
 from frappe.utils.background_jobs import enqueue, is_job_enqueued
 from frappe.utils.scheduler import is_scheduler_inactive
 
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
+	get_accounting_dimensions,
+)
+
 
 class POSInvoiceMergeLog(Document):
 	def validate(self):
@@ -83,6 +87,11 @@ def on_submit(self):
 		pos_invoice_docs = [
 			frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
 		]
+		accounting_dimensions = get_accounting_dimensions()
+		for d in pos_invoice_docs:
+			for dimension in accounting_dimensions:
+				dimension_value = frappe.db.get_value("POS Profile", d.pos_profile, dimension)
+				d.set(dimension, dimension_value)
 
 		returns = [d for d in pos_invoice_docs if d.get("is_return") == 1]
 		sales = [d for d in pos_invoice_docs if d.get("is_return") == 0]
@@ -426,11 +435,9 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
 				)
 				merge_log.customer = customer
 				merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None
-
 				merge_log.set("pos_invoices", _invoices)
 				merge_log.save(ignore_permissions=True)
 				merge_log.submit()
-
 		if closing_entry:
 			closing_entry.set_status(update=True, status="Submitted")
 			closing_entry.db_set("error_message", "")
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index 0a89aee8e9c7..ff27dc1a9d96 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -1,5 +1,7 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
+frappe.provide("erpnext.accounts");
+
 
 frappe.ui.form.on('POS Profile', {
 	setup: function(frm) {
@@ -135,11 +137,20 @@ frappe.ui.form.on('POS Profile', {
 		if (frm.doc.company) {
 			frm.trigger("toggle_display_account_head");
 		}
+		frappe.call({
+			method: 'erpnext.accounts.doctype.pos_profile.pos_profile.required_accounting_dimensions',
+			callback: function(r) {
+				r.message.forEach((acc_dim) => {
+					frm.toggle_reqd(acc_dim, true);
+				})
+			}
+		});
 	},
 
 	company: function(frm) {
 		frm.trigger("toggle_display_account_head");
 		erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+
 	},
 
 	toggle_display_account_head: function(frm) {
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py
index e8aee737f29d..c30617af547b 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py
@@ -197,6 +197,25 @@ def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
 	return pos_profile
 
 
+@frappe.whitelist()
+def required_accounting_dimensions():
+
+	p = frappe.qb.DocType("Accounting Dimension")
+	c = frappe.qb.DocType("Accounting Dimension Detail")
+
+	acc_dim_doc = (
+		frappe.qb.from_(p)
+		.inner_join(c)
+		.on(p.name == c.parent)
+		.select(c.parent)
+		.where(c.mandatory_for_bs == 1 or c.mandatory_for_pl == 1)
+		.where(p.disabled == 0)
+	).run(as_dict=1)
+
+	acc_dim_names = [d.parent.lower() for d in acc_dim_doc]
+	return acc_dim_names
+
+
 @frappe.whitelist()
 def set_default_profile(pos_profile, company):
 	modified = now()
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.js b/erpnext/accounts/report/balance_sheet/balance_sheet.js
index c65b9e8ccc74..ecc13d7dc8aa 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.js
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.js
@@ -15,7 +15,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function () {
 		fieldtype: "Check",
 		default: 1,
 	});
-	console.log(frappe.query_reports["Balance Sheet"]["filters"]);
 
 	frappe.query_reports["Balance Sheet"]["filters"].push({
 		fieldname: "include_default_book_entries",


Code review comments:
diff_hunk: @@ -83,6 +87,11 @@ def on_submit(self):
 		pos_invoice_docs = [
 			frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
 		]
+		accounting_dimensions = get_accounting_dimensions()
path: erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
text: @user1:
Why set in every POS invoice, this can be set just in the final consolidated invoice

@author:
fixed it