Reposting logic fixes (#24520)

* fix: Dependant sle logic fixes

* fix: negative qty validation

* fix: Travis fixes

* fix: test fix
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index e562d6c..06a8e19 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -544,7 +544,7 @@
 		expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
 		for row in ste3.items:
 			self.assertEquals(row.qty, expected_qty.get(row.item_code))
-
+		ste_cancel_list.reverse()
 		for ste_doc in ste_cancel_list:
 			ste_doc.cancel()
 
@@ -586,7 +586,7 @@
 		for ste_row in ste2.items:
 			if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
 				self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
-
+		ste_cancel_list.reverse()
 		for ste_doc in ste_cancel_list:
 			ste_doc.cancel()
 
diff --git a/erpnext/regional/united_states/test_united_states.py b/erpnext/regional/united_states/test_united_states.py
index ad95010..513570e 100644
--- a/erpnext/regional/united_states/test_united_states.py
+++ b/erpnext/regional/united_states/test_united_states.py
@@ -26,7 +26,6 @@
         make_payment_entry_to_irs_1099_supplier()
         filters = frappe._dict({"fiscal_year": "_Test Fiscal Year 2016", "company": "_Test Company 1"})
         columns, data = execute_1099_report(filters)
-        print(columns, data)
         expected_row = {'supplier': '_US 1099 Test Supplier',
                         'supplier_group': 'Services',
                         'payments': 100.0,
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index ab19b77..1088b41 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -17,7 +17,7 @@
 		'''Called from erpnext.stock.utils.update_bin'''
 		self.update_qty(args)
 		if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
-			from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
+			from erpnext.stock.stock_ledger import update_entries_after, validate_negative_qty_in_future_sle
 
 			if not args.get("posting_date"):
 				args["posting_date"] = nowdate()
@@ -37,8 +37,8 @@
 				"sle_id": args.name
 			}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
 
-			# Update qty_after_transaction in future SLEs of this item and warehouse
-			update_qty_in_future_sle(args)
+			# Validate negative qty in future transactions
+			validate_negative_qty_in_future_sle(args)
 
 	def update_qty(self, args):
 		# update the stock values (for current quantities)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 37e0c7f..ca58ab2 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -580,9 +580,6 @@
 		dn.cancel()
 		pr1.cancel()
 
-		dn.cancel()
-		pr1.cancel()
-
 	def test_auto_asset_creation(self):
 		asset_item = "Test Asset Item"
 
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
index e429cd5..b3e4286 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -31,7 +31,7 @@
 		}
 	},
 	refresh: function(frm) {
-		if (frm.doc.status == "Failed") {
+		if (frm.doc.status == "Failed" && frm.doc.docstatus==1) {
 			frm.add_custom_button(__('Restart'), function () {
 				frm.trigger("restart_reposting");
 			}).addClass("btn-primary");
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 2b2a7a2..46919c8 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -62,7 +62,7 @@
 	sle.submit()
 	return sle
 
-def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=False, via_landed_cost_voucher=False):
+def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False):
 	if not args and voucher_type and voucher_no:
 		args = get_args_for_voucher(voucher_type, voucher_no)
 
@@ -181,7 +181,7 @@
 				self.process_sle(sle)
 
 				if sle.dependant_sle_voucher_detail_no:
-					self.get_dependent_entries_to_fix(entries_to_fix, sle)
+					entries_to_fix = self.get_dependent_entries_to_fix(entries_to_fix, sle)
 
 		if self.exceptions:
 			self.raise_exceptions()
@@ -221,13 +221,15 @@
 			excluded_sle=sle.name)
 
 		if not dependant_sle:
-			return
+			return entries_to_fix
 		elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
-			return
-		elif dependant_sle.item_code != self.item_code \
-				and (dependant_sle.item_code, dependant_sle.warehouse) not in self.new_items:
-			self.new_items[(dependant_sle.item_code, dependant_sle.warehouse)] = dependant_sle
-			return
+			return entries_to_fix
+		elif dependant_sle.item_code != self.item_code:
+			if (dependant_sle.item_code, dependant_sle.warehouse) not in self.new_items:
+				self.new_items[(dependant_sle.item_code, dependant_sle.warehouse)] = dependant_sle
+			return entries_to_fix
+		elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse in self.data:
+			return entries_to_fix
 
 		self.initialize_previous_data(dependant_sle)
 
