Merge pull request #27258 from deepeshgarg007/tds_validity

feat: Validity dates in Tax Withholding Rates
diff --git a/.github/helper/semgrep_rules/report.yml b/.github/helper/semgrep_rules/report.yml
index 7f3dd01..f2a9b16 100644
--- a/.github/helper/semgrep_rules/report.yml
+++ b/.github/helper/semgrep_rules/report.yml
@@ -19,3 +19,16 @@
   languages: [python]
   severity: ERROR
 
+- id: frappe-translated-values-in-business-logic
+  paths:
+    include:
+    - "**/report"
+  patterns:
+    - pattern-inside: |
+        {..., filters: [...], ...}
+    - pattern: |
+        {..., options: [..., __("..."), ...], ...}
+  message: |
+      Using translated values in options field will require you to translate the values while comparing in business logic. Instead of passing translated labels provide objects that contain both label and value. e.g. { label: __("Option value"), value: "Option value"}
+  languages: [javascript]
+  severity: ERROR
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index b5620ae..e476439 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -247,7 +247,7 @@
    "depends_on": "customer",
    "fetch_from": "customer.customer_name",
    "fieldname": "customer_name",
-   "fieldtype": "Data",
+   "fieldtype": "Small Text",
    "hide_days": 1,
    "hide_seconds": 1,
    "in_global_search": 1,
@@ -1061,6 +1061,7 @@
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "Apply Additional Discount On",
+   "length": 15,
    "options": "\nGrand Total\nNet Total",
    "print_hide": 1
   },
@@ -1147,7 +1148,7 @@
   {
    "description": "In Words will be visible once you save the Sales Invoice.",
    "fieldname": "base_in_words",
-   "fieldtype": "Data",
+   "fieldtype": "Small Text",
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "In Words (Company Currency)",
@@ -1207,7 +1208,7 @@
   },
   {
    "fieldname": "in_words",
-   "fieldtype": "Data",
+   "fieldtype": "Small Text",
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "In Words",
@@ -1560,6 +1561,7 @@
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "Print Language",
+   "length": 6,
    "print_hide": 1,
    "read_only": 1
   },
@@ -1647,6 +1649,7 @@
    "hide_seconds": 1,
    "in_standard_filter": 1,
    "label": "Status",
+   "length": 30,
    "no_copy": 1,
    "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer",
    "print_hide": 1,
@@ -1706,6 +1709,7 @@
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "Is Opening Entry",
+   "length": 4,
    "oldfieldname": "is_opening",
    "oldfieldtype": "Select",
    "options": "No\nYes",
@@ -1717,6 +1721,7 @@
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "C-Form Applicable",
+   "length": 4,
    "no_copy": 1,
    "options": "No\nYes",
    "print_hide": 1
@@ -2017,7 +2022,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2021-08-27 20:13:40.456462",
+ "modified": "2021-09-08 15:24:25.486499",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 445eb3c..8171b3b 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -400,6 +400,7 @@
 
 		invoice.flags.ignore_mandatory = True
 
