diff --git a/erpnext/docs/user/manual/en/human-resources/training.md b/erpnext/docs/user/manual/en/human-resources/training.md
index 39b9790246..2aa06791f0 100644
--- a/erpnext/docs/user/manual/en/human-resources/training.md
+++ b/erpnext/docs/user/manual/en/human-resources/training.md
@@ -9,22 +9,23 @@ Schedule seminars, workshops, conferences etc using Training Event. You can also
### Inviting Employees for Event
You can invite your employees to attend the event. You can do so by selecting the employees to be invited in the employee table.
+
By default the status of the employee will be 'Open'.
-The system shall notify the employee with status 'Open' by sending a email to the office email address of the employee as mentioned in the employee master if you have selected 'Send Email' checkbox.
-The status is changed to 'Invited' when an invitation email is sent to the employee by the system.
-When an Employee confirms his/her presence for the event you can change the status to 'Confirmed'.
+When you submit the Training Event, a notifcation will be sent to the employee notifying that the Training has been scheduled. This is sent via Email Alert "Training Scheduled". You can modifiy this Email Alert to customize the message.
+
### Training Result
-After compleation of the training Employee Wise training results can be stored based on the Feedback received from the Trainer.
+After compleation of the training Employee-wise training results can be stored based on the Feedback received from the Trainer.
+When the Training Result is submitted, all the employees will receive an email notifying them that they must share their feedback via "Training Feedback". This is also managed via an Email Alert, so you can customize this alert too.
-### Trainig Feedback
+### Training Feedback
-Collect feedback regarding the event from your Employees using Training Feedback.
+Employees can then share their feedback via Training Feedback.
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index a078ef2033..03626cdc5c 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -289,3 +289,15 @@ def create_user(employee, user = None):
})
user.insert()
return user.name
+
+def get_employee_emails(employee_list):
+ '''Returns list of employee emails either based on user_id or company_email'''
+ employee_emails = []
+ for employee in employee_list:
+ if not employee:
+ continue
+ user, email = frappe.db.get_value('Employee', employee, ['user_id', 'company_email'])
+ if user or email:
+ employee_emails.append(user or email)
+
+ return employee_emails
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/test_training_event.js b/erpnext/hr/doctype/training_event/tests/test_training_event.js
similarity index 100%
rename from erpnext/hr/doctype/training_event/test_training_event.js
rename to erpnext/hr/doctype/training_event/tests/test_training_event.js
diff --git a/erpnext/hr/doctype/training_event/tests/test_training_event_attandance.js b/erpnext/hr/doctype/training_event/tests/test_training_event_attandance.js
new file mode 100644
index 0000000000..6364308f73
--- /dev/null
+++ b/erpnext/hr/doctype/training_event/tests/test_training_event_attandance.js
@@ -0,0 +1,40 @@
+QUnit.module('hr');
+
+QUnit.test("test: Training Event", function (assert) {
+ // number of asserts
+ assert.expect(1);
+ let done = assert.async();
+
+ frappe.run_serially([
+ // insert a new Training Event
+ () => frappe.set_route("List", "Training Event", "List"),
+ () => frappe.new_doc("Training Event"),
+ () => frappe.timeout(1),
+ () => frappe.click_link('Edit in full page'),
+ () => cur_frm.set_value("event_name", "Test Event " + frappe.utils.get_random(10)),
+ () => cur_frm.set_value("start_time", "2017-07-26, 2:00 pm PDT"),
+ () => cur_frm.set_value("end_time", "2017-07-26, 2:30 pm PDT"),
+ () => cur_frm.set_value("introduction", "This is a test report"),
+ () => cur_frm.set_value("location", "Fake office"),
+ () => frappe.click_button('Add Row'),
+ () => frappe.db.get_value('Employee', {'employee_name':'Test Employee 1'}, 'name'),
+ (r) => {
+ console.log(r);
+ return cur_frm.fields_dict.employees.grid.grid_rows[0].doc.employee = r.message.name;
+ },
+ () => {
+ return cur_frm.fields_dict.employees.grid.grid_rows[0].doc.attendance = "Optional";
+ },
+ () => frappe.click_button('Save'),
+ () => frappe.timeout(2),
+ () => frappe.click_button('Submit'),
+ () => frappe.timeout(2),
+ () => frappe.click_button('Yes'),
+ () => frappe.timeout(1),
+ () => {
+ assert.equal(cur_frm.doc.docstatus, 1);
+ },
+ () => done()
+ ]);
+
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js
index ebe0c7907c..6a6e8fe0a6 100644
--- a/erpnext/hr/doctype/training_event/training_event.js
+++ b/erpnext/hr/doctype/training_event/training_event.js
@@ -18,4 +18,4 @@ frappe.ui.form.on('Training Event', {
});
}
}
-});
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/training_event.json b/erpnext/hr/doctype/training_event/training_event.json
index 03b58b4802..7be9d974fe 100644
--- a/erpnext/hr/doctype/training_event/training_event.json
+++ b/erpnext/hr/doctype/training_event/training_event.json
@@ -25,7 +25,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Event Name",
"length": 0,
@@ -55,7 +55,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 1,
"label": "Event Status",
"length": 0,
@@ -115,12 +115,12 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 1,
"label": "Type",
"length": 0,
"no_copy": 0,
- "options": "Seminar\nTheory\nWorkshop\nConference\nExam\nInternet",
+ "options": "Seminar\nTheory\nWorkshop\nConference\nExam\nInternet\nSelf-Study",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -386,7 +386,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 1,
"label": "Location",
"length": 0,
@@ -581,37 +581,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Will send an email about the event to employees with status 'Open'",
- "fieldname": "send_email",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Send Email",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
@@ -672,6 +641,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_emails",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Emails",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Email",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -684,7 +684,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-05-29 06:13:38.411039",
+ "modified": "2017-08-11 03:11:25.768563",
"modified_by": "Administrator",
"module": "HR",
"name": "Training Event",
diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py
index 27ae8cf549..cc568414a0 100644
--- a/erpnext/hr/doctype/training_event/training_event.py
+++ b/erpnext/hr/doctype/training_event/training_event.py
@@ -3,24 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
from frappe.model.document import Document
+from erpnext.hr.doctype.employee.employee import get_employee_emails
class TrainingEvent(Document):
- def on_update(self):
- self.invite_employee()
-
- def on_update_after_submit(self):
- self.invite_employee()
-
- def invite_employee(self):
- if self.event_status == "Scheduled" and self.send_email:
- subject = _("""You are invited for to attend {0} - {1} scheduled from {2} to {3} at {4}."""\
- .format(self.type, self.event_name, self.start_time, self.end_time, self.location))
-
- for emp in self.employees:
- if emp.status== "Open":
- frappe.sendmail(frappe.db.get_value("Employee", emp.employee, "company_email"), \
- subject=subject, content= self.introduction)
- emp.status= "Invited"
\ No newline at end of file
+ def validate(self):
+ self.employee_emails = ', '.join(get_employee_emails([d.employee
+ for d in self.employees]))
diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.json b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
index 575d0e7582..a8a72b1a70 100644
--- a/erpnext/hr/doctype/training_event_employee/training_event_employee.json
+++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -21,6 +23,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Employee",
@@ -40,6 +43,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -50,6 +54,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee Name",
@@ -69,6 +74,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -79,6 +85,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
@@ -96,6 +103,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -107,12 +115,44 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 1,
- "options": "Open\nInvited\nConfirmed\nAttended\nWithdrawn",
+ "options": "Open\nInvited\nCompleted\nFeedback Submitted",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "attendance",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Attendance",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Mandatory\nOptional",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -126,17 +166,17 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2016-12-14 11:43:40.996578",
+ "modified": "2017-08-11 03:36:22.738253",
"modified_by": "Administrator",
"module": "HR",
"name": "Training Event Employee",
@@ -146,7 +186,9 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
+ "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
+ "track_changes": 0,
"track_seen": 0
}
\ 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 2a0403bd53..20a3bc5652 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -5,6 +5,19 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe import _
class TrainingFeedback(Document):
- pass
+ 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')))
+
+ def on_submit(self):
+ training_event = frappe.get_doc("Training Event", self.training_event)
+ for e in training_event.employees:
+ if e.employee == self.employee:
+ training_event.status = 'Feedback Submitted'
+ break
+
+ training_event.update_after_submit()
diff --git a/erpnext/hr/doctype/training_result/test_training_result.js b/erpnext/hr/doctype/training_result/test_training_result.js
new file mode 100644
index 0000000000..cb1d7fb27a
--- /dev/null
+++ b/erpnext/hr/doctype/training_result/test_training_result.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Training Result", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Training Result
+ () => frappe.tests.make('Training Result', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/training_result/training_result.json b/erpnext/hr/doctype/training_result/training_result.json
index e5fbb5fd42..41142b59e6 100644
--- a/erpnext/hr/doctype/training_result/training_result.json
+++ b/erpnext/hr/doctype/training_result/training_result.json
@@ -26,7 +26,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Training Event",
"length": 0,
@@ -133,6 +133,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_emails",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Emails",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Email",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -145,7 +176,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-15 08:16:01.566531",
+ "modified": "2017-08-11 03:53:21.283968",
"modified_by": "Administrator",
"module": "HR",
"name": "Training Result",
diff --git a/erpnext/hr/doctype/training_result/training_result.py b/erpnext/hr/doctype/training_result/training_result.py
index 36c3cb93bc..7cdc51f801 100644
--- a/erpnext/hr/doctype/training_result/training_result.py
+++ b/erpnext/hr/doctype/training_result/training_result.py
@@ -6,19 +6,27 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
+from erpnext.hr.doctype.employee.employee import get_employee_emails
class TrainingResult(Document):
+ 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')))
+
+ self.employee_emails = ', '.join(get_employee_emails([d.employee
+ for d in self.employees]))
+
def on_submit(self):
- self.send_result()
-
- def send_result(self):
- for emp in self.employees:
- message = "Thank You for attending {0}.".format(self.training_event)
- if emp.grade:
- message = message + "Your grade: {0}".format(emp.grade)
- frappe.sendmail(frappe.db.get_value("Employee", emp.employee, "company_email"), \
- subject=_("{0} Results".format(self.training_event)), \
- content=message)
+ training_event = frappe.get_doc("Training Event", self.training_event)
+ training_event.status = 'Completed'
+ for e in self.employees:
+ for e1 in training_event.employees:
+ if e1.employee == e.employee:
+ e1.status = 'Completed'
+ break
+
+ training_event.save()
@frappe.whitelist()
def get_employees(training_event):
diff --git a/erpnext/hr/email_alert/__init__.py b/erpnext/hr/email_alert/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/email_alert/training_feedback/__init__.py b/erpnext/hr/email_alert/training_feedback/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/email_alert/training_feedback/training_feedback.html b/erpnext/hr/email_alert/training_feedback/training_feedback.html
new file mode 100644
index 0000000000..fd8fef9e82
--- /dev/null
+++ b/erpnext/hr/email_alert/training_feedback/training_feedback.html
@@ -0,0 +1,6 @@
+
{{ _("Hello") }},
+ +You attended training {{ frappe.utils.get_link_to_form( + "Training Event", doc.training_event) }}
+ +{{ _("Please share your feedback to the training by clicking on 'Training Feedback' and then 'New'") }}
\ No newline at end of file diff --git a/erpnext/hr/email_alert/training_feedback/training_feedback.json b/erpnext/hr/email_alert/training_feedback/training_feedback.json new file mode 100644 index 0000000000..51f6cedfec --- /dev/null +++ b/erpnext/hr/email_alert/training_feedback/training_feedback.json @@ -0,0 +1,24 @@ +{ + "attach_print": 0, + "creation": "2017-08-11 03:17:11.769210", + "days_in_advance": 0, + "docstatus": 0, + "doctype": "Email Alert", + "document_type": "Training Result", + "enabled": 1, + "event": "Submit", + "idx": 0, + "is_standard": 1, + "message": "{{ message }}
\n\n{{ message }}
+ +{{ doc.introduction }}
+ +{{ doc.introduction }}
\n\n{{ message }}
+ +{{ message }}
+ +{{_("Please update your status for this training event")}}:
+ + +{% else %} +{{_("Please confirm once you have completed your training")}}:
+ +{% endif %} +{{_("Thank you")}},
+{{ user_fullname }}