diff options
author | Markus Krogh <markus@nordu.net> | 2016-03-10 11:53:42 +0000 |
---|---|---|
committer | Markus Krogh <markus@nordu.net> | 2016-03-10 11:53:42 +0000 |
commit | 4575c7ea47680e7f589477c917a73353d6faef73 (patch) | |
tree | 5f1fb1d8d120b8d609b2018a5eb8e8ad30183952 | |
parent | 67abade3147d6d706c18beaac219d549fb71c35e (diff) |
Manager mail + ceo mail
-rw-r--r-- | maconomy/__init__.py | 3 | ||||
-rw-r--r-- | maconomy/cli.py | 3 | ||||
-rw-r--r-- | maconomy/models.py | 25 | ||||
-rw-r--r-- | maconomy/repositories.py | 6 | ||||
-rw-r--r-- | maconomy/templates.py | 35 | ||||
-rw-r--r-- | maconomy/views.py | 37 | ||||
-rw-r--r-- | maconomy_hours.py | 61 | ||||
-rw-r--r-- | templates/_employee_status.html | 6 | ||||
-rw-r--r-- | templates/ceo.html | 2 | ||||
-rw-r--r-- | templates/manager.html | 9 | ||||
-rw-r--r-- | test/templates/__init__.py | 0 | ||||
-rw-r--r-- | test/templates/test_ceo_template.py | 19 | ||||
-rw-r--r-- | test/templates/test_employee_status_template.py | 25 | ||||
-rw-r--r-- | test/templates/test_manager_template.py | 39 | ||||
-rw-r--r-- | test/templates/test_missing_email_template.py | 13 | ||||
-rw-r--r-- | test/templates/test_unsubmitted_email_template.py | 13 | ||||
-rw-r--r-- | test/test_templates.py | 61 | ||||
-rw-r--r-- | test/views/__init__.py | 0 | ||||
-rw-r--r-- | test/views/test_employee_email.py | 25 |
19 files changed, 291 insertions, 91 deletions
diff --git a/maconomy/__init__.py b/maconomy/__init__.py index 09f2516..6f51466 100644 --- a/maconomy/__init__.py +++ b/maconomy/__init__.py @@ -1,4 +1,5 @@ from maconomy.models import Employee, Timesheet from maconomy.repositories import create_db, TimeRegistrationRepository from maconomy.mailer import Mailer -from maconomy.templates import UnsubmittedEmailTemplate, MissingEmailTemplate, ManagerEmailTemplate +from maconomy.templates import * +from maconomy.views import * diff --git a/maconomy/cli.py b/maconomy/cli.py index 0a11db5..426e826 100644 --- a/maconomy/cli.py +++ b/maconomy/cli.py @@ -5,6 +5,9 @@ def parse(): parser = argparse.ArgumentParser(description="Notifies people of missing hours registration") parser.add_argument("-c", "--config", required=True) parser.add_argument("--dry", action="store_true", default=False, help="Do not send emails to users, but print affected users instead") + parser.add_argument("--manager", action="store_true", default=False, help="Sends email to managers about employees missing submission and not yet approved") + parser.add_argument("--ceo", action="store_true", default=False, help="Sends a executive summery employees missing submission and not yet approved") + parser.add_argument("--summary", action="store_true", default=False, help="Prints unsubmitted, missing and non approved status") return parser.parse_args() def load_config(conf_file): diff --git a/maconomy/models.py b/maconomy/models.py index 15fb46b..14629ca 100644 --- a/maconomy/models.py +++ b/maconomy/models.py @@ -1,15 +1,32 @@ class Employee: - def __init__(self, result): - self.id, self.name, self.email = result[:3] + def __init__(self, id, name, email): + self.id = id + self.name = name + self.email = email + @classmethod + def from_result(cls, result): + id, name, email = result[:3] + return cls(id, name, email) + def __unicode__(self): return u"{} ({})".format(self.name, self.id) class Timesheet: - def __init__(self, result): - self.week, self.submitted, self.approved = result[:3] + def __init__(self, week, submitted, approved, employee, approver): + self.week = week + self.submitted = submitted + self.approved = approved + self.employee = employee + self.approver = approver + + @classmethod + def from_result(cls, result): + employee = Employee.from_result(result) + week, submitted, approved, approver = result[3:7] + return cls(week, submitted, approved, employee, approver) def status(self): return "submitted" if self.is_submitted() else "unsubmitted" diff --git a/maconomy/repositories.py b/maconomy/repositories.py index fb143e8..2dcb019 100644 --- a/maconomy/repositories.py +++ b/maconomy/repositories.py @@ -1,5 +1,5 @@ import cx_Oracle -from maconomy.models import Employee, Timesheet +from maconomy.models import Timesheet def create_db(config): user = config.get("db", "user") @@ -17,7 +17,7 @@ class DBRepository: class TimeRegistrationRepository(DBRepository): def all_active(self): - query = """SELECT e.EMPLOYEENUMBER,e.NAME1,e.ELECTRONICMAILADDRESS, t.WEEKNUMBER, t.SUBMITTED, t.APPROVED from EMPLOYEE e + query = """SELECT e.EMPLOYEENUMBER,e.NAME1,e.ELECTRONICMAILADDRESS, t.WEEKNUMBER, t.SUBMITTED, t.APPROVED, e.SUPERIOREMPLOYEE from EMPLOYEE e LEFT OUTER JOIN TIMESHEETHEADER t ON e.EMPLOYEENUMBER = t.EMPLOYEENUMBER and t.PERIODSTART=to_char(trunc(sysdate-7, 'IW'),'YYYY.MM.DD') @@ -31,5 +31,5 @@ class TimeRegistrationRepository(DBRepository): res = self.cursor.execute(query) rows = res.fetchall() - return [(Employee(r), Timesheet(r[3:])) for r in rows] + return [Timesheet.from_result(r) for r in rows] diff --git a/maconomy/templates.py b/maconomy/templates.py index 07cbeb1..4889c48 100644 --- a/maconomy/templates.py +++ b/maconomy/templates.py @@ -30,11 +30,38 @@ class MissingEmailTemplate(BaseTemplate): class ManagerEmailTemplate(BaseTemplate): def __init__(self): self.set_template("templates/manager.html") + self.status_template = EmployeeStatusTemplate() - def build(self, employee, week, maconomyurl, **kwargs): - submitted = '' if 'submitted' in kwargs and kwargs['submitted'] else 'not' - approved = '' if 'approved' in kwargs and kwargs['approved'] else 'not' - return self.template.substitute(employee=employee.__unicode__(),week=week,maconomyurl=maconomyurl, submitted=submitted, approved=approved) + def build(self, timesheets, maconomyurl): + statuslist = self.build_statuslist(timesheets) + return self.template.substitute(statuslist=statuslist,maconomyurl=maconomyurl) + def build_statuslist(self, timesheets): + statuslist = [self.status_template.build(timesheet) for timesheet in timesheets] + return "\n".join(statuslist) +class EmployeeStatusTemplate(BaseTemplate): + def __init__(self, include_approver=False): + self.set_template("templates/_employee_status.html") + self.include_approver = include_approver + def build(self, timesheet): + employee = timesheet.employee + submitted = '' if timesheet.is_submitted() else 'not' + approver = timesheet.approver if self.include_approver else 'you' + approved = '' if timesheet.is_approved() else 'not' + return self.template.substitute(employee=employee.__unicode__(), submitted=submitted, approved=approved, approver=approver) + +class CEOEmailTemplate(BaseTemplate): + def __init__(self): + self.set_template("templates/ceo.html") + self.status_template = EmployeeStatusTemplate(include_approver=True) + + def build(self, timesheets): + statuslist = self.build_statuslist(timesheets) + return self.template.substitute(statuslist=statuslist) + + def build_statuslist(self, timesheets): + statuslist = [self.status_template.build(timesheet) for timesheet in timesheets] + return "\n".join(statuslist) + diff --git a/maconomy/views.py b/maconomy/views.py new file mode 100644 index 0000000..10e9c06 --- /dev/null +++ b/maconomy/views.py @@ -0,0 +1,37 @@ +from maconomy import MissingEmailTemplate, UnsubmittedEmailTemplate, ManagerEmailTemplate, CEOEmailTemplate + +class EmployeeEmailView(object): + def __init__(self, config): + self.missing_template = MissingEmailTemplate() + self.unsubmitted_template = UnsubmittedEmailTemplate() + self.maconomyurl = config.get("view", "maconomyurl") + self.helpurl = config.get("view", "helpurl") + + def render(self,timesheet): + if timesheet.is_missing(): + return self.missing_template.build( + maconomyurl=self.maconomyurl, + helpurl=self.helpurl) + elif not timesheet.is_submitted(): + return self.unsubmitted_template.build( + week=timesheet.week, + maconomyurl=self.maconomyurl, + helpurl=self.helpurl) + else: + return None + + +class ManagerEmailView(object): + def __init__(self, config): + self.maconomyurl = config.get("view", "maconomyurl") + self.template = ManagerEmailTemplate() + + def render(self, timesheets): + return self.template.build(timesheets, self.maconomyurl) + +class CEOEmailView(object): + def __init__(self): + self.template = CEOEmailTemplate() + + def render(self, timesheets): + return self.template.build(timesheets) diff --git a/maconomy_hours.py b/maconomy_hours.py index 1001964..62a328f 100644 --- a/maconomy_hours.py +++ b/maconomy_hours.py @@ -1,21 +1,62 @@ -from maconomy import cli, Employee, Timesheet, create_db, TimeRegistrationRepository +from maconomy import cli, create_db, TimeRegistrationRepository +from maconomy.views import EmployeeEmailView, ManagerEmailView, CEOEmailView -def main(config, dry_run): +def main(config, options): db = create_db(config) timereg_repo = TimeRegistrationRepository(db) + timesheets = timereg_repo.all_active() - for employee, timesheet in timereg_repo.all_active(): - if timesheet.is_missing(): - print u"Timesheet for {} has not been created".format(employee) - elif not timesheet.is_submitted(): - print u"Missing time sheet for {}".format(employee) - elif not timesheet.is_approved(): - print u"Timesheet for {} not approved".format(employee) + if options.manager: + manager(timesheets, config, options.dry) + elif options.ceo: + ceo(timesheets, config, options.dry) + elif options.summary: + summary(timesheets) + else: + normal(timesheets, config, options.dry) + # Close stuff timereg_repo.close() db.close() +def normal(timesheets, config, dry_run): + view = EmployeeEmailView(config) + for timesheet in timesheets: + if not timesheet.is_submitted(): + mail = view.render(timesheet) + subjct = u"Timesheet reminder for {}".format(timesheet.employee) + if dry_run: + print subjct + print mail + else: + pass +def manager(timesheets, config, dry_run): + relevant = [t for t in timesheets if need_manager_mail(t)] + view = ManagerEmailView(config) + mail = view.render(relevant) + if dry_run: + print mail + +def ceo(timesheets, config, dry_run): + relevant = [t for t in timesheets if need_manager_mail(t)] + view = CEOEmailView() + mail = view.render(relevant) + if dry_run: + print mail + +def need_manager_mail(timesheet): + return not timesheet.is_submitted() or not timesheet.is_approved() + +def summary(timesheets): + for timesheet in timesheets: + if timesheet.is_missing(): + print u"[Not created] {}".format(timesheet.employee) + elif not timesheet.is_submitted(): + print u"[Unsubmitted] {}".format(timesheet.employee) + elif not timesheet.is_approved(): + print u"[Not approved] {}".format(timesheet.employee) + if __name__ == '__main__': args = cli.parse() config = cli.load_config(args.config) - main(config, args.dry) + main(config, args) diff --git a/templates/_employee_status.html b/templates/_employee_status.html new file mode 100644 index 0000000..6e6095a --- /dev/null +++ b/templates/_employee_status.html @@ -0,0 +1,6 @@ +<p>Status for $employee + <ul> + <li>Timesheet has $submitted been submitted</li> + <li>Timesheet has $approved been approved by $approver.</li> + </ul> +</p> diff --git a/templates/ceo.html b/templates/ceo.html index ebc2ea9..8485009 100644 --- a/templates/ceo.html +++ b/templates/ceo.html @@ -1,3 +1,3 @@ <p>Time registration status mail.</p> -$status +$statuslist: diff --git a/templates/manager.html b/templates/manager.html index 6e956e2..2cb8054 100644 --- a/templates/manager.html +++ b/templates/manager.html @@ -1,10 +1,5 @@ -<p>Missing time registration for your employee $employee, please submit and approve before tuesday 2 AM (CET)</p> +<p>Missing time registrations for your employees, please submit and approve before tuesday 2 AM (CET)</p> -<p>Status for $employee in Week $week - <ul> - <li>Timesheet has $submitted been submitted</li> - <li>Timesheet has $approved been approved by you.</li> - </ul> -</p> +$statuslist <p>Please go to <a href="$maconomyurl">Maconomy Portal</a> to submit and approve time.</p> diff --git a/test/templates/__init__.py b/test/templates/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/templates/__init__.py diff --git a/test/templates/test_ceo_template.py b/test/templates/test_ceo_template.py new file mode 100644 index 0000000..6962a20 --- /dev/null +++ b/test/templates/test_ceo_template.py @@ -0,0 +1,19 @@ +from maconomy import CEOEmailTemplate, Timesheet +import unittest + +class CEOEmailTemplateTest(unittest.TestCase): + def setUp(self): + self.template = CEOEmailTemplate() + self.not_approved = Timesheet.from_result(("MK", "Markus Krogh", "markus@nordu.net", "11", 1, 0, "JK")) + self.not_submitted = Timesheet.from_result(("MKR", "Markus Krogh", "markusk@nordu.net", "11", 0, 0, "JKL")) + + def test_ceo_email(self): + result = self.template.build(timesheets=[self.not_approved, self.not_submitted]) + + self.assertIn("Markus Krogh (MKR)", result) + self.assertIn("Markus Krogh (MK)", result) + self.assertIn("has not been approved by JK", result) + self.assertIn("has not been approved by JKL", result) + self.assertIn("has been submitted", result) + self.assertIn("has not been submitted", result) + diff --git a/test/templates/test_employee_status_template.py b/test/templates/test_employee_status_template.py new file mode 100644 index 0000000..0d37d3e --- /dev/null +++ b/test/templates/test_employee_status_template.py @@ -0,0 +1,25 @@ +from maconomy import EmployeeStatusTemplate, Employee, Timesheet +import unittest + +class EmployeeStatusTemplateTest(unittest.TestCase): + + def setUp(self): + self.template = EmployeeStatusTemplate() + self.employee = Employee.from_result(("MK", "Markus Krogh", "markus@nordu.net")) + + def test_substitute(self): + timesheet = Timesheet("11", 0, 0, self.employee, "JK") + result = self.template.build(timesheet) + self.assertIn("Markus Krogh (MK)", result) + self.assertIn("not been submitted", result) + self.assertIn("not been approved", result) + + def test_submitted(self): + timesheet = Timesheet("11", submitted=1, approved=0, employee=self.employee, approver="JK") + result = self.template.build(timesheet) + self.assertIn("has been submitted", result) + + def test_approved(self): + timesheet = Timesheet("11", submitted=1, approved=1, employee=self.employee, approver="JK") + result = self.template.build(timesheet) + self.assertIn("has been approved", result) diff --git a/test/templates/test_manager_template.py b/test/templates/test_manager_template.py new file mode 100644 index 0000000..bdc7387 --- /dev/null +++ b/test/templates/test_manager_template.py @@ -0,0 +1,39 @@ +from maconomy import ManagerEmailTemplate, Employee, Timesheet +import unittest + +class ManagerEmailTemplateTest(unittest.TestCase): + def setUp(self): + self.template = ManagerEmailTemplate() + self.not_approved = Timesheet.from_result(("MK", "Markus Krogh", "markus@nordu.net", "11", 1, 0, "JK")) + self.not_submitted = Timesheet.from_result(("MKR", "Markus Krogh", "markus@nordu.net", "11", 0, 0, "JK")) + + def test_not_approved(self): + result = self.template.build( + timesheets=[self.not_approved], + maconomyurl="http://localhost/") + self.assertIn("Markus Krogh (MK)", result) + self.assertIn("has not been approved", result) + self.assertIn("has been submitted", result) + self.assertIn("href=\"http://localhost/\"", result) + + def test_not_submitted(self): + result = self.template.build( + timesheets=[self.not_submitted], + maconomyurl="http://localhost/") + self.assertIn("Markus Krogh (MKR)", result) + self.assertIn("has not been approved", result) + self.assertIn("has not been submitted", result) + self.assertIn("href=\"http://localhost/\"", result) + + def test_multiple_timesheets(self): + result = self.template.build( + timesheets=[self.not_submitted, self.not_approved], + maconomyurl="http://localhost/") + + self.assertIn("Markus Krogh (MKR)", result) + self.assertIn("Markus Krogh (MK)", result) + self.assertIn("has not been approved", result) + self.assertIn("has been submitted", result) + self.assertIn("has not been submitted", result) + self.assertIn("href=\"http://localhost/\"", result) + diff --git a/test/templates/test_missing_email_template.py b/test/templates/test_missing_email_template.py new file mode 100644 index 0000000..60e923a --- /dev/null +++ b/test/templates/test_missing_email_template.py @@ -0,0 +1,13 @@ +from maconomy import MissingEmailTemplate +import unittest + + +class MissingEmailTemplateTest(unittest.TestCase): + + def setUp(self): + self.template = MissingEmailTemplate() + + def test_substitution(self): + result = self.template.build(maconomyurl="http://localhost/", helpurl="http://example.com") + self.assertIn("href=\"http://localhost/\"", result) + self.assertIn("href=\"http://example.com\"", result) diff --git a/test/templates/test_unsubmitted_email_template.py b/test/templates/test_unsubmitted_email_template.py new file mode 100644 index 0000000..ab13700 --- /dev/null +++ b/test/templates/test_unsubmitted_email_template.py @@ -0,0 +1,13 @@ +from maconomy import UnsubmittedEmailTemplate +import unittest + +class UnsubmittedEmailTemplateTest(unittest.TestCase): + + def setUp(self): + self.template = UnsubmittedEmailTemplate() + + def test_substitution(self): + result = self.template.build(week=10, maconomyurl="http://localhost/", helpurl="http://example.com") + self.assertIn("week 10", result) + self.assertIn("href=\"http://localhost/\"", result) + self.assertIn("href=\"http://example.com\"", result) diff --git a/test/test_templates.py b/test/test_templates.py deleted file mode 100644 index ee05ac6..0000000 --- a/test/test_templates.py +++ /dev/null @@ -1,61 +0,0 @@ -from maconomy import UnsubmittedEmailTemplate, MissingEmailTemplate, ManagerEmailTemplate, Employee -import unittest - -class UnsubmittedEmailTemplateTest(unittest.TestCase): - - def setUp(self): - self.template = UnsubmittedEmailTemplate() - - def test_substitution(self): - result = self.template.build(week=10, maconomyurl="http://localhost/", helpurl="http://example.com") - self.assertIn("week 10", result) - self.assertIn("href=\"http://localhost/\"", result) - self.assertIn("href=\"http://example.com\"", result) - -class MissingEmailTemplateTest(unittest.TestCase): - - def setUp(self): - self.template = MissingEmailTemplate() - - def test_substitution(self): - result = self.template.build(maconomyurl="http://localhost/", helpurl="http://example.com") - self.assertIn("href=\"http://localhost/\"", result) - self.assertIn("href=\"http://example.com\"", result) - -class ManagerEmailTemplateTest(unittest.TestCase): - - def setUp(self): - self.template = ManagerEmailTemplate() - self.employee = Employee(("MK", "Markus Krogh", "markus@nordu.net")) - - def test_substitute(self): - result = self.template.build( - employee=self.employee, - week=11, - maconomyurl="http://localhost/", - ) - self.assertIn("Markus Krogh (MK)", result) - self.assertIn("Week 11", result) - self.assertIn("not been submitted", result) - self.assertIn("not been approved", result) - self.assertIn("href=\"http://localhost/\"", result) - - def test_submitted(self): - result = self.template.build( - employee=self.employee, - week=11, - maconomyurl="http://localhost/", - submitted = True, - ) - self.assertIn("has been submitted", result) - def test_approved(self): - result = self.template.build( - employee=self.employee, - week=11, - maconomyurl="http://localhost/", - approved = True, - ) - self.assertIn("has been approved", result) - - - diff --git a/test/views/__init__.py b/test/views/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/views/__init__.py diff --git a/test/views/test_employee_email.py b/test/views/test_employee_email.py new file mode 100644 index 0000000..75ebbd6 --- /dev/null +++ b/test/views/test_employee_email.py @@ -0,0 +1,25 @@ +from maconomy import EmployeeEmailView, Timesheet +from ConfigParser import SafeConfigParser +import unittest + +class EmployeeEmailViewTest(unittest.TestCase): + def setUp(self): + self.config = SafeConfigParser() + self.config.add_section("view") + self.config.set("view", "maconomyurl", "http://localhost/maconomy") + self.config.set("view", "helpurl", "http://localhost/help") + self.view = EmployeeEmailView(self.config) + self.timesheet = Timesheet.from_result(("Markus Krogh", "MK", "markus@nordu.net", 11, 0, 0, "JK")) + + def test_missing_timereg(self): + self.timesheet.submitted=None + result = self.view.render(self.timesheet) + self.assertIn("href=\"http://localhost/maconomy\"", result) + self.assertIn("href=\"http://localhost/help\"", result) + + def test_unsubmitted_timereg(self): + self.timesheet.submitted=0 + result = self.view.render(self.timesheet) + self.assertIn("week 11", result) + self.assertIn("href=\"http://localhost/maconomy\"", result) + self.assertIn("href=\"http://localhost/help\"", result) |