Merge pull request #24773 from UrvashiKishnani/patch-1

fix: GL Entries for AP/AR Summary
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 5e3822e..69d605d 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -18,7 +18,6 @@
 class LeaveAllocation(Document):
 	def validate(self):
 		self.validate_period()
-		self.validate_new_leaves_allocated_value()
 		self.validate_allocation_overlap()
 		self.validate_back_dated_allocation()
 		self.set_total_leaves_allocated()
@@ -72,11 +71,6 @@
 		if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
 			frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
 
-	def validate_new_leaves_allocated_value(self):
-		"""validate that leave allocation is in multiples of 0.5"""
-		if flt(self.new_leaves_allocated) % 0.5:
-			frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
-
 	def validate_allocation_overlap(self):
 		leave_allocation = frappe.db.sql("""
 			SELECT
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
index a0327bd..3373350 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
@@ -106,12 +106,14 @@
    "fieldname": "leaves_allocated",
    "fieldtype": "Check",
    "hidden": 1,
-   "label": "Leaves Allocated"
+   "label": "Leaves Allocated",
+   "no_copy": 1,
+   "print_hide": 1
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-12-31 16:43:30.695206",
+ "modified": "2021-03-01 17:54:01.014509",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Policy Assignment",
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
index a5068bc..4064c56 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -6,7 +6,7 @@
 import frappe
 from frappe.model.document import Document
 from frappe import _, bold
-from frappe.utils import getdate, date_diff, comma_and, formatdate
+from frappe.utils import getdate, date_diff, comma_and, formatdate, get_datetime, flt
 from math import ceil
 import json
 from six import string_types
@@ -84,17 +84,52 @@
 		return allocation.name, new_leaves_allocated
 
 	def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+		from frappe.model.meta import get_field_precision
+		precision = get_field_precision(frappe.get_meta("Leave Allocation").get_field("new_leaves_allocated"))
+
+		# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
+		if leave_type_details.get(leave_type).is_compensatory == 1:
+			new_leaves_allocated = 0
+
+		elif leave_type_details.get(leave_type).is_earned_leave == 1:
+			if self.assignment_based_on == "Leave Period":
+				new_leaves_allocated = self.get_leaves_for_passed_months(leave_type, new_leaves_allocated, leave_type_details, date_of_joining)
+			else:
+				new_leaves_allocated = 0
 		# Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
-		if getdate(date_of_joining) > getdate(self.effective_from):
+		elif getdate(date_of_joining) > getdate(self.effective_from):
 			remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1))
 			new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
 
-		# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
-		if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
-			new_leaves_allocated = 0
+		return flt(new_leaves_allocated, precision)
+
+	def get_leaves_for_passed_months(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+		from erpnext.hr.utils import get_monthly_earned_leave
+
+		current_month = get_datetime().month
+		current_year = get_datetime().year
+
+		from_date = frappe.db.get_value("Leave Period", self.leave_period, "from_date")
+		if getdate(date_of_joining) > getdate(from_date):
+			from_date = date_of_joining
+
+		from_date_month = get_datetime(from_date).month
+		from_date_year = get_datetime(from_date).year
+
+		months_passed = 0
+		if current_year == from_date_year and current_month > from_date_month:
+			months_passed = current_month - from_date_month
+		elif current_year > from_date_year:
+			months_passed = (12 - from_date_month) + current_month
+
+		if months_passed > 0:
+			monthly_earned_leave = get_monthly_earned_leave(new_leaves_allocated,
+				leave_type_details.get(leave_type).earned_leave_frequency, leave_type_details.get(leave_type).rounding)
+			new_leaves_allocated = monthly_earned_leave * months_passed
 
 		return new_leaves_allocated
 
+
 @frappe.whitelist()
 def grant_leave_for_multiple_employees(leave_policy_assignments):
 	leave_policy_assignments = json.loads(leave_policy_assignments)
@@ -156,7 +191,8 @@
 def get_leave_type_details():
 	leave_type_details = frappe._dict()
 	leave_types = frappe.get_all("Leave Type",
-		fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
+		fields=["name", "is_lwp", "is_earned_leave", "is_compensatory",
+			"is_carry_forward", "expire_carry_forwarded_leaves_after_days", "earned_leave_frequency", "rounding"])
 	for d in leave_types:
 		leave_type_details.setdefault(d.name, d)
 	return leave_type_details
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index a209291..fc577ef 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -172,7 +172,7 @@
    "fieldname": "rounding",
    "fieldtype": "Select",
    "label": "Rounding",
-   "options": "0.5\n1.0"
+   "options": "\n0.25\n0.5\n1.0"
   },
   {
    "depends_on": "is_carry_forward",
@@ -197,6 +197,7 @@
    "label": "Based On Date Of Joining"
   },
   {
+   "default": "0",
    "depends_on": "eval:doc.is_lwp == 0",
    "fieldname": "is_ppl",
    "fieldtype": "Check",
@@ -213,7 +214,7 @@
  "icon": "fa fa-flag",
  "idx": 1,
  "links": [],
- "modified": "2020-10-15 15:49:47.555105",
+ "modified": "2021-03-02 11:22:33.776320",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Type",
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index e2aa7a4..d57ef59 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -316,13 +316,7 @@
 				update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
 
 def update_previous_leave_allocation(allocation, annual_allocation, e_leave_type):
-	divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
-	if annual_allocation:
-		earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
-		if e_leave_type.rounding == "0.5":
-			earned_leaves = round(earned_leaves * 2) / 2
-		else:
-			earned_leaves = round(earned_leaves)
+		earned_leaves = get_monthly_earned_leave(annual_allocation, e_leave_type.earned_leave_frequency, e_leave_type.rounding)
 
 		allocation = frappe.get_doc('Leave Allocation', allocation.name)
 		new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
@@ -335,6 +329,21 @@
 			today_date = today()
 			create_additional_leave_ledger_entry(allocation, earned_leaves, today_date)
 
+def get_monthly_earned_leave(annual_leaves, frequency, rounding):
+	earned_leaves = 0.0
+	divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
+	if annual_leaves:
+		earned_leaves = flt(annual_leaves) / divide_by_frequency[frequency]
+		if rounding:
+			if rounding == "0.25":
+				earned_leaves = round(earned_leaves * 4) / 4
+			elif rounding == "0.5":
+				earned_leaves = round(earned_leaves * 2) / 2
+			else:
+				earned_leaves = round(earned_leaves)
+
+	return earned_leaves
+
 
 def get_leave_allocations(date, leave_type):
 	return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
index 3200363..d968e1f 100644
--- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -1,13 +1,24 @@
 import frappe
 from frappe import _
-from frappe.utils import getdate, get_time
+from frappe.utils import getdate, get_time, today
 from erpnext.stock.stock_ledger import update_entries_after
 from erpnext.accounts.utils import update_gl_entries_after
 
 def execute():
-	frappe.reload_doc('stock', 'doctype', 'repost_item_valuation')
+	for doctype in ('repost_item_valuation', 'stock_entry_detail', 'purchase_receipt_item',
+			'purchase_invoice_item', 'delivery_note_item', 'sales_invoice_item', 'packed_item'):
+		frappe.reload_doc('stock', 'doctype', doctype)
+	frappe.reload_doc('buying', 'doctype', 'purchase_receipt_item_supplied')
 
 	reposting_project_deployed_on = get_creation_time()
+	posting_date = getdate(reposting_project_deployed_on)
+	posting_time = get_time(reposting_project_deployed_on)
+
+	if posting_date == today():
+		return
+
+	frappe.clear_cache()
+	frappe.flags.warehouse_account_map = {}
 
 	data = frappe.db.sql('''
 		SELECT
@@ -41,8 +52,6 @@
 
 
 	print("Reposting General Ledger Entries...")
-	posting_date = getdate(reposting_project_deployed_on)
-	posting_time = get_time(reposting_project_deployed_on)
 
 	for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
 		update_gl_entries_after(posting_date, posting_time, company=row.name)
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 60aff02..1f8bfea 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -1123,6 +1123,7 @@
 	#calculate total working hours, earnings based on hourly wages and totals
 	def calculate_total_for_salary_slip_based_on_timesheet(self):
 		if self.timesheets:
+			self.total_working_hours = 0
 			for timesheet in self.timesheets:
 				if timesheet.working_hours:
 					self.total_working_hours += timesheet.working_hours
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.json b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
index bfeb96b..8dfe2d6 100644
--- a/erpnext/quality_management/doctype/non_conformance/non_conformance.json
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
@@ -70,18 +70,18 @@
   },
   {
    "fieldname": "corrective_action",
-   "fieldtype": "Text",
+   "fieldtype": "Text Editor",
    "label": "Corrective Action"
   },
   {
    "fieldname": "preventive_action",
-   "fieldtype": "Text",
+   "fieldtype": "Text Editor",
    "label": "Preventive Action"
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2020-10-26 15:27:47.247814",
+ "modified": "2021-02-26 15:27:47.247814",
  "modified_by": "Administrator",
  "module": "Quality Management",
  "name": "Non Conformance",
@@ -115,4 +115,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 36033d9..c041d26 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -140,7 +140,7 @@
 			doc: frm.doc,
 			freeze: true,
 			callback: function() {
-				frappe.msgprint(__("Default tax templates for sales and purchase are created."));
+				frappe.msgprint(__("Default tax templates for sales, purchase and items are created."));
 			}
 		})
 	},
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index e66fa76..c3c1593 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -29,6 +29,7 @@
 	try:
 		if accounts:
 			make_sales_and_purchase_tax_templates(accounts, template_name)
+			make_item_tax_templates(accounts, template_name)
 	except frappe.NameError:
 		if frappe.message_log: frappe.message_log.pop()
 	except RootNotEditable:
@@ -84,6 +85,27 @@
 	doc = frappe.get_doc(purchase_tax_template)
 	doc.insert(ignore_permissions=True)
 
+def make_item_tax_templates(accounts, template_name=None):
+	if not template_name:
+		template_name = accounts[0].name
+
+	item_tax_template = {
+		"doctype": "Item Tax Template",
+		"title": template_name,
+		"company": accounts[0].company,
+		'taxes': []
+	}
+
+
+	for account in accounts:
+		item_tax_template['taxes'].append({
+			"tax_type": account.name,
+			"tax_rate": account.tax_rate
+		})
+
+	# Items
+	frappe.get_doc(copy.deepcopy(item_tax_template)).insert(ignore_permissions=True)
+
 def get_tax_account_group(company):
 	tax_group = frappe.db.get_value("Account",
 		{"account_name": "Duties and Taxes", "is_group": 1, "company": company})
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index c8424f1..8fdda56 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -93,7 +93,7 @@
 
 			if create_new_batch:
 				if batch_number_series:
-					self.batch_id = make_autoname(batch_number_series)
+					self.batch_id = make_autoname(batch_number_series, doc=self)
 				elif batch_uses_naming_series():
 					self.batch_id = self.get_name_from_naming_series()
 				else:
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index d721014..70687bda 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -324,10 +324,12 @@
 						else:
 							loss_account = self.get_company_default("default_expense_account")
 
+						cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
+
 						gl_entries.append(self.get_gl_dict({
 							"account": loss_account,
 							"against": warehouse_account[d.warehouse]["account"],
-							"cost_center": d.cost_center,
+							"cost_center": cost_center,
 							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
 							"debit": divisional_loss,
 							"project": d.project