Daily work summary refactor (#12944)
* added daily work summary setting doctype and code to support feature this will allow multiple setting for daily work summary * added daily work summary setting user doctype * made changes in daily work summary code * [minor] entry change in hr config file * deleted previous daily work summary settings (and its company) doctype * removed unwanted permission check * toggled read_only option for enabled field * removed print statements * add patch for the changes * doc changes * [minor] indentation fix * fixed tests * indentation fixes * codacy issue fix * formatting fixes * renamed doctype Renamed Daily Work Summary Setting to Daily Work Summary Group and did related code and doc changes * fixed typo * updated doc * codacy issue fix * [minor] renamed doctype name in json * Renamed old doctype * fixed indentation * codacy fix * indentation fix * renamed doctype * handled patch exception * fixed exception * Update daily_work_summary_group.py * rename patch file removed abbreviation in file name * handled exception in patch code * removed Unnecessary pass statement * [minor] indentation fix
This commit is contained in:
parent
b8c088edb7
commit
d3069fee4d
@ -244,8 +244,8 @@ def get_data():
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Daily Work Summary Settings"
|
||||
},
|
||||
"name": "Daily Work Summary Group"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1,15 +1,24 @@
|
||||
# Daily Work Summary
|
||||
|
||||
Daily Work Summary is way to get a automated way to get a summary of work done by all employees in a company. Once you set it up, each active Employee of the Company gets an email asking them what did they work on during the day.
|
||||
Daily Work Summary is way to get a automated way to get a summary of work done by users.
|
||||
|
||||
Replies of all users who choose to respond is collected and sent as a summary at midnight. Emails are only sent based on the Holiday List selected for the group
|
||||
|
||||
**Note:**
|
||||
> You must have one active incoming email account setup for this to work.
|
||||
|
||||
Replies of all employees who choose to respond is collected and sent as a summary at midnight. Emails are only sent based on the Holiday List setup in the Company or Employee master.
|
||||
|
||||
*Note:* You must have one active incoming email account setup for this to work.
|
||||
|
||||
### How to Use
|
||||
|
||||
Go to "Daily Work Summary Settings" via HR module or search bar and set the company for which you want to activate this feature.
|
||||
Go to "Daily Work Summary Group" via HR module or search bar and set the users for whom you want to send the reminder.
|
||||
|
||||
You can also choose to Customize the Message you send to your employees:
|
||||
You can set multiple groups with different set of _users_ from your user list with different _time to send emails_ and with separate _holiday list_ for each.
|
||||
|
||||
You can also choose to customize the _Message_ you send to users.
|
||||
|
||||
**Note:**
|
||||
>1. If no holiday list is selected then the email will be sent every day.
|
||||
>2. Name of a "Daily Work Summary Group" will be sent as the title for daily summary email.
|
||||
>3. Mail will not be sent to the users of a disabled Daily Work Summary Group.
|
||||
|
||||
<img class="screenshot" alt="Department" src="{{docs_base_url}}/assets/img/human-resources/department.png">
|
||||
|
@ -218,7 +218,7 @@ doc_events = {
|
||||
scheduler_events = {
|
||||
"hourly": [
|
||||
"erpnext.accounts.doctype.subscription.subscription.make_subscription_entry",
|
||||
'erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.trigger_emails'
|
||||
'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails'
|
||||
],
|
||||
"daily": [
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
@ -230,7 +230,7 @@ scheduler_events = {
|
||||
"erpnext.hr.doctype.employee.employee.send_birthday_reminders",
|
||||
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
||||
"erpnext.assets.doctype.asset.depreciation.post_depreciation_entries",
|
||||
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
|
||||
"erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.send_summary",
|
||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
|
||||
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
|
||||
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history",
|
||||
|
@ -2,7 +2,7 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Daily Work Summary', {
|
||||
refresh: function(frm) {
|
||||
refresh: function (frm) {
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@ -12,22 +13,24 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldname": "daily_work_summary_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"label": "Daily Work Summary Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"options": "Daily Work Summary Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -41,6 +44,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -52,6 +56,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": "Status",
|
||||
@ -71,6 +76,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -81,6 +87,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": "Email Sent To",
|
||||
@ -99,17 +106,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 1,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-21 01:05:55.258867",
|
||||
"modified": "2018-02-16 11:02:06.727749",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Daily Work Summary",
|
||||
@ -126,7 +133,6 @@
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
@ -147,7 +153,6 @@
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
@ -162,7 +167,9 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
@ -11,52 +11,66 @@ from erpnext.hr.doctype.employee.employee import is_holiday
|
||||
from frappe.utils import global_date_format
|
||||
from markdown2 import markdown
|
||||
|
||||
|
||||
class DailyWorkSummary(Document):
|
||||
def send_mails(self, settings, emails):
|
||||
'''Send emails to get daily work summary to all employees'''
|
||||
def send_mails(self, dws_group, emails):
|
||||
'''Send emails to get daily work summary to all users \
|
||||
in selected daily work summary group'''
|
||||
incoming_email_account = frappe.db.get_value('Email Account',
|
||||
dict(enable_incoming=1, default_incoming=1), 'email_id')
|
||||
dict(enable_incoming=1, default_incoming=1),
|
||||
'email_id')
|
||||
|
||||
self.db_set('email_sent_to', '\n'.join(emails))
|
||||
frappe.sendmail(recipients = emails, message = settings.message,
|
||||
subject = settings.subject, reference_doctype=self.doctype,
|
||||
reference_name=self.name, reply_to = incoming_email_account)
|
||||
frappe.sendmail(recipients=emails,
|
||||
message=dws_group.message,
|
||||
subject=dws_group.subject,
|
||||
reference_doctype=self.doctype,
|
||||
reference_name=self.name,
|
||||
reply_to=incoming_email_account)
|
||||
|
||||
def send_summary(self):
|
||||
'''Send summary of all replies. Called at midnight'''
|
||||
args = self.get_message_details()
|
||||
|
||||
frappe.sendmail(recipients = get_employee_emails(self.company, False),
|
||||
emails = get_user_emails_from_group(self.daily_work_summary_group)
|
||||
frappe.sendmail(recipients=emails,
|
||||
template='daily_work_summary',
|
||||
args=args,
|
||||
subject = _('Daily Work Summary for {0}').format(self.company),
|
||||
reference_doctype=self.doctype, reference_name=self.name)
|
||||
subject=_(self.daily_work_summary_group),
|
||||
reference_doctype=self.doctype,
|
||||
reference_name=self.name)
|
||||
|
||||
self.db_set('status', 'Sent')
|
||||
|
||||
def get_message_details(self):
|
||||
'''Return args for template'''
|
||||
settings = frappe.get_doc('Daily Work Summary Settings')
|
||||
dws_group = frappe.get_doc('Daily Work Summary Group',
|
||||
self.daily_work_summary_group)
|
||||
|
||||
replies = frappe.get_all('Communication', fields=['content', 'text_content', 'sender'],
|
||||
filters=dict(reference_doctype=self.doctype, reference_name=self.name,
|
||||
communication_type='Communication', sent_or_received='Received'),
|
||||
order_by='creation asc')
|
||||
replies = frappe.get_all('Communication',
|
||||
fields=['content', 'text_content', 'sender'],
|
||||
filters=dict(reference_doctype=self.doctype,
|
||||
reference_name=self.name,
|
||||
communication_type='Communication',
|
||||
sent_or_received='Received'),
|
||||
order_by='creation asc')
|
||||
|
||||
did_not_reply = self.email_sent_to.split()
|
||||
|
||||
for d in replies:
|
||||
emp = frappe.db.get_values("Employee", {"user_id": d.sender},
|
||||
["employee_name", "image"], as_dict=True)
|
||||
user = frappe.db.get_values("User",
|
||||
{"email": d.sender},
|
||||
["full_name", "user_image"],
|
||||
as_dict=True)
|
||||
|
||||
d.sender_name = user[0].full_name if user else d.sender
|
||||
d.image = user[0].image if user and user[0].image else None
|
||||
|
||||
d.sender_name = emp[0].employee_name if emp else d.sender
|
||||
d.image = emp[0].image if emp and emp[0].image else None
|
||||
|
||||
original_image = d.image
|
||||
# make thumbnail image
|
||||
try:
|
||||
if original_image:
|
||||
file_name = frappe.get_list('File', {'file_url': original_image})
|
||||
file_name = frappe.get_list('File',
|
||||
{'file_url': original_image})
|
||||
|
||||
if file_name:
|
||||
file_name = file_name[0].name
|
||||
@ -74,34 +88,27 @@ class DailyWorkSummary(Document):
|
||||
if d.sender in did_not_reply:
|
||||
did_not_reply.remove(d.sender)
|
||||
if d.text_content:
|
||||
d.content = markdown(EmailReplyParser.parse_reply(d.text_content))
|
||||
d.content = markdown(
|
||||
EmailReplyParser.parse_reply(d.text_content)
|
||||
)
|
||||
|
||||
|
||||
did_not_reply = [(frappe.db.get_value("Employee", {"user_id": email}, "employee_name") or email)
|
||||
did_not_reply = [(frappe.db.get_value("User", {"email": email}, "full_name") or email)
|
||||
for email in did_not_reply]
|
||||
|
||||
return dict(replies=replies,
|
||||
original_message=settings.message,
|
||||
title=_('Daily Work Summary for {0}'.format(global_date_format(self.creation))),
|
||||
did_not_reply= ', '.join(did_not_reply) or '',
|
||||
did_not_reply_title = _('No replies from'))
|
||||
original_message=dws_group.message,
|
||||
title=_('Work Summary for {0}'.format(
|
||||
global_date_format(self.creation)
|
||||
)),
|
||||
did_not_reply=', '.join(did_not_reply) or '',
|
||||
did_not_reply_title=_('No replies from'))
|
||||
|
||||
|
||||
def get_employee_emails(company, only_working=True):
|
||||
'''Returns list of Employee user ids for the given company who are working today
|
||||
|
||||
:param company: Company `name`'''
|
||||
employee_list = frappe.get_all('Employee', fields=['name', 'user_id'],
|
||||
filters={'status': 'Active', 'company': company})
|
||||
|
||||
out = []
|
||||
for e in employee_list:
|
||||
if e.user_id:
|
||||
if only_working and is_holiday(e.name):
|
||||
# don't add if holiday
|
||||
continue
|
||||
out.append(e.user_id)
|
||||
|
||||
return out
|
||||
def get_user_emails_from_group(group):
|
||||
'''Returns list of email of users from the given group
|
||||
|
||||
:param group: Daily Work Summary Group `name`'''
|
||||
group_doc = frappe.get_doc('Daily Work Summary Group', group)
|
||||
emails = [d.email for d in group_doc.users]
|
||||
|
||||
return emails
|
||||
|
@ -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: Daily Work Summary", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Daily Work Summary
|
||||
() => frappe.tests.make('Daily Work Summary', [
|
||||
// values to be set
|
||||
{ key: 'value' }
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -13,30 +13,31 @@ import frappe.utils
|
||||
class TestDailyWorkSummary(unittest.TestCase):
|
||||
def test_email_trigger(self):
|
||||
self.setup_and_prepare_test()
|
||||
for d in self.employees:
|
||||
# check that email is sent to this employee
|
||||
self.assertTrue(d.user_id in [d.recipient for d in self.emails
|
||||
if self.settings.subject in d.message])
|
||||
for d in self.users:
|
||||
# check that email is sent to users
|
||||
self.assertTrue(d.email in [d.recipient for d in self.emails
|
||||
if self.groups.subject in d.message])
|
||||
|
||||
def test_email_trigger_failed(self):
|
||||
hour = '00'
|
||||
if frappe.utils.nowtime().split(':')[0]=='00':
|
||||
hour = '01'
|
||||
hour = '00:00'
|
||||
if frappe.utils.nowtime().split(':')[0] == '00':
|
||||
hour = '01:00'
|
||||
|
||||
self.setup_and_prepare_test(hour)
|
||||
|
||||
for d in self.employees:
|
||||
# check that email is sent to this employee
|
||||
self.assertFalse(d.user_id in [d.recipient for d in self.emails
|
||||
if self.settings.subject in d.message])
|
||||
for d in self.users:
|
||||
# check that email is not sent to users
|
||||
self.assertFalse(d.email in [d.recipient for d in self.emails
|
||||
if self.groups.subject in d.message])
|
||||
|
||||
def test_incoming(self):
|
||||
# get test mail with message-id as in-reply-to
|
||||
self.setup_and_prepare_test()
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "test_data", "test-reply.raw"), "r") as f:
|
||||
test_mails = [f.read().replace('{{ sender }}', self.employees[-1].user_id)\
|
||||
.replace('{{ message_id }}', self.emails[-1].message_id)]
|
||||
test_mails = [f.read().replace('{{ sender }}',
|
||||
self.users[-1].email).replace('{{ message_id }}',
|
||||
self.emails[-1].message_id)]
|
||||
|
||||
# pull the mail
|
||||
email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
|
||||
@ -55,30 +56,38 @@ class TestDailyWorkSummary(unittest.TestCase):
|
||||
frappe.db.sql('delete from `tabEmail Queue`')
|
||||
frappe.db.sql('delete from `tabEmail Queue Recipient`')
|
||||
frappe.db.sql('delete from `tabCommunication`')
|
||||
frappe.db.sql('delete from `tabDaily Work Summary Group`')
|
||||
|
||||
self.setup_settings(hour)
|
||||
self.users = frappe.get_all('User',
|
||||
fields=['email'],
|
||||
filters=dict(email=('!=', 'test@example.com')))
|
||||
self.setup_groups(hour)
|
||||
|
||||
from erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings \
|
||||
from erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group \
|
||||
import trigger_emails
|
||||
trigger_emails()
|
||||
|
||||
# check if emails are created
|
||||
self.employees = frappe.get_all('Employee', fields = ['user_id'],
|
||||
filters=dict(company='_Test Company', status='Active', user_id=('!=', 'test@example.com')))
|
||||
|
||||
self.emails = frappe.db.sql("""select r.recipient, q.message, q.message_id from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r where q.name = r.parent""", as_dict=1)
|
||||
self.emails = frappe.db.sql("""select r.recipient, q.message, q.message_id \
|
||||
from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r \
|
||||
where q.name = r.parent""", as_dict=1)
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
def setup_settings(self, hour=None):
|
||||
# setup email to trigger at this our
|
||||
def setup_groups(self, hour=None):
|
||||
# setup email to trigger at this hour
|
||||
if not hour:
|
||||
hour = frappe.utils.nowtime().split(':')[0]
|
||||
self.settings = frappe.get_doc('Daily Work Summary Settings')
|
||||
self.settings.companies = []
|
||||
hour = hour+':00'
|
||||
|
||||
self.settings.append('companies', dict(company='_Test Company',
|
||||
send_emails_at=hour + ':00'))
|
||||
self.settings.test_subject = 'this is a subject for testing summary emails'
|
||||
self.settings.save()
|
||||
groups = frappe.get_doc(dict(doctype="Daily Work Summary Group",
|
||||
name="Daily Work Summary",
|
||||
users=self.users,
|
||||
send_emails_at=hour,
|
||||
subject="this is a subject for testing summary emails",
|
||||
message='this is a message for testing summary emails'))
|
||||
groups.insert()
|
||||
|
||||
self.groups = groups
|
||||
self.groups.save()
|
||||
|
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Daily Work Summary Group', {
|
||||
refresh: function (frm) {
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Daily Work Summary'), function () {
|
||||
frappe.set_route('List', 'Daily Work Summary');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,31 +1,35 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "Prompt",
|
||||
"beta": 0,
|
||||
"creation": "2016-11-08 04:55:08.231715",
|
||||
"creation": "2018-02-12 15:06:18.767239",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Emails will be sent to all Active Employees of the company at the given hour, if they do not have holiday. Summary of responses will be sent at midnight.",
|
||||
"fieldname": "select_companies",
|
||||
"fieldtype": "Section Break",
|
||||
"default": "1",
|
||||
"fieldname": "enabled",
|
||||
"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": "Select Companies",
|
||||
"label": "Enabled",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@ -41,22 +45,85 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "companies",
|
||||
"fieldname": "select_users",
|
||||
"fieldtype": "Section Break",
|
||||
"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": "Select Users",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "users",
|
||||
"fieldtype": "Table",
|
||||
"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": "Companies",
|
||||
"label": "Users",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Daily Work Summary Settings Company",
|
||||
"options": "Daily Work Summary Group User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "send_emails_at",
|
||||
"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": "Send Emails At",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "00:00\n01:00\n02:00\n03:00\n04:00\n05:00\n06:00\n07:00\n08:00\n09:00\n10:00\n11:00\n12:00\n13:00\n14:00\n15:00\n16:00\n17:00\n18:00\n19:00\n20:00\n21:00\n22:00\n23:00",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -70,19 +137,52 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "message_section",
|
||||
"fieldname": "holiday_list",
|
||||
"fieldtype": "Link",
|
||||
"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": "Holiday List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Holiday List",
|
||||
"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": "mail_details",
|
||||
"fieldtype": "Section Break",
|
||||
"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": "Message",
|
||||
"label": "Reminder",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@ -98,6 +198,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -109,6 +210,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": "Subject",
|
||||
@ -127,6 +229,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -138,6 +241,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": "Message",
|
||||
@ -156,20 +260,20 @@
|
||||
"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": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-21 00:55:20.726328",
|
||||
"modified": "2018-02-16 10:56:03.998495",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Daily Work Summary Settings",
|
||||
"name": "Daily Work Summary Group",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
@ -180,14 +284,13 @@
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
@ -198,7 +301,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
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
# # -*- coding: utf-8 -*-
|
||||
# # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# # For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
import frappe.utils
|
||||
from frappe import _
|
||||
|
||||
|
||||
class DailyWorkSummaryGroup(Document):
|
||||
def validate(self):
|
||||
if self.users:
|
||||
if not frappe.flags.in_test and not is_incoming_account_enabled():
|
||||
frappe.throw(_('Please enable default incoming account before creating Daily Work Summary Group'))
|
||||
|
||||
|
||||
def trigger_emails():
|
||||
'''Send emails to Employees at the given hour asking
|
||||
them what did they work on today'''
|
||||
groups = frappe.get_all("Daily Work Summary Group")
|
||||
for d in groups:
|
||||
group_doc = frappe.get_doc("Daily Work Summary Group", d)
|
||||
if (is_current_hour(group_doc.send_emails_at)
|
||||
and not is_holiday_today(group_doc.holiday_list)
|
||||
and group_doc.enabled):
|
||||
emails = [d.email for d in group_doc.users]
|
||||
# find emails relating to a company
|
||||
if emails:
|
||||
daily_work_summary = frappe.get_doc(
|
||||
dict(doctype='Daily Work Summary', daily_work_summary_group=group_doc.name)
|
||||
).insert()
|
||||
daily_work_summary.send_mails(group_doc, emails)
|
||||
|
||||
|
||||
def is_current_hour(hour):
|
||||
return frappe.utils.nowtime().split(':')[0] == hour.split(':')[0]
|
||||
|
||||
|
||||
def is_holiday_today(holiday_list):
|
||||
date = frappe.utils.today()
|
||||
if holiday_list:
|
||||
return frappe.get_all('Holiday List',
|
||||
dict(name=holiday_list, holiday_date=date)) and True or False
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def send_summary():
|
||||
'''Send summary to everyone'''
|
||||
for d in frappe.get_all('Daily Work Summary', dict(status='Open')):
|
||||
daily_work_summary = frappe.get_doc('Daily Work Summary', d.name)
|
||||
daily_work_summary.send_summary()
|
||||
|
||||
|
||||
def is_incoming_account_enabled():
|
||||
return frappe.db.get_value('Email Account', dict(enable_incoming=1, default_incoming=1))
|
@ -1,9 +1,10 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-11-08 05:44:02.502527",
|
||||
"creation": "2018-02-12 14:57:38.332692",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
@ -12,22 +13,24 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -35,29 +38,30 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"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,
|
||||
"default": "17:00",
|
||||
"fieldname": "send_emails_at",
|
||||
"fieldtype": "Select",
|
||||
"fieldname": "email",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Send Emails At",
|
||||
"label": "email",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "00:00\n01:00\n02:00\n03:00\n04:00\n05:00\n06:00\n07:00\n08:00\n09:00\n10:00\n11:00\n12:00\n13:00\n14:00\n15:00\n16:00\n17:00\n18:00\n19:00\n20:00\n21:00\n22:00\n23:00",
|
||||
"options": "user.email",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -65,33 +69,35 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"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-11-08 05:46:09.198788",
|
||||
"modified": "2018-02-12 15:57:01.332287",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Daily Work Summary Settings Company",
|
||||
"name": "Daily Work Summary Group User",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DailyWorkSummarySettingsCompany(Document):
|
||||
class DailyWorkSummaryGroupUser(Document):
|
||||
pass
|
@ -1,10 +0,0 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Daily Work Summary Settings', {
|
||||
refresh: function(frm) {
|
||||
frm.add_custom_button(__('Daily Work Summary'), function() {
|
||||
frappe.set_route('List', 'Daily Work Summary');
|
||||
});
|
||||
}
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
import frappe.utils
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_employee_emails
|
||||
|
||||
class DailyWorkSummarySettings(Document):
|
||||
def validate(self):
|
||||
if self.companies:
|
||||
if not frappe.flags.in_test and not frappe.db.get_value('Email Account', dict(enable_incoming=1,
|
||||
default_incoming=1)):
|
||||
frappe.throw(_('There must be a default incoming Email Account enabled for this to work. Please setup a default incoming Email Account (POP/IMAP) and try again.'))
|
||||
|
||||
def trigger_emails():
|
||||
'''Send emails to Employees of the enabled companies at the give hour asking
|
||||
them what did they work on today'''
|
||||
settings = frappe.get_doc('Daily Work Summary Settings')
|
||||
for d in settings.companies:
|
||||
# if current hour
|
||||
if frappe.utils.nowtime().split(':')[0] == d.send_emails_at.split(':')[0]:
|
||||
emails = get_employee_emails(d.company)
|
||||
# find emails relating to a company
|
||||
if emails:
|
||||
daily_work_summary = frappe.get_doc(dict(doctype='Daily Work Summary',
|
||||
company=d.company)).insert()
|
||||
daily_work_summary.send_mails(settings, emails)
|
||||
|
||||
def send_summary():
|
||||
'''Send summary to everyone'''
|
||||
for d in frappe.get_all('Daily Work Summary', dict(status='Open')):
|
||||
daily_work_summary = frappe.get_doc('Daily Work Summary', d.name)
|
||||
daily_work_summary.send_summary()
|
@ -8,9 +8,9 @@ frappe.pages['team-updates'].on_page_load = function(wrapper) {
|
||||
frappe.team_updates.make(page);
|
||||
frappe.team_updates.run();
|
||||
|
||||
if(frappe.model.can_read('Daily Work Summary Settings')) {
|
||||
page.add_menu_item(__('Daily Work Summary Settings'), function() {
|
||||
frappe.set_route('Form', 'Daily Work Summary Settings');
|
||||
if(frappe.model.can_read('Daily Work Summary Group')) {
|
||||
page.add_menu_item(__('Daily Work Summary Group'), function() {
|
||||
frappe.set_route('Form', 'Daily Work Summary Group');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -501,3 +501,4 @@ erpnext.patches.v10_0.set_b2c_limit
|
||||
erpnext.patches.v10_0.update_translatable_fields
|
||||
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
||||
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
|
||||
|
@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2018, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
# check if Daily Work Summary Settings Company table exists
|
||||
try:
|
||||
frappe.db.sql('DESC `tabDaily Work Summary Settings Company`')
|
||||
except Exception:
|
||||
return
|
||||
|
||||
# get the previously saved settings
|
||||
previous_setting = get_previous_setting()
|
||||
if previous_setting["companies"]:
|
||||
for d in previous_setting["companies"]:
|
||||
users = frappe.get_list("Employee", dict(
|
||||
company=d.company, user_id=("!=", " ")), "user_id as user")
|
||||
if(len(users)):
|
||||
# create new group entry for each company entry
|
||||
new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group",
|
||||
name="Daily Work Summary for " + d.company,
|
||||
users=users,
|
||||
send_emails_at=d.send_emails_at,
|
||||
subject=previous_setting["subject"],
|
||||
message=previous_setting["message"]))
|
||||
new_group.insert(ignore_permissions=True)
|
||||
new_group.save()
|
||||
frappe.delete_doc("Daily Work Summary Settings")
|
||||
frappe.delete_doc("Daily Work Summary Settings Company")
|
||||
|
||||
def get_setting_companies():
|
||||
return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
|
||||
|
||||
|
||||
def get_previous_setting():
|
||||
obj = {}
|
||||
setting_data = frappe.db.sql(
|
||||
"select field, value from tabSingles where doctype='Daily Work Summary Settings'")
|
||||
for field, value in setting_data:
|
||||
obj[field] = value
|
||||
obj["companies"] = get_setting_companies()
|
||||
return obj
|
@ -29,7 +29,7 @@ def check_setup_wizard_not_completed():
|
||||
|
||||
def set_single_defaults():
|
||||
for dt in ('Accounts Settings', 'Print Settings', 'HR Settings', 'Buying Settings',
|
||||
'Selling Settings', 'Stock Settings', 'Daily Work Summary Settings'):
|
||||
'Selling Settings', 'Stock Settings'):
|
||||
default_values = frappe.db.sql("""select fieldname, `default` from `tabDocField`
|
||||
where parent=%s""", dt)
|
||||
if default_values:
|
||||
|
Loading…
x
Reference in New Issue
Block a user