← Back to team overview

oerppy-hackers team mailing list archive

[Branch ~oerppy-hackers/oerppy/trunk] Rev 40: * Added a script and script class for getting table metadata out of OpenERP.

 

------------------------------------------------------------
revno: 40
committer: duncan@xxxxxxxxxx
branch nick: trunk
timestamp: Mon 2011-06-06 12:29:31 -0600
message:
  * Added a script and script class for getting table metadata out of OpenERP.
  * Added new models for project.timeentry*.
  * Split the query method that gets all timeentries from the beginning until now
    into a general method for any time entry period and a new *
    since-the-beginning one that uses the new method.
  * Split out more Canonical-specific code (and data models).
  * Added a check in the results set class: if there are no results, just leave
    as an empty list and do no processing.
  * Converted more methods to use the data model classes.
  * Simplified logic in get_all_weeks_oem_timesheets.
  * Added missing docstrings for some script classes.
added:
  bin/get_table_metadata
  oerppy/addons/canonical/scripting/metadata.py
renamed:
  oerppy/addons/canonical/tests/test_canonical.py => oerppy/addons/canonical/tests/test_model.py
modified:
  oerppy/addons/canonical/model.py
  oerppy/addons/canonical/query.py
  oerppy/addons/canonical/scripting/export.py
  oerppy/addons/project/model.py
  oerppy/addons/project/query.py
  oerppy/addons/project/tests/test_model.py
  oerppy/model.py
  oerppy/query.py
  oerppy/addons/canonical/tests/test_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
=== added file 'bin/get_table_metadata'
--- bin/get_table_metadata	1970-01-01 00:00:00 +0000
+++ bin/get_table_metadata	2011-06-06 18:29:31 +0000
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+from oerppy.config import get_config_data
+from oerppy.reg import registry
+
+# XXX we probably want to eventually put these addons in their own project
+from oerppy.addons.canonical import query
+from oerppy.addons.canonical.scripting import metadata
+
+
+# get configuration; note that option parsing is handled by the script
+# class(es)
+config_data = get_config_data()
+# setup any addons that we want
+registry.add("canonical", query.CanonicalQuery)
+# run the exporter
+monthly_export = metadata.TableMetadata(config_data)
+monthly_export.run()

=== modified file 'oerppy/addons/canonical/model.py'
--- oerppy/addons/canonical/model.py	2011-06-03 22:03:45 +0000
+++ oerppy/addons/canonical/model.py	2011-06-06 18:29:31 +0000
@@ -1,4 +1,5 @@
 from oerppy import model
+from oerppy.addons import project
 
 
 class UserCategory(model.Model):
@@ -21,3 +22,22 @@
 class UserCategoriesSet(model.ResultSet):
 
     model = UserCategory
+
+
+
+class TaskWork(project.model.TaskWork):
+
+    def __init__(self, row, depts):
+        super(TaskWork, self).__init__(row, depts)
+        self.project = model.KeyValuePairField(row.get("project_id"))
+        self.week_start = row.get("week_start")
+
+
+class TaskWorkSet(project.model.TaskWorkSet):
+
+    model = TaskWork
+
+    def get_work(self, project_id):
+        for project in self:
+            if project.project.key == project_id:
+                return project

=== modified file 'oerppy/addons/canonical/query.py'
--- oerppy/addons/canonical/query.py	2011-06-06 16:07:36 +0000
+++ oerppy/addons/canonical/query.py	2011-06-06 18:29:31 +0000
@@ -1,4 +1,7 @@
+from datetime import date, timedelta
+
 from oerppy import query
+from oerppy.addons import project
 from oerppy.addons.canonical import const, model
 from oerppy.reg import registry
 
@@ -25,13 +28,24 @@
         if not self.user_dept:
             self.user_dept = registry.get_addon("hr").get_departments()
         if report == const.TIMESHEET_HOURS:
-            records = self.timesheet_hours(domains)
+            records = self.get_timesheet_hours(domains)
         elif report == const.TIMESHEETS_WEEKLY:
-            records = self.weekly_oem_timesheets(domains)
+            records = self.get_all_weeks_oem_timesheets(domains)
         else:
             raise OpenERPPyParameterError("Unknown value for 'report.'")
         return records
 
