Merge pull request #30110 from nextchamp-saqib/fix-customer-credit-limit-update

fix: customer credit limit validation on update
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index d554d52..3fe6b2d 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -68,6 +68,28 @@
 });
 
 frappe.ui.form.on('Asset Repair Consumed Item', {
+	item_code: function(frm, cdt, cdn) {
+		var item = locals[cdt][cdn];
+
+		let item_args = {
+			'item_code': item.item_code,
+			'warehouse': frm.doc.warehouse,
+			'qty': item.consumed_quantity,
+			'serial_no': item.serial_no,
+			'company': frm.doc.company
+		};
+
+		frappe.call({
+			method: 'erpnext.stock.utils.get_incoming_rate',
+			args: {
+				args: item_args
+			},
+			callback: function(r) {
+				frappe.model.set_value(cdt, cdn, 'valuation_rate', r.message);
+			}
+		});
+	},
+
 	consumed_quantity: function(frm, cdt, cdn) {
 		var row = locals[cdt][cdn];
 		frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
diff --git a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
index f63add1..4685a09 100644
--- a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
+++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
@@ -13,12 +13,10 @@
  ],
  "fields": [
   {
-   "fetch_from": "item.valuation_rate",
    "fieldname": "valuation_rate",
    "fieldtype": "Currency",
    "in_list_view": 1,
-   "label": "Valuation Rate",
-   "read_only": 1
+   "label": "Valuation Rate"
   },
   {
    "fieldname": "consumed_quantity",
@@ -49,7 +47,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-11-11 18:23:00.492483",
+ "modified": "2022-02-08 17:37:20.028290",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset Repair Consumed Item",
diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py
index 118cc98..c74967d 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.py
+++ b/erpnext/hr/doctype/attendance/test_attendance.py
@@ -1,10 +1,9 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
 # See license.txt
 
-import unittest
-
 import frappe
-from frappe.utils import add_days, get_first_day, getdate, nowdate
+from frappe.tests.utils import FrappeTestCase
+from frappe.utils import add_days, get_first_day, getdate, now_datetime, nowdate
 
 from erpnext.hr.doctype.attendance.attendance import (
 	get_month_map,
@@ -16,7 +15,7 @@
 
 test_records = frappe.get_test_records('Attendance')
 
-class TestAttendance(unittest.TestCase):
+class TestAttendance(FrappeTestCase):
 	def test_mark_absent(self):
 		employee = make_employee("test_mark_absent@example.com")
 		date = nowdate()
@@ -74,12 +73,14 @@
 		self.assertNotIn(first_sunday, unmarked_days)
 
 	def test_unmarked_days_as_per_joining_and_relieving_dates(self):
-		first_day = get_first_day(getdate())
+		now = now_datetime()
+		previous_month = now.month - 1
+		first_day = now.replace(day=1).replace(month=previous_month).date()
 
 		doj = add_days(first_day, 1)
 		relieving_date = add_days(first_day, 5)
 		employee = make_employee('test_unmarked_days_as_per_doj@example.com', date_of_joining=doj,
-			date_of_relieving=relieving_date)
+			relieving_date=relieving_date)
 		frappe.db.delete('Attendance', {'employee': employee})
 
 		attendance_date = add_days(first_day, 2)
@@ -104,4 +105,4 @@
 	month_number = date.month
 	for month, number in get_month_map().items():
 		if number == month_number:
-			return month
\ No newline at end of file
+			return month
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 70250f5..ef5f4bc 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -4,6 +4,7 @@
 
 import frappe
 from frappe import _
+from frappe.query_builder.functions import Max, Min, Sum
 from frappe.utils import (
 	add_days,
 	cint,
@@ -567,28 +568,39 @@
 	return get_remaining_leaves(allocation, leaves_taken, date, expiry)
 
 def get_leave_allocation_records(employee, date, leave_type=None):
-	''' returns the total allocated leaves and carry forwarded leaves based on ledger entries '''
+	"""Returns the total allocated leaves and carry forwarded leaves based on ledger entries"""
+	Ledger = frappe.qb.DocType("Leave Ledger Entry")
 
-	conditions = ("and leave_type='%s'" % leave_type) if leave_type else ""
-	allocation_details = frappe.db.sql("""
-		SELECT
-			SUM(CASE WHEN is_carry_forward = 1 THEN leaves ELSE 0 END) as cf_leaves,
-			SUM(CASE WHEN is_carry_forward = 0 THEN leaves ELSE 0 END) as new_leaves,
-			MIN(from_date) as from_date,
-			MAX(to_date) as to_date,
-			leave_type
-		FROM `tabLeave Ledger Entry`
-		WHERE
-			from_date <= %(date)s
-			AND to_date >= %(date)s
-			AND docstatus=1
-			AND transaction_type="Leave Allocation"
-			AND employee=%(employee)s
-			AND is_expired=0
-			AND is_lwp=0
-			{0}
-		GROUP BY employee, leave_type
-	""".format(conditions), dict(date=date, employee=employee), as_dict=1) #nosec
+	cf_leave_case = frappe.qb.terms.Case().when(Ledger.is_carry_forward == "1", Ledger.leaves).else_(0)
+	sum_cf_leaves = Sum(cf_leave_case).as_("cf_leaves")
+
+	new_leaves_case = frappe.qb.terms.Case().when(Ledger.is_carry_forward == "0", Ledger.leaves).else_(0)
+	sum_new_leaves = Sum(new_leaves_case).as_("new_leaves")
+
+	query = (
+		frappe.qb.from_(Ledger)
+		.select(
+			sum_cf_leaves,
+			sum_new_leaves,
+			Min(Ledger.from_date).as_("from_date"),
+			Max(Ledger.to_date).as_("to_date"),
+			Ledger.leave_type
+		).where(
+			(Ledger.from_date <= date)
+			& (Ledger.to_date >= date)
+			& (Ledger.docstatus == 1)
+			& (Ledger.transaction_type == "Leave Allocation")
+			& (Ledger.employee == employee)
+			& (Ledger.is_expired == 0)
+			& (Ledger.is_lwp == 0)
+		)
+	)
+
+	if leave_type:
+		query = query.where((Ledger.leave_type == leave_type))
+	query = query.groupby(Ledger.employee, Ledger.leave_type)
+
+	allocation_details = query.run(as_dict=True)
 
 	allocated_leaves = frappe._dict()
 	for d in allocation_details:
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 6d27f4a..7b3aa49 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -792,4 +792,4 @@
 		order by holiday_date
 	""", (holiday_list, month_start_date, month_end_date))[0][0]
 
-	return first_sunday
\ No newline at end of file
+	return first_sunday
diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py
index 1eb3d0d..3ca28c1 100644
--- a/erpnext/projects/report/project_profitability/test_project_profitability.py
+++ b/erpnext/projects/report/project_profitability/test_project_profitability.py
@@ -1,6 +1,5 @@
-import unittest
-
 import frappe
+from frappe.tests.utils import FrappeTestCase
 from frappe.utils import add_days, getdate
 
 from erpnext.hr.doctype.employee.test_employee import make_employee
@@ -12,7 +11,7 @@
 from erpnext.projects.report.project_profitability.project_profitability import execute
 
 
-class TestProjectProfitability(unittest.TestCase):
+class TestProjectProfitability(FrappeTestCase):
 	def setUp(self):
 		frappe.db.sql('delete from `tabTimesheet`')
 		emp = make_employee('test_employee_9@salary.com', company='_Test Company')
@@ -67,6 +66,3 @@
 
 		fractional_cost = self.salary_slip.base_gross_pay * utilization
 		self.assertEqual(fractional_cost, row.fractional_cost)
-
-	def tearDown(self):
-		frappe.db.rollback()
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
index 4a245e1..56e1eb5 100644
--- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
@@ -156,24 +156,24 @@
 		customer_record = customer_details.get(record.customer)
 		item_record = item_details.get(record.item_code)
 		row = {
-			"item_code": record.item_code,
-			"item_name": item_record.item_name,
-			"item_group": item_record.item_group,
-			"description": record.description,
-			"quantity": record.qty,
-			"uom": record.uom,
-			"rate": record.base_rate,
-			"amount": record.base_amount,
-			"sales_order": record.name,
-			"transaction_date": record.transaction_date,
-			"customer": record.customer,
-			"customer_name": customer_record.customer_name,
-			"customer_group": customer_record.customer_group,
-			"territory": record.territory,
-			"project": record.project,
-			"delivered_quantity": flt(record.delivered_qty),
-			"billed_amount": flt(record.billed_amt),
-			"company": record.company
+			"item_code": record.get('item_code'),
+			"item_name": item_record.get('item_name'),
+			"item_group": item_record.get('item_group'),
+			"description": record.get('description'),
+			"quantity": record.get('qty'),
+			"uom": record.get('uom'),
+			"rate": record.get('base_rate'),
+			"amount": record.get('base_amount'),
+			"sales_order": record.get('name'),
+			"transaction_date": record.get('transaction_date'),
+			"customer": record.get('customer'),
+			"customer_name": customer_record.get('customer_name'),
+			"customer_group": customer_record.get('customer_group'),
+			"territory": record.get('territory'),
+			"project": record.get('project'),
+			"delivered_quantity": flt(record.get('delivered_qty')),
+			"billed_amount": flt(record.get('billed_amt')),
+			"company": record.get('company')
 		}
 		data.append(row)
 
diff --git a/erpnext/setup/doctype/item_group/item_group.js b/erpnext/setup/doctype/item_group/item_group.js
index 885d874..f570c2f 100644
--- a/erpnext/setup/doctype/item_group/item_group.js
+++ b/erpnext/setup/doctype/item_group/item_group.js
@@ -14,6 +14,16 @@
 				]
 			}
 		}
+		frm.fields_dict['item_group_defaults'].grid.get_field("default_discount_account").get_query = function(doc, cdt, cdn) {
+			const row = locals[cdt][cdn];
+			return {
+				filters: {
+					'report_type': 'Profit and Loss',
+					'company': row.company,
+					"is_group": 0
+				}
+			};
+		}
 		frm.fields_dict["item_group_defaults"].grid.get_field("expense_account").get_query = function(doc, cdt, cdn) {
 			const row = locals[cdt][cdn];
 			return {
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 5484a11..b2eaecb 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -272,9 +272,9 @@
 			and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
 			{warehouse_condition}
 		GROUP BY
-			`warehouse`,
-			`batch_no`,
-			`item_code`
+			sle.`warehouse`,
+			sle.`batch_no`,
+			sle.`item_code`
 		HAVING `qty` > 0
 		ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
 	""".format(warehouse_condition=warehouse_condition), { #nosec