[MERGE] trunk
bzr revid: abo@openerp.com-20130214173522-2ama9xjn4c2hloap
This commit is contained in:
commit
74ba45d1fc
|
@ -6,6 +6,8 @@ Changelog
|
||||||
`trunk`
|
`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__.py` descriptor files.
|
||||||
- Removed support for `<terp>` root element in XML files.
|
- Removed support for `<terp>` root element in XML files.
|
||||||
- Removed support for the non-openerp namespace (e.g. importing `tools` instead
|
- Removed support for the non-openerp namespace (e.g. importing `tools` instead
|
||||||
|
|
|
@ -35,6 +35,7 @@ OpenERP Server API
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
orm-methods.rst
|
||||||
api_models.rst
|
api_models.rst
|
||||||
routing.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
|
the :py:func:`openerp.http.handler` decorator while adding an RPC endpoint is
|
||||||
done with the :py:func:`openerp.http.rpc` decorator.
|
done with the :py:func:`openerp.http.rpc` decorator.
|
||||||
|
|
||||||
|
.. _routing-decorators:
|
||||||
|
|
||||||
Routing decorators
|
Routing decorators
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -3911,20 +3911,44 @@ class BaseModel(object):
|
||||||
returned_ids = [x['id'] for x in cr.dictfetchall()]
|
returned_ids = [x['id'] for x in cr.dictfetchall()]
|
||||||
self._check_record_rules_result_count(cr, uid, sub_ids, returned_ids, operation, context=context)
|
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):
|
def create_workflow(self, cr, uid, ids, context=None):
|
||||||
"""Call given workflow trigger as a result of a CRUD operation"""
|
"""Create a workflow instance for each given record IDs."""
|
||||||
wf_service = netsvc.LocalService("workflow")
|
from openerp import workflow
|
||||||
for res_id in ids:
|
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"""
|
"""Send given workflow signal and return a dict mapping ids to workflow results"""
|
||||||
wf_service = netsvc.LocalService("workflow")
|
from openerp import workflow
|
||||||
result = {}
|
result = {}
|
||||||
for res_id in ids:
|
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
|
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):
|
def unlink(self, cr, uid, ids, context=None):
|
||||||
"""
|
"""
|
||||||
Delete records with given ids
|
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)
|
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)
|
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)
|
self.check_access_rule(cr, uid, ids, 'unlink', context=context)
|
||||||
pool_model_data = self.pool.get('ir.model.data')
|
pool_model_data = self.pool.get('ir.model.data')
|
||||||
|
@ -4268,7 +4292,7 @@ class BaseModel(object):
|
||||||
todo.append(id)
|
todo.append(id)
|
||||||
self.pool.get(object)._store_set_values(cr, user, todo, fields_to_recompute, context)
|
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
|
return True
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -4484,7 +4508,7 @@ class BaseModel(object):
|
||||||
self.name_get(cr, user, [id_new], context=context)[0][1] + \
|
self.name_get(cr, user, [id_new], context=context)[0][1] + \
|
||||||
"' " + _("created.")
|
"' " + _("created.")
|
||||||
self.log(cr, user, id_new, message, True, context=context)
|
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
|
return id_new
|
||||||
|
|
||||||
def browse(self, cr, uid, select, context=None, list_class=None, fields_process=None):
|
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 """
|
""" stuff to do right after the registry is built """
|
||||||
pass
|
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
|
# keep this import here, at top it will cause dependency cycle errors
|
||||||
import expression
|
import expression
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ def exec_workflow_cr(cr, uid, obj, signal, *args):
|
||||||
if not object:
|
if not object:
|
||||||
raise except_orm('Object Error', 'Object %s doesn\'t exist' % str(obj))
|
raise except_orm('Object Error', 'Object %s doesn\'t exist' % str(obj))
|
||||||
res_id = args[0]
|
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
|
@check
|
||||||
def exec_workflow(db, uid, obj, signal, *args):
|
def exec_workflow(db, uid, obj, signal, *args):
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import openerp.netsvc
|
import openerp.netsvc
|
||||||
import openerp.pooler
|
import openerp.pooler
|
||||||
|
from openerp import tools
|
||||||
|
|
||||||
|
import security
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -105,7 +110,7 @@ def exp_report(db, uid, object, ids, datas=None, context=None):
|
||||||
cr.close()
|
cr.close()
|
||||||
return True
|
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
|
return id
|
||||||
|
|
||||||
def _check_report(report_id):
|
def _check_report(report_id):
|
||||||
|
|
Loading…
Reference in New Issue