+    def get_entity_fields(self, entity_name):
+        """
+        Query an entity, returning just the column/field names.
+        """
+        raw_results = self.client.searchfields(
+            entity=entity_name,
+            query=[],
+            fields=[])
+        #import pdb;pdb.set_trace()
+        return raw_results[0].keys()
+
     def get_oem_users(self):
         """
         Get the IDs for everyone who uses the OEM timesheets.
@@ -54,50 +68,82 @@
         result = model.UserCategoriesSet(raw_results).get_first()
         return result.user_ids
 
-    def weekly_oem_timesheets(self, domains):
+    def get_timesheet_hours(self, domains=None):
+        if not domains:
+            domains = []
+        raw_results = self.client.searchfields(
+            entity="project.task.work",
+            query=domains,
+            fields=[])
+        return model.TaskWorkSet(raw_results, self.user_dept)
+
+    def get_timeentry_week_range(self, start_date, end_date):
+        """
+        Get timeentry data for a particular range.
+        """
+        raw_results = self.client.searchfields(
+            entity="project.timeentry.week",
+            query=[
+                (['week','>',start_date]),
+                ('week','<=', end_date)
+                ],
+            fields=[])
+        return project.model.TimeEntryWeekSet(raw_results)
+
+    def get_all_timeentry_weeks(self):
+        """
+        Get timeentry data since we've been tracking it.
+        """
+        start_date = "2010-12-31"
+        today = date.today()
+        last_week = today - timedelta(days=-7)
+        return self.get_timeentry_week_range(
+            start_date, last_week.isoformat())
+
+    def get_users_timeentry(self, week, user_ids):
+        """
+        Get the timeentry for a given week.
+        """
+        raw_results = self.client.searchfields(
+            'project.timeentry',
+            [('week_start', '=', week.date),('user_id', 'in', user_ids)],
+            [])
+        return project.model.TimeEntrySet(raw_results)
+
+    def get_all_weeks_oem_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 = registry.get_addon("project").get_all_timeentry_weeks()
+        weeks = self.get_all_timeentry_weeks()
         user_ids = self.get_oem_user_ids()
         users = registry.get_addon("base").get_user_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 week in weeks:
             # get timesheets for the week
-            timesheets = registry.get_addon("project").get_users_timeentry(
-                week, user_ids)
+            timesheets = self.get_users_timeentry(week, user_ids)
             # store lookup of total time by user for this week
             total_time = {}
             if timesheets:
-                for t in timesheets:
-                    total_time[t['user_id'][0]] = {
-                        'time':t['total_time'], 'state':t['state']}
+                for timesheet in timesheets:
+                    total_time[timesheet.user.key] = {
+                        'time': timesheet.total_time,
+                        'state': timesheet.state}
 
-            for u in user_ids:
-                if not total_time.get(u,None):
+            for user_id in user_ids:
+                record = {
+                    'Week Commencing': week.date,
+                    'User': users.get_user(user_id).name,
+                    'Department': self.user_dept.get(user_id, '?')}
+                if total_time.get(user_id):
+                    record['Total Time'] = total_time.get(
+                        user_id,{}).get('time',0)
+                    record['State'] = total_time[user_id]['state'].capitalize()
+                else:
                     # missing timesheet
-                    line = {
-                       'Week Commencing': week['week'],
-                       'User': user_list[u],
-                       'Department': self.user_dept.get(u, '?'),
-                       'Total Time': 0,
-                       'State': 'Missing',
-                    }
-                else:
-                    line = {
-                       'Week Commencing': week['week'],
-                       'User': user_list[u],
-                       'Department': self.user_dept.get(u, '?'),
-                       'Total Time': total_time.get(u,{}).get('time',0),
-                       'State': total_time[u]['state'].capitalize(),
-                    }
-                records.append(line)
+                    record['Total Time'] = 0
+                    record['State'] = 'Missing'
+                records.append(record)
         return records
 
     # XXX fill this in

=== modified file 'oerppy/addons/canonical/scripting/export.py'
--- oerppy/addons/canonical/scripting/export.py	2011-06-03 22:03:45 +0000
+++ oerppy/addons/canonical/scripting/export.py	2011-06-06 18:29:31 +0000
@@ -33,10 +33,13 @@
 
 
 class AllWeeksExport(ExportScript):
-
+    """
+    Generate an export of each week's timesheet data since OpenERP was
+    installed at Canonical.
+    """
     def get_option_parser(self):
         """
