Merge pull request #26650 from deepeshgarg007/exchange_rate_reval_fixes_v13

fix: Exchange rate revaluation posting date and precision fixes
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 7c6b843..cc98f45 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -1,16 +1,25 @@
 name: Backport
 on:
-  pull_request:
+  pull_request_target:
     types:
       - closed
       - labeled
 
 jobs:
-  backport:
-    runs-on: ubuntu-18.04
-    name: Backport
+  main:
+    runs-on: ubuntu-latest
     steps:
-      - name: Backport
-        uses: tibdex/backport@v1
+      - name: Checkout Actions
+        uses: actions/checkout@v2
         with:
-          github_token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+          repository: "ankush/backport"
+          path: ./actions
+          ref: develop
+      - name: Install Actions
+        run: npm install --production --prefix ./actions
+      - name: Run backport
+        uses: ./actions/backport
+        with:
+          token: ${{secrets.BACKPORT_BOT_TOKEN}}
+          labelsToAdd: "backport"
+          title: "{{originalTitle}}"
diff --git a/CODEOWNERS b/CODEOWNERS
index 219b6bb..a4a14de 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -21,13 +21,13 @@
 erpnext/shopping_cart/          @marination
 erpnext/stock/                  @marination @rohitwaghchaure @ankush
 
-erpnext/crm/                    @ruchamahabal
-erpnext/education/              @ruchamahabal
-erpnext/healthcare/             @ruchamahabal
-erpnext/hr/                     @ruchamahabal
+erpnext/crm/                    @ruchamahabal @pateljannat
+erpnext/education/              @ruchamahabal @pateljannat
+erpnext/healthcare/             @ruchamahabal @pateljannat @chillaranand
+erpnext/hr/                     @ruchamahabal @pateljannat
 erpnext/non_profit/             @ruchamahabal
-erpnext/payroll                 @ruchamahabal
-erpnext/projects/               @ruchamahabal
+erpnext/payroll                 @ruchamahabal @pateljannat
+erpnext/projects/               @ruchamahabal @pateljannat
 
 erpnext/controllers             @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
 
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 6635128..d788d91 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -306,5 +306,5 @@
 				}
 			]
 		})
-
+		jv.flags.ignore_mandatory = True
 		jv.submit()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index ece627c..cbb3cc8 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -24,7 +24,6 @@
 
 	def on_cancel(self):
 		self.ignore_linked_doctypes = ('GL Entry')
-		self.set_status()
 
 	def set_status(self):
 		if self.docstatus == 0:
@@ -231,4 +230,4 @@
 		if mode_of_payment_type == "Bank":
 			voucher_type = "Bank Entry"
 
-	return voucher_type
\ No newline at end of file
+	return voucher_type
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 8f8dbb2..95e2806 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -36,8 +36,8 @@
 		if self.task and not self.project:
 			self.project = frappe.db.get_value("Task", self.task, "project")
 
