← Back to team overview

oerppy-hackers team mailing list archive

[Branch ~oerppy-hackers/oerppy/trunk] Rev 34: * Started creating object data models for results (including unit tests).

 

------------------------------------------------------------
revno: 34
committer: duncan@xxxxxxxxxx
branch nick: trunk
timestamp: Thu 2011-06-02 16:46:11 -0600
message:
  * Started creating object data models for results (including unit tests).
  * Converted two of the main query methods in the Canonical addon to use the
    new data model classes; this has resulted in the addon code being much more
    readable.
  * Broke remaining method into lots of smaller methods that will now be much
    easer to convert into data-model-based queries.
  * Minor tweaks to the Makefile.
added:
  oerppy/tests/test_model.py
modified:
  Makefile
  oerppy/addons/canonical/query.py
  oerppy/client.py
  oerppy/model.py


--
lp:oerppy
https://code.launchpad.net/~oerppy-hackers/oerppy/trunk

Your team oerppy Hackers is subscribed to branch lp:oerppy.
To unsubscribe from this branch go to https://code.launchpad.net/~oerppy-hackers/oerppy/trunk/+edit-subscription
=== modified file 'Makefile'
--- Makefile	2011-06-02 19:03:01 +0000
+++ Makefile	2011-06-02 22:46:11 +0000
@@ -3,6 +3,7 @@
 	find ./ -name "*.pyc" -exec rm {} \;
 	find ./ -name "*.pyo" -exec rm {} \;
 	find . -name "*.sw[op]" -exec rm {} \;
+	rm -rf MSG.backup _trial_temp/
 
 check:
 	trial oerppy

=== modified file 'oerppy/addons/canonical/query.py'
--- oerppy/addons/canonical/query.py	2011-06-02 19:03:01 +0000
+++ oerppy/addons/canonical/query.py	2011-06-02 22:46:11 +0000
@@ -1,5 +1,6 @@
 from datetime import date, timedelta
 
+from oerppy import model
 from oerppy.addons.canonical import const
 
 
@@ -26,7 +27,7 @@
         if not domains:
             domains = []
         if not self.user_dept:
-            self.get_departments()
+            self.set_departments()
         if report == const.TIMESHEET_HOURS:
             records = self.timesheet_hours(domains)
         elif report == const.TIMESHEETS_WEEKLY:
@@ -35,95 +36,89 @@
             raise OpenERPPyParameterError("Unknown value for 'report.'")
         return records
 
-    # XXX many of these methods will become more simplified through the use of
-    # a parser object... cleanly dividing code along the lines of
-    # functionality:
-    #   1) create a query and send it out
-    #   2) parse the result set
-    #   3) convert the parsed data into a model instance
-    # then, of course, one is able to work with the data quite easily
-
-    def get_departments(self):
+    def set_departments(self):
         """
         Build a lookup dictionary of department vs user_id.
         """