-        Options for monthly exports.
+        Options for all-weeks exports.
         """
         now = datetime.now()
         parser = super(AllWeeksExport, self).get_option_parser()
@@ -58,7 +61,9 @@
 
 
 class OEMUsersExport(ExportScript):
-
+    """
+    Export a list of OEM Users.
+    """
     def run(self):
         # we need to set purge to true here, since the options will have
         # already been gotten by the parent class at this time, and we need the

=== added file 'oerppy/addons/canonical/scripting/metadata.py'
--- oerppy/addons/canonical/scripting/metadata.py	1970-01-01 00:00:00 +0000
+++ oerppy/addons/canonical/scripting/metadata.py	2011-06-06 18:29:31 +0000
@@ -0,0 +1,26 @@
+from oerppy.scripting import Script
+
+
+class TableMetadata(Script):
+    """
+    Get the table metadata corresponding to the given OpenERP entity.
+    """
+    def get_option_parser(self):
+        parser = super(TableMetadata, self).get_option_parser()
+        parser.add_option(
+            "-e", "--openerp-entity", dest="entity", action="store",
+            help="the OpenERP dotted entity name to query")
+        return parser
+
+    def run(self):
+        # we need to set purge to true here, since the options will have
+        # already been gotten by the parent class at this time, and we need the
+        # options of this class added to those
+        options = self.get_options(purge=True)
+        parser = self.get_option_parser()
+        if options.entity == None:
+            parser.error("You must supply the -e or --openerp-entity option. "
+                         "For more information, use --help.")
+        addon = self.service.get_addon("canonical")
+        print addon.get_entity_fields(options.entity)
+        

=== renamed file 'oerppy/addons/canonical/tests/test_canonical.py' => 'oerppy/addons/canonical/tests/test_model.py'
--- oerppy/addons/canonical/tests/test_canonical.py	2011-06-02 15:16:11 +0000
+++ oerppy/addons/canonical/tests/test_model.py	2011-06-06 18:29:31 +0000
@@ -0,0 +1,49 @@
+import unittest
+
+from oerppy.addons import hr
+from oerppy.addons.hr.tests.test_model import employee_results
+from oerppy.addons.canonical import model
+
+
+class ProjectTaskWorkTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.work_results = [
+            {"project_id": [1, "Manhattan"],
+             "task_id": [1001, "Figure out Atoms"],
+             "user_id": [314, "Alice"],
+             "hours": 273,
+             "department_id": [1, "Crypto"],
+             "date": "2011-05-01",
+             "week_start": 172},
+            {"project_id": [2, "Turing"],
+             "task_id": [1002, "Build a von Nuemann machine"],
+             "user_id": [315, "Bob"],
+             "hours": 735,
+             "department_id": [2, "Maths"],
+             "date": "2011-05-01",
+             "week_start": 172},
+            ]
+        self.results = hr.model.EmployeeSet(employee_results)
+        self.table = self.results.build_department_lookup_table()
+
+    def test_project_task_work(self):
+
+        work = model.TaskWork(self.work_results[1], self.table)
+        self.assertEqual(work.project.key, 2)
+        self.assertEqual(work.project.value, "Turing")
+        self.assertEqual(work.task.key, 1002)
+        self.assertEqual(work.user.key, 315)
+        self.assertEqual(work.department_name, "Maths")
+        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_start, 172)
+
+    def test_project_task_work_set(self):
+        results = model.TaskWorkSet(self.work_results, self.table)
+        self.assertEqual(len(results), 2)
+        work = results.get_work(1)
+        self.assertEqual(work.hours, 273)
+

=== modified file 'oerppy/addons/project/model.py'
--- oerppy/addons/project/model.py	2011-06-03 18:46:30 +0000
+++ oerppy/addons/project/model.py	2011-06-06 18:29:31 +0000
@@ -7,12 +7,15 @@
     "project.task.work" entity.
     """
     def __init__(self, row, depts):
+        self.hours = row.get("hours")
+        self.date = row.get("date")
+        self.week_start = row.get("week_start")
+        # The following are key/value pairs, each with .key and .value
+        # attributes
         self.project = model.KeyValuePairField(row.get("project_id"))
         self.task = model.KeyValuePairField(row.get("task_id"))
         self.user = model.KeyValuePairField(row.get("user_id"))
-        self.hours = row.get("hours")
-        self.date = row.get("date")
-        self.week_start = row.get("week_start")
+        # The following are computed attributes
         self.year = int(self.date[0:4])
         self.month = int(self.date[5:7])
         self.department_name = depts.get(self.user.key)
