oerppy-hackers team mailing list archive
-
oerppy-hackers team
-
Mailing list archive
-
Message #00020
[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)