-        employees = self.client.searchfields(
-            "hr.employee",
-            [],
-            ['name','department_id','resource_id','user_id'])
-
-        # Build dictionary of resource_id vs department
-        user_dept = {}
-        for empl in employees:
-            if empl['department_id'] and empl['user_id']:
-                user_dept[empl['user_id'][0]] = empl['department_id'][1]
-            else:
-                if empl['user_id']:
-                    user_dept[empl['user_id'][0]] = '?'
-                else:
-                    user_dept[0] = '?'
-
-        self.user_dept = user_dept
-
-    def timesheet_hours(self, domain):
-        recs = self.client.searchfields(
-            "project.task.work", 
-            domain, 
-            self.fields)
-        records = []
-        for r in recs:
-            line = {
-                'Project': r['project_id'][1],
-                'Task': r['task_id'][1],
-                'User': r['user_id'][1],
-                'Hours': r['hours'],
-                'Department': self.user_dept.get(r['user_id'][0], '?'),
-                'Date': r['date'],
-                'Week': r['week_start'],
-                'Year': r['date'][0:4],
-                'Month': r['date'][5:7],
-                }
-            records.append(line)
-        return records
-
-    def weekly_timesheets(self, domain):
-        """
-        Get the weekly timeentry records, highlighting the missing weeks.
-        """
-        # Get user Ids of timesheet users and the weeks we're interested in
+        raw_results = self.client.searchfields(
+            entity="hr.employee",
+            query=[],
+            fields=['name','department_id','resource_id','user_id'])
+        results = model.HREmployeeSet(raw_results)
+        # build dictionary of resource_id vs department
+        self.user_dept = results.build_department_lookup_table()
+
+    def timesheet_hours(self, domains):
+        raw_results = self.client.searchfields(
+            entity="project.task.work", 
+            query=domains, 
+            fields=self.fields)
+        return model.ProjectTaskWorkSet(raw_results, self.user_dept)
+
+    def get_all_timeentry_weeks(self):
+        """
+        Get timeentry data since we've been tracking it.
+        """
         today = date.today()
         last_week = today - timedelta(days=-7)
         weeks = self.client.searchfields(
-            'project.timeentry.week',
-            [
+            entity='project.timeentry.week',
+            query=[
                 (['week','>','2010-12-31']),
                 ('week','<=', last_week.isoformat())
             ],
+            fields=[])
+
+    def get_timeentry(self, week):
+        """
+        Get the timeentry for a given week.
+        """
+        timesheets = self.client.searchfields(
+            'project.timeentry',
+            [('week_start','=',week['week']),('user_id','in', user_ids)],
             [])
+        return timesheets
+
+    def get_oem_user_ids(self):
+        """
+        Get the IDs for everyone who uses the OEM timesheets.
+        """
         user_fields = self.client.searchfields(
             'canonical.user.category',
             [('code','=','OEMTIMESHEET')],
             ['user_ids'])
-        user_ids = user_fields[0]['user_ids']
+        return user_fields[0]['user_ids']
+
+    def get_user_names(self, user_ids):
+        """
+        Get the OpenERP user names for the user IDs provided.
+        """
         users = self.client.searchfields(
             'res.users' ,
             [('id','in', user_ids)],
             ['id', 'name'])
-
-        # Build list of names for each user id
+        return users
+
+    def weekly_timesheets(self, domains):
+        """
+        Get the weekly timeentry records, highlighting the missing weeks.
+        """
+        # get user IDs of timesheet users and the weeks we're interested in
+
+        weeks = self.get_all_timeentry_weeks()
+        user_ids = self.get_oem_user_ids()
+        users = self.get_users_names(user_ids)
+        # build list of names for each user id
         user_list = {}
         for u in users:
             user_list[u['id']] = u['name']
 
         records = []
-        for w in weeks:
-            # Get timesheets for the week
-            timesheets = self.client.searchfields(
-                'project.timeentry',
-                [('week_start','=',w['week']),('user_id','in', user_ids)],
-                [])
+        for week in weeks:
+            # get timesheets for the week
+            timesheets = self.get_timeentry(week["week"])
 
-            # Store lookup of total time by user for this week
+            # store lookup of total time by user for this week
             total_time = {}
             if timesheets:
                 for t in timesheets:
@@ -132,7 +127,7 @@
 
             for u in user_ids:
                 if not total_time.get(u,None):
-                    # Missing timesheet
+                    # missing timesheet
                     line = {
                        'Week Commencing': w['week'],
                        'User': user_list[u],

=== modified file 'oerppy/client.py'
--- oerppy/client.py	2011-06-02 19:03:01 +0000
+++ oerppy/client.py	2011-06-02 22:46:11 +0000
@@ -69,7 +69,7 @@
         return self.endpoints.object.execute(entity, "read", ids, fields)
 
     @parse_results
-    def searchfields(self, entity, query, fields):
+    def searchfields(self, entity="", query="", fields=None):
         """
         """
         ids = self.search(entity, query)

=== modified file 'oerppy/model.py'
--- oerppy/model.py	2011-06-01 04:50:04 +0000
+++ oerppy/model.py	2011-06-02 22:46:11 +0000
@@ -1,4 +1,82 @@
+
 class Model(object):
     """
     Base class for representing result sets and result data.
     """
+
+
+class ResultSet(set):
+    """
+    Base class for collections of models, all together representing result sets
+    in queries to the OpenERP server.
+    """
+    model = Model
+
+    def __init__(self, results, *args, **kwds):
+        for row in results:
+            self.add(self.model(row, *args, **kwds))
+
+
+class HREmployee(Model):
+    """
+    This is an object model that maps to search results from OpenERP's
+    "hr.employee" entity.
+    """
+    def __init__(self, row):
+        self.name = row["name"][0]
+        self.department_id = row["department_id"][1]
+        self.resource_id = row["resource_id"][0]
+        self.user_id = row["user_id"][0]
+
+
+class HREmployeeSet(ResultSet):
+    """
+    An object for collecting HREmployees together.
+    """
+    model = HREmployee
+
+    def get_user(self, user_id):
+        for user in self:
+            if user.user_id == user_id:
+                return user
+
+    def build_department_lookup_table(self):
+        table = {}
+        table["unknown"] = 0
+        for user in self:
+            if user.department_id and user.user_id:
+                table[user.user_id] = user.department_id
+            elif user.user_id:
+                table[user.user_id] = "?"
+            else:
+                table["unknown"] += 1
+        return table
+
+
+class ProjectTaskWork(Model):
+    """
+    This is an object model that maps to search results from OpenERP's
+    "project.task.work" entity.
+    """
+    def __init__(self, row, depts):
+        self.project_id = row['project_id'][1]
+        self.task_id = row['task_id'][1]
+        self.user_id = row['user_id'][1]
+        self.department_id = depts.get(self.user_id, "?")
+        self.hours = row['hours']
+        self.date = row['date']
+        self.year = int(row['date'][0:4])
+        self.month = int(row['date'][5:7])
+        self.week = row['week_start']
+
+
+class ProjectTaskWorkSet(ResultSet):
+    """
+    An object for collecting HREmployees together.
+    """
+    model = ProjectTaskWork
+
+    def get_work(self, project_id):
+        for project in self:
+            if project.project_id == project_id:
+                return project

=== added file 'oerppy/tests/test_model.py'
--- oerppy/tests/test_model.py	1970-01-01 00:00:00 +0000
+++ oerppy/tests/test_model.py	2011-06-02 22:46:11 +0000
@@ -0,0 +1,93 @@
+import unittest
+
+from oerppy import model
+
+
+class HRTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.user_results = [
+            {"name": ["Bob"],
+             "user_id": [314],
+             "department_id": ["what's this field?", 1],
+             "resource_id": [34]},
+            {"name": ["Alice"],
+             "user_id": [315],
+             "department_id": ["UKN", 2],
+             "resource_id": [37]},
+            {"name": ["Carol"],
+             "user_id": [316],
+             "department_id": ["UKN", None],
+             "resource_id": [42]},
+            ]
+
+    def test_hr_employee(self):
+        employee = model.HREmployee(self.user_results[1])
+        self.assertEqual(employee.user_id, 315)
+        self.assertEqual(employee.name, "Alice")
+        self.assertEqual(employee.department_id, 2)
+        self.assertEqual(employee.resource_id, 37)
+
+    def test_hr_employee_set(self):
+        results = model.HREmployeeSet(self.user_results)
+        self.assertEqual(len(results), 3)
+        user = results.get_user(314)
+        self.assertEqual(user.name, "Bob")
+        table = results.build_department_lookup_table()
+        self.assertEqual(table.get(315), 2)
+        self.assertEqual(table.get(316), "?")
+
+class ProjectTaskWorkTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.user_results = [
+            {"name": ["Bob"],
+             "user_id": [314],
+             "department_id": ["what's this field?", 1],
+             "resource_id": [34]},
+            {"name": ["Alice"],
+             "user_id": [315],
+             "department_id": ["UKN", 2],
+             "resource_id": [37]},
+            {"name": ["Carol"],
+             "user_id": [316],
+             "department_id": ["UKN", None],
+             "resource_id": [42]},
+            ]
+        self.work_results = [
+            {"project_id": ["UKN", 1],
+             "task_id": ["UKN", 1001],
+             "user_id": ["UKN", 314],
+             "hours": 273,
+             "department_id": ["what's this field?", 1],
+             "date": "2011-05-01",
+             "week_start": 172},
+            {"project_id": ["UKN", 2],
+             "task_id": ["UKN", 1002],
+             "user_id": ["UKN", 315],
+             "hours": 735,
+             "department_id": ["what's this field?", 2],
+             "date": "2011-05-01",
+             "week_start": 172},
+            ]
+        self.results = model.HREmployeeSet(self.user_results)
+        self.table = self.results.build_department_lookup_table()
+
+    def test_project_task_work(self):
+
+        work = model.ProjectTaskWork(self.work_results[1], self.table)
+        self.assertEqual(work.project_id, 2)
+        self.assertEqual(work.task_id, 1002)
+        self.assertEqual(work.user_id, 315)
+        self.assertEqual(work.department_id, 2)
+        self.assertEqual(work.hours, 735)
+        self.assertEqual(work.date, "2011-05-01")
+        self.assertEqual(work.year, 2011)
+        self.assertEqual(work.month, 5)
+        self.assertEqual(work.week, 172)
+
+    def test_project_task_work_set(self):
+        results = model.ProjectTaskWorkSet(self.work_results, self.table)
+        self.assertEqual(len(results), 2)
+        work = results.get_work(1)
+        self.assertEqual(work.hours, 273)