@@ -20,11 +23,90 @@
 
 class TaskWorkSet(model.ResultSet):
     """
-    An object for collecting HREmployees together.
+    An object for collecting TaskWork records together.
     """
     model = TaskWork
 
-    def get_work(self, project_id):
-        for project in self:
-            if project.project.key == project_id:
-                return project
+
+class TimeEntry(model.Model):
+    """
+    This is an object model that maps to search results from OpenERP's
+    "project.timeentry" entity.
+    """
+    def __init__(self, row):
+        self.id = row.get("id")
+        self.week_start = row.get("week_start")
+        self.submitted_date = row.get("submitted")
+        self.state = row.get("state")
+        # The following are key/value pairs, each with .key and .value
+        # attributes 
+        self.user = model.KeyValuePairField(row.get("user_id"))
+
+        self.project1 = model.KeyValuePairField(row.get("project1_id"))
+        self.project2 = model.KeyValuePairField(row.get("project2_id"))
+        self.project3 = model.KeyValuePairField(row.get("project3_id"))
+        self.project4 = model.KeyValuePairField(row.get("project4_id"))
+        self.project5 = model.KeyValuePairField(row.get("project5_id"))
+        self.project6 = model.KeyValuePairField(row.get("project6_id"))
+        self.project7 = model.KeyValuePairField(row.get("project7_id"))
+        self.project8 = model.KeyValuePairField(row.get("project8_id"))
+        self.project9 = model.KeyValuePairField(row.get("project9_id"))
+        self.project10 = model.KeyValuePairField(row.get("project10_id"))
+
+        self.task1 = model.KeyValuePairField(row.get("task1_id"))
+        self.task2 = model.KeyValuePairField(row.get("task2_id"))
+        self.task3 = model.KeyValuePairField(row.get("task3_id"))
+        self.task4 = model.KeyValuePairField(row.get("task4_id"))
+        self.task5 = model.KeyValuePairField(row.get("task5_id"))
+        self.task6 = model.KeyValuePairField(row.get("task6_id"))
+        self.task7 = model.KeyValuePairField(row.get("task7_id"))
+        self.task8 = model.KeyValuePairField(row.get("task8_id"))
+        self.task9 = model.KeyValuePairField(row.get("task9_id"))
+        self.task10 = model.KeyValuePairField(row.get("task10_id"))
+        
+        self.work1 = model.KeyValuePairField(row.get("work1_id"))
+        self.work2 = model.KeyValuePairField(row.get("work2_id"))
+        self.work3 = model.KeyValuePairField(row.get("work3_id"))
+        self.work4 = model.KeyValuePairField(row.get("work4_id"))
+        self.work5 = model.KeyValuePairField(row.get("work5_id"))
+        self.work6 = model.KeyValuePairField(row.get("work6_id"))
+        self.work7 = model.KeyValuePairField(row.get("work7_id"))
+        self.work8 = model.KeyValuePairField(row.get("work8_id"))
+        self.work9 = model.KeyValuePairField(row.get("work9_id"))
+        self.work10 = model.KeyValuePairField(row.get("work10_id"))
+        # The following are computed attributes
+        self.hours1 = float(row.get("hours1"))
+        self.hours2 = float(row.get("hours2"))
+        self.hours3 = float(row.get("hours3"))
+        self.hours4 = float(row.get("hours4"))
+        self.hours5 = float(row.get("hours5"))
+        self.hours6 = float(row.get("hours6"))
+        self.hours7 = float(row.get("hours7"))
+        self.hours8 = float(row.get("hours8"))
+        self.hours9 = float(row.get("hours9"))
+        self.hours10 = float(row.get("hours10"))
+        self.total_time = float(row.get("total_time"))
+
+
+class TimeEntrySet(model.ResultSet):
+    """
+    An object for collecting TimeEntry records together.
+    """
+    model = TimeEntry
+
+
+class TimeEntryWeek(model.Model):
+    """
+    This is an object model that maps to search results from OpenERP's
+    "project.timeentry.week" entity.
+    """
+    def __init__(self, row):
+        self.id = row.get("id")
+        self.date = row.get("week")
+
+
+class TimeEntryWeekSet(model.ResultSet):
+    """
+    An object for collecting TimeEntryWeek records together.
+    """
+    model = TimeEntryWeek

