From c00e57756336358e9800fc8fc89392253dbf4ed8 Mon Sep 17 00:00:00 2001
From: Markus Krogh
Date: Tue, 8 Mar 2016 18:51:12 +0000
Subject: Initial commmit, still needs wireing for email
---
.gitignore | 3 +++
TODO.md | 9 +++++++
__init__.py | 0
config.cfg.dist | 5 ++++
maconomy/__init__.py | 4 +++
maconomy/cli.py | 13 ++++++++++
maconomy/mailer.py | 20 +++++++++++++++
maconomy/models.py | 25 +++++++++++++++++++
maconomy/repositories.py | 35 ++++++++++++++++++++++++++
maconomy/templates.py | 40 ++++++++++++++++++++++++++++++
maconomy_hours.py | 21 ++++++++++++++++
requirements.txt | 1 +
templates/ceo.html | 3 +++
templates/manager.html | 10 ++++++++
templates/missing.html | 6 +++++
templates/unsubmitted.html | 5 ++++
test/__init__.py | 0
test/test_templates.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++
18 files changed, 261 insertions(+)
create mode 100644 TODO.md
create mode 100644 __init__.py
create mode 100644 config.cfg.dist
create mode 100644 maconomy/__init__.py
create mode 100644 maconomy/cli.py
create mode 100644 maconomy/mailer.py
create mode 100644 maconomy/models.py
create mode 100644 maconomy/repositories.py
create mode 100644 maconomy/templates.py
create mode 100644 maconomy_hours.py
create mode 100644 requirements.txt
create mode 100644 templates/ceo.html
create mode 100644 templates/manager.html
create mode 100644 templates/missing.html
create mode 100644 templates/unsubmitted.html
create mode 100644 test/__init__.py
create mode 100644 test/test_templates.py
diff --git a/.gitignore b/.gitignore
index 908a064..c239cc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,6 @@ celerybeat-schedule
# Spyder project settings
.spyderproject
+
+*.cfg
+*.conf
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..2bc4e9f
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,9 @@
+# TODO
+
+- Simple CLI version
+- Properties for db + passwords
+- SQLalchemy for db management
+- Flask frontend?
+- Maconomy Rest version
+ - If not then SOAP?
+
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/config.cfg.dist b/config.cfg.dist
new file mode 100644
index 0000000..0844421
--- /dev/null
+++ b/config.cfg.dist
@@ -0,0 +1,5 @@
+[db]
+host=
+
+[mail]
+server=
diff --git a/maconomy/__init__.py b/maconomy/__init__.py
new file mode 100644
index 0000000..09f2516
--- /dev/null
+++ b/maconomy/__init__.py
@@ -0,0 +1,4 @@
+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
diff --git a/maconomy/cli.py b/maconomy/cli.py
new file mode 100644
index 0000000..0a11db5
--- /dev/null
+++ b/maconomy/cli.py
@@ -0,0 +1,13 @@
+import argparse
+from ConfigParser import SafeConfigParser
+
+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")
+ return parser.parse_args()
+
+def load_config(conf_file):
+ config = SafeConfigParser()
+ config.read(conf_file)
+ return config
diff --git a/maconomy/mailer.py b/maconomy/mailer.py
new file mode 100644
index 0000000..ab443c0
--- /dev/null
+++ b/maconomy/mailer.py
@@ -0,0 +1,20 @@
+import smtplib
+from email.mime.text import MIMEText
+
+class Mailer:
+ def __init__(self, config):
+ self.me = config.get("mail", "from")
+ server_addr = config.get("mail", "server")
+ self.server = smtplib.SMTP(server_addr)
+
+ def send(to, subject, body):
+ msg = MIMEText(body,'plain')
+ msg['To']=to
+ msg['From']=self.me
+ msg['Subject'] = subject
+ self.server.sendmail(self.me, to, msg.as_string())
+
+ def close(self):
+ self.server.quit()
+
+
diff --git a/maconomy/models.py b/maconomy/models.py
new file mode 100644
index 0000000..15fb46b
--- /dev/null
+++ b/maconomy/models.py
@@ -0,0 +1,25 @@
+
+class Employee:
+ def __init__(self, result):
+ self.id, self.name, self.email = result[:3]
+
+ 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 status(self):
+ return "submitted" if self.is_submitted() else "unsubmitted"
+ def is_submitted(self):
+ return self.submitted == 1
+ def is_missing(self):
+ return self.submitted is None
+ def is_approved(self):
+ return self.approved == 1
+ def __str__(self):
+ return self.__unicode__()
+ def __unicode__(self):
+ u"{} ({})".format(self.week, self.status)
diff --git a/maconomy/repositories.py b/maconomy/repositories.py
new file mode 100644
index 0000000..fb143e8
--- /dev/null
+++ b/maconomy/repositories.py
@@ -0,0 +1,35 @@
+import cx_Oracle
+from maconomy.models import Employee, Timesheet
+
+def create_db(config):
+ user = config.get("db", "user")
+ pw = config.get("db", "password")
+ server = config.get("db", "server")
+ return cx_Oracle.connect(user, pw, server)
+
+class DBRepository:
+ def __init__(self, dbcon):
+ self.db = dbcon
+ self.cursor = dbcon.cursor()
+
+ def close(self):
+ self.cursor.close()
+
+class TimeRegistrationRepository(DBRepository):
+ def all_active(self):
+ query = """SELECT e.EMPLOYEENUMBER,e.NAME1,e.ELECTRONICMAILADDRESS, t.WEEKNUMBER, t.SUBMITTED, t.APPROVED 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')
+ WHERE e.blocked=0
+ and (e.DATEENDEMPLOYMENT >= to_char(sysdate,'YYYY.MM.DD') or e.DATEENDEMPLOYMENT = ' ')
+ and e.employeenumber <> '99'
+ and e.MUSTUSETIMESHEETS=1
+ ORDER BY e.employeenumber
+ """
+
+ res = self.cursor.execute(query)
+ rows = res.fetchall()
+
+ return [(Employee(r), Timesheet(r[3:])) for r in rows]
+
diff --git a/maconomy/templates.py b/maconomy/templates.py
new file mode 100644
index 0000000..07cbeb1
--- /dev/null
+++ b/maconomy/templates.py
@@ -0,0 +1,40 @@
+from string import Template
+
+class BaseTemplate(object):
+ def __init__(self, template_file):
+ self.set_template(template_file)
+
+ def build(self, **kwargs):
+ return self.template.substitute(**kwargs)
+
+ def set_template(self, template_file):
+ with open(template_file, 'r') as f:
+ template_base = f.read()
+ self.template = Template(template_base)
+
+
+class UnsubmittedEmailTemplate(BaseTemplate):
+ def __init__(self):
+ self.set_template("templates/unsubmitted.html")
+
+ def build(self, week, maconomyurl, helpurl):
+ return self.template.substitute(week=week, maconomyurl=maconomyurl, helpurl=helpurl)
+
+class MissingEmailTemplate(BaseTemplate):
+ def __init__(self):
+ self.set_template("templates/missing.html")
+
+ def build(self, maconomyurl, helpurl):
+ return self.template.substitute(maconomyurl=maconomyurl, helpurl=helpurl)
+
+class ManagerEmailTemplate(BaseTemplate):
+ def __init__(self):
+ self.set_template("templates/manager.html")
+
+ 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)
+
+
+
diff --git a/maconomy_hours.py b/maconomy_hours.py
new file mode 100644
index 0000000..1001964
--- /dev/null
+++ b/maconomy_hours.py
@@ -0,0 +1,21 @@
+from maconomy import cli, Employee, Timesheet, create_db, TimeRegistrationRepository
+
+def main(config, dry_run):
+ db = create_db(config)
+ timereg_repo = TimeRegistrationRepository(db)
+
+ 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)
+
+ timereg_repo.close()
+ db.close()
+
+if __name__ == '__main__':
+ args = cli.parse()
+ config = cli.load_config(args.config)
+ main(config, args.dry)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..a491756
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+cx_Oracle
diff --git a/templates/ceo.html b/templates/ceo.html
new file mode 100644
index 0000000..ebc2ea9
--- /dev/null
+++ b/templates/ceo.html
@@ -0,0 +1,3 @@
+Time registration status mail.
+
+$status
diff --git a/templates/manager.html b/templates/manager.html
new file mode 100644
index 0000000..6e956e2
--- /dev/null
+++ b/templates/manager.html
@@ -0,0 +1,10 @@
+Missing time registration for your employee $employee, please submit and approve before tuesday 2 AM (CET)
+
+Status for $employee in Week $week
+
+ - Timesheet has $submitted been submitted
+ - Timesheet has $approved been approved by you.
+
+
+
+Please go to Maconomy Portal to submit and approve time.
diff --git a/templates/missing.html b/templates/missing.html
new file mode 100644
index 0000000..c17c8fc
--- /dev/null
+++ b/templates/missing.html
@@ -0,0 +1,6 @@
+Timesheet for last week has not been created.
+
+Please go to Maconomy Portal to register time.
+
+For information on how to use time registration please see Time registration in Maconomy
+
diff --git a/templates/unsubmitted.html b/templates/unsubmitted.html
new file mode 100644
index 0000000..73af949
--- /dev/null
+++ b/templates/unsubmitted.html
@@ -0,0 +1,5 @@
+Timesheet for week $week has not been submitted.
+
+Please go to Maconomy Portal to register time.
+
+For information on how to use time registration please see Time registration in Maconomy
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/test_templates.py b/test/test_templates.py
new file mode 100644
index 0000000..ee05ac6
--- /dev/null
+++ b/test/test_templates.py
@@ -0,0 +1,61 @@
+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)
+
+
+
--
cgit v1.1