[MERGE] trunk
bzr revid: abo@openerp.com-20130214173522-2ama9xjn4c2hloap
This commit is contained in:
commit
74ba45d1fc
|
@ -6,6 +6,8 @@ Changelog
|
|||
`trunk`
|
||||
-------
|
||||
|
||||
- Added :ref:`orm-workflows` to the ORM.
|
||||
- Added :ref:`routing-decorators` to the RPC and WSGI stack.
|
||||
- Removed support for `__terp__.py` descriptor files.
|
||||
- Removed support for `<terp>` root element in XML files.
|
||||
- Removed support for the non-openerp namespace (e.g. importing `tools` instead
|
||||
|
|
|
@ -35,6 +35,7 @@ OpenERP Server API
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
orm-methods.rst
|
||||
api_models.rst
|
||||
routing.rst
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
.. _orm-methods:
|
||||
|
||||
ORM methods
|
||||
===========
|
||||
|
||||
.. _orm-workflows:
|
||||
|
||||
Workflow-related methods
|
||||
------------------------
|
||||
|
||||
.. versionadded:: 7.1
|
||||
|
||||
Creating, deleting, or otherwise manipulating workflow instances is possible
|
||||
right from a Model instance. (Previously, workflows were handled throught a
|
||||
call to ``LocalService('workflow')``. Using the ORM methods is now the preferred
|
||||
way.)
|
||||
|
||||
.. currentmodule:: openerp.osv.orm
|
||||
|
||||
.. automethod:: BaseModel.create_workflow
|
||||
:noindex:
|
||||
|
||||
This is used instead of ``LocalService('workflow').trg_create()``.
|
||||
|
||||
.. automethod:: BaseModel.delete_workflow
|
||||
:noindex:
|
||||
|
||||
This is used instead of ``LocalService('workflow').trg_delete()``.
|
||||
|
||||
.. automethod:: BaseModel.step_workflow
|
||||
:noindex:
|
||||
|
||||
This is used instead of ``LocalService('workflow').trg_write()``.
|
||||
|
||||
.. automethod:: BaseModel.redirect_workflow
|
||||
:noindex:
|
||||
|
||||
.. automethod:: BaseModel.signal_workflow
|
||||
:noindex:
|
||||
|
||||
This is used instead of ``LocalService('workflow').trg_validate()``.
|
||||
|
||||
.. method:: BaseModel.signal_xxx(cr, uid, ids)
|
||||
:noindex:
|
||||
|
||||
Sends a signal ``xxx`` to the workflow instances bound to the given record
|
||||
IDs. (This is implemented using ``__getattr__`` so no source link is
|
||||
rendered on the right.)
|
||||
|
||||
This is used instead of ``LocalService('workflow').trg_validate()``.
|
||||
|
||||
|
||||
.. note::
|
||||
Low-level access to the workflows is still possible by using the
|
||||
``openerp.workflow`` module, that is, in a similar way to what was possible
|
||||
with the previous ``LocalService('workflow')`` access. This may be useful
|
||||
when looking-up a model in the registry and/or its records is not necessary.
|
||||
For instance when working with raw model names and record IDs is preferred (to
|
||||
avoid hitting unnecessarily the database). But this is something that should be
|
||||
carefully considered as it would bypass the ORM methods (and thus any inherited
|
||||
behaviors).
|
|
@ -19,6 +19,8 @@ Starting with OpenERP 7.1, exposing a new arbitrary WSGI handler is done with
|
|||
the :py:func:`openerp.http.handler` decorator while adding an RPC endpoint is
|
||||
done with the :py:func:`openerp.http.rpc` decorator.
|
||||
|
||||
.. _routing-decorators:
|
||||
|
||||
Routing decorators
|
||||
------------------
|
||||
|
||||
|
|
|
@ -3911,20 +3911,44 @@ class BaseModel(object):
|
|||
returned_ids = [x['id'] for x in cr.dictfetchall()]
|
||||
self._check_record_rules_result_count(cr, uid, sub_ids, returned_ids, operation, context=context)
|
||||
|
||||
def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
|
||||
"""Call given workflow trigger as a result of a CRUD operation"""
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
def create_workflow(self, cr, uid, ids, context=None):
|
||||
"""Create a workflow instance for each given record IDs."""
|
||||
from openerp import workflow
|
||||
for res_id in ids:
|
||||
getattr(wf_service, trigger)(uid, self._name, res_id, cr)
|
||||
workflow.trg_create(uid, self._name, res_id, cr)
|
||||
return True
|
||||
|
||||
def _workflow_signal(self, cr, uid, ids, signal, context=None):
|
||||
def delete_workflow(self, cr, uid, ids, context=None):
|
||||
"""Delete the workflow instances bound to the given record IDs."""
|
||||
from openerp import workflow
|
||||
for res_id in ids:
|
||||
workflow.trg_delete(uid, self._name, res_id, cr)
|
||||
return True
|
||||
|
||||
def step_workflow(self, cr, uid, ids, context=None):
|
||||
"""Reevaluate the workflow instances of the given record IDs."""
|
||||
from openerp import workflow
|
||||
for res_id in ids:
|
||||
workflow.trg_write(uid, self._name, res_id, cr)
|
||||
return True
|
||||
|
||||
def signal_workflow(self, cr, uid, ids, signal, context=None):
|
||||
"""Send given workflow signal and return a dict mapping ids to workflow results"""
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
from openerp import workflow
|
||||
result = {}
|
||||
for res_id in ids:
|
||||
result[res_id] = wf_service.trg_validate(uid, self._name, res_id, signal, cr)
|
||||
result[res_id] = workflow.trg_validate(uid, self._name, res_id, signal, cr)
|
||||
return result
|
||||
|
||||
def redirect_workflow(self, cr, uid, old_new_ids, context=None):
|
||||
""" Rebind the workflow instance bound to the given 'old' record IDs to
|
||||
the given 'new' IDs. (``old_new_ids`` is a list of pairs ``(old, new)``.
|
||||
"""
|
||||
from openerp import workflow
|
||||
for old_id, new_id in old_new_ids:
|
||||
workflow.trg_redirect(uid, self._name, old_id, new_id, cr)
|
||||
return True
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Delete records with given ids
|
||||
|
@ -3963,7 +3987,7 @@ class BaseModel(object):
|
|||
property_ids = ir_property.search(cr, uid, [('res_id', 'in', ['%s,%s' % (self._name, i) for i in ids])], context=context)
|
||||
ir_property.unlink(cr, uid, property_ids, context=context)
|
||||
|
||||
self._workflow_trigger(cr, uid, ids, 'trg_delete', context=context)
|
||||
self.delete_workflow(cr, uid, ids, context=context)
|
||||
|
||||
self.check_access_rule(cr, uid, ids, 'unlink', context=context)
|
||||
pool_model_data = self.pool.get('ir.model.data')
|
||||
|
@ -4268,7 +4292,7 @@ class BaseModel(object):
|
|||
todo.append(id)
|
||||
self.pool.get(object)._store_set_values(cr, user, todo, fields_to_recompute, context)
|
||||
|
||||
self._workflow_trigger(cr, user, ids, 'trg_write', context=context)
|
||||
self.step_workflow(cr, user, ids, context=context)
|
||||
return True
|
||||
|
||||
#
|
||||
|
@ -4484,7 +4508,7 @@ class BaseModel(object):
|
|||
self.name_get(cr, user, [id_new], context=context)[0][1] + \
|
||||
"' " + _("created.")
|
||||
self.log(cr, user, id_new, message, True, context=context)
|
||||
self._workflow_trigger(cr, user, [id_new], 'trg_create', context=context)
|
||||
self.create_workflow(cr, user, [id_new], context=context)
|
||||
return id_new
|
||||
|
||||
def browse(self, cr, uid, select, context=None, list_class=None, fields_process=None):
|
||||
|
@ -5248,6 +5272,14 @@ class BaseModel(object):
|
|||
""" stuff to do right after the registry is built """
|
||||
pass
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('signal_'):
|
||||
signal_name = name[len('signal_'):]
|
||||
assert signal_name
|
||||
return (lambda *args, **kwargs:
|
||||
self.signal_workflow(*args, signal=signal_name, **kwargs))
|
||||
return super(BaseModel, self).__getattr__(name)
|
||||
|
||||
# keep this import here, at top it will cause dependency cycle errors
|
||||
import expression
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ def exec_workflow_cr(cr, uid, obj, signal, *args):
|
|||
if not object:
|
||||
raise except_orm('Object Error', 'Object %s doesn\'t exist' % str(obj))
|
||||
res_id = args[0]
|
||||
return object._workflow_signal(cr, uid, [res_id], signal)[res_id]
|
||||
return object.signal_workflow(cr, uid, [res_id], signal)[res_id]
|
||||
|
||||
@check
|
||||
def exec_workflow(db, uid, obj, signal, *args):
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import openerp.netsvc
|
||||
import openerp.pooler
|
||||
from openerp import tools
|
||||
|
||||
import security
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -105,7 +110,7 @@ def exp_report(db, uid, object, ids, datas=None, context=None):
|
|||
cr.close()
|
||||
return True
|
||||
|
||||
thread.start_new_thread(go, (id, uid, ids, datas, context))
|
||||
threading.Thread(target=go, args=(id, uid, ids, datas, context)).start()
|
||||
return id
|
||||
|
||||
def _check_report(report_id):
|
||||
|
|
Loading…
Reference in New Issue