=== modified file 'oerppy/addons/project/query.py'
--- oerppy/addons/project/query.py	2011-06-03 22:03:45 +0000
+++ oerppy/addons/project/query.py	2011-06-06 18:29:31 +0000
@@ -1,5 +1,3 @@
-from datetime import date, timedelta
-
 from oerppy import query
 from oerppy.addons.project import model
 
@@ -18,23 +16,8 @@
         """
         Get timeentry data since we've been tracking it.
         """
-        today = date.today()
-        last_week = today - timedelta(days=-7)
-        weeks = self.client.searchfields(
+        raw_results = self.client.searchfields(
             entity='project.timeentry.week',
-            query=[
-                (['week','>','2010-12-31']),
-                ('week','<=', last_week.isoformat())
-            ],
+            query=[],
             fields=[])
-        return weeks
-
-    def get_users_timeentry(self, week, user_ids):
-        """
-        Get the timeentry for a given week.
-        """
-        timesheets = self.client.searchfields(
-            'project.timeentry',
-            [('week_start','=',week['week']),('user_id','in', user_ids)],
-            [])
-        return timesheets
+        return model.TimeEntryWeekSet(raw_results)

=== modified file 'oerppy/addons/project/tests/test_model.py'
--- oerppy/addons/project/tests/test_model.py	2011-06-03 20:29:11 +0000
+++ oerppy/addons/project/tests/test_model.py	2011-06-06 18:29:31 +0000
@@ -9,20 +9,16 @@
 
     def setUp(self):
         self.work_results = [
-            {"project_id": [1, "Manhattan"],
-             "task_id": [1001, "Figure out Atoms"],
+            {"task_id": [1001, "Figure out Atoms"],
              "user_id": [314, "Alice"],
              "hours": 273,
              "department_id": [1, "Crypto"],
-             "date": "2011-05-01",
-             "week_start": 172},
-            {"project_id": [2, "Turing"],
-             "task_id": [1002, "Build a von Nuemann machine"],
+             "date": "2011-05-01"},
+            {"task_id": [1002, "Build a von Nuemann machine"],
              "user_id": [315, "Bob"],
              "hours": 735,
              "department_id": [2, "Maths"],
-             "date": "2011-05-01",
-             "week_start": 172},
+             "date": "2011-05-01"},
             ]
         self.results = hr.model.EmployeeSet(employee_results)
         self.table = self.results.build_department_lookup_table()
@@ -30,8 +26,6 @@
     def test_project_task_work(self):
 
         work = model.TaskWork(self.work_results[1], self.table)
-        self.assertEqual(work.project.key, 2)
-        self.assertEqual(work.project.value, "Turing")
         self.assertEqual(work.task.key, 1002)
         self.assertEqual(work.user.key, 315)
         self.assertEqual(work.department_name, "Maths")
@@ -39,10 +33,7 @@
         self.assertEqual(work.date, "2011-05-01")
         self.assertEqual(work.year, 2011)
         self.assertEqual(work.month, 5)
-        self.assertEqual(work.week_start, 172)
 
     def test_project_task_work_set(self):
         results = model.TaskWorkSet(self.work_results, self.table)
         self.assertEqual(len(results), 2)
-        work = results.get_work(1)
-        self.assertEqual(work.hours, 273)

=== modified file 'oerppy/model.py'
--- oerppy/model.py	2011-06-03 22:03:45 +0000
+++ oerppy/model.py	2011-06-06 18:29:31 +0000
@@ -36,6 +36,8 @@
     model = Model
 
     def __init__(self, results, *args, **kwds):
+        if not results:
+            return
         for row in results:
             try:
                 self.append(self.model(row, *args, **kwds))

=== modified file 'oerppy/query.py'
--- oerppy/query.py	2011-06-03 22:03:45 +0000
+++ oerppy/query.py	2011-06-06 18:29:31 +0000
@@ -27,15 +27,14 @@
             entity='res.users',
             query=[],
             fields=[])
-        results = model.UsersSet(raw_results)
-        return results
+        return model.UsersSet(raw_results)
 
     def get_user_names(self, user_ids):
         """
         Get the OpenERP user names for the user IDs provided.
         """
-        users = self.client.searchfields(
+        raw_results = self.client.searchfields(
             'res.users' ,
             [('id','in', user_ids)],
             ['id', 'name'])
-        return users
+        return model.UsersSet(raw_results)