fix: remove energy points / social module
This commit is contained in:
parent
3c8a879f37
commit
a1fca6ab63
29 changed files with 1 additions and 1748 deletions
|
|
@ -21,10 +21,6 @@ from frappe.permissions import has_permission
|
|||
from frappe.query_builder import DocType
|
||||
from frappe.query_builder.functions import Count
|
||||
from frappe.query_builder.terms import ParameterizedValueWrapper, SubQuery
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
|
||||
from frappe.social.doctype.energy_point_settings.energy_point_settings import (
|
||||
is_energy_point_enabled,
|
||||
)
|
||||
from frappe.utils import add_user_info, cstr, get_system_timezone
|
||||
from frappe.utils.change_log import get_versions
|
||||
from frappe.utils.frappecloud import on_frappecloud
|
||||
|
|
@ -99,10 +95,7 @@ def get_bootinfo():
|
|||
bootinfo.lang_dict = get_lang_dict()
|
||||
bootinfo.success_action = get_success_action()
|
||||
bootinfo.update(get_email_accounts(user=frappe.session.user))
|
||||
bootinfo.energy_points_enabled = is_energy_point_enabled()
|
||||
bootinfo.website_tracking_enabled = is_tracking_enabled()
|
||||
bootinfo.sms_gateway_enabled = bool(frappe.db.get_single_value("SMS Settings", "sms_gateway_url"))
|
||||
bootinfo.points = get_energy_points(frappe.session.user)
|
||||
bootinfo.frequently_visited_links = frequently_visited_links()
|
||||
bootinfo.link_preview_doctypes = get_link_preview_doctypes()
|
||||
bootinfo.additional_filters_config = get_additional_filters_from_hooks()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import frappe
|
|||
common_default_keys = ["__default", "__global"]
|
||||
|
||||
doctypes_for_mapping = {
|
||||
"Energy Point Rule",
|
||||
"Assignment Rule",
|
||||
"Milestone Tracker",
|
||||
"Document Naming Rule",
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ def get_docinfo(doc=None, doctype=None, name=None):
|
|||
"permissions": get_doc_permissions(doc),
|
||||
"shared": get_docshares(doc),
|
||||
"views": get_view_logs(doc),
|
||||
"energy_point_logs": get_point_logs(doc.doctype, doc.name),
|
||||
# "energy_point_logs": get_point_logs(doc.doctype, doc.name),
|
||||
"additional_timeline_content": get_additional_timeline_content(doc.doctype, doc.name),
|
||||
"milestones": get_milestones(doc.doctype, doc.name),
|
||||
"is_document_followed": is_document_followed(doc.doctype, doc.name, frappe.session.user),
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ doc_events = {
|
|||
"frappe.core.doctype.file.utils.attach_files_to_document",
|
||||
],
|
||||
"on_change": [
|
||||
"frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points",
|
||||
"frappe.automation.doctype.milestone_tracker.milestone_tracker.evaluate_milestone",
|
||||
],
|
||||
"after_delete": ["frappe.core.doctype.permission_log.permission_log.make_perm_log"],
|
||||
|
|
@ -248,7 +247,6 @@ scheduler_events = {
|
|||
"frappe.email.doctype.notification.notification.trigger_daily_alerts",
|
||||
"frappe.website.doctype.personal_data_deletion_request.personal_data_deletion_request.remove_unverified_record",
|
||||
"frappe.desk.form.document_follow.send_daily_updates",
|
||||
"frappe.social.doctype.energy_point_settings.energy_point_settings.allocate_review_points",
|
||||
"frappe.integrations.doctype.google_contacts.google_contacts.sync",
|
||||
"frappe.automation.doctype.auto_repeat.auto_repeat.make_auto_repeat_entry",
|
||||
],
|
||||
|
|
@ -263,13 +261,11 @@ scheduler_events = {
|
|||
"frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_weekly",
|
||||
"frappe.desk.form.document_follow.send_weekly_updates",
|
||||
"frappe.utils.change_log.check_for_update",
|
||||
"frappe.social.doctype.energy_point_log.energy_point_log.send_weekly_summary",
|
||||
"frappe.integrations.doctype.google_drive.google_drive.weekly_backup",
|
||||
"frappe.desk.doctype.changelog_feed.changelog_feed.fetch_changelog_feed",
|
||||
],
|
||||
"monthly": [
|
||||
"frappe.email.doctype.auto_email_report.auto_email_report.send_monthly",
|
||||
"frappe.social.doctype.energy_point_log.energy_point_log.send_monthly_summary",
|
||||
],
|
||||
"monthly_long": [
|
||||
"frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_monthly"
|
||||
|
|
|
|||
|
|
@ -8,5 +8,4 @@ Desk
|
|||
Integrations
|
||||
Printing
|
||||
Contacts
|
||||
Social
|
||||
Automation
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import "./assign_to";
|
||||
import "./attachments";
|
||||
import "./share";
|
||||
import "./review";
|
||||
import "./document_follow";
|
||||
import "./user_image";
|
||||
import "./form_sidebar_users";
|
||||
|
|
@ -28,7 +27,6 @@ frappe.ui.form.Sidebar = class {
|
|||
this.image_wrapper = this.image_section.find(".sidebar-image-wrapper");
|
||||
this.make_assignments();
|
||||
this.make_attachments();
|
||||
this.make_review();
|
||||
this.make_shared();
|
||||
|
||||
this.make_tags();
|
||||
|
|
@ -214,18 +212,6 @@ frappe.ui.form.Sidebar = class {
|
|||
|
||||
refresh_image() {}
|
||||
|
||||
make_review() {
|
||||
const review_wrapper = this.sidebar.find(".form-reviews");
|
||||
if (frappe.boot.energy_points_enabled && !this.frm.is_new()) {
|
||||
this.frm.reviews = new frappe.ui.form.Review({
|
||||
parent: review_wrapper,
|
||||
frm: this.frm,
|
||||
});
|
||||
} else {
|
||||
review_wrapper.remove();
|
||||
}
|
||||
}
|
||||
|
||||
reload_docinfo(callback) {
|
||||
frappe.call({
|
||||
method: "frappe.desk.form.load.get_docinfo",
|
||||
|
|
|
|||
|
|
@ -74,18 +74,6 @@
|
|||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="sidebar-section form-reviews">
|
||||
<div class="reviews">
|
||||
<span class="form-sidebar-items">
|
||||
<span>
|
||||
<span class="ellipsis">{%= __("Reviews") %}</span>
|
||||
</span>
|
||||
<button class="add-review-btn btn btn-link icon-btn">
|
||||
<svg class="es-icon icon-sm"><use href="#es-line-add"></use></svg>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section form-tags">
|
||||
<div>
|
||||
<span class="form-sidebar-items">
|
||||
|
|
|
|||
|
|
@ -871,60 +871,6 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.form-reviews {
|
||||
.reviews {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.review {
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
height: 28px;
|
||||
border-radius: 14px;
|
||||
font-size: var(--text-xs);
|
||||
margin-bottom: var(--margin-sm);
|
||||
margin-right: var(--margin-xs);
|
||||
border: 1px solid var(--dark-border-color);
|
||||
padding: 2px 3px;
|
||||
align-items: center;
|
||||
min-width: 60px;
|
||||
background: var(--fg-color);
|
||||
.avatar {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.review-points {
|
||||
margin-left: 3px;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.review-popover {
|
||||
padding: 0px;
|
||||
min-width: 200px;
|
||||
max-width: 250px;
|
||||
|
||||
.popover-body,
|
||||
.popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
.body {
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.subject,
|
||||
.body {
|
||||
padding: var(--padding-sm);
|
||||
overflow-wrap: break-word;
|
||||
p {
|
||||
margin-top: var(--margin-xs);
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.liked-by-popover {
|
||||
.popover-body {
|
||||
min-height: 30px;
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2018, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Energy Point Log", {
|
||||
refresh: function (frm) {
|
||||
frm.events.make_reference_name_link(frm);
|
||||
if (frm.doc.reverted) {
|
||||
frm.set_intro(__("This document has been reverted"));
|
||||
} else if (frm.doc.type === "Auto" && frappe.user_roles.includes("System Manager")) {
|
||||
frm.add_custom_button(__("Revert"), () => frm.events.show_revert_dialog(frm));
|
||||
}
|
||||
},
|
||||
show_revert_dialog(frm) {
|
||||
const revert_dialog = new frappe.ui.Dialog({
|
||||
title: __("Revert"),
|
||||
fields: [
|
||||
{
|
||||
fieldname: "reason",
|
||||
fieldtype: "Small Text",
|
||||
label: __("Reason"),
|
||||
reqd: 1,
|
||||
},
|
||||
],
|
||||
primary_action: (values) => {
|
||||
return frm
|
||||
.call("revert", {
|
||||
reason: values.reason,
|
||||
})
|
||||
.then((res) => {
|
||||
let revert_log = res.message;
|
||||
revert_dialog.hide();
|
||||
revert_dialog.clear();
|
||||
frappe.model.docinfo[frm.doc.reference_doctype][
|
||||
frm.doc.reference_name
|
||||
].energy_point_logs.unshift(revert_log);
|
||||
frm.refresh();
|
||||
});
|
||||
},
|
||||
primary_action_label: __("Submit"),
|
||||
});
|
||||
revert_dialog.show();
|
||||
},
|
||||
make_reference_name_link(frm) {
|
||||
let dt = frm.doc.reference_doctype;
|
||||
let dn = frm.doc.reference_name;
|
||||
frm.fields_dict.reference_name.$input_wrapper
|
||||
.find(".control-value")
|
||||
.wrapInner(`<a href='/app/${frappe.router.slug(dt)}/${dn}'></a>`);
|
||||
},
|
||||
});
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2018-06-21 14:58:55.913619",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"user",
|
||||
"type",
|
||||
"points",
|
||||
"rule",
|
||||
"column_break_5",
|
||||
"reference_doctype",
|
||||
"reference_name",
|
||||
"reverted",
|
||||
"revert_of",
|
||||
"section_break_10",
|
||||
"reason",
|
||||
"seen"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"options": "Auto\nAppreciation\nCriticism\nReview\nRevert",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rule",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Rule",
|
||||
"options": "Energy Point Rule",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Reference Document Type",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Reference Name",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "points",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Points",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reason",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Reason",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "reverted",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Reverted"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.type === 'Revert'",
|
||||
"fieldname": "revert_of",
|
||||
"fieldtype": "Link",
|
||||
"label": "Revert Of",
|
||||
"options": "Energy Point Log",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_10",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "seen",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Seen"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-23 16:03:25.006938",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Social",
|
||||
"name": "Energy Point Log",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager"
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Desk User"
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "user"
|
||||
}
|
||||
|
|
@ -1,391 +0,0 @@
|
|||
# Copyright (c) 2018, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.desk.doctype.notification_log.notification_log import (
|
||||
enqueue_create_notification,
|
||||
get_title,
|
||||
get_title_html,
|
||||
)
|
||||
from frappe.desk.doctype.notification_settings.notification_settings import (
|
||||
is_email_notifications_enabled,
|
||||
is_email_notifications_enabled_for_type,
|
||||
)
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint, get_fullname, get_link_to_form, getdate
|
||||
|
||||
|
||||
class EnergyPointLog(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
points: DF.Int
|
||||
reason: DF.Text | None
|
||||
reference_doctype: DF.Link | None
|
||||
reference_name: DF.Data | None
|
||||
revert_of: DF.Link | None
|
||||
reverted: DF.Check
|
||||
rule: DF.Link | None
|
||||
seen: DF.Check
|
||||
type: DF.Literal["Auto", "Appreciation", "Criticism", "Review", "Revert"]
|
||||
user: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
def validate(self):
|
||||
self.map_milestone_reference()
|
||||
if self.type in ["Appreciation", "Criticism"] and self.user == self.owner:
|
||||
frappe.throw(_("You cannot give review points to yourself"))
|
||||
|
||||
def map_milestone_reference(self):
|
||||
# link energy point to the original reference, if set by milestone
|
||||
if self.reference_doctype == "Milestone":
|
||||
self.reference_doctype, self.reference_name = frappe.db.get_value(
|
||||
"Milestone", self.reference_name, ["reference_type", "reference_name"]
|
||||
)
|
||||
|
||||
def after_insert(self):
|
||||
alert_dict = get_alert_dict(self)
|
||||
if alert_dict:
|
||||
frappe.publish_realtime(
|
||||
"energy_point_alert", message=alert_dict, user=self.user, after_commit=True
|
||||
)
|
||||
|
||||
frappe.cache.hdel("energy_points", self.user)
|
||||
|
||||
if self.type != "Review" and frappe.get_cached_value(
|
||||
"Notification Settings", self.user, "energy_points_system_notifications"
|
||||
):
|
||||
reference_user = self.user if self.type == "Auto" else self.owner
|
||||
notification_doc = {
|
||||
"type": "Energy Point",
|
||||
"document_type": self.reference_doctype,
|
||||
"document_name": self.reference_name,
|
||||
"subject": get_notification_message(self),
|
||||
"from_user": reference_user,
|
||||
"email_content": f"<div>{self.reason}</div>" if self.reason else None,
|
||||
}
|
||||
|
||||
enqueue_create_notification(self.user, notification_doc)
|
||||
|
||||
def on_trash(self):
|
||||
if self.type == "Revert":
|
||||
reference_log = frappe.get_doc("Energy Point Log", self.revert_of)
|
||||
reference_log.reverted = 0
|
||||
reference_log.save()
|
||||
|
||||
@frappe.whitelist()
|
||||
def revert(self, reason, ignore_permissions=False):
|
||||
if not ignore_permissions:
|
||||
frappe.only_for("System Manager")
|
||||
|
||||
if self.type != "Auto":
|
||||
frappe.throw(_("This document cannot be reverted"))
|
||||
|
||||
if self.get("reverted"):
|
||||
return
|
||||
|
||||
self.reverted = 1
|
||||
self.save(ignore_permissions=True)
|
||||
|
||||
return frappe.get_doc(
|
||||
{
|
||||
"doctype": "Energy Point Log",
|
||||
"points": -(self.points),
|
||||
"type": "Revert",
|
||||
"user": self.user,
|
||||
"reason": reason,
|
||||
"reference_doctype": self.reference_doctype,
|
||||
"reference_name": self.reference_name,
|
||||
"revert_of": self.name,
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def get_notification_message(doc):
|
||||
owner_name = get_fullname(doc.owner)
|
||||
points = doc.points
|
||||
title = get_title(doc.reference_doctype, doc.reference_name)
|
||||
|
||||
if doc.type == "Auto":
|
||||
owner_name = frappe.bold("You")
|
||||
if points == 1:
|
||||
message = _("{0} gained {1} point for {2} {3}")
|
||||
else:
|
||||
message = _("{0} gained {1} points for {2} {3}")
|
||||
message = message.format(owner_name, frappe.bold(points), doc.rule, get_title_html(title))
|
||||
elif doc.type == "Appreciation":
|
||||
if points == 1:
|
||||
message = _("{0} appreciated your work on {1} with {2} point")
|
||||
else:
|
||||
message = _("{0} appreciated your work on {1} with {2} points")
|
||||
message = message.format(frappe.bold(owner_name), get_title_html(title), frappe.bold(points))
|
||||
elif doc.type == "Criticism":
|
||||
if points == 1:
|
||||
message = _("{0} criticized your work on {1} with {2} point")
|
||||
else:
|
||||
message = _("{0} criticized your work on {1} with {2} points")
|
||||
|
||||
message = message.format(frappe.bold(owner_name), get_title_html(title), frappe.bold(points))
|
||||
elif doc.type == "Revert":
|
||||
if points == 1:
|
||||
message = _("{0} reverted your point on {1}")
|
||||
else:
|
||||
message = _("{0} reverted your points on {1}")
|
||||
message = message.format(frappe.bold(owner_name), get_title_html(title))
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def get_alert_dict(doc):
|
||||
alert_dict = frappe._dict()
|
||||
owner_name = get_fullname(doc.owner)
|
||||
if doc.reference_doctype:
|
||||
doc_link = get_link_to_form(doc.reference_doctype, doc.reference_name)
|
||||
points = doc.points
|
||||
bold_points = frappe.bold(doc.points)
|
||||
if doc.type == "Auto":
|
||||
if points == 1:
|
||||
message = _("You gained {0} point")
|
||||
else:
|
||||
message = _("You gained {0} points")
|
||||
alert_dict.message = message.format(bold_points)
|
||||
alert_dict.indicator = "green"
|
||||
elif doc.type == "Appreciation":
|
||||
if points == 1:
|
||||
message = _("{0} appreciated your work on {1} with {2} point")
|
||||
else:
|
||||
message = _("{0} appreciated your work on {1} with {2} points")
|
||||
alert_dict.message = message.format(owner_name, doc_link, bold_points)
|
||||
alert_dict.indicator = "green"
|
||||
elif doc.type == "Criticism":
|
||||
if points == 1:
|
||||
message = _("{0} criticized your work on {1} with {2} point")
|
||||
else:
|
||||
message = _("{0} criticized your work on {1} with {2} points")
|
||||
|
||||
alert_dict.message = message.format(owner_name, doc_link, bold_points)
|
||||
alert_dict.indicator = "red"
|
||||
elif doc.type == "Revert":
|
||||
if points == 1:
|
||||
message = _("{0} reverted your point on {1}")
|
||||
else:
|
||||
message = _("{0} reverted your points on {1}")
|
||||
alert_dict.message = message.format(
|
||||
owner_name,
|
||||
doc_link,
|
||||
)
|
||||
alert_dict.indicator = "red"
|
||||
|
||||
return alert_dict
|
||||
|
||||
|
||||
def create_energy_points_log(ref_doctype, ref_name, doc, apply_only_once=False):
|
||||
doc = frappe._dict(doc)
|
||||
if doc.rule:
|
||||
log_exists = check_if_log_exists(
|
||||
ref_doctype, ref_name, doc.rule, None if apply_only_once else doc.user
|
||||
)
|
||||
if log_exists:
|
||||
return frappe.get_doc("Energy Point Log", log_exists)
|
||||
|
||||
new_log = frappe.new_doc("Energy Point Log")
|
||||
new_log.reference_doctype = ref_doctype
|
||||
new_log.reference_name = ref_name
|
||||
new_log.update(doc)
|
||||
new_log.insert(ignore_permissions=True)
|
||||
return new_log
|
||||
|
||||
|
||||
def check_if_log_exists(ref_doctype, ref_name, rule, user=None):
|
||||
"""'Checks if Energy Point Log already exists"""
|
||||
filters = frappe._dict(
|
||||
{"rule": rule, "reference_doctype": ref_doctype, "reference_name": ref_name, "reverted": 0}
|
||||
)
|
||||
|
||||
if user:
|
||||
filters.user = user
|
||||
|
||||
return frappe.db.exists("Energy Point Log", filters)
|
||||
|
||||
|
||||
def create_review_points_log(user, points, reason=None, doctype=None, docname=None):
|
||||
return frappe.get_doc(
|
||||
{
|
||||
"doctype": "Energy Point Log",
|
||||
"points": points,
|
||||
"type": "Review",
|
||||
"user": user,
|
||||
"reason": reason,
|
||||
"reference_doctype": doctype,
|
||||
"reference_name": docname,
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_review_points(user, points):
|
||||
frappe.only_for("System Manager")
|
||||
create_review_points_log(user, points)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_energy_points(user):
|
||||
points = get_user_energy_and_review_points(user)
|
||||
return frappe._dict(points.get(user, {}))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_user_energy_and_review_points(user=None, from_date=None, as_dict=True):
|
||||
conditions = ""
|
||||
given_points_condition = ""
|
||||
values = frappe._dict()
|
||||
if user:
|
||||
conditions = "WHERE `user` = %(user)s"
|
||||
values.user = user
|
||||
if from_date:
|
||||
conditions += "WHERE" if not conditions else "AND"
|
||||
given_points_condition += "AND `creation` >= %(from_date)s"
|
||||
conditions += " `creation` >= %(from_date)s OR `type`='Review'"
|
||||
values.from_date = from_date
|
||||
|
||||
points_list = frappe.db.sql(
|
||||
f"""
|
||||
SELECT
|
||||
SUM(CASE WHEN `type` != 'Review' THEN `points` ELSE 0 END) AS energy_points,
|
||||
SUM(CASE WHEN `type` = 'Review' THEN `points` ELSE 0 END) AS review_points,
|
||||
SUM(CASE
|
||||
WHEN `type`='Review' AND `points` < 0 {given_points_condition}
|
||||
THEN ABS(`points`)
|
||||
ELSE 0
|
||||
END) as given_points,
|
||||
`user`
|
||||
FROM `tabEnergy Point Log`
|
||||
{conditions}
|
||||
GROUP BY `user`
|
||||
ORDER BY `energy_points` DESC
|
||||
""",
|
||||
values=values,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
if not as_dict:
|
||||
return points_list
|
||||
|
||||
dict_to_return = frappe._dict()
|
||||
for d in points_list:
|
||||
dict_to_return[d.pop("user")] = d
|
||||
return dict_to_return
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def review(doc, points, to_user, reason, review_type="Appreciation"):
|
||||
current_review_points = get_energy_points(frappe.session.user).review_points
|
||||
doc = doc.as_dict() if hasattr(doc, "as_dict") else frappe._dict(json.loads(doc))
|
||||
points = abs(cint(points))
|
||||
if current_review_points < points:
|
||||
frappe.msgprint(_("You do not have enough review points"))
|
||||
return
|
||||
|
||||
review_doc = create_energy_points_log(
|
||||
doc.doctype,
|
||||
doc.name,
|
||||
{
|
||||
"type": review_type,
|
||||
"reason": reason,
|
||||
"points": points if review_type == "Appreciation" else -points,
|
||||
"user": to_user,
|
||||
},
|
||||
)
|
||||
|
||||
# deduct review points from reviewer
|
||||
create_review_points_log(
|
||||
user=frappe.session.user,
|
||||
points=-points,
|
||||
reason=reason,
|
||||
doctype=review_doc.doctype,
|
||||
docname=review_doc.name,
|
||||
)
|
||||
|
||||
return review_doc
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reviews(doctype, docname):
|
||||
return frappe.get_all(
|
||||
"Energy Point Log",
|
||||
filters={
|
||||
"reference_doctype": doctype,
|
||||
"reference_name": docname,
|
||||
"type": ["in", ("Appreciation", "Criticism")],
|
||||
},
|
||||
fields=["points", "owner", "type", "user", "reason", "creation"],
|
||||
)
|
||||
|
||||
|
||||
def send_weekly_summary():
|
||||
send_summary("Weekly")
|
||||
|
||||
|
||||
def send_monthly_summary():
|
||||
send_summary("Monthly")
|
||||
|
||||
|
||||
def send_summary(timespan):
|
||||
from frappe.social.doctype.energy_point_settings.energy_point_settings import (
|
||||
is_energy_point_enabled,
|
||||
)
|
||||
from frappe.utils.user import get_enabled_system_users
|
||||
|
||||
if not is_energy_point_enabled():
|
||||
return
|
||||
|
||||
if not is_email_notifications_enabled_for_type(frappe.session.user, "Energy Point"):
|
||||
return
|
||||
|
||||
from_date = frappe.utils.add_to_date(None, weeks=-1)
|
||||
if timespan == "Monthly":
|
||||
from_date = frappe.utils.add_to_date(None, months=-1)
|
||||
|
||||
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()
|
||||
|
||||
# select only those users that have energy point email notifications enabled
|
||||
all_users = [
|
||||
user.email
|
||||
for user in get_enabled_system_users()
|
||||
if is_email_notifications_enabled_for_type(user.name, "Energy Point")
|
||||
]
|
||||
|
||||
frappe.sendmail(
|
||||
subject=f"{timespan} energy points summary",
|
||||
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[:10], # top 10
|
||||
"footer_message": get_footer_message(timespan).format(from_date, to_date),
|
||||
},
|
||||
with_container=1,
|
||||
)
|
||||
|
||||
|
||||
def get_footer_message(timespan):
|
||||
if timespan == "Monthly":
|
||||
return _("Stats based on last month's performance (from {0} to {1})")
|
||||
else:
|
||||
return _("Stats based on last week's performance (from {0} to {1})")
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
frappe.listview_settings["Energy Point Log"] = {
|
||||
hide_name_column: true,
|
||||
add_fields: ["type", "reference_doctype", "reference_name"],
|
||||
get_indicator: function (doc) {
|
||||
let colors = {
|
||||
Appreciation: "green",
|
||||
Criticism: "red",
|
||||
Auto: "blue",
|
||||
Revert: "orange",
|
||||
Review: "grey",
|
||||
};
|
||||
return [__(doc.type), colors[doc.type], "type,=," + doc.type];
|
||||
},
|
||||
|
||||
button: {
|
||||
show: function (doc) {
|
||||
return doc.reference_name;
|
||||
},
|
||||
get_label: function () {
|
||||
return __("View Ref");
|
||||
},
|
||||
get_description: function (doc) {
|
||||
return __("Open {0}", [`${doc.reference_doctype} ${doc.reference_name}`]);
|
||||
},
|
||||
action: function (doc) {
|
||||
frappe.set_route("Form", doc.reference_doctype, doc.reference_name);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,389 +0,0 @@
|
|||
# Copyright (c) 2019, Frappe Technologies and Contributors
|
||||
# License: MIT. See LICENSE
|
||||
from unittest.case import skipIf
|
||||
|
||||
import frappe
|
||||
from frappe.cache_manager import clear_doctype_map
|
||||
from frappe.desk.form.assign_to import add as assign_to
|
||||
from frappe.desk.page.user_profile.user_profile import get_energy_points_heatmap_data
|
||||
from frappe.tests import IntegrationTestCase, UnitTestCase
|
||||
from frappe.utils.testutils import add_custom_field, clear_custom_fields
|
||||
|
||||
from .energy_point_log import create_review_points_log, review
|
||||
from .energy_point_log import get_energy_points as _get_energy_points
|
||||
|
||||
|
||||
class UnitTestEnergyPointLog(UnitTestCase):
|
||||
"""
|
||||
Unit tests for EnergyPointLog.
|
||||
Use this class for testing individual functions and methods.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestEnergyPointLog(IntegrationTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
settings = frappe.get_single("Energy Point Settings")
|
||||
settings.enabled = 1
|
||||
settings.save()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
settings = frappe.get_single("Energy Point Settings")
|
||||
settings.enabled = 0
|
||||
settings.save()
|
||||
|
||||
def setUp(self):
|
||||
clear_doctype_map("Energy Point Rule")
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
frappe.db.delete("Energy Point Log")
|
||||
frappe.db.delete("Energy Point Rule")
|
||||
clear_doctype_map("Energy Point Rule")
|
||||
|
||||
def test_user_energy_point(self):
|
||||
frappe.set_user("test@example.com")
|
||||
todo_point_rule = create_energy_point_rule_for_todo()
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user + todo_point_rule.points)
|
||||
|
||||
created_todo.save()
|
||||
points_after_double_save = get_points("test@example.com")
|
||||
|
||||
# point should not be awarded more than once for same doc
|
||||
self.assertEqual(points_after_double_save, energy_point_of_user + todo_point_rule.points)
|
||||
|
||||
def test_points_based_on_multiplier_field(self):
|
||||
frappe.set_user("test@example.com")
|
||||
add_custom_field("ToDo", "multiplier", "Float")
|
||||
multiplier_value = 0.51
|
||||
|
||||
todo_point_rule = create_energy_point_rule_for_todo("multiplier")
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
created_todo.status = "Closed"
|
||||
created_todo.multiplier = multiplier_value
|
||||
created_todo.save()
|
||||
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
self.assertEqual(
|
||||
points_after_closing_todo,
|
||||
energy_point_of_user + round(todo_point_rule.points * multiplier_value),
|
||||
)
|
||||
|
||||
clear_custom_fields("ToDo")
|
||||
|
||||
def test_points_based_on_max_points(self):
|
||||
frappe.set_user("test@example.com")
|
||||
# here multiplier is high
|
||||
# let see if points get capped to max_point limit
|
||||
multiplier_value = 15
|
||||
max_points = 50
|
||||
|
||||
add_custom_field("ToDo", "multiplier", "Float")
|
||||
todo_point_rule = create_energy_point_rule_for_todo("multiplier", max_points=max_points)
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
created_todo.status = "Closed"
|
||||
created_todo.multiplier = multiplier_value
|
||||
created_todo.save()
|
||||
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
# test max_points cap
|
||||
self.assertNotEqual(
|
||||
points_after_closing_todo,
|
||||
energy_point_of_user + round(todo_point_rule.points * multiplier_value),
|
||||
)
|
||||
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user + max_points)
|
||||
|
||||
clear_custom_fields("ToDo")
|
||||
|
||||
def test_disabled_energy_points(self):
|
||||
settings = frappe.get_single("Energy Point Settings")
|
||||
settings.enabled = 0
|
||||
settings.save()
|
||||
|
||||
frappe.set_user("test@example.com")
|
||||
create_energy_point_rule_for_todo()
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
# no change in points
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user)
|
||||
|
||||
settings.enabled = 1
|
||||
settings.save()
|
||||
|
||||
def test_review(self):
|
||||
created_todo = create_a_todo()
|
||||
review_points = 20
|
||||
create_review_points_log("test2@example.com", review_points)
|
||||
|
||||
# reviewer
|
||||
frappe.set_user("test2@example.com")
|
||||
|
||||
review_points_before_review = get_points("test2@example.com", "review_points")
|
||||
self.assertEqual(review_points_before_review, review_points)
|
||||
|
||||
# for appreciation
|
||||
appreciation_points = 5
|
||||
energy_points_before_review = get_points("test@example.com")
|
||||
review(created_todo, appreciation_points, "test@example.com", "good job")
|
||||
energy_points_after_review = get_points("test@example.com")
|
||||
review_points_after_review = get_points("test2@example.com", "review_points")
|
||||
self.assertEqual(energy_points_after_review, energy_points_before_review + appreciation_points)
|
||||
self.assertEqual(review_points_after_review, review_points_before_review - appreciation_points)
|
||||
|
||||
# for criticism
|
||||
criticism_points = 2
|
||||
todo = create_a_todo(description="Bad patch")
|
||||
energy_points_before_review = energy_points_after_review
|
||||
review_points_before_review = review_points_after_review
|
||||
review(todo, criticism_points, "test@example.com", "You could have done better.", "Criticism")
|
||||
energy_points_after_review = get_points("test@example.com")
|
||||
review_points_after_review = get_points("test2@example.com", "review_points")
|
||||
self.assertEqual(energy_points_after_review, energy_points_before_review - criticism_points)
|
||||
self.assertEqual(review_points_after_review, review_points_before_review - criticism_points)
|
||||
|
||||
def test_user_energy_point_as_admin(self):
|
||||
frappe.set_user("Administrator")
|
||||
create_energy_point_rule_for_todo()
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
|
||||
points_after_closing_todo = get_points("Administrator")
|
||||
|
||||
# no points for admin
|
||||
self.assertEqual(points_after_closing_todo, 0)
|
||||
|
||||
def test_revert_points_on_cancelled_doc(self):
|
||||
frappe.set_user("test@example.com")
|
||||
create_energy_point_rule_for_todo()
|
||||
created_todo = create_a_todo()
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
|
||||
energy_point_logs = frappe.get_all("Energy Point Log")
|
||||
|
||||
self.assertEqual(len(energy_point_logs), 1)
|
||||
|
||||
# for submit and cancel permission
|
||||
frappe.set_user("Administrator")
|
||||
# submit
|
||||
created_todo.docstatus = 1
|
||||
created_todo.save()
|
||||
|
||||
# cancel
|
||||
created_todo.docstatus = 2
|
||||
created_todo.save()
|
||||
|
||||
energy_point_logs = frappe.get_all("Energy Point Log", fields=["reference_name", "type", "reverted"])
|
||||
|
||||
self.assertListEqual(
|
||||
energy_point_logs,
|
||||
[
|
||||
{"reference_name": created_todo.name, "type": "Revert", "reverted": 0},
|
||||
{"reference_name": created_todo.name, "type": "Auto", "reverted": 1},
|
||||
],
|
||||
)
|
||||
|
||||
def test_energy_point_for_new_document_creation(self):
|
||||
frappe.set_user("test@example.com")
|
||||
todo_point_rule = create_energy_point_rule_for_todo(for_doc_event="New")
|
||||
|
||||
points_before_todo_creation = get_points("test@example.com")
|
||||
create_a_todo()
|
||||
points_after_todo_creation = get_points("test@example.com")
|
||||
|
||||
self.assertEqual(points_after_todo_creation, points_before_todo_creation + todo_point_rule.points)
|
||||
|
||||
def test_point_allocation_for_assigned_users(self):
|
||||
todo = create_a_todo()
|
||||
|
||||
assign_users_to_todo(todo.name, ["test@example.com", "test2@example.com"])
|
||||
|
||||
test_user_before_points = get_points("test@example.com")
|
||||
test2_user_before_points = get_points("test2@example.com")
|
||||
|
||||
rule = create_energy_point_rule_for_todo(for_assigned_users=1)
|
||||
|
||||
todo.status = "Closed"
|
||||
todo.save()
|
||||
|
||||
test_user_after_points = get_points("test@example.com")
|
||||
test2_user_after_points = get_points("test2@example.com")
|
||||
|
||||
self.assertEqual(test_user_after_points, test_user_before_points + rule.points)
|
||||
|
||||
self.assertEqual(test2_user_after_points, test2_user_before_points + rule.points)
|
||||
|
||||
@skipIf(
|
||||
frappe.conf.db_type == "sqlite",
|
||||
"Not for SQLite for now",
|
||||
)
|
||||
def test_eps_heatmap_query(self):
|
||||
# Just asserts that query works, not correctness.
|
||||
self.assertIsInstance(get_energy_points_heatmap_data(user="test@example.com", date=None), dict)
|
||||
|
||||
def test_points_on_field_value_change(self):
|
||||
rule = create_energy_point_rule_for_todo(for_doc_event="Value Change", field_to_check="description")
|
||||
|
||||
frappe.set_user("test@example.com")
|
||||
points_before_todo_creation = get_points("test@example.com")
|
||||
todo = create_a_todo()
|
||||
todo.status = "Closed"
|
||||
todo.save()
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
self.assertEqual(points_after_closing_todo, points_before_todo_creation)
|
||||
|
||||
todo.description = "This is new todo"
|
||||
todo.save()
|
||||
points_after_changing_todo_description = get_points("test@example.com")
|
||||
self.assertEqual(points_after_changing_todo_description, points_before_todo_creation + rule.points)
|
||||
|
||||
def test_apply_only_once(self):
|
||||
frappe.set_user("test@example.com")
|
||||
todo_point_rule = create_energy_point_rule_for_todo(apply_once=True, user_field="modified_by")
|
||||
first_user_points = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
|
||||
first_user_points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
self.assertEqual(first_user_points_after_closing_todo, first_user_points + todo_point_rule.points)
|
||||
|
||||
frappe.set_user("test2@example.com")
|
||||
second_user_points = get_points("test2@example.com")
|
||||
created_todo.save(ignore_permissions=True)
|
||||
second_user_points_after_closing_todo = get_points("test2@example.com")
|
||||
|
||||
# point should not be awarded more than once for same doc (irrespective of user)
|
||||
self.assertEqual(second_user_points_after_closing_todo, second_user_points)
|
||||
|
||||
def test_allow_creation_of_new_log_if_the_previous_log_was_reverted(self):
|
||||
frappe.set_user("test@example.com")
|
||||
todo_point_rule = create_energy_point_rule_for_todo()
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
log_name = frappe.db.exists("Energy Point Log", {"reference_name": created_todo.name})
|
||||
frappe.get_doc("Energy Point Log", log_name).revert("Just for test")
|
||||
points_after_reverting_todo = get_points("test@example.com")
|
||||
created_todo.save()
|
||||
points_after_saving_todo_again = get_points("test@example.com")
|
||||
|
||||
rule_points = todo_point_rule.points
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user + rule_points)
|
||||
self.assertEqual(points_after_reverting_todo, points_after_closing_todo - rule_points)
|
||||
self.assertEqual(points_after_saving_todo_again, points_after_reverting_todo + rule_points)
|
||||
|
||||
def test_energy_points_disabled_user(self):
|
||||
frappe.set_user("test@example.com")
|
||||
user = frappe.get_doc("User", "test@example.com")
|
||||
user.enabled = 0
|
||||
user.save()
|
||||
todo_point_rule = create_energy_point_rule_for_todo()
|
||||
energy_point_of_user = get_points("test@example.com")
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = "Closed"
|
||||
created_todo.save()
|
||||
points_after_closing_todo = get_points("test@example.com")
|
||||
|
||||
# do not update energy points for disabled user
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user)
|
||||
|
||||
with self.set_user("Administrator"):
|
||||
user.enabled = 1
|
||||
user.save()
|
||||
|
||||
created_todo.save()
|
||||
points_after_re_saving_todo = get_points("test@example.com")
|
||||
self.assertEqual(points_after_re_saving_todo, energy_point_of_user + todo_point_rule.points)
|
||||
|
||||
|
||||
def create_energy_point_rule_for_todo(
|
||||
multiplier_field=None,
|
||||
for_doc_event="Custom",
|
||||
max_points=None,
|
||||
for_assigned_users=0,
|
||||
field_to_check=None,
|
||||
apply_once=False,
|
||||
user_field="owner",
|
||||
):
|
||||
name = "ToDo Closed"
|
||||
point_rule_exists = frappe.db.exists("Energy Point Rule", name)
|
||||
|
||||
if point_rule_exists:
|
||||
return frappe.get_doc("Energy Point Rule", name)
|
||||
|
||||
return frappe.get_doc(
|
||||
{
|
||||
"doctype": "Energy Point Rule",
|
||||
"rule_name": name,
|
||||
"points": 5,
|
||||
"reference_doctype": "ToDo",
|
||||
"condition": 'doc.status == "Closed"',
|
||||
"for_doc_event": for_doc_event,
|
||||
"user_field": user_field,
|
||||
"for_assigned_users": for_assigned_users,
|
||||
"multiplier_field": multiplier_field,
|
||||
"max_points": max_points,
|
||||
"field_to_check": field_to_check,
|
||||
"apply_only_once": apply_once,
|
||||
}
|
||||
).insert(ignore_permissions=1)
|
||||
|
||||
|
||||
def create_a_todo(description=None):
|
||||
if not description:
|
||||
description = "Fix a bug"
|
||||
return frappe.get_doc(
|
||||
{
|
||||
"doctype": "ToDo",
|
||||
"description": description,
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def get_points(user, point_type="energy_points"):
|
||||
return _get_energy_points(user).get(point_type, 0)
|
||||
|
||||
|
||||
def assign_users_to_todo(todo_name, users):
|
||||
for user in users:
|
||||
assign_to({"assign_to": [user], "doctype": "ToDo", "name": todo_name})
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (c) 2018, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Energy Point Rule", {
|
||||
validate(frm) {
|
||||
frm.set_df_property("user_field", "reqd", !frm.doc.for_assigned_users);
|
||||
frm.set_df_property("condition", "reqd", frm.doc.for_doc_event === "Custom");
|
||||
},
|
||||
refresh(frm) {
|
||||
frm.events.set_field_options(frm);
|
||||
},
|
||||
for_doc_event(frm) {
|
||||
if (frm.doc.for_assigned_users) {
|
||||
frm.set_value("for_assigned_users", !frm.doc.for_doc_event === "New");
|
||||
}
|
||||
},
|
||||
reference_doctype(frm) {
|
||||
frm.events.set_field_options(frm);
|
||||
},
|
||||
set_field_options(frm) {
|
||||
// sets options for field_to_check, user_field and multiplier fields
|
||||
// based on reference doctype
|
||||
const reference_doctype = frm.doc.reference_doctype;
|
||||
if (!reference_doctype) return;
|
||||
|
||||
frappe.model.with_doctype(reference_doctype, () => {
|
||||
const map_for_options = (df) => ({ label: df.label, value: df.fieldname });
|
||||
const fields = frappe.meta
|
||||
.get_docfields(frm.doc.reference_doctype)
|
||||
.filter(frappe.model.is_value_type);
|
||||
|
||||
const fields_to_check = fields.map(map_for_options);
|
||||
|
||||
const user_fields = fields
|
||||
.filter(
|
||||
(df) =>
|
||||
(df.fieldtype === "Link" && df.options === "User") ||
|
||||
df.fieldtype === "Data"
|
||||
)
|
||||
.map(map_for_options)
|
||||
.concat([
|
||||
{ label: __("Owner"), value: "owner" },
|
||||
{ label: __("Modified By"), value: "modified_by" },
|
||||
]);
|
||||
|
||||
const multiplier_fields = fields
|
||||
.filter((df) => ["Int", "Float"].includes(df.fieldtype))
|
||||
.map(map_for_options);
|
||||
|
||||
// blank option for the ability to unset the multiplier field
|
||||
multiplier_fields.unshift(null);
|
||||
|
||||
frm.set_df_property("field_to_check", "options", fields_to_check);
|
||||
frm.set_df_property("user_field", "options", user_fields);
|
||||
frm.set_df_property("multiplier_field", "options", multiplier_fields);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
{
|
||||
"actions": [],
|
||||
"autoname": "field:rule_name",
|
||||
"creation": "2018-06-20 10:08:36.275253",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"section_break_2",
|
||||
"rule_name",
|
||||
"reference_doctype",
|
||||
"for_doc_event",
|
||||
"field_to_check",
|
||||
"points",
|
||||
"for_assigned_users",
|
||||
"user_field",
|
||||
"multiplier_field",
|
||||
"max_points",
|
||||
"column_break_12",
|
||||
"apply_only_once",
|
||||
"condition"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Enabled",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rule_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Rule Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Reference Document Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:['Custom', 'Value Change'].includes(doc.for_doc_event)",
|
||||
"description": "If the condition is satisfied user will be rewarded with the points. eg. doc.status == 'Closed'\n",
|
||||
"fieldname": "condition",
|
||||
"fieldtype": "Code",
|
||||
"in_list_view": 1,
|
||||
"label": "Condition"
|
||||
},
|
||||
{
|
||||
"fieldname": "points",
|
||||
"fieldtype": "Int",
|
||||
"label": "Points",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.for_assigned_users || doc.for_doc_event==='New'",
|
||||
"description": "The user from this field will be rewarded points",
|
||||
"fieldname": "user_field",
|
||||
"fieldtype": "Select",
|
||||
"label": "User Field"
|
||||
},
|
||||
{
|
||||
"fieldname": "multiplier_field",
|
||||
"fieldtype": "Select",
|
||||
"label": "Multiplier Field"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.multiplier_field",
|
||||
"description": "Maximum points allowed after multiplying points with the multiplier value\n(Note: For no limit leave this field empty or set 0)",
|
||||
"fieldname": "max_points",
|
||||
"fieldtype": "Int",
|
||||
"label": "Maximum Points"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "Custom",
|
||||
"fieldname": "for_doc_event",
|
||||
"fieldtype": "Select",
|
||||
"label": "For Document Event",
|
||||
"options": "New\nSubmit\nCancel\nValue Change\nCustom"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.for_doc_event !=='New'",
|
||||
"description": "Users assigned to the reference document will get points.",
|
||||
"fieldname": "for_assigned_users",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allot Points To Assigned Users"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.for_doc_event=='Value Change'",
|
||||
"fieldname": "field_to_check",
|
||||
"fieldtype": "Select",
|
||||
"label": "Field To Check"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_12",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Apply this rule only once per document",
|
||||
"fieldname": "apply_only_once",
|
||||
"fieldtype": "Check",
|
||||
"label": "Apply Only Once"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-23 16:03:25.142267",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Social",
|
||||
"name": "Energy Point Rule",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
# Copyright (c) 2018, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
import frappe
|
||||
import frappe.cache_manager
|
||||
from frappe import _
|
||||
from frappe.core.doctype.user.user import get_enabled_users
|
||||
from frappe.model import log_types
|
||||
from frappe.model.document import Document
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import create_energy_points_log
|
||||
from frappe.social.doctype.energy_point_settings.energy_point_settings import (
|
||||
is_energy_point_enabled,
|
||||
)
|
||||
|
||||
|
||||
class EnergyPointRule(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
apply_only_once: DF.Check
|
||||
condition: DF.Code | None
|
||||
enabled: DF.Check
|
||||
field_to_check: DF.Literal[None]
|
||||
for_assigned_users: DF.Check
|
||||
for_doc_event: DF.Literal["New", "Submit", "Cancel", "Value Change", "Custom"]
|
||||
max_points: DF.Int
|
||||
multiplier_field: DF.Literal[None]
|
||||
points: DF.Int
|
||||
reference_doctype: DF.Link
|
||||
rule_name: DF.Data
|
||||
user_field: DF.Literal[None]
|
||||
# end: auto-generated types
|
||||
|
||||
def on_update(self):
|
||||
frappe.cache_manager.clear_doctype_map("Energy Point Rule", self.reference_doctype)
|
||||
|
||||
def on_trash(self):
|
||||
frappe.cache_manager.clear_doctype_map("Energy Point Rule", self.reference_doctype)
|
||||
|
||||
def apply(self, doc):
|
||||
if self.rule_condition_satisfied(doc):
|
||||
multiplier = 1
|
||||
|
||||
points = self.points
|
||||
if self.multiplier_field:
|
||||
multiplier = doc.get(self.multiplier_field) or 1
|
||||
points = round(points * multiplier)
|
||||
max_points = self.max_points
|
||||
if max_points and points > max_points:
|
||||
points = max_points
|
||||
|
||||
reference_doctype = doc.doctype
|
||||
reference_name = doc.name
|
||||
users = []
|
||||
if self.for_assigned_users:
|
||||
users = doc.get_assigned_users()
|
||||
else:
|
||||
users = [doc.get(self.user_field)]
|
||||
rule = self.name
|
||||
|
||||
# incase of zero as result after roundoff
|
||||
if not points:
|
||||
return
|
||||
|
||||
try:
|
||||
for user in users:
|
||||
if not is_eligible_user(user):
|
||||
continue
|
||||
create_energy_points_log(
|
||||
reference_doctype,
|
||||
reference_name,
|
||||
{"points": points, "user": user, "rule": rule},
|
||||
self.apply_only_once,
|
||||
)
|
||||
except Exception:
|
||||
self.log_error("Energy points failed")
|
||||
|
||||
def rule_condition_satisfied(self, doc):
|
||||
if self.for_doc_event == "New":
|
||||
# indicates that this was a new doc
|
||||
return doc.get_doc_before_save() is None
|
||||
if self.for_doc_event == "Submit":
|
||||
return doc.docstatus.is_submitted()
|
||||
if self.for_doc_event == "Cancel":
|
||||
return doc.docstatus.is_cancelled()
|
||||
if self.for_doc_event == "Value Change":
|
||||
field_to_check = self.field_to_check
|
||||
if not field_to_check:
|
||||
return False
|
||||
doc_before_save = doc.get_doc_before_save()
|
||||
# check if the field has been changed
|
||||
# if condition is set check if it is satisfied
|
||||
return (
|
||||
doc_before_save
|
||||
and doc_before_save.get(field_to_check) != doc.get(field_to_check)
|
||||
and (not self.condition or self.eval_condition(doc))
|
||||
)
|
||||
|
||||
if self.for_doc_event == "Custom" and self.condition:
|
||||
return self.eval_condition(doc)
|
||||
return False
|
||||
|
||||
def eval_condition(self, doc):
|
||||
return self.condition and frappe.safe_eval(self.condition, None, {"doc": doc.as_dict()})
|
||||
|
||||
|
||||
def process_energy_points(doc, state):
|
||||
if (
|
||||
frappe.flags.in_patch
|
||||
or frappe.flags.in_install
|
||||
or frappe.flags.in_migrate
|
||||
or frappe.flags.in_import
|
||||
or frappe.flags.in_setup_wizard
|
||||
or doc.doctype in log_types
|
||||
):
|
||||
return
|
||||
|
||||
if not is_energy_point_enabled():
|
||||
return
|
||||
|
||||
old_doc = doc.get_doc_before_save()
|
||||
|
||||
# check if doc has been cancelled
|
||||
if old_doc and old_doc.docstatus.is_submitted() and doc.docstatus.is_cancelled():
|
||||
return revert_points_for_cancelled_doc(doc)
|
||||
|
||||
for d in frappe.cache_manager.get_doctype_map(
|
||||
"Energy Point Rule", doc.doctype, dict(reference_doctype=doc.doctype, enabled=1)
|
||||
):
|
||||
frappe.get_doc("Energy Point Rule", d.get("name")).apply(doc)
|
||||
|
||||
|
||||
def revert_points_for_cancelled_doc(doc):
|
||||
energy_point_logs = frappe.get_all(
|
||||
"Energy Point Log",
|
||||
{"reference_doctype": doc.doctype, "reference_name": doc.name, "type": "Auto"},
|
||||
)
|
||||
for log in energy_point_logs:
|
||||
reference_log = frappe.get_doc("Energy Point Log", log.name)
|
||||
reference_log.revert(_("Reference document has been cancelled"), ignore_permissions=True)
|
||||
|
||||
|
||||
def get_energy_point_doctypes():
|
||||
return [
|
||||
d.reference_doctype
|
||||
for d in frappe.get_all("Energy Point Rule", ["reference_doctype"], {"enabled": 1})
|
||||
]
|
||||
|
||||
|
||||
def is_eligible_user(user):
|
||||
"""Checks if user is eligible to get energy points"""
|
||||
enabled_users = get_enabled_users()
|
||||
return user and user in enabled_users and user != "Administrator"
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2019, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Energy Point Settings", {
|
||||
refresh: function (frm) {
|
||||
if (frm.doc.enabled) {
|
||||
frm.add_custom_button(__("Give Review Points"), show_review_points_dialog);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function show_review_points_dialog() {
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: __("Give Review Points"),
|
||||
fields: [
|
||||
{
|
||||
label: "User",
|
||||
fieldname: "user",
|
||||
fieldtype: "Link",
|
||||
options: "User",
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
label: "Points",
|
||||
fieldname: "points",
|
||||
fieldtype: "Int",
|
||||
reqd: 1,
|
||||
},
|
||||
],
|
||||
primary_action: function (values) {
|
||||
frappe
|
||||
.xcall(
|
||||
"frappe.social.doctype.energy_point_log.energy_point_log.add_review_points",
|
||||
{
|
||||
user: values.user,
|
||||
points: values.points,
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
frappe.show_alert({
|
||||
message: __("Successfully Done"),
|
||||
indicator: "green",
|
||||
});
|
||||
})
|
||||
.finally(() => dialog.hide());
|
||||
},
|
||||
primary_action_label: __("Submit"),
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2019-03-19 13:17:51.710241",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"section_break_2",
|
||||
"review_levels",
|
||||
"point_allocation_periodicity",
|
||||
"last_point_allocation_date"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"depends_on": "enabled",
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "review_levels",
|
||||
"fieldtype": "Table",
|
||||
"label": "Review Levels",
|
||||
"options": "Review Level"
|
||||
},
|
||||
{
|
||||
"default": "Weekly",
|
||||
"fieldname": "point_allocation_periodicity",
|
||||
"fieldtype": "Select",
|
||||
"label": "Point Allocation Periodicity",
|
||||
"options": "Daily\nWeekly\nMonthly"
|
||||
},
|
||||
{
|
||||
"fieldname": "last_point_allocation_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Last Point Allocation Date",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-23 16:03:25.273422",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Social",
|
||||
"name": "Energy Point Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
# Copyright (c) 2019, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import create_review_points_log
|
||||
from frappe.utils import add_to_date, getdate, today
|
||||
|
||||
|
||||
class EnergyPointSettings(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.social.doctype.review_level.review_level import ReviewLevel
|
||||
from frappe.types import DF
|
||||
|
||||
enabled: DF.Check
|
||||
last_point_allocation_date: DF.Date | None
|
||||
point_allocation_periodicity: DF.Literal["Daily", "Weekly", "Monthly"]
|
||||
review_levels: DF.Table[ReviewLevel]
|
||||
# end: auto-generated types
|
||||
|
||||
def on_update(self):
|
||||
if self.has_value_changed("enabled"):
|
||||
frappe.cache.delete_key("bootinfo")
|
||||
|
||||
|
||||
def is_energy_point_enabled():
|
||||
return frappe.client_cache.get_doc("Energy Point Settings").enabled
|
||||
|
||||
|
||||
def allocate_review_points():
|
||||
settings = frappe.get_single("Energy Point Settings")
|
||||
|
||||
if not can_allocate_today(settings.last_point_allocation_date, settings.point_allocation_periodicity):
|
||||
return
|
||||
|
||||
user_point_map = {}
|
||||
|
||||
for level in settings.review_levels:
|
||||
users = get_users_with_role(level.role)
|
||||
for user in users:
|
||||
user_point_map.setdefault(user, 0)
|
||||
# to avoid duplicate point allocation
|
||||
user_point_map[user] = max([user_point_map[user], level.review_points])
|
||||
|
||||
for user, points in user_point_map.items():
|
||||
create_review_points_log(user, points)
|
||||
|
||||
settings.last_point_allocation_date = today()
|
||||
settings.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def can_allocate_today(last_date, periodicity):
|
||||
if not last_date:
|
||||
return True
|
||||
|
||||
days_to_add = {"Daily": 1, "Weekly": 7, "Monthly": 30}.get(periodicity, 1)
|
||||
|
||||
next_allocation_date = add_to_date(last_date, days=days_to_add)
|
||||
|
||||
return getdate(next_allocation_date) <= getdate()
|
||||
|
||||
|
||||
def get_users_with_role(role):
|
||||
return [
|
||||
p[0]
|
||||
for p in frappe.db.sql(
|
||||
"""SELECT DISTINCT `tabUser`.`name`
|
||||
FROM `tabHas Role`, `tabUser`
|
||||
WHERE `tabHas Role`.`role`=%s
|
||||
AND `tabUser`.`name`!='Administrator'
|
||||
AND `tabHas Role`.`parent`=`tabUser`.`name`
|
||||
AND `tabUser`.`enabled`=1""",
|
||||
role,
|
||||
)
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright (c) 2021, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests import IntegrationTestCase, UnitTestCase
|
||||
|
||||
|
||||
class UnitTestEnergyPointSettings(UnitTestCase):
|
||||
"""
|
||||
Unit tests for EnergyPointSettings.
|
||||
Use this class for testing individual functions and methods.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestEnergyPointSettings(IntegrationTestCase):
|
||||
pass
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// Copyright (c) 2019, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Review Level", {
|
||||
// refresh: function(frm) {
|
||||
// }
|
||||
});
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2019-03-19 13:16:12.762352",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"level_name",
|
||||
"role",
|
||||
"review_points"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "level_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Level Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "role",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Role",
|
||||
"options": "Role",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "review_points",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Review Points",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-23 16:03:36.743533",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Social",
|
||||
"name": "Review Level",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Copyright (c) 2019, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class ReviewLevel(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
level_name: DF.Data
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
review_points: DF.Int
|
||||
role: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
Loading…
Add table
Reference in a new issue