Merge pull request #26960 from deepeshgarg007/distributed_budget_variance_report
fix: Budget variance missing values
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index fc577ef..8f2ae6e 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -214,7 +214,7 @@
"icon": "fa fa-flag",
"idx": 1,
"links": [],
- "modified": "2021-03-02 11:22:33.776320",
+ "modified": "2021-08-12 16:10:36.464690",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
@@ -248,5 +248,6 @@
}
],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py
index 313f90e..9b32136 100644
--- a/erpnext/hr/doctype/training_event/test_training_event.py
+++ b/erpnext/hr/doctype/training_event/test_training_event.py
@@ -11,21 +11,34 @@
class TestTrainingEvent(unittest.TestCase):
def setUp(self):
create_training_program("Basic Training")
- self.employee = make_employee("robert_loan@trainig.com")
- self.employee2 = make_employee("suzie.tan@trainig.com")
+ employee = make_employee("robert_loan@trainig.com")
+ employee2 = make_employee("suzie.tan@trainig.com")
+ self.attendees = [
+ {"employee": employee},
+ {"employee": employee2}
+ ]
- def test_create_training_event(self):
- if not frappe.db.get_value("Training Event", "Basic Training Event"):
- frappe.get_doc({
- "doctype": "Training Event",
- "event_name": "Basic Training Event",
- "training_program": "Basic Training",
- "location": "Union Square",
- "start_time": add_days(today(), 5),
- "end_time": add_days(today(), 6),
- "introduction": "Welcome to the Basic Training Event",
- "employees": get_attendees(self.employee, self.employee2)
- }).insert()
+ def test_training_event_status_update(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ for entry in training_event.employees:
+ self.assertEqual(entry.status, "Completed")
+
+ training_event.event_status = "Scheduled"
+ training_event.save()
+ training_event.reload()
+
+ for entry in training_event.employees:
+ self.assertEqual(entry.status, "Open")
+
+ def tearDown(self):
+ frappe.db.rollback()
+
def create_training_program(training_program):
if not frappe.db.get_value("Training Program", training_program):
@@ -35,8 +48,14 @@
"description": training_program
}).insert()
-def get_attendees(employee, employee2):
- return [
- {"employee": employee},
- {"employee": employee2}
- ]
\ No newline at end of file
+def create_training_event(attendees):
+ return frappe.get_doc({
+ "doctype": "Training Event",
+ "event_name": "Basic Training Event",
+ "training_program": "Basic Training",
+ "location": "Union Square",
+ "start_time": add_days(today(), 5),
+ "end_time": add_days(today(), 6),
+ "introduction": "Welcome to the Basic Training Event",
+ "employees": attendees
+ }).insert()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py
index 5064f03..e2c30cb 100644
--- a/erpnext/hr/doctype/training_event/training_event.py
+++ b/erpnext/hr/doctype/training_event/training_event.py
@@ -14,10 +14,25 @@
self.set_employee_emails()
self.validate_period()
+ def on_update_after_submit(self):
+ self.set_status_for_attendees()
+
def set_employee_emails(self):
self.employee_emails = ', '.join(get_employee_emails([d.employee
for d in self.employees]))
def validate_period(self):
if time_diff_in_seconds(self.end_time, self.start_time) <= 0:
- frappe.throw(_('End time cannot be before start time'))
\ No newline at end of file
+ frappe.throw(_('End time cannot be before start time'))
+
+ def set_status_for_attendees(self):
+ if self.event_status == 'Completed':
+ for employee in self.employees:
+ if employee.attendance == 'Present' and employee.status != 'Feedback Submitted':
+ employee.status = 'Completed'
+
+ elif self.event_status == 'Scheduled':
+ for employee in self.employees:
+ employee.status = 'Open'
+
+ self.db_update_all()
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
index 3455998..c30a3ad 100644
--- a/erpnext/hr/doctype/training_feedback/test_training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
@@ -5,8 +5,63 @@
import frappe
import unittest
-
-# test_records = frappe.get_test_records('Training Feedback')
-
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
+from erpnext.hr.doctype.training_event.test_training_event import create_training_program, create_training_event
class TestTrainingFeedback(unittest.TestCase):
- pass
+ def setUp(self):
+ create_training_program("Basic Training")
+ self.employee = make_employee("robert_loan@trainig.com")
+ self.employee2 = make_employee("suzie.tan@trainig.com")
+ self.attendees = [{"employee": self.employee}]
+
+ def test_employee_validations_for_feedback(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ # should not allow creating feedback since employee2 was not part of the event
+ feedback = create_training_feedback(training_event.name, self.employee2)
+ self.assertRaises(frappe.ValidationError, feedback.save)
+
+ # cannot record feedback for absent employee
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": training_event.name,
+ "employee": self.employee
+ }, "name")
+
+ frappe.db.set_value("Training Event Employee", employee, "attendance", "Absent")
+ feedback = create_training_feedback(training_event.name, self.employee)
+ self.assertRaises(frappe.ValidationError, feedback.save)
+
+ def test_training_feedback_status(self):
+ training_event = create_training_event(self.attendees)
+ training_event.submit()
+
+ training_event.event_status = "Completed"
+ training_event.save()
+ training_event.reload()
+
+ feedback = create_training_feedback(training_event.name, self.employee)
+ feedback.submit()
+
+ status = frappe.db.get_value("Training Event Employee", {
+ "parent": training_event.name,
+ "employee": self.employee
+ }, "status")
+
+ self.assertEqual(status, "Feedback Submitted")
+
+ def tearDown(self):
+ frappe.db.rollback()
+
+
+def create_training_feedback(event, employee):
+ return frappe.get_doc({
+ "doctype": "Training Feedback",
+ "training_event": event,
+ "employee": employee,
+ "feedback": "Test"
+ })
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
index 1a33450..0d32de7 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -11,15 +11,35 @@
def validate(self):
training_event = frappe.get_doc("Training Event", self.training_event)
if training_event.docstatus != 1:
- frappe.throw(_('{0} must be submitted').format(_('Training Event')))
+ frappe.throw(_("{0} must be submitted").format(_("Training Event")))
+
+ emp_event_details = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ }, ["name", "attendance"], as_dict=True)
+
+ if not emp_event_details:
+ frappe.throw(_("Employee {0} not found in Training Event Participants.").format(
+ frappe.bold(self.employee_name)))
+
+ if emp_event_details.attendance == "Absent":
+ frappe.throw(_("Feedback cannot be recorded for an absent Employee."))
def on_submit(self):
- training_event = frappe.get_doc("Training Event", self.training_event)
- event_status = None
- for e in training_event.employees:
- if e.employee == self.employee:
- event_status = 'Feedback Submitted'
- break
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ })
- if event_status:
- frappe.db.set_value("Training Event", self.training_event, "event_status", event_status)
+ if employee:
+ frappe.db.set_value("Training Event Employee", employee, "status", "Feedback Submitted")
+
+ def on_cancel(self):
+ employee = frappe.db.get_value("Training Event Employee", {
+ "parent": self.training_event,
+ "employee": self.employee
+ })
+
+ if employee:
+ frappe.db.set_value("Training Event Employee", employee, "status", "Completed")
+
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 86356e3..0fc50c5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -296,7 +296,7 @@
erpnext.patches.v13_0.update_amt_in_work_order_required_items
erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
erpnext.patches.v13_0.delete_orphaned_tables
-erpnext.patches.v13_0.update_export_type_for_gst
+erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.shopify_deprecation_warning
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
index 478a2a6..3e20212 100644
--- a/erpnext/patches/v13_0/update_export_type_for_gst.py
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -8,11 +8,19 @@
# 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', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
+ })
fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
if fieldname:
- frappe.db.set_value('Custom Field', fieldname, 'default', '')
+ frappe.db.set_value('Custom Field', fieldname,
+ {
+ 'default': '',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
+ })
# Update Customer/Supplier Masters
frappe.db.sql("""
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index b4f146c..2d6b913 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -642,7 +642,8 @@
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)'
}
],
'Customer': [
@@ -660,7 +661,8 @@
'fieldtype': 'Select',
'insert_after': 'gst_category',
'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
- 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax',
+ 'mandatory_depends_on': 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
}
],
'Member': [