Merge pull request #19946 from rohitwaghchaure/pricing_rule_not_working_for_product_discount

fix: pricing rule not working for product discount
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
index deedafd..33ae454 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
@@ -15,8 +15,8 @@
 		with open(frappe.uploaded_file, "rb") as upfile:
 			fcontent = upfile.read()
 	else:
-		from frappe.utils.file_manager import get_uploaded_content
-		fname, fcontent = get_uploaded_content()
+		fcontent = frappe.local.uploaded_file
+		fname = frappe.local.uploaded_filename
 
 	if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')):
 		from frappe.utils.csvutils import read_csv_content
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index bd5a149..87f6822 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -284,7 +284,7 @@
 			status = True
 
 		# if user has created item price against the transaction UOM
-		if rule.get("uom") == args.get("uom"):
+		if args and rule.get("uom") == args.get("uom"):
 			conversion_factor = 1.0
 
 		if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html
index 4081723..50947ec 100644
--- a/erpnext/accounts/report/financial_statements.html
+++ b/erpnext/accounts/report/financial_statements.html
@@ -1,5 +1,6 @@
 {%
 	var report_columns = report.get_columns_for_print();
+	report_columns = report_columns.filter(col => !col.hidden);
 
 	if (report_columns.length > 8) {
 		frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
@@ -15,34 +16,35 @@
 		height: 37px;
 	}
 </style>
-{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) %}
-{% if(letterhead) { %}
-<div style="margin-bottom: 7px;" class="text-center">
-	{%= frappe.boot.letter_heads[letterhead].header %}
-</div>
-{% } %}
+
 <h2 class="text-center">{%= __(report.report_name) %}</h2>
 <h3 class="text-center">{%= filters.company %}</h3>
+
 {% if 'cost_center' in filters %}
 	<h3 class="text-center">{%= filters.cost_center %}</h3>
 {% endif %}
+
 <h3 class="text-center">{%= filters.fiscal_year %}</h3>