+		invoice.set_missing_values()
 		invoice.save()
 
 		if self.submit_invoice:
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index b6c6689..81c60bb 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -4,7 +4,7 @@
 frappe.query_reports["Accounts Payable"] = {
 	"filters": [
 		{
-			"fieldname":"company",
+			"fieldname": "company",
 			"label": __("Company"),
 			"fieldtype": "Link",
 			"options": "Company",
@@ -12,19 +12,19 @@
 			"default": frappe.defaults.get_user_default("Company")
 		},
 		{
-			"fieldname":"report_date",
+			"fieldname": "report_date",
 			"label": __("Posting Date"),
 			"fieldtype": "Date",
 			"default": frappe.datetime.get_today()
 		},
 		{
-			"fieldname":"finance_book",
+			"fieldname": "finance_book",
 			"label": __("Finance Book"),
 			"fieldtype": "Link",
 			"options": "Finance Book"
 		},
 		{
-			"fieldname":"cost_center",
+			"fieldname": "cost_center",
 			"label": __("Cost Center"),
 			"fieldtype": "Link",
 			"options": "Cost Center",
@@ -38,7 +38,7 @@
 			}
 		},
 		{
-			"fieldname":"supplier",
+			"fieldname": "supplier",
 			"label": __("Supplier"),
 			"fieldtype": "Link",
 			"options": "Supplier",
@@ -54,48 +54,48 @@
 			}
 		},
 		{
-			"fieldname":"ageing_based_on",
+			"fieldname": "ageing_based_on",
 			"label": __("Ageing Based On"),
 			"fieldtype": "Select",
 			"options": 'Posting Date\nDue Date\nSupplier Invoice Date',
 			"default": "Due Date"
 		},
 		{
-			"fieldname":"range1",
+			"fieldname": "range1",
 			"label": __("Ageing Range 1"),
 			"fieldtype": "Int",
 			"default": "30",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range2",
+			"fieldname": "range2",
 			"label": __("Ageing Range 2"),
 			"fieldtype": "Int",
 			"default": "60",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range3",
+			"fieldname": "range3",
 			"label": __("Ageing Range 3"),
 			"fieldtype": "Int",
 			"default": "90",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range4",
+			"fieldname": "range4",
 			"label": __("Ageing Range 4"),
 			"fieldtype": "Int",
 			"default": "120",
 			"reqd": 1
 		},
 		{
-			"fieldname":"payment_terms_template",
+			"fieldname": "payment_terms_template",
 			"label": __("Payment Terms Template"),
 			"fieldtype": "Link",
 			"options": "Payment Terms Template"
 		},
 		{
-			"fieldname":"supplier_group",
+			"fieldname": "supplier_group",
 			"label": __("Supplier Group"),
 			"fieldtype": "Link",
 			"options": "Supplier Group"
@@ -106,12 +106,17 @@
 			"fieldtype": "Check"
 		},
 		{
-			"fieldname":"based_on_payment_terms",
+			"fieldname": "based_on_payment_terms",
 			"label": __("Based On Payment Terms"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"tax_id",
+			"fieldname": "show_remarks",
+			"label": __("Show Remarks"),
+			"fieldtype": "Check",
+		},
+		{
+			"fieldname": "tax_id",
 			"label": __("Tax Id"),
 			"fieldtype": "Data",
 			"hidden": 1
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 1a32e2a..5700298 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -4,7 +4,7 @@
 frappe.query_reports["Accounts Receivable"] = {
 	"filters": [
 		{
-			"fieldname":"company",
+			"fieldname": "company",
 			"label": __("Company"),
 			"fieldtype": "Link",
 			"options": "Company",
@@ -12,19 +12,19 @@
 			"default": frappe.defaults.get_user_default("Company")
 		},
 		{
-			"fieldname":"report_date",
+			"fieldname": "report_date",
 			"label": __("Posting Date"),
 			"fieldtype": "Date",
 			"default": frappe.datetime.get_today()
 		},
 		{
-			"fieldname":"finance_book",
+			"fieldname": "finance_book",
 			"label": __("Finance Book"),
 			"fieldtype": "Link",
 			"options": "Finance Book"
 		},
 		{
-			"fieldname":"cost_center",
+			"fieldname": "cost_center",
 			"label": __("Cost Center"),
 			"fieldtype": "Link",
 			"options": "Cost Center",
@@ -38,7 +38,7 @@
 			}
 		},
 		{
-			"fieldname":"customer",
+			"fieldname": "customer",
 			"label": __("Customer"),
 			"fieldtype": "Link",
 			"options": "Customer",
@@ -67,66 +67,66 @@
 			}
 		},
 		{
-			"fieldname":"ageing_based_on",
+			"fieldname": "ageing_based_on",
 			"label": __("Ageing Based On"),
 			"fieldtype": "Select",
 			"options": 'Posting Date\nDue Date',
 			"default": "Due Date"
 		},
 		{
-			"fieldname":"range1",
+			"fieldname": "range1",
 			"label": __("Ageing Range 1"),
 			"fieldtype": "Int",
 			"default": "30",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range2",
+			"fieldname": "range2",
 			"label": __("Ageing Range 2"),
 			"fieldtype": "Int",
 			"default": "60",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range3",
+			"fieldname": "range3",
 			"label": __("Ageing Range 3"),
 			"fieldtype": "Int",
 			"default": "90",
 			"reqd": 1
 		},
 		{
-			"fieldname":"range4",
+			"fieldname": "range4",
 			"label": __("Ageing Range 4"),
 			"fieldtype": "Int",
 			"default": "120",
 			"reqd": 1
 		},
 		{
-			"fieldname":"customer_group",
+			"fieldname": "customer_group",
 			"label": __("Customer Group"),
 			"fieldtype": "Link",
 			"options": "Customer Group"
 		},
 		{
-			"fieldname":"payment_terms_template",
+			"fieldname": "payment_terms_template",
 			"label": __("Payment Terms Template"),
 			"fieldtype": "Link",
 			"options": "Payment Terms Template"
 		},
 		{
-			"fieldname":"sales_partner",
+			"fieldname": "sales_partner",
 			"label": __("Sales Partner"),
 			"fieldtype": "Link",
 			"options": "Sales Partner"
 		},
 		{
-			"fieldname":"sales_person",
+			"fieldname": "sales_person",
 			"label": __("Sales Person"),
 			"fieldtype": "Link",
 			"options": "Sales Person"
 		},
 		{
-			"fieldname":"territory",
+			"fieldname": "territory",
 			"label": __("Territory"),
 			"fieldtype": "Link",
 			"options": "Territory"
@@ -137,45 +137,50 @@
 			"fieldtype": "Check"
 		},
 		{
-			"fieldname":"based_on_payment_terms",
+			"fieldname": "based_on_payment_terms",
 			"label": __("Based On Payment Terms"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"show_future_payments",
+			"fieldname": "show_future_payments",
 			"label": __("Show Future Payments"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"show_delivery_notes",
+			"fieldname": "show_delivery_notes",
 			"label": __("Show Linked Delivery Notes"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"show_sales_person",
+			"fieldname": "show_sales_person",
 			"label": __("Show Sales Person"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"tax_id",
+			"fieldname": "show_remarks",
+			"label": __("Show Remarks"),
+			"fieldtype": "Check",
+		},
+		{
+			"fieldname": "tax_id",
 			"label": __("Tax Id"),
 			"fieldtype": "Data",
 			"hidden": 1
 		},
 		{
-			"fieldname":"customer_name",
+			"fieldname": "customer_name",
 			"label": __("Customer Name"),
 			"fieldtype": "Data",
 			"hidden": 1
 		},
 		{
-			"fieldname":"payment_terms",
+			"fieldname": "payment_terms",
 			"label": __("Payment Tems"),
 			"fieldtype": "Data",
 			"hidden": 1
 		},
 		{
-			"fieldname":"credit_limit",
+			"fieldname": "credit_limit",
 			"label": __("Credit Limit"),
 			"fieldtype": "Currency",
 			"hidden": 1
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index e91fdf2..7f8eade 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -106,6 +106,7 @@
 					party = gle.party,
 					posting_date = gle.posting_date,
 					account_currency = gle.account_currency,
+					remarks = gle.remarks if self.filters.get("show_remarks") else None,
 					invoiced = 0.0,
 					paid = 0.0,
 					credit_note = 0.0,
@@ -583,10 +584,12 @@
 		else:
 			select_fields = "debit, credit"
 
+		remarks = ", remarks" if self.filters.get("show_remarks") else ""
+
 		self.gl_entries = frappe.db.sql("""
 			select
 				name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
-				against_voucher_type, against_voucher, account_currency, {0}
+				against_voucher_type, against_voucher, account_currency, {0} {remarks}
 			from
 				`tabGL Entry`
 			where
@@ -595,7 +598,7 @@
 				and party_type=%s
 				and (party is not null and party != '')
 				{1} {2} {3}"""
-			.format(select_fields, date_condition, conditions, order_by), values, as_dict=True)
+			.format(select_fields, date_condition, conditions, order_by, remarks=remarks), values, as_dict=True)
 
 	def get_sales_invoices_or_customers_based_on_sales_person(self):
 		if self.filters.get("sales_person"):
@@ -754,6 +757,10 @@
 		self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data')
 		self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link',
 			options='voucher_type', width=180)
+
+		if self.filters.show_remarks:
+			self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200),
+
 		self.add_column(label='Due Date', fieldtype='Date')
 
 		if self.party_type == "Supplier":
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 095f5ed..b296876 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -110,9 +110,26 @@
 			"fieldname":"group_by",
 			"label": __("Group by"),
 			"fieldtype": "Select",
-			"options": ["", __("Group by Voucher"), __("Group by Voucher (Consolidated)"),
-				__("Group by Account"), __("Group by Party")],
-			"default": __("Group by Voucher (Consolidated)")
+			"options": [
+				"",
+				{
+					label: __("Group by Voucher"),
+					value: "Group by Voucher",
+				},
+				{
+					label: __("Group by Voucher (Consolidated)"),
+					value: "Group by Voucher (Consolidated)",
+				},
+				{
+					label: __("Group by Account"),
+					value: "Group by Account",
+				},
+				{
+					label: __("Group by Party"),
+					value: "Group by Party",
+				},
+			],
+			"default": "Group by Voucher (Consolidated)"
 		},
 		{
 			"fieldname":"tax_id",
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index a044518..5bd6e58 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -62,14 +62,14 @@
 			if not account_details.get(account):
 				frappe.throw(_("Account {0} does not exists").format(account))
 
-	if (filters.get("account") and filters.get("group_by") == _('Group by Account')):
+	if (filters.get("account") and filters.get("group_by") == 'Group by Account'):
 		filters.account = frappe.parse_json(filters.get('account'))
 		for account in filters.account:
 			if account_details[account].is_group == 0:
 				frappe.throw(_("Can not filter based on Child Account, if grouped by Account"))
 
 	if (filters.get("voucher_no")
-		and filters.get("group_by") in [_('Group by Voucher')]):
+		and filters.get("group_by") in ['Group by Voucher']):
 		frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
 
 	if filters.from_date > filters.to_date:
@@ -153,7 +153,7 @@
 	if filters.get("include_dimensions"):
 		order_by_statement = "order by posting_date, creation"
 
-	if filters.get("group_by") == _("Group by Voucher"):
+	if filters.get("group_by") == "Group by Voucher":
 		order_by_statement = "order by posting_date, voucher_type, voucher_no"
 
 	if filters.get("include_default_book_entries"):
@@ -312,13 +312,13 @@
 	# Opening for filtered account
 	data.append(totals.opening)
 
-	if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
+	if filters.get("group_by") != 'Group by Voucher (Consolidated)':
 		for acc, acc_dict in iteritems(gle_map):
 			# acc
 			if acc_dict.entries:
 				# opening
 				data.append({})
-				if filters.get("group_by") != _("Group by Voucher"):
+				if filters.get("group_by") != "Group by Voucher":
 					data.append(acc_dict.totals.opening)
 
 				data += acc_dict.entries
@@ -327,7 +327,7 @@
 				data.append(acc_dict.totals.total)
 
 				# closing
-				if filters.get("group_by") != _("Group by Voucher"):
+				if filters.get("group_by") != "Group by Voucher":
 					data.append(acc_dict.totals.closing)
 		data.append({})
 	else:
@@ -357,9 +357,9 @@
 	)
 
 def group_by_field(group_by):
-	if group_by == _('Group by Party'):
+	if group_by == 'Group by Party':
 		return 'party'
-	elif group_by in [_('Group by Voucher (Consolidated)'), _('Group by Account')]:
+	elif group_by in ['Group by Voucher (Consolidated)', 'Group by Account']:
 		return 'account'
 	else:
 		return 'voucher_no'
@@ -423,9 +423,9 @@
 		elif gle.posting_date <= to_date:
 			update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle)
 			update_value_in_dict(totals, 'total', gle)
-			if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
+			if filters.get("group_by") != 'Group by Voucher (Consolidated)':
 				gle_map[gle.get(group_by)].entries.append(gle)
-			elif filters.get("group_by") == _('Group by Voucher (Consolidated)'):
+			elif filters.get("group_by") == 'Group by Voucher (Consolidated)':
 				keylist = [gle.get("voucher_type"), gle.get("voucher_no"), gle.get("account")]
 				for dim in accounting_dimensions:
 					keylist.append(gle.get(dim))
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 7b4b7c3..db0f2c5 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -434,6 +434,25 @@
 	}
 });
 