@@ -236,7 +238,7 @@
 		future_sle_for_dependant = list(self.get_sle_after_datetime(args))
 
 		entries_to_fix.extend(future_sle_for_dependant)
-		entries_to_fix = sorted(entries_to_fix, key=lambda k: k['timestamp'])
+		return sorted(entries_to_fix, key=lambda k: k['timestamp'])
 
 	def process_sle(self, sle):
 		# previous sle data for this warehouse
@@ -612,11 +614,11 @@
 				frappe.local.flags.currently_saving):
 
 				msg = _("{0} units of {1} needed in {2} to complete this transaction.").format(
-					abs(deficiency), frappe.get_desk_link('Item', self.item_code),
+					abs(deficiency), frappe.get_desk_link('Item', exceptions[0]["item_code"]),
 					frappe.get_desk_link('Warehouse', warehouse))
 			else:
 				msg = _("{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.").format(
-					abs(deficiency), frappe.get_desk_link('Item', self.item_code),
+					abs(deficiency), frappe.get_desk_link('Item', exceptions[0]["item_code"]),
 					frappe.get_desk_link('Warehouse', warehouse),
 					exceptions[0]["posting_date"], exceptions[0]["posting_time"],
 					frappe.get_desk_link(exceptions[0]["voucher_type"], exceptions[0]["voucher_no"]))
@@ -761,25 +763,6 @@
 
 	return valuation_rate
 
-def update_qty_in_future_sle(args, allow_negative_stock=None):
-	frappe.db.sql("""
-		update `tabStock Ledger Entry`
-		set qty_after_transaction = qty_after_transaction + {qty}
-		where
-			item_code = %(item_code)s
-			and warehouse = %(warehouse)s
-			and voucher_no != %(voucher_no)s
-			and is_cancelled = 0
-			and (timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s)
-				or (
-					timestamp(posting_date, posting_time) = timestamp(%(posting_date)s, %(posting_time)s)
-					and creation > %(creation)s
-				)
-			)
-	""".format(qty=args.actual_qty), args)
-
-	validate_negative_qty_in_future_sle(args, allow_negative_stock)
-
 def validate_negative_qty_in_future_sle(args, allow_negative_stock=None):
 	allow_negative_stock = allow_negative_stock \
 		or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
@@ -808,6 +791,7 @@
 			and voucher_no != %(voucher_no)s
 			and timestamp(posting_date, posting_time) >= timestamp(%(posting_date)s, %(posting_time)s)
 			and is_cancelled = 0
-			and qty_after_transaction < 0
+			and qty_after_transaction + {0} < 0
+		order by timestamp(posting_date, posting_time) asc
 		limit 1
-	""", args, as_dict=1)
\ No newline at end of file
+	""".format(args.actual_qty), args, as_dict=1)
\ No newline at end of file
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.py b/erpnext/support/report/issue_analytics/issue_analytics.py
index 0b62915..3fdb10d 100644
--- a/erpnext/support/report/issue_analytics/issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/issue_analytics.py
@@ -147,8 +147,7 @@
 
 		self.entries = frappe.db.get_all('Issue',
 			fields=[self.field_map.get(self.filters.based_on), 'name', 'opening_date'],
-			filters=filters,
-			debug=1
+			filters=filters
 		)
 
 	def get_common_filters(self):
diff --git a/erpnext/support/report/issue_analytics/test_issue_analytics.py b/erpnext/support/report/issue_analytics/test_issue_analytics.py
index 432906d..fc6bb58 100644
--- a/erpnext/support/report/issue_analytics/test_issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/test_issue_analytics.py
@@ -17,8 +17,11 @@
 
 		current_month_date = getdate()
 		last_month_date = add_months(current_month_date, -1)
-		self.current_month = str(months[current_month_date.month - 1]).lower() + '_' + str(current_month_date.year)
-		self.last_month = str(months[last_month_date.month - 1]).lower() + '_' + str(last_month_date.year)
+		self.current_month = str(months[current_month_date.month - 1]).lower()
+		self.last_month = str(months[last_month_date.month - 1]).lower()
+		if current_month_date.year != last_month_date.year:
+			self.current_month += '_' + str(current_month_date.year)
+			self.last_month += '_' + str(last_month_date.year)
 
 	def test_issue_analytics(self):
 		create_service_level_agreements_for_issues()