diff --git a/frappe/hooks.py b/frappe/hooks.py index d66046b87d..9ca6d8587e 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -186,10 +186,12 @@ scheduler_events = { "frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_weekly", "frappe.utils.change_log.check_for_update", "frappe.desk.doctype.route_history.route_history.flush_old_route_records", - "frappe.desk.form.document_follow.send_weekly_updates" + "frappe.desk.form.document_follow.send_weekly_updates", + "frappe.social.doctype.energy_point_log.energy_point_log.send_weekly_report" ], "monthly": [ "frappe.email.doctype.auto_email_report.auto_email_report.send_monthly" + "frappe.social.doctype.energy_point_log.energy_point_log.send_monthly_report" ], "monthly_long": [ "frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_monthly" diff --git a/frappe/social/doctype/energy_point_log/energy_point_log.py b/frappe/social/doctype/energy_point_log/energy_point_log.py index 5d3c97ce6a..4b3693dc00 100644 --- a/frappe/social/doctype/energy_point_log/energy_point_log.py +++ b/frappe/social/doctype/energy_point_log/energy_point_log.py @@ -7,7 +7,9 @@ import frappe from frappe import _ import json from frappe.model.document import Document -from frappe.utils import cint, get_fullname +from frappe.utils import cint, get_fullname, getdate +from frappe.utils.user import get_enabled_system_users +from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled class EnergyPointLog(Document): def validate(self): @@ -34,23 +36,23 @@ def get_alert_dict(doc): if doc.type == 'Auto': alert_dict.message=_('You gained {} points').format(points) elif doc.type == 'Appreciation': - alert_dict.message = _('{} appreciated your work on {} with {} points'.format( + alert_dict.message = _('{} appreciated your work on {} with {} points').format( owner_name, doc_link, points - )) + ) elif doc.type == 'Criticism': - alert_dict.message = _('{} criticized your work on {} with {} points'.format( + alert_dict.message = _('{} criticized your work on {} with {} points').format( owner_name, doc_link, points - )) + ) alert_dict.indicator = 'red' elif doc.type == 'Revert': - alert_dict.message = _('{} reverted your points on {}'.format( + alert_dict.message = _('{} reverted your points on {}').format( owner_name, doc_link, - )) + ) alert_dict.indicator = 'red' else: alert_dict = {} @@ -107,11 +109,16 @@ def get_energy_points(user): return frappe._dict(points.get(user, {})) @frappe.whitelist() -def get_user_energy_and_review_points(user=None): +def get_user_energy_and_review_points(user=None, from_date=None, as_dict=True): + conditions = '' + values = [] if user: - where_user = 'WHERE `user` = %s' - else: - where_user = '' + conditions = 'WHERE `user` = %s' + values.append(user) + if from_date: + conditions += 'WHERE' if not conditions else 'AND' + conditions += ' `creation` >= %s' + values.append(conditions) points_list = frappe.db.sql(""" SELECT @@ -120,9 +127,13 @@ def get_user_energy_and_review_points(user=None): SUM(CASE WHEN `type`='Review' and `points` < 0 THEN ABS(`points`) ELSE 0 END) as given_points, `user` FROM `tabEnergy Point Log` - {where_user} + {conditions} GROUP BY `user` - """.format(where_user=where_user), values=user or (), as_dict=1) + ORDER BY `energy_points` DESC + """.format(conditions=conditions), values=values or (), as_dict=1) + + if not as_dict: + return points_list dict_to_return = frappe._dict() for d in points_list: @@ -187,4 +198,46 @@ def revert(name, reason): 'revert_of': doc_to_revert.name }).insert() - return revert_log \ No newline at end of file + return revert_log + +def send_weekly_summary(): + send_summary('Weekly') + +def send_monthly_summary(): + send_summary('Monthly') + +def send_summary(timespan): + if not is_energy_point_enabled(): + return + + from_date = frappe.utils.add_days(None, -7) + if timespan == 'Monthly': + from_date = frappe.utils.add_days(None, -30) + + user_points = get_user_energy_and_review_points(from_date=from_date, as_dict=False) + + # do not send report if no activity found + if not user_points or not user_points[0].energy_points: return + + from_date = getdate(from_date) + to_date = getdate() + all_users = [user.email for user in get_enabled_system_users()] + + frappe.sendmail( + subject='{} energy points summary'.format(timespan), + recipients=all_users, + template="energy_points_summary", + args={ + 'top_performer': user_points[0], + 'top_reviewer': max(user_points, key=lambda x:x['given_points']), + 'standings': user_points, + 'footer_message': get_footer_message(timespan).format(from_date, to_date) + } + ) + +def get_footer_message(timespan): + if timespan == 'Monthly': + return _("Stats based on last month's performance (from {} to {})") + else: + return _("Stats based on last week's performance (from {} to {})") + diff --git a/frappe/templates/emails/energy_points_summary.html b/frappe/templates/emails/energy_points_summary.html new file mode 100644 index 0000000000..d57e4f5039 --- /dev/null +++ b/frappe/templates/emails/energy_points_summary.html @@ -0,0 +1,41 @@ +{% if top_performer.energy_points %} +

{{ _('Top Performer') }} 🏆

+

{{ frappe.get_fullname(top_performer.user) }} + + {{ frappe._('gained {} points'.format(frappe.utils.cint(top_performer.energy_points))) }} + +

+{% endif %} + +{% if top_reviewer.given_points %} +

{{ _('Top Reviewer') }} ❤️

+

{{ frappe.get_fullname(top_reviewer.user) }} + + {{ frappe._('gave {} points'.format(frappe.utils.cint(top_reviewer.given_points))) }} + +

+ +
+{% endif %} + + +

{{ _('Standings') }}

+ + + + + + + + {% for user in standings %} + + + + + + {% endfor %} +
{{ frappe._('User') }}{{ frappe._('Energy Points') }}{{ frappe._('Points Given') }}
{{ frappe.get_fullname(user.user) }}{{ frappe.utils.cint(user.energy_points) }}{{ frappe.utils.cint(user.given_points) }}
+ +

+ {{ footer_message }} +

\ No newline at end of file