summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Krogh <markus@nordu.net>2016-03-10 11:53:42 +0000
committerMarkus Krogh <markus@nordu.net>2016-03-10 11:53:42 +0000
commit4575c7ea47680e7f589477c917a73353d6faef73 (patch)
tree5f1fb1d8d120b8d609b2018a5eb8e8ad30183952
parent67abade3147d6d706c18beaac219d549fb71c35e (diff)
Manager mail + ceo mail
-rw-r--r--maconomy/__init__.py3
-rw-r--r--maconomy/cli.py3
-rw-r--r--maconomy/models.py25
-rw-r--r--maconomy/repositories.py6
-rw-r--r--maconomy/templates.py35
-rw-r--r--maconomy/views.py37
-rw-r--r--maconomy_hours.py61
-rw-r--r--templates/_employee_status.html6
-rw-r--r--templates/ceo.html2
-rw-r--r--templates/manager.html9
-rw-r--r--test/templates/__init__.py0
-rw-r--r--test/templates/test_ceo_template.py19
-rw-r--r--test/templates/test_employee_status_template.py25
-rw-r--r--test/templates/test_manager_template.py39
-rw-r--r--test/templates/test_missing_email_template.py13
-rw-r--r--test/templates/test_unsubmitted_email_template.py13
-rw-r--r--test/test_templates.py61
-rw-r--r--test/views/__init__.py0
-rw-r--r--test/views/test_employee_email.py25
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)