-	def set_status(self):
-		self.status = {
+	def set_status(self, update=False):
+		status = {
 			"0": "Draft",
 			"1": "Submitted",
 			"2": "Cancelled"
@@ -45,14 +45,18 @@
 
 		paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount)
 		precision = self.precision("grand_total")
-		if (self.is_paid or (flt(self.total_sanctioned_amount) > 0
-			and flt(self.grand_total, precision) ==  flt(paid_amount, precision))) \
-			and self.docstatus == 1 and self.approval_status == 'Approved':
-				self.status = "Paid"
+		if (self.is_paid or (flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1
+			and flt(self.grand_total, precision) == flt(paid_amount, precision))) and self.approval_status == 'Approved':
+			status = "Paid"
 		elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
-			self.status = "Unpaid"
+			status = "Unpaid"
 		elif self.docstatus == 1 and self.approval_status == 'Rejected':
-			self.status = 'Rejected'
+			status = 'Rejected'
+
+		if update:
+			self.db_set("status", status)
+		else:
+			self.status = status
 
 	def on_update(self):
 		share_doc_with_approver(self, self.expense_approver)
@@ -75,7 +79,7 @@
 		if self.is_paid:
 			update_reimbursed_amount(self)
 
-		self.set_status()
+		self.set_status(update=True)
 		self.update_claimed_amount_in_employee_advance()
 
 	def on_cancel(self):
@@ -87,7 +91,6 @@
 		if self.is_paid:
 			update_reimbursed_amount(self)
 
-		self.set_status()
 		self.update_claimed_amount_in_employee_advance()
 
 	def update_claimed_amount_in_employee_advance(self):
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2a83635..b891719 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -293,3 +293,4 @@
 erpnext.patches.v13_0.update_level_in_bom #1234sswef
 erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
 erpnext.patches.v13_0.update_subscription_status_in_memberships
+erpnext.patches.v13_0.update_export_type_for_gst
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
new file mode 100644
index 0000000..478a2a6
--- /dev/null
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -0,0 +1,24 @@
+import frappe
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	# Update custom fields
+	fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
+	if fieldname:
+		frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+	fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
+	if fieldname:
+		frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+	# Update Customer/Supplier Masters
+	frappe.db.sql("""
+		UPDATE `tabCustomer` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas', 'Deemed Export')
+	""")
+
+	frappe.db.sql("""
+		UPDATE `tabSupplier` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas')
+	""")
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index dbf7514..e9e6f81 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -4,11 +4,18 @@
 frappe.ui.form.on('Salary Component', {
 	setup: function(frm) {
 		frm.set_query("account", "accounts", function(doc, cdt, cdn) {
-			var d = locals[cdt][cdn];
+			let d = frappe.get_doc(cdt, cdn);
+
+			let root_type = "Liability";
+			if (frm.doc.type == "Deduction") {
+				root_type = "Expense";
+			}
+
 			return {
 				filters: {
 					"is_group": 0,
-					"company": d.company
+					"company": d.company,
+					"root_type": root_type
 				}
 			};
 		});
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 52efbb5..53d5278 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -65,28 +65,23 @@
 		this.frm.refresh_fields();
 	},
 
-	calculate_discount_amount: function(){
+	calculate_discount_amount: function() {
 		if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
-			this.calculate_item_values();
-			this.calculate_net_total();
 			this.set_discount_amount();
 			this.apply_discount_amount();
 		}
 	},
 
 	_calculate_taxes_and_totals: function() {
-		frappe.run_serially([
-			() => this.validate_conversion_rate(),
-			() => this.calculate_item_values(),
-			() => this.update_item_tax_map(),
-			() => this.initialize_taxes(),
-			() => this.determine_exclusive_rate(),
-			() => this.calculate_net_total(),
-			() => this.calculate_taxes(),
-			() => this.manipulate_grand_total_for_inclusive_tax(),
-			() => this.calculate_totals(),
-			() => this._cleanup()
-		]);
+		this.validate_conversion_rate();
+		this.calculate_item_values();
+		this.initialize_taxes();
+		this.determine_exclusive_rate();
+		this.calculate_net_total();
+		this.calculate_taxes();
+		this.manipulate_grand_total_for_inclusive_tax();
+		this.calculate_totals();
+		this._cleanup();
 	},
 
 	validate_conversion_rate: function() {
@@ -107,7 +102,7 @@
 	},
 
 	calculate_item_values: function() {
-		var me = this;
+		let me = this;
 		if (!this.discount_amount_applied) {
 			$.each(this.frm.doc["items"] || [], function(i, item) {
 				frappe.model.round_floats_in(item);
@@ -268,46 +263,6 @@
 		frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
 	},
 
-	update_item_tax_map: function() {
-		let me = this;
-		let item_codes = [];
-		let item_rates = {};
-		let item_tax_templates = {};
-
-		$.each(this.frm.doc.items || [], function(i, item) {
-			if (item.item_code) {
-				// Use combination of name and item code in case same item is added multiple times
-				item_codes.push([item.item_code, item.name]);
-				item_rates[item.name] = item.net_rate;
-				item_tax_templates[item.name] = item.item_tax_template;
-			}
-		});
-
-		if (item_codes.length) {
-			return this.frm.call({
-				method: "erpnext.stock.get_item_details.get_item_tax_info",
-				args: {
-					company: me.frm.doc.company,
-					tax_category: cstr(me.frm.doc.tax_category),
-					item_codes: item_codes,
-					item_rates: item_rates,
-					item_tax_templates: item_tax_templates
-				},
-				callback: function(r) {
-					if (!r.exc) {
-						$.each(me.frm.doc.items || [], function(i, item) {
-							if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
-								item.item_tax_template = r.message[item.name].item_tax_template;
-								item.item_tax_rate = r.message[item.name].item_tax_rate;
-								me.add_taxes_from_item_tax_template(item.item_tax_rate);
-							}
-						});
-					}
-				}
-			});
-		}
-	},
-
 	add_taxes_from_item_tax_template: function(item_tax_map) {
 		let me = this;
 
@@ -632,8 +587,6 @@
 				tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
 			});
 		}
-
-		this.frm.refresh_fields();
 	},
 
 	set_discount_amount: function() {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index b3af3d6..5475383 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -826,9 +826,9 @@
 
 				frappe.run_serially([
 					() => me.frm.script_manager.trigger("currency"),
+					() => me.update_item_tax_map(),
 					() => me.apply_default_taxes(),
-					() => me.apply_pricing_rule(),
-					() => me.calculate_taxes_and_totals()
+					() => me.apply_pricing_rule()
 				]);
 			}
 		}
@@ -1787,6 +1787,46 @@
 		]);
 	},
 
