Merge pull request #25845 from noahjacob/item_so_variant_fix

fix: production plan not fetching sales order of a variant
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 603e21e..6c25f00 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -249,7 +249,7 @@
 
 def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
 	if budget_against_field == "project":
-		budget_against = "_Test Project"
+		budget_against = frappe.db.get_value("Project", {"project_name": "_Test Project"})
 	else:
 		budget_against = budget_against_CC or "_Test Cost Center - _TC"
 
@@ -275,7 +275,7 @@
 			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
 		elif budget_against_field == "project":
 			make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
+			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project=budget_against, posting_date=nowdate())
 
 def make_budget(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index dc9094c..c588d45 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -134,7 +134,7 @@
 					},
 					get_query_filters: {
 						docstatus: 1,
-						status: ["not in", ["Closed", "Completed"]],
+						status: ["not in", ["Closed", "Completed", "Return Issued"]],
 						company: me.frm.doc.company,
 						is_return: 0
 					}
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 1ba752a..e6b6cc4 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -430,7 +430,8 @@
 		'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
 		'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
 		'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
-		'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
+		'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount',
+		'erpnext.stock.doctype.item.item.set_item_tax_from_hsn_code': 'erpnext.regional.india.utils.set_item_tax_from_hsn_code'
 	},
 	'United Arab Emirates': {
 		'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index b978cbe..381f399 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -112,11 +112,11 @@
 		no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
 		return amount_per_day * no_of_days
 
-@frappe.whitelist()
 def get_additional_salaries(employee, start_date, end_date, component_type):
 	additional_salary_list = frappe.db.sql("""
-		select name, salary_component as component, type, amount, overwrite_salary_structure_amount as overwrite,
-		deduct_full_tax_on_selected_payroll_date, is_recurring
+		select name, salary_component as component, type, amount,
+		overwrite_salary_structure_amount as overwrite,
+		deduct_full_tax_on_selected_payroll_date
 		from `tabAdditional Salary`
 		where employee=%(employee)s
 			and docstatus = 1
diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json
index 97608d7..393f647 100644
--- a/erpnext/payroll/doctype/salary_detail/salary_detail.json
+++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json
@@ -12,7 +12,6 @@
   "year_to_date",
   "section_break_5",
   "additional_salary",
-  "is_recurring_additional_salary",
   "statistical_component",
   "depends_on_payment_days",
   "exempted_from_income_tax",
@@ -236,19 +235,11 @@
    "label": "Year To Date",
    "options": "currency",
    "read_only": 1
-  },
-  {
-   "default": "0",
-   "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='earnings' && doc.additional_salary",
-   "fieldname": "is_recurring_additional_salary",
-   "fieldtype": "Check",
-   "label": "Is Recurring Additional Salary",
-   "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2021-03-14 13:39:15.847158",
+ "modified": "2021-01-14 13:39:15.847158",
  "modified_by": "Administrator",
  "module": "Payroll",
  "name": "Salary Detail",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 3e82c0d..7e1fb06 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -7,12 +7,12 @@
 
 from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day
 from frappe.model.naming import make_autoname
-from frappe.utils.background_jobs import enqueue
 
 from frappe import msgprint, _
 from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 from erpnext.utilities.transaction_base import TransactionBase
+from frappe.utils.background_jobs import enqueue
 from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
 from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
 from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
@@ -618,8 +618,7 @@
 				get_salary_component_data(additional_salary.component),
 				additional_salary.amount,
 				component_type,
-				additional_salary,
-				is_recurring = additional_salary.is_recurring
+				additional_salary
 			)
 
 	def add_tax_components(self, payroll_period):
@@ -640,7 +639,7 @@
 			tax_row = get_salary_component_data(d)
 			self.update_component_row(tax_row, tax_amount, "deductions")
 
-	def update_component_row(self, component_data, amount, component_type, additional_salary=None, is_recurring = 0):
+	def update_component_row(self, component_data, amount, component_type, additional_salary=None):
 		component_row = None
 		for d in self.get(component_type):
 			if d.salary_component != component_data.salary_component:
@@ -681,7 +680,6 @@
 			component_row.set('abbr', abbr)
 
 		if additional_salary:
-			component_row.is_recurring_additional_salary = is_recurring
 			component_row.default_amount = 0
 			component_row.additional_amount = amount
 			component_row.additional_salary = additional_salary.name
@@ -715,7 +713,6 @@
 		# get remaining numbers of sub-period (period for which one salary is processed)
 		remaining_sub_periods = get_period_factor(self.employee,
 			self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
-
 		# get taxable_earnings, paid_taxes for previous period
 		previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date,
 			self.start_date, tax_slab.allow_tax_exemption)
@@ -875,16 +872,8 @@
 
 			if earning.is_tax_applicable:
 				if additional_amount:
-					if not earning.is_recurring_additional_salary:
-						taxable_earnings += (amount - additional_amount)
-						additional_income += additional_amount
-					else:
-						to_date = frappe.db.get_value("Additional Salary", earning.additional_salary, 'to_date')
-						period = (getdate(to_date).month - getdate(self.start_date).month) + 1
-						if period > 0:
-							taxable_earnings += (amount - additional_amount) * period
-							additional_income += additional_amount * period
-
+					taxable_earnings += (amount - additional_amount)
+					additional_income += additional_amount
 					if earning.deduct_full_tax_on_selected_payroll_date:
 						additional_income_with_full_tax += additional_amount
 					continue
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index cd85f6b..e65442d 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -316,10 +316,6 @@
 	))
 
 def get_return_doc_reference(invoice):
-	if not invoice.return_against:
-		frappe.throw(_('For generating IRN, reference to the original invoice is mandatory for a credit note. Please set {} field to generate e-invoice.')
-			.format(frappe.bold('Return Against')), title=_('Missing Field'))
-
 	invoice_date = frappe.db.get_value('Sales Invoice', invoice.return_against, 'posting_date')
 	return frappe._dict(dict(
 		invoice_name=invoice.return_against, invoice_date=format_date(invoice_date, 'dd/mm/yyyy')
@@ -435,7 +431,7 @@
 	if invoice.is_pos and invoice.base_paid_amount:
 		payment_details = get_payment_details(invoice)
 
-	if invoice.is_return:
+	if invoice.is_return and invoice.return_against:
 		prev_doc_details = get_return_doc_reference(invoice)
 
 	if invoice.transporter and not invoice.is_return:
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 04db9b3..ac195a6 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -851,4 +851,15 @@
 
 		depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
 
-	return depreciation_amount
\ No newline at end of file
+	return depreciation_amount
+
+def set_item_tax_from_hsn_code(item):
+	if not item.taxes and item.gst_hsn_code: 
+		hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
+
+		for tax in hsn_doc.taxes:
+			item.append('taxes', {
+				'item_tax_template': tax.item_tax_template,
+				'tax_category': tax.tax_category,
+				'valid_from': tax.valid_from
+			})
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
index 9313f95..23e5947 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -54,7 +54,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-05-08 23:13:48.049879",
+ "modified": "2021-08-04 20:15:59.071493",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Transaction Deletion Record",
@@ -70,6 +70,7 @@
    "report": 1,
    "role": "System Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   }
  ],
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index cbd272d..a85a022 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -269,11 +269,14 @@
 		batch2 = create_batch('_Test Batch Price Item', 300, 1)
 		batch3 = create_batch('_Test Batch Price Item', 400, 0)
 
+		company = "_Test Company with perpetual inventory"
+		currency = frappe.get_cached_value("Company",  company,  "default_currency")
+
 		args = frappe._dict({
 			"item_code": "_Test Batch Price Item",
-			"company": "_Test Company with perpetual inventory",
+			"company": company,
 			"price_list": "_Test Price List",
-			"currency": "_Test Currency",
+			"currency": currency,
 			"doctype": "Sales Invoice",
 			"conversion_rate": 1,
 			"price_list_currency": "_Test Currency",
@@ -333,4 +336,4 @@
 	except frappe.DuplicateEntryError:
 		batch = frappe.get_doc("Batch", args.batch_id)
 
-	return batch
\ No newline at end of file
+	return batch
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 264baea..3ca9873 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -138,20 +138,6 @@
 		frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
 	},
 
-	gst_hsn_code: function(frm) {
-		if((!frm.doc.taxes || !frm.doc.taxes.length) && frm.doc.gst_hsn_code) {
-			frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
-				$.each(hsn_doc.taxes || [], function(i, tax) {
-					let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
-					a.item_tax_template = tax.item_tax_template;
-					a.tax_category = tax.tax_category;
-					a.valid_from = tax.valid_from;
-					frm.refresh_field('taxes');
-				});
-			});
-		}
-	},
-
 	is_fixed_asset: function(frm) {
 		// set serial no to false & toggles its visibility
 		frm.set_value('has_serial_no', 0);
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index fbd30cf..9bf4dbf 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -123,6 +123,7 @@
 		self.cant_change()
 		self.update_show_in_website()
 		self.validate_item_tax_net_rate_range()
+		set_item_tax_from_hsn_code(self)
 
 		if not self.is_new():
 			self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
@@ -1305,3 +1306,7 @@
 def on_doctype_update():
 	# since route is a Text column, it needs a length for indexing
 	frappe.db.add_index("Item", ["route(500)"])
+
+@erpnext.allow_regional
+def set_item_tax_from_hsn_code(item):
+	pass
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/regional/india.js b/erpnext/stock/doctype/item/regional/india.js
new file mode 100644
index 0000000..77ae51f
--- /dev/null
+++ b/erpnext/stock/doctype/item/regional/india.js
@@ -0,0 +1,15 @@
+frappe.ui.form.on('Item', {
+	gst_hsn_code: function(frm) {
+		if ((!frm.doc.taxes || !frm.doc.taxes.length) && frm.doc.gst_hsn_code) {
+			frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
+				$.each(hsn_doc.taxes || [], function(i, tax) {
+					let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
+					a.item_tax_template = tax.item_tax_template;
+					a.tax_category = tax.tax_category;
+					a.valid_from = tax.valid_from;
+					frm.refresh_field('taxes');
+				});
+			});
+		}
+	},
+});
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index c7467a5..9ec44d2 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -83,14 +83,17 @@
 
 		make_test_objects("Item Price")
 
+		company = "_Test Company"
+		currency = frappe.get_cached_value("Company",  company,  "default_currency")
+
 		details = get_item_details({
 			"item_code": "_Test Item",
-			"company": "_Test Company",
+			"company": company,
 			"price_list": "_Test Price List",
-			"currency": "_Test Currency",
+			"currency": currency,
 			"doctype": "Sales Order",
 			"conversion_rate": 1,
-			"price_list_currency": "_Test Currency",
+			"price_list_currency": currency,
 			"plc_conversion_rate": 1,
 			"order_type": "Sales",
 			"customer": "_Test Customer",
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 2eb8bfd..ca6e61f 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -23,9 +23,7 @@
 
 	def test_reverse_purchase_receipt_sle(self):
 
-		frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 0)
-
-		pr = make_purchase_receipt(qty=0.5)
+		pr = make_purchase_receipt(qty=0.5, item_code="_Test Item Home Desktop 200")
 
 		sl_entry = frappe.db.get_all("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
 			"voucher_no": pr.name}, ['actual_qty'])
@@ -41,8 +39,6 @@
 		self.assertEqual(len(sl_entry_cancelled), 2)
 		self.assertEqual(sl_entry_cancelled[1].actual_qty, -0.5)
 
-		frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 1)
-
 	def test_make_purchase_invoice(self):
 		if not frappe.db.exists('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice'):
 			frappe.get_doc({