+frappe.ui.form.on("Production Plan Sales Order", {
+	sales_order(frm, cdt, cdn) {
+		const { sales_order } = locals[cdt][cdn];
+		if (!sales_order) {
+			return;
+		}
+		frappe.call({
+			method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_so_details",
+			args: { sales_order },
+			callback(r) {
+				const {transaction_date, customer, grand_total} = r.message;
+				frappe.model.set_value(cdt, cdn, 'sales_order_date', transaction_date);
+				frappe.model.set_value(cdt, cdn, 'customer', customer);
+				frappe.model.set_value(cdt, cdn, 'grand_total', grand_total);
+			}
+		});
+	}
+});
+
 cur_frm.fields_dict['sales_orders'].grid.get_field("sales_order").get_query = function() {
 	return{
 		filters: [
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index b5ed288..56cf2b4 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -16,10 +16,12 @@
   "customer",
   "warehouse",
   "project",
+  "sales_order_status",
   "column_break2",
   "from_date",
   "to_date",
-  "sales_order_status",
+  "from_delivery_date",
+  "to_delivery_date",
   "sales_orders_detail",
   "get_sales_orders",
   "sales_orders",
@@ -358,13 +360,23 @@
    "fieldname": "get_sub_assembly_items",
    "fieldtype": "Button",
    "label": "Get Sub Assembly Items"
+  },
+  {
+   "fieldname": "from_delivery_date",
+   "fieldtype": "Date",
+   "label": "From Delivery Date"
+  },
+  {
+   "fieldname": "to_delivery_date",
+   "fieldtype": "Date",
+   "label": "To Delivery Date"
   }
  ],
  "icon": "fa fa-calendar",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-08-23 17:26:03.799876",
+ "modified": "2021-09-06 18:35:59.642232",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 91e5748..a28fc7a 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -735,43 +735,42 @@
 def get_sales_orders(self):
 	so_filter = item_filter = ""
 	bom_item = "bom.item = so_item.item_code"
-	if self.from_date:
-		so_filter += " and so.transaction_date >= %(from_date)s"
-	if self.to_date:
-		so_filter += " and so.transaction_date <= %(to_date)s"
-	if self.customer:
-		so_filter += " and so.customer = %(customer)s"
-	if self.project:
-		so_filter += " and so.project = %(project)s"
-	if self.sales_order_status:
-		so_filter += "and so.status = %(sales_order_status)s"
+
+	date_field_mapper = {
+		'from_date': ('>=', 'so.transaction_date'),
+		'to_date': ('<=', 'so.transaction_date'),
+		'from_delivery_date': ('>=', 'so_item.delivery_date'),
+		'to_delivery_date': ('<=', 'so_item.delivery_date')
+	}
+
+	for field, value in date_field_mapper.items():
+		if self.get(field):
+			so_filter += f" and {value[1]} {value[0]} %({field})s"
+
+	for field in ['customer', 'project', 'sales_order_status']:
+		if self.get(field):
+			so_field = 'status' if field == 'sales_order_status' else field
+			so_filter += f" and so.{so_field} = %({field})s"
 
 	if self.item_code and frappe.db.exists('Item', self.item_code):
 		bom_item = self.get_bom_item() or bom_item
-		item_filter += " and so_item.item_code = %(item)s"
+		item_filter += " and so_item.item_code = %(item_code)s"
 
-	open_so = frappe.db.sql("""
+	open_so = frappe.db.sql(f"""
 		select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
 		from `tabSales Order` so, `tabSales Order Item` so_item
 		where so_item.parent = so.name
 			and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
 			and so.company = %(company)s
-			and so_item.qty > so_item.work_order_qty {0} {1}
-			and (exists (select name from `tabBOM` bom where {2}
+			and so_item.qty > so_item.work_order_qty {so_filter} {item_filter}
+			and (exists (select name from `tabBOM` bom where {bom_item}
 					and bom.is_active = 1)
 				or exists (select name from `tabPacked Item` pi
 					where pi.parent = so.name and pi.parent_item = so_item.item_code
 						and exists (select name from `tabBOM` bom where bom.item=pi.item_code
 							and bom.is_active = 1)))
-		""".format(so_filter, item_filter, bom_item), {
-			"from_date": self.from_date,
-			"to_date": self.to_date,
-			"customer": self.customer,
-			"project": self.project,
-			"item": self.item_code,
-			"company": self.company,
-			"sales_order_status": self.sales_order_status
-		}, as_dict=1)
+		""", self.as_dict(), as_dict=1)
+
 	return open_so
 
 @frappe.whitelist()
@@ -800,6 +799,12 @@
 		group by item_code, warehouse
 	""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
 
+@frappe.whitelist()
+def get_so_details(sales_order):
+	return frappe.db.get_value("Sales Order", sales_order,
+		['transaction_date', 'customer', 'grand_total'], as_dict=1
+	)
+
 def get_warehouse_list(warehouses):
 	warehouse_list = []