-<h5 class="text-center">{%=  __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %} </h4>
+<h5 class="text-center">
+	{%=  __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
+</h5>
 {% if (filters.from_date) { %}
-	<h4 class="text-center">{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}</h3>
+	<h5 class="text-center">
+		{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}
+	</h5>
 {% } %}
 <hr>
 <table class="table table-bordered">
 	<thead>
 		<tr>
-			<th style="width: {%= 100 - (report_columns.length - 2) * 13 %}%"></th>
-			{% for(var i=2, l=report_columns.length; i<l; i++) { %}
+			<th style="width: {%= 100 - (report_columns.length - 1) * 13 %}%"></th>
+			{% for (let i=1, l=report_columns.length; i<l; i++) { %}
 				<th class="text-right">{%= report_columns[i].label %}</th>
 			{% } %}
 		</tr>
 	</thead>
 	<tbody>
-		{% for(var j=0, k=data.length-1; j<k; j++) { %}
+		{% for(let j=0, k=data.length-1; j<k; j++) { %}
 			{%
 				var row = data[j];
 				var row_class = data[j].parent_account ? "" : "financial-statements-important";
@@ -52,11 +54,11 @@
 				<td>
 					<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
 				</td>
-				{% for(var i=2, l=report_columns.length; i<l; i++) { %}
+				{% for(let i=1, l=report_columns.length; i<l; i++) { %}
 					<td class="text-right">
-						{% var fieldname = report_columns[i].fieldname; %}
+						{% const fieldname = report_columns[i].fieldname; %}
 						{% if (!is_null(row[fieldname])) { %}
-							{%= format_currency(row[fieldname], filters.presentation_currency) %}
+							{%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
 						{% } %}
 					</td>
 				{% } %}
@@ -64,4 +66,6 @@
 		{% } %}
 	</tbody>
 </table>
-<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
+<p class="text-right text-muted">
+	Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
+</p>
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 3c8de60..40d5682 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -264,8 +264,8 @@
 
 def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
 	total_row = {
-		"account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
-		"account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
+		"account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
+		"account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
 		"currency": company_currency
 	}
 
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 6b3f2c7..f6a7fa2 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -144,6 +144,10 @@
 			frm.set_df_property('purchase_invoice', 'read_only', 1);
 			frm.set_df_property('purchase_receipt', 'read_only', 1);
 		}
+		else if (frm.doc.is_existing_asset) {
+			frm.toggle_reqd('purchase_receipt', 0);
+			frm.toggle_reqd('purchase_invoice', 0);
+		}
 		else if (frm.doc.purchase_receipt) {
 			// if purchase receipt link is set then set PI disabled
 			frm.toggle_reqd('purchase_invoice', 0);
@@ -256,6 +260,7 @@
 	},
 
 	is_existing_asset: function(frm) {
+		frm.trigger("toggle_reference_doc");
 		// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
 	},
 
diff --git a/erpnext/patches/v12_0/set_gst_category.py b/erpnext/patches/v12_0/set_gst_category.py
index 54bc5b3..55bbdee 100644
--- a/erpnext/patches/v12_0/set_gst_category.py
+++ b/erpnext/patches/v12_0/set_gst_category.py
@@ -7,6 +7,8 @@
 	if not company:
 		return
 
+	frappe.reload_doc('accounts', 'doctype', 'Tax Category')
+
 	make_custom_fields()
 
 	for doctype in ['Sales Invoice', 'Purchase Invoice']:
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 77bcc80..0f9156a 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -179,6 +179,8 @@
 
 	if not party_details.place_of_supply: return
 
+	if not party_details.company_gstin: return
+
 	if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
 		and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
 		"Purchase Order", "Purchase Receipt") and party_details.supplier_gstin and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2])):
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 2eee919..ff35154 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -14,6 +14,7 @@
 from frappe.contacts.address_and_contact import load_address_and_contact
 from frappe.utils.nestedset import NestedSet
 
+from past.builtins import cmp
 import functools
 
 class Company(NestedSet):
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 8e34a8a..060175f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -245,7 +245,7 @@
 					negative_expense_to_be_booked += flt(d.item_tax_amount)
 
 					# Amount added through landed-cost-voucher
-					if landed_cost_entries:
+					if d.landed_cost_voucher_amount and landed_cost_entries:
 						for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
 							gl_entries.append(self.get_gl_dict({
 								"account": account,
@@ -622,8 +622,7 @@
 	based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
 
 	for item in landed_cost_voucher_doc.items:
-		if item.receipt_document == purchase_document:
-			total_item_cost += item.get(based_on_field)
+		total_item_cost += item.get(based_on_field)
 
 	for item in landed_cost_voucher_doc.items:
 		if item.receipt_document == purchase_document:
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 4770471..79ce231 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -622,7 +622,7 @@
 					if(r.message) {
 						var d = locals[cdt][cdn];
 						$.each(r.message, function(k, v) {
-							d[k] = v;
+							frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered
 						});
 						refresh_field("items");
 						erpnext.stock.select_batch_and_serial_no(frm, d);
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index f81fa68..00d27ef 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -649,6 +649,12 @@
 		gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
 
 		total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+		divide_based_on = total_basic_amount
+
+		if self.get("additional_costs") and not total_basic_amount:
+			# if total_basic_amount is 0, distribute additional charges based on qty
+			divide_based_on = sum(item.qty for item in list(self.get("items")))
+
 		item_account_wise_additional_cost = {}
 
 		for t in self.get("additional_costs"):
@@ -656,8 +662,11 @@
 				if d.t_warehouse:
 					item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
 					item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
+
+					multiply_based_on = d.basic_amount if total_basic_amount else d.qty
+
 					item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
-						(t.amount * d.basic_amount) / total_basic_amount
+						(t.amount * multiply_based_on) / divide_based_on
 
 		if item_account_wise_additional_cost:
 			for d in self.get("items"):
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index eddab5d..ee5f237 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -790,6 +790,50 @@
 			filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening")
 		self.assertEqual(is_opening, "Yes")
 
+	def test_total_basic_amount_zero(self):
+		se = frappe.get_doc({"doctype":"Stock Entry",
+		"purpose":"Material Receipt",
+		"stock_entry_type":"Material Receipt",
+		"posting_date": nowdate(),
+		"company":"_Test Company with perpetual inventory",
+		"items":[
+			{
+				"item_code":"Basil Leaves",
+				"description":"Basil Leaves",
+				"qty": 1,
+				"basic_rate": 0,
+				"uom":"Nos",
+				"t_warehouse": "Stores - TCP1",
+				"allow_zero_valuation_rate": 1,
+				"cost_center": "Main - TCP1"
+			 },
+			 {
+				"item_code":"Basil Leaves",
+				"description":"Basil Leaves",
+				"qty": 2,
+				"basic_rate": 0,
+				"uom":"Nos",
+				"t_warehouse": "Stores - TCP1",
+				"allow_zero_valuation_rate": 1,
+				"cost_center": "Main - TCP1"
+			 },
+			 ],
+		"additional_costs":[
+			{"expense_account":"Miscellaneous Expenses - TCP1",
+			"amount":100,
+			"description": "miscellanous"}
+			]
+		})
+		se.insert()
+		se.submit()
+
+		self.check_gl_entries("Stock Entry", se.name,
+			sorted([
+				["Stock Adjustment - TCP1", 100.0, 0.0],
+				["Miscellaneous Expenses - TCP1", 0.0, 100.0]
+			])
+		)
+
 def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
 	se = frappe.copy_doc(test_records[0])
 	se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"