+	update_item_tax_map: function() {
+		let me = this;
+		let item_codes = [];
+		let item_rates = {};
+		let item_tax_templates = {};
+
+		$.each(this.frm.doc.items || [], function(i, item) {
+			if (item.item_code) {
+				// Use combination of name and item code in case same item is added multiple times
+				item_codes.push([item.item_code, item.name]);
+				item_rates[item.name] = item.net_rate;
+				item_tax_templates[item.name] = item.item_tax_template;
+			}
+		});
+
+		if (item_codes.length) {
+			return this.frm.call({
+				method: "erpnext.stock.get_item_details.get_item_tax_info",
+				args: {
+					company: me.frm.doc.company,
+					tax_category: cstr(me.frm.doc.tax_category),
+					item_codes: item_codes,
+					item_rates: item_rates,
+					item_tax_templates: item_tax_templates
+				},
+				callback: function(r) {
+					if (!r.exc) {
+						$.each(me.frm.doc.items || [], function(i, item) {
+							if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
+								item.item_tax_template = r.message[item.name].item_tax_template;
+								item.item_tax_rate = r.message[item.name].item_tax_rate;
+								me.add_taxes_from_item_tax_template(item.item_tax_rate);
+							}
+						});
+					}
+				}
+			});
+		}
+	},
+
 	item_tax_template: function(doc, cdt, cdn) {
 		var me = this;
 		if(me.frm.updating_party_details) return;
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 6415204..0ee5b09 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -214,9 +214,8 @@
 
 			for d in item_details:
 				if d.item_code not in self.invoice_items.get(d.parent, {}):
-					self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
-						sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in item_details
-							if i.item_code == d.item_code and i.parent == d.parent))
+					self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0)
+					self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
 
 				if d.is_nil_exempt and d.item_code not in self.is_nil_exempt:
 					self.is_nil_exempt.append(d.item_code)
@@ -281,9 +280,15 @@
 		if self.get('invoice_items'):
 			# Build itemised tax for export invoices, nil and exempted where tax table is blank
 			for invoice, items in iteritems(self.invoice_items):
-				if invoice not in self.items_based_on_tax_rate and (self.invoice_detail_map.get(invoice, {}).get('export_type')
-					== "Without Payment of Tax"):
+				if invoice not in self.items_based_on_tax_rate and self.invoice_detail_map.get(invoice, {}).get('export_type') \
+					== "Without Payment of Tax" and self.invoice_detail_map.get(invoice, {}).get('gst_category') == "Overseas":
 					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
+				else:
+					for item in items.keys():
+						if item in self.is_nil_exempt + self.is_non_gst and \
+							item not in self.items_based_on_tax_rate.get(invoice, {}).get(0, []):
+								self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, [])
+								self.items_based_on_tax_rate[invoice][0].append(item)
 
 	def set_outward_taxable_supplies(self):
 		inter_state_supply_details = {}
@@ -322,6 +327,9 @@
 									inter_state_supply_details[(gst_category, place_of_supply)]['txval'] += taxable_value
 									inter_state_supply_details[(gst_category, place_of_supply)]['iamt'] += (taxable_value * rate /100)
 
+			if self.invoice_cess.get(inv):
+				self.report_dict['sup_details']['osup_det']['csamt'] += flt(self.invoice_cess.get(inv), 2)
+
 		self.set_inter_state_supply(inter_state_supply_details)
 
 	def set_supplies_liable_to_reverse_charge(self):
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 9265460..e9372f9 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -641,7 +641,6 @@
 				'label': 'Export Type',
 				'fieldtype': 'Select',
 				'insert_after': 'gst_category',
-				'default': 'Without Payment of Tax',
 				'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
 				'options': '\nWith Payment of Tax\nWithout Payment of Tax'
 			}
@@ -660,7 +659,6 @@
 				'label': 'Export Type',
 				'fieldtype': 'Select',
 				'insert_after': 'gst_category',
-				'default': 'Without Payment of Tax',
 				'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
 				'options': '\nWith Payment of Tax\nWithout Payment of Tax'
 			}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index cfcb8c3..4b73094 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -217,9 +217,8 @@
 
 		for d in items:
 			if d.item_code not in self.invoice_items.get(d.parent, {}):
-				self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
-					sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in items
-						if i.item_code == d.item_code and i.parent == d.parent))
+				self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0)
+				self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
 
 				item_tax_rate = {}
 
@@ -287,7 +286,8 @@
 		# Build itemised tax for export invoices where tax table is blank
 		for invoice, items in iteritems(self.invoice_items):
 			if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \
-				and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax":
+				and self.invoices.get(invoice, {}).get('export_type') == "Without Payment of Tax" \
+				and self.invoices.get(invoice, {}).get('gst_category') == "Overseas":
 					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
 
 	def get_columns(self):