[MERGE] Latest trunk.
bzr revid: vta@openerp.com-20121015082458-rudm5r0718ky7829
This commit is contained in:
commit
68cf1f2d6a
34
Makefile
34
Makefile
|
@ -1,34 +0,0 @@
|
||||||
.PHONY: all doc release clean
|
|
||||||
|
|
||||||
HOST = 127.0.0.1
|
|
||||||
PORT = 8080
|
|
||||||
|
|
||||||
all: run
|
|
||||||
|
|
||||||
run:
|
|
||||||
python openerp-web.py -a ${HOST} -p ${PORT}
|
|
||||||
|
|
||||||
release:
|
|
||||||
python setup.py sdist
|
|
||||||
|
|
||||||
install:
|
|
||||||
python setup.py install
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@find . -name '*.pyc' -exec rm -f {} +
|
|
||||||
@find . -name '*.pyo' -exec rm -f {} +
|
|
||||||
@find . -name '*.swp' -exec rm -f {} +
|
|
||||||
@find . -name '*~' -exec rm -f {} +
|
|
||||||
@rm -rf build
|
|
||||||
@rm -rf dist
|
|
||||||
@rm -rf *.egg-info
|
|
||||||
|
|
||||||
doc:
|
|
||||||
make -C doc html
|
|
||||||
|
|
||||||
cloc:
|
|
||||||
cloc addons/*/common/*.py addons/*/controllers/*.py addons/*/static/src/*.js addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml
|
|
||||||
|
|
||||||
blamestat:
|
|
||||||
echo addons/*/common/*.py addons/*/controllers/*.py addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml | xargs -t -n 1 bzr blame -v --long --all | awk '{print $2}' | sort | uniq -c | sort -n
|
|
||||||
|
|
|
@ -8,9 +8,4 @@ The OpenERP Web Client supports the following web browsers:
|
||||||
* Firefox 13+
|
* Firefox 13+
|
||||||
* Any browser using the latest version of Chrome Frame
|
* Any browser using the latest version of Chrome Frame
|
||||||
|
|
||||||
To build the documentation use:
|
|
||||||
|
|
||||||
$ make doc
|
|
||||||
|
|
||||||
then look at doc/build/html/index.html
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,4 @@
|
||||||
import logging
|
import http
|
||||||
|
import controllers
|
||||||
from . import common
|
|
||||||
from . import controllers
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class Options(object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def wsgi_postload():
|
|
||||||
import openerp
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
import getpass
|
|
||||||
_logger.info("embedded mode")
|
|
||||||
o = Options()
|
|
||||||
o.dbfilter = openerp.tools.config['dbfilter']
|
|
||||||
o.server_wide_modules = openerp.conf.server_wide_modules or ['web']
|
|
||||||
try:
|
|
||||||
username = getpass.getuser()
|
|
||||||
except Exception:
|
|
||||||
username = "unknown"
|
|
||||||
o.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
|
|
||||||
o.addons_path = openerp.modules.module.ad_paths
|
|
||||||
o.serve_static = True
|
|
||||||
o.backend = 'local'
|
|
||||||
|
|
||||||
app = common.http.Root(o)
|
|
||||||
openerp.wsgi.register_wsgi_handler(app)
|
|
||||||
|
|
||||||
|
wsgi_postload = http.wsgi_postload
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
from . import http
|
|
||||||
from . import nonliterals
|
|
||||||
from . import release
|
|
||||||
from . import session
|
|
||||||
from . import xml2json
|
|
|
@ -1,32 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright (C) Stephane Wirtel
|
|
||||||
# Copyright (C) 2011 Nicolas Vanhoren
|
|
||||||
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
# list of conditions and the following disclaimer.
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
from .main import *
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright (C) Stephane Wirtel
|
|
||||||
# Copyright (C) 2011 Nicolas Vanhoren
|
|
||||||
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
# list of conditions and the following disclaimer.
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d"
|
|
||||||
DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S"
|
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % (
|
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
|
||||||
DEFAULT_SERVER_TIME_FORMAT)
|
|
||||||
|
|
||||||
def str_to_datetime(str):
|
|
||||||
"""
|
|
||||||
Converts a string to a datetime object using OpenERP's
|
|
||||||
datetime string format (exemple: '2011-12-01 15:12:35').
|
|
||||||
|
|
||||||
No timezone information is added, the datetime is a naive instance, but
|
|
||||||
according to OpenERP 6.1 specification the timezone is always UTC.
|
|
||||||
"""
|
|
||||||
if not str:
|
|
||||||
return str
|
|
||||||
return datetime.datetime.strptime(str, DEFAULT_SERVER_DATETIME_FORMAT)
|
|
||||||
|
|
||||||
def str_to_date(str):
|
|
||||||
"""
|
|
||||||
Converts a string to a date object using OpenERP's
|
|
||||||
date string format (exemple: '2011-12-01').
|
|
||||||
"""
|
|
||||||
if not str:
|
|
||||||
return str
|
|
||||||
return datetime.datetime.strptime(str, DEFAULT_SERVER_DATE_FORMAT).date()
|
|
||||||
|
|
||||||
def str_to_time(str):
|
|
||||||
"""
|
|
||||||
Converts a string to a time object using OpenERP's
|
|
||||||
time string format (exemple: '15:12:35').
|
|
||||||
"""
|
|
||||||
if not str:
|
|
||||||
return str
|
|
||||||
return datetime.datetime.strptime(str, DEFAULT_SERVER_TIME_FORMAT).time()
|
|
||||||
|
|
||||||
def datetime_to_str(obj):
|
|
||||||
"""
|
|
||||||
Converts a datetime object to a string using OpenERP's
|
|
||||||
datetime string format (exemple: '2011-12-01 15:12:35').
|
|
||||||
|
|
||||||
The datetime instance should not have an attached timezone and be in UTC.
|
|
||||||
"""
|
|
||||||
if not obj:
|
|
||||||
return False
|
|
||||||
return obj.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
|
||||||
|
|
||||||
def date_to_str(obj):
|
|
||||||
"""
|
|
||||||
Converts a date object to a string using OpenERP's
|
|
||||||
date string format (exemple: '2011-12-01').
|
|
||||||
"""
|
|
||||||
if not obj:
|
|
||||||
return False
|
|
||||||
return obj.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
||||||
|
|
||||||
def time_to_str(obj):
|
|
||||||
"""
|
|
||||||
Converts a time object to a string using OpenERP's
|
|
||||||
time string format (exemple: '15:12:35').
|
|
||||||
"""
|
|
||||||
if not obj:
|
|
||||||
return False
|
|
||||||
return obj.strftime(DEFAULT_SERVER_TIME_FORMAT)
|
|
||||||
|
|
|
@ -1,311 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright (C) Stephane Wirtel
|
|
||||||
# Copyright (C) 2011 Nicolas Vanhoren
|
|
||||||
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
# list of conditions and the following disclaimer.
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
OpenERP Client Library
|
|
||||||
|
|
||||||
Home page: http://pypi.python.org/pypi/openerp-client-lib
|
|
||||||
Code repository: https://code.launchpad.net/~niv-openerp/openerp-client-lib/trunk
|
|
||||||
"""
|
|
||||||
|
|
||||||
import xmlrpclib
|
|
||||||
import logging
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def _getChildLogger(logger, subname):
|
|
||||||
return logging.getLogger(logger.name + "." + subname)
|
|
||||||
|
|
||||||
class Connector(object):
|
|
||||||
"""
|
|
||||||
The base abstract class representing a connection to an OpenERP Server.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__logger = _getChildLogger(_logger, 'connector')
|
|
||||||
|
|
||||||
def get_service(self, service_name):
|
|
||||||
"""
|
|
||||||
Returns a Service instance to allow easy manipulation of one of the services offered by the remote server.
|
|
||||||
|
|
||||||
:param service_name: The name of the service.
|
|
||||||
"""
|
|
||||||
return Service(self, service_name)
|
|
||||||
|
|
||||||
class XmlRPCConnector(Connector):
|
|
||||||
"""
|
|
||||||
A type of connector that uses the XMLRPC protocol.
|
|
||||||
"""
|
|
||||||
PROTOCOL = 'xmlrpc'
|
|
||||||
|
|
||||||
__logger = _getChildLogger(_logger, 'connector.xmlrpc')
|
|
||||||
|
|
||||||
def __init__(self, hostname, port=8069):
|
|
||||||
"""
|
|
||||||
Initialize by specifying the hostname and the port.
|
|
||||||
:param hostname: The hostname of the computer holding the instance of OpenERP.
|
|
||||||
:param port: The port used by the OpenERP instance for XMLRPC (default to 8069).
|
|
||||||
"""
|
|
||||||
self.url = 'http://%s:%d/xmlrpc' % (hostname, port)
|
|
||||||
|
|
||||||
def send(self, service_name, method, *args):
|
|
||||||
url = '%s/%s' % (self.url, service_name)
|
|
||||||
service = xmlrpclib.ServerProxy(url)
|
|
||||||
return getattr(service, method)(*args)
|
|
||||||
|
|
||||||
class XmlRPCSConnector(XmlRPCConnector):
|
|
||||||
"""
|
|
||||||
A type of connector that uses the secured XMLRPC protocol.
|
|
||||||
"""
|
|
||||||
PROTOCOL = 'xmlrpcs'
|
|
||||||
|
|
||||||
__logger = _getChildLogger(_logger, 'connector.xmlrpcs')
|
|
||||||
|
|
||||||
def __init__(self, hostname, port=8069):
|
|
||||||
super(XmlRPCSConnector, self).__init__(hostname, port)
|
|
||||||
self.url = 'https://%s:%d/xmlrpc' % (hostname, port)
|
|
||||||
|
|
||||||
class Service(object):
|
|
||||||
"""
|
|
||||||
A class to execute RPC calls on a specific service of the remote server.
|
|
||||||
"""
|
|
||||||
def __init__(self, connector, service_name):
|
|
||||||
"""
|
|
||||||
:param connector: A valid Connector instance.
|
|
||||||
:param service_name: The name of the service on the remote server.
|
|
||||||
"""
|
|
||||||
self.connector = connector
|
|
||||||
self.service_name = service_name
|
|
||||||
self.__logger = _getChildLogger(_getChildLogger(_logger, 'service'),service_name or "")
|
|
||||||
|
|
||||||
def __getattr__(self, method):
|
|
||||||
"""
|
|
||||||
:param method: The name of the method to execute on the service.
|
|
||||||
"""
|
|
||||||
self.__logger.debug('method: %r', method)
|
|
||||||
def proxy(*args):
|
|
||||||
"""
|
|
||||||
:param args: A list of values for the method
|
|
||||||
"""
|
|
||||||
self.__logger.debug('args: %r', args)
|
|
||||||
result = self.connector.send(self.service_name, method, *args)
|
|
||||||
self.__logger.debug('result: %r', result)
|
|
||||||
return result
|
|
||||||
return proxy
|
|
||||||
|
|
||||||
class Connection(object):
|
|
||||||
"""
|
|
||||||
A class to represent a connection with authentication to an OpenERP Server.
|
|
||||||
It also provides utility methods to interact with the server more easily.
|
|
||||||
"""
|
|
||||||
__logger = _getChildLogger(_logger, 'connection')
|
|
||||||
|
|
||||||
def __init__(self, connector,
|
|
||||||
database=None,
|
|
||||||
login=None,
|
|
||||||
password=None,
|
|
||||||
user_id=None):
|
|
||||||
"""
|
|
||||||
Initialize with login information. The login information is facultative to allow specifying
|
|
||||||
it after the initialization of this object.
|
|
||||||
|
|
||||||
:param connector: A valid Connector instance to send messages to the remote server.
|
|
||||||
:param database: The name of the database to work on.
|
|
||||||
:param login: The login of the user.
|
|
||||||
:param password: The password of the user.
|
|
||||||
:param user_id: The user id is a number identifying the user. This is only useful if you
|
|
||||||
already know it, in most cases you don't need to specify it.
|
|
||||||
"""
|
|
||||||
self.connector = connector
|
|
||||||
|
|
||||||
self.set_login_info(database, login, password, user_id)
|
|
||||||
self.user_context = None
|
|
||||||
|
|
||||||
def set_login_info(self, database, login, password, user_id=None):
|
|
||||||
"""
|
|
||||||
Set login information after the initialisation of this object.
|
|
||||||
|
|
||||||
:param connector: A valid Connector instance to send messages to the remote server.
|
|
||||||
:param database: The name of the database to work on.
|
|
||||||
:param login: The login of the user.
|
|
||||||
:param password: The password of the user.
|
|
||||||
:param user_id: The user id is a number identifying the user. This is only useful if you
|
|
||||||
already know it, in most cases you don't need to specify it.
|
|
||||||
"""
|
|
||||||
self.database, self.login, self.password = database, login, password
|
|
||||||
|
|
||||||
self.user_id = user_id
|
|
||||||
|
|
||||||
def check_login(self, force=True):
|
|
||||||
"""
|
|
||||||
Checks that the login information is valid. Throws an AuthenticationError if the
|
|
||||||
authentication fails.
|
|
||||||
|
|
||||||
:param force: Force to re-check even if this Connection was already validated previously.
|
|
||||||
Default to True.
|
|
||||||
"""
|
|
||||||
if self.user_id and not force:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.database or not self.login or self.password is None:
|
|
||||||
raise AuthenticationError("Credentials not provided")
|
|
||||||
|
|
||||||
# TODO use authenticate instead of login
|
|
||||||
self.user_id = self.get_service("common").login(self.database, self.login, self.password)
|
|
||||||
if not self.user_id:
|
|
||||||
raise AuthenticationError("Authentication failure")
|
|
||||||
self.__logger.debug("Authenticated with user id %s", self.user_id)
|
|
||||||
|
|
||||||
def get_user_context(self):
|
|
||||||
"""
|
|
||||||
Query the default context of the user.
|
|
||||||
"""
|
|
||||||
if not self.user_context:
|
|
||||||
self.user_context = self.get_model('res.users').context_get()
|
|
||||||
return self.user_context
|
|
||||||
|
|
||||||
def get_model(self, model_name):
|
|
||||||
"""
|
|
||||||
Returns a Model instance to allow easy remote manipulation of an OpenERP model.
|
|
||||||
|
|
||||||
:param model_name: The name of the model.
|
|
||||||
"""
|
|
||||||
return Model(self, model_name)
|
|
||||||
|
|
||||||
def get_service(self, service_name):
|
|
||||||
"""
|
|
||||||
Returns a Service instance to allow easy manipulation of one of the services offered by the remote server.
|
|
||||||
Please note this Connection instance does not need to have valid authentication information since authentication
|
|
||||||
is only necessary for the "object" service that handles models.
|
|
||||||
|
|
||||||
:param service_name: The name of the service.
|
|
||||||
"""
|
|
||||||
return self.connector.get_service(service_name)
|
|
||||||
|
|
||||||
class AuthenticationError(Exception):
|
|
||||||
"""
|
|
||||||
An error thrown when an authentication to an OpenERP server failed.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Model(object):
|
|
||||||
"""
|
|
||||||
Useful class to dialog with one of the models provided by an OpenERP server.
|
|
||||||
An instance of this class depends on a Connection instance with valid authentication information.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, connection, model_name):
|
|
||||||
"""
|
|
||||||
:param connection: A valid Connection instance with correct authentication information.
|
|
||||||
:param model_name: The name of the model.
|
|
||||||
"""
|
|
||||||
self.connection = connection
|
|
||||||
self.model_name = model_name
|
|
||||||
self.__logger = _getChildLogger(_getChildLogger(_logger, 'object'), model_name or "")
|
|
||||||
|
|
||||||
def __getattr__(self, method):
|
|
||||||
"""
|
|
||||||
Provides proxy methods that will forward calls to the model on the remote OpenERP server.
|
|
||||||
|
|
||||||
:param method: The method for the linked model (search, read, write, unlink, create, ...)
|
|
||||||
"""
|
|
||||||
def proxy(*args, **kw):
|
|
||||||
"""
|
|
||||||
:param args: A list of values for the method
|
|
||||||
"""
|
|
||||||
self.connection.check_login(False)
|
|
||||||
self.__logger.debug(args)
|
|
||||||
result = self.connection.get_service('object').execute_kw(
|
|
||||||
self.connection.database,
|
|
||||||
self.connection.user_id,
|
|
||||||
self.connection.password,
|
|
||||||
self.model_name,
|
|
||||||
method,
|
|
||||||
args, kw)
|
|
||||||
if method == "read":
|
|
||||||
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
|
|
||||||
index = {}
|
|
||||||
for r in result:
|
|
||||||
index[r['id']] = r
|
|
||||||
result = [index[x] for x in args[0] if x in index]
|
|
||||||
self.__logger.debug('result: %r', result)
|
|
||||||
return result
|
|
||||||
return proxy
|
|
||||||
|
|
||||||
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
|
|
||||||
"""
|
|
||||||
A shortcut method to combine a search() and a read().
|
|
||||||
|
|
||||||
:param domain: The domain for the search.
|
|
||||||
:param fields: The fields to extract (can be None or [] to extract all fields).
|
|
||||||
:param offset: The offset for the rows to read.
|
|
||||||
:param limit: The maximum number of rows to read.
|
|
||||||
:param order: The order to class the rows.
|
|
||||||
:param context: The context.
|
|
||||||
:return: A list of dictionaries containing all the specified fields.
|
|
||||||
"""
|
|
||||||
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
|
|
||||||
if not record_ids: return []
|
|
||||||
records = self.read(record_ids, fields or [], context or {})
|
|
||||||
return records
|
|
||||||
|
|
||||||
def get_connector(hostname=None, protocol="xmlrpc", port="auto"):
|
|
||||||
"""
|
|
||||||
A shortcut method to easily create a connector to a remote server using XMLRPC.
|
|
||||||
|
|
||||||
:param hostname: The hostname to the remote server.
|
|
||||||
:param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs".
|
|
||||||
:param port: The number of the port. Defaults to auto.
|
|
||||||
"""
|
|
||||||
if port == 'auto':
|
|
||||||
port = 8069
|
|
||||||
if protocol == "xmlrpc":
|
|
||||||
return XmlRPCConnector(hostname, port)
|
|
||||||
elif protocol == "xmlrpcs":
|
|
||||||
return XmlRPCSConnector(hostname, port)
|
|
||||||
else:
|
|
||||||
raise ValueError("You must choose xmlrpc or xmlrpcs")
|
|
||||||
|
|
||||||
def get_connection(hostname=None, protocol="xmlrpc", port='auto', database=None,
|
|
||||||
login=None, password=None, user_id=None):
|
|
||||||
"""
|
|
||||||
A shortcut method to easily create a connection to a remote OpenERP server.
|
|
||||||
|
|
||||||
:param hostname: The hostname to the remote server.
|
|
||||||
:param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs".
|
|
||||||
:param port: The number of the port. Defaults to auto.
|
|
||||||
:param connector: A valid Connector instance to send messages to the remote server.
|
|
||||||
:param database: The name of the database to work on.
|
|
||||||
:param login: The login of the user.
|
|
||||||
:param password: The password of the user.
|
|
||||||
:param user_id: The user id is a number identifying the user. This is only useful if you
|
|
||||||
already know it, in most cases you don't need to specify it.
|
|
||||||
"""
|
|
||||||
return Connection(get_connector(hostname, protocol, port), database, login, password, user_id)
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
name = 'openerp-web'
|
|
||||||
version = '7.0alpha'
|
|
||||||
description = "OpenERP Web"
|
|
||||||
long_description = "OpenERP Web is the web interface of OpenERP, an Open Source Business Application Suite"
|
|
||||||
author = "OpenERP SA"
|
|
||||||
author_email = "info@openerp.com"
|
|
||||||
support_email = 'support@openerp.com'
|
|
||||||
url = "http://www.openerp.com/"
|
|
||||||
download_url = ''
|
|
||||||
license = "AGPL"
|
|
|
@ -1,26 +0,0 @@
|
||||||
# xml2json-direct
|
|
||||||
# Simple and straightforward XML-to-JSON converter in Python
|
|
||||||
# New BSD Licensed
|
|
||||||
#
|
|
||||||
# URL: http://code.google.com/p/xml2json-direct/
|
|
||||||
|
|
||||||
def from_elementtree(el, preserve_whitespaces=False):
|
|
||||||
res = {}
|
|
||||||
if el.tag[0] == "{":
|
|
||||||
ns, name = el.tag.rsplit("}", 1)
|
|
||||||
res["tag"] = name
|
|
||||||
res["namespace"] = ns[1:]
|
|
||||||
else:
|
|
||||||
res["tag"] = el.tag
|
|
||||||
res["attrs"] = {}
|
|
||||||
for k, v in el.items():
|
|
||||||
res["attrs"][k] = v
|
|
||||||
kids = []
|
|
||||||
if el.text and (preserve_whitespaces or el.text.strip() != ''):
|
|
||||||
kids.append(el.text)
|
|
||||||
for kid in el:
|
|
||||||
kids.append(from_elementtree(kid, preserve_whitespaces))
|
|
||||||
if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''):
|
|
||||||
kids.append(kid.tail)
|
|
||||||
res["children"] = kids
|
|
||||||
return res
|
|
|
@ -27,8 +27,11 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
xlwt = None
|
xlwt = None
|
||||||
|
|
||||||
from .. import common
|
import openerp
|
||||||
openerpweb = common.http
|
|
||||||
|
from .. import http
|
||||||
|
from .. import nonliterals
|
||||||
|
openerpweb = http
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web helpers
|
# OpenERP Web helpers
|
||||||
|
@ -135,7 +138,7 @@ def db_list(req):
|
||||||
dbs = proxy.list()
|
dbs = proxy.list()
|
||||||
h = req.httprequest.environ['HTTP_HOST'].split(':')[0]
|
h = req.httprequest.environ['HTTP_HOST'].split(':')[0]
|
||||||
d = h.split('.')[0]
|
d = h.split('.')[0]
|
||||||
r = req.config.dbfilter.replace('%h', h).replace('%d', d)
|
r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
|
||||||
dbs = [i for i in dbs if re.match(r, i)]
|
dbs = [i for i in dbs if re.match(r, i)]
|
||||||
return dbs
|
return dbs
|
||||||
|
|
||||||
|
@ -227,11 +230,12 @@ def module_installed_bypass_session(dbname):
|
||||||
return sorted_modules
|
return sorted_modules
|
||||||
|
|
||||||
def module_boot(req):
|
def module_boot(req):
|
||||||
return [m for m in req.config.server_wide_modules if m in openerpweb.addons_manifest]
|
server_wide_modules = openerp.conf.server_wide_modules or ['web']
|
||||||
|
return [m for m in server_wide_modules if m in openerpweb.addons_manifest]
|
||||||
# TODO the following will be enabled once we separate the module code and translation loading
|
# TODO the following will be enabled once we separate the module code and translation loading
|
||||||
serverside = []
|
serverside = []
|
||||||
dbside = []
|
dbside = []
|
||||||
for i in req.config.server_wide_modules:
|
for i in server_wide_modules:
|
||||||
if i in openerpweb.addons_manifest:
|
if i in openerpweb.addons_manifest:
|
||||||
serverside.append(i)
|
serverside.append(i)
|
||||||
# if only one db load every module at boot
|
# if only one db load every module at boot
|
||||||
|
@ -502,12 +506,12 @@ def fix_view_modes(action):
|
||||||
|
|
||||||
def parse_domain(domain, session):
|
def parse_domain(domain, session):
|
||||||
""" Parses an arbitrary string containing a domain, transforms it
|
""" Parses an arbitrary string containing a domain, transforms it
|
||||||
to either a literal domain or a :class:`common.nonliterals.Domain`
|
to either a literal domain or a :class:`nonliterals.Domain`
|
||||||
|
|
||||||
:param domain: the domain to parse, if the domain is not a string it
|
:param domain: the domain to parse, if the domain is not a string it
|
||||||
is assumed to be a literal domain and is returned as-is
|
is assumed to be a literal domain and is returned as-is
|
||||||
:param session: Current OpenERP session
|
:param session: Current OpenERP session
|
||||||
:type session: openerpweb.openerpweb.OpenERPSession
|
:type session: openerpweb.OpenERPSession
|
||||||
"""
|
"""
|
||||||
if not isinstance(domain, basestring):
|
if not isinstance(domain, basestring):
|
||||||
return domain
|
return domain
|
||||||
|
@ -515,24 +519,23 @@ def parse_domain(domain, session):
|
||||||
return ast.literal_eval(domain)
|
return ast.literal_eval(domain)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# not a literal
|
# not a literal
|
||||||
return common.nonliterals.Domain(session, domain)
|
return nonliterals.Domain(session, domain)
|
||||||
|
|
||||||
def parse_context(context, session):
|
def parse_context(context, session):
|
||||||
""" Parses an arbitrary string containing a context, transforms it
|
""" Parses an arbitrary string containing a context, transforms it
|
||||||
to either a literal context or a :class:`common.nonliterals.Context`
|
to either a literal context or a :class:`nonliterals.Context`
|
||||||
|
|
||||||
:param context: the context to parse, if the context is not a string it
|
:param context: the context to parse, if the context is not a string it
|
||||||
is assumed to be a literal domain and is returned as-is
|
is assumed to be a literal domain and is returned as-is
|
||||||
:param session: Current OpenERP session
|
:param session: Current OpenERP session
|
||||||
:type session: openerpweb.openerpweb.OpenERPSession
|
:type session: openerpweb.OpenERPSession
|
||||||
"""
|
"""
|
||||||
if not isinstance(context, basestring):
|
if not isinstance(context, basestring):
|
||||||
return context
|
return context
|
||||||
try:
|
try:
|
||||||
return ast.literal_eval(context)
|
return ast.literal_eval(context)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return common.nonliterals.Context(session, context)
|
return nonliterals.Context(session, context)
|
||||||
|
|
||||||
|
|
||||||
def _local_web_translations(trans_file):
|
def _local_web_translations(trans_file):
|
||||||
messages = []
|
messages = []
|
||||||
|
@ -546,6 +549,31 @@ def _local_web_translations(trans_file):
|
||||||
messages.append({'id': x.id, 'string': x.string})
|
messages.append({'id': x.id, 'string': x.string})
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
|
def from_elementtree(el, preserve_whitespaces=False):
|
||||||
|
""" xml2json-direct
|
||||||
|
Simple and straightforward XML-to-JSON converter in Python
|
||||||
|
New BSD Licensed
|
||||||
|
http://code.google.com/p/xml2json-direct/
|
||||||
|
"""
|
||||||
|
res = {}
|
||||||
|
if el.tag[0] == "{":
|
||||||
|
ns, name = el.tag.rsplit("}", 1)
|
||||||
|
res["tag"] = name
|
||||||
|
res["namespace"] = ns[1:]
|
||||||
|
else:
|
||||||
|
res["tag"] = el.tag
|
||||||
|
res["attrs"] = {}
|
||||||
|
for k, v in el.items():
|
||||||
|
res["attrs"][k] = v
|
||||||
|
kids = []
|
||||||
|
if el.text and (preserve_whitespaces or el.text.strip() != ''):
|
||||||
|
kids.append(el.text)
|
||||||
|
for kid in el:
|
||||||
|
kids.append(from_elementtree(kid, preserve_whitespaces))
|
||||||
|
if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''):
|
||||||
|
kids.append(kid.tail)
|
||||||
|
res["children"] = kids
|
||||||
|
return res
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web web Controllers
|
# OpenERP Web web Controllers
|
||||||
|
@ -612,7 +640,6 @@ class Home(openerpweb.Controller):
|
||||||
def login(self, req, db, login, key):
|
def login(self, req, db, login, key):
|
||||||
return login_and_redirect(req, db, login, key)
|
return login_and_redirect(req, db, login, key)
|
||||||
|
|
||||||
|
|
||||||
class WebClient(openerpweb.Controller):
|
class WebClient(openerpweb.Controller):
|
||||||
_cp_path = "/web/webclient"
|
_cp_path = "/web/webclient"
|
||||||
|
|
||||||
|
@ -746,7 +773,7 @@ class WebClient(openerpweb.Controller):
|
||||||
@openerpweb.jsonrequest
|
@openerpweb.jsonrequest
|
||||||
def version_info(self, req):
|
def version_info(self, req):
|
||||||
return {
|
return {
|
||||||
"version": common.release.version
|
"version": openerp.release.version
|
||||||
}
|
}
|
||||||
|
|
||||||
class Proxy(openerpweb.Controller):
|
class Proxy(openerpweb.Controller):
|
||||||
|
@ -862,12 +889,10 @@ class Session(openerpweb.Controller):
|
||||||
@openerpweb.jsonrequest
|
@openerpweb.jsonrequest
|
||||||
def authenticate(self, req, db, login, password, base_location=None):
|
def authenticate(self, req, db, login, password, base_location=None):
|
||||||
wsgienv = req.httprequest.environ
|
wsgienv = req.httprequest.environ
|
||||||
release = common.release
|
|
||||||
env = dict(
|
env = dict(
|
||||||
base_location=base_location,
|
base_location=base_location,
|
||||||
HTTP_HOST=wsgienv['HTTP_HOST'],
|
HTTP_HOST=wsgienv['HTTP_HOST'],
|
||||||
REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
|
REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
|
||||||
user_agent="%s / %s" % (release.name, release.version),
|
|
||||||
)
|
)
|
||||||
req.session.authenticate(db, login, password, env)
|
req.session.authenticate(db, login, password, env)
|
||||||
|
|
||||||
|
@ -942,8 +967,8 @@ class Session(openerpweb.Controller):
|
||||||
no group by should be performed)
|
no group by should be performed)
|
||||||
"""
|
"""
|
||||||
context, domain = eval_context_and_domain(req.session,
|
context, domain = eval_context_and_domain(req.session,
|
||||||
common.nonliterals.CompoundContext(*(contexts or [])),
|
nonliterals.CompoundContext(*(contexts or [])),
|
||||||
common.nonliterals.CompoundDomain(*(domains or [])))
|
nonliterals.CompoundDomain(*(domains or [])))
|
||||||
|
|
||||||
group_by_sequence = []
|
group_by_sequence = []
|
||||||
for candidate in (group_by_seq or []):
|
for candidate in (group_by_seq or []):
|
||||||
|
@ -1165,14 +1190,14 @@ class DataSet(openerpweb.Controller):
|
||||||
|
|
||||||
def _call_kw(self, req, model, method, args, kwargs):
|
def _call_kw(self, req, model, method, args, kwargs):
|
||||||
for i in xrange(len(args)):
|
for i in xrange(len(args)):
|
||||||
if isinstance(args[i], common.nonliterals.BaseContext):
|
if isinstance(args[i], nonliterals.BaseContext):
|
||||||
args[i] = req.session.eval_context(args[i])
|
args[i] = req.session.eval_context(args[i])
|
||||||
elif isinstance(args[i], common.nonliterals.BaseDomain):
|
elif isinstance(args[i], nonliterals.BaseDomain):
|
||||||
args[i] = req.session.eval_domain(args[i])
|
args[i] = req.session.eval_domain(args[i])
|
||||||
for k in kwargs.keys():
|
for k in kwargs.keys():
|
||||||
if isinstance(kwargs[k], common.nonliterals.BaseContext):
|
if isinstance(kwargs[k], nonliterals.BaseContext):
|
||||||
kwargs[k] = req.session.eval_context(kwargs[k])
|
kwargs[k] = req.session.eval_context(kwargs[k])
|
||||||
elif isinstance(kwargs[k], common.nonliterals.BaseDomain):
|
elif isinstance(kwargs[k], nonliterals.BaseDomain):
|
||||||
kwargs[k] = req.session.eval_domain(kwargs[k])
|
kwargs[k] = req.session.eval_domain(kwargs[k])
|
||||||
|
|
||||||
# Temporary implements future display_name special field for model#read()
|
# Temporary implements future display_name special field for model#read()
|
||||||
|
@ -1303,7 +1328,7 @@ class View(openerpweb.Controller):
|
||||||
xml = self.transform_view(arch, session, evaluation_context)
|
xml = self.transform_view(arch, session, evaluation_context)
|
||||||
else:
|
else:
|
||||||
xml = ElementTree.fromstring(arch)
|
xml = ElementTree.fromstring(arch)
|
||||||
fvg['arch'] = common.xml2json.from_elementtree(xml, preserve_whitespaces)
|
fvg['arch'] = from_elementtree(xml, preserve_whitespaces)
|
||||||
|
|
||||||
if 'id' in fvg['fields']:
|
if 'id' in fvg['fields']:
|
||||||
# Special case for id's
|
# Special case for id's
|
||||||
|
@ -1436,12 +1461,12 @@ class SearchView(View):
|
||||||
try:
|
try:
|
||||||
parsed_context = parse_context(filter["context"], req.session)
|
parsed_context = parse_context(filter["context"], req.session)
|
||||||
filter["context"] = (parsed_context
|
filter["context"] = (parsed_context
|
||||||
if not isinstance(parsed_context, common.nonliterals.BaseContext)
|
if not isinstance(parsed_context, nonliterals.BaseContext)
|
||||||
else req.session.eval_context(parsed_context))
|
else req.session.eval_context(parsed_context))
|
||||||
|
|
||||||
parsed_domain = parse_domain(filter["domain"], req.session)
|
parsed_domain = parse_domain(filter["domain"], req.session)
|
||||||
filter["domain"] = (parsed_domain
|
filter["domain"] = (parsed_domain
|
||||||
if not isinstance(parsed_domain, common.nonliterals.BaseDomain)
|
if not isinstance(parsed_domain, nonliterals.BaseDomain)
|
||||||
else req.session.eval_domain(parsed_domain))
|
else req.session.eval_domain(parsed_domain))
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Failed to parse custom filter %s in %s",
|
logger.exception("Failed to parse custom filter %s in %s",
|
||||||
|
@ -1932,7 +1957,7 @@ class Reports(View):
|
||||||
|
|
||||||
report_srv = req.session.proxy("report")
|
report_srv = req.session.proxy("report")
|
||||||
context = req.session.eval_context(
|
context = req.session.eval_context(
|
||||||
common.nonliterals.CompoundContext(
|
nonliterals.CompoundContext(
|
||||||
req.context or {}, action[ "context"]))
|
req.context or {}, action[ "context"]))
|
||||||
|
|
||||||
report_data = {}
|
report_data = {}
|
||||||
|
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
@ -1,6 +1,16 @@
|
||||||
API changes from OpenERP Web 6.1 to 7.0
|
API changes from OpenERP Web 6.1 to 7.0
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
|
Supported browsers
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The OpenERP Web Client supports the following web browsers:
|
||||||
|
|
||||||
|
* Internet Explorer 9+
|
||||||
|
* Google Chrome 22+
|
||||||
|
* Firefox 13+
|
||||||
|
* Any browser using the latest version of Chrome Frame
|
||||||
|
|
||||||
DataSet -> Model
|
DataSet -> Model
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -6,15 +6,18 @@ import ast
|
||||||
import cgi
|
import cgi
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
|
import getpass
|
||||||
import logging
|
import logging
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import urllib
|
import urllib
|
||||||
|
import urlparse
|
||||||
import uuid
|
import uuid
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
|
|
||||||
|
@ -26,18 +29,15 @@ import werkzeug.utils
|
||||||
import werkzeug.wrappers
|
import werkzeug.wrappers
|
||||||
import werkzeug.wsgi
|
import werkzeug.wsgi
|
||||||
|
|
||||||
from . import nonliterals
|
import openerp
|
||||||
from . import session
|
|
||||||
from . import openerplib
|
|
||||||
import urlparse
|
|
||||||
|
|
||||||
__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
|
import nonliterals
|
||||||
'WebRequest', 'JsonRequest', 'HttpRequest']
|
import session
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web RequestHandler
|
# RequestHandler
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
class WebRequest(object):
|
class WebRequest(object):
|
||||||
""" Parent class for all OpenERP Web request types, mostly deals with
|
""" Parent class for all OpenERP Web request types, mostly deals with
|
||||||
|
@ -46,7 +46,6 @@ class WebRequest(object):
|
||||||
|
|
||||||
:param request: a wrapped werkzeug Request object
|
:param request: a wrapped werkzeug Request object
|
||||||
:type request: :class:`werkzeug.wrappers.BaseRequest`
|
:type request: :class:`werkzeug.wrappers.BaseRequest`
|
||||||
:param config: configuration object
|
|
||||||
|
|
||||||
.. attribute:: httprequest
|
.. attribute:: httprequest
|
||||||
|
|
||||||
|
@ -58,10 +57,6 @@ class WebRequest(object):
|
||||||
a :class:`~collections.Mapping` holding the HTTP session data for the
|
a :class:`~collections.Mapping` holding the HTTP session data for the
|
||||||
current http session
|
current http session
|
||||||
|
|
||||||
.. attribute:: config
|
|
||||||
|
|
||||||
config parameter provided to the request object
|
|
||||||
|
|
||||||
.. attribute:: params
|
.. attribute:: params
|
||||||
|
|
||||||
:class:`~collections.Mapping` of request parameters, not generally
|
:class:`~collections.Mapping` of request parameters, not generally
|
||||||
|
@ -85,11 +80,10 @@ class WebRequest(object):
|
||||||
|
|
||||||
``bool``, indicates whether the debug mode is active on the client
|
``bool``, indicates whether the debug mode is active on the client
|
||||||
"""
|
"""
|
||||||
def __init__(self, request, config):
|
def __init__(self, request):
|
||||||
self.httprequest = request
|
self.httprequest = request
|
||||||
self.httpresponse = None
|
self.httpresponse = None
|
||||||
self.httpsession = request.session
|
self.httpsession = request.session
|
||||||
self.config = config
|
|
||||||
|
|
||||||
def init(self, params):
|
def init(self, params):
|
||||||
self.params = dict(params)
|
self.params = dict(params)
|
||||||
|
@ -98,7 +92,6 @@ class WebRequest(object):
|
||||||
self.session = self.httpsession.get(self.session_id)
|
self.session = self.httpsession.get(self.session_id)
|
||||||
if not self.session:
|
if not self.session:
|
||||||
self.httpsession[self.session_id] = self.session = session.OpenERPSession()
|
self.httpsession[self.session_id] = self.session = session.OpenERPSession()
|
||||||
self.session.config = self.config
|
|
||||||
self.context = self.params.pop('context', None)
|
self.context = self.params.pop('context', None)
|
||||||
self.debug = self.params.pop('debug', False) != False
|
self.debug = self.params.pop('debug', False) != False
|
||||||
|
|
||||||
|
@ -180,7 +173,7 @@ class JsonRequest(WebRequest):
|
||||||
_logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest))
|
_logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest))
|
||||||
response['id'] = self.jsonrequest.get('id')
|
response['id'] = self.jsonrequest.get('id')
|
||||||
response["result"] = method(controller, self, **self.params)
|
response["result"] = method(controller, self, **self.params)
|
||||||
except openerplib.AuthenticationError:
|
except session.AuthenticationError:
|
||||||
error = {
|
error = {
|
||||||
'code': 100,
|
'code': 100,
|
||||||
'message': "OpenERP Session Invalid",
|
'message': "OpenERP Session Invalid",
|
||||||
|
@ -238,8 +231,8 @@ def jsonrequest(f):
|
||||||
beforehand)
|
beforehand)
|
||||||
"""
|
"""
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def json_handler(controller, request, config):
|
def json_handler(controller, request):
|
||||||
return JsonRequest(request, config).dispatch(controller, f)
|
return JsonRequest(request).dispatch(controller, f)
|
||||||
json_handler.exposed = True
|
json_handler.exposed = True
|
||||||
return json_handler
|
return json_handler
|
||||||
|
|
||||||
|
@ -325,13 +318,13 @@ def httprequest(f):
|
||||||
and ``debug`` keys (which are stripped out beforehand)
|
and ``debug`` keys (which are stripped out beforehand)
|
||||||
"""
|
"""
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def http_handler(controller, request, config):
|
def http_handler(controller, request):
|
||||||
return HttpRequest(request, config).dispatch(controller, f)
|
return HttpRequest(request).dispatch(controller, f)
|
||||||
http_handler.exposed = True
|
http_handler.exposed = True
|
||||||
return http_handler
|
return http_handler
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web Controller registration with a metaclass
|
# Controller registration with a metaclass
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
addons_module = {}
|
addons_module = {}
|
||||||
addons_manifest = {}
|
addons_manifest = {}
|
||||||
|
@ -348,7 +341,7 @@ class Controller(object):
|
||||||
__metaclass__ = ControllerType
|
__metaclass__ = ControllerType
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web Session context manager
|
# Session context manager
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
STORES = {}
|
STORES = {}
|
||||||
|
|
||||||
|
@ -419,12 +412,13 @@ def session_context(request, storage_path, session_cookie='httpsessionid'):
|
||||||
session_store.save(request.session)
|
session_store.save(request.session)
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERP Web WSGI Application
|
# WSGI Application
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# Add potentially missing (older ubuntu) font mime types
|
# Add potentially missing (older ubuntu) font mime types
|
||||||
mimetypes.add_type('application/font-woff', '.woff')
|
mimetypes.add_type('application/font-woff', '.woff')
|
||||||
mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
|
mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
|
||||||
mimetypes.add_type('application/x-font-ttf', '.ttf')
|
mimetypes.add_type('application/x-font-ttf', '.ttf')
|
||||||
|
|
||||||
class DisableCacheMiddleware(object):
|
class DisableCacheMiddleware(object):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
@ -449,45 +443,23 @@ class DisableCacheMiddleware(object):
|
||||||
|
|
||||||
class Root(object):
|
class Root(object):
|
||||||
"""Root WSGI application for the OpenERP Web Client.
|
"""Root WSGI application for the OpenERP Web Client.
|
||||||
|
|
||||||
:param options: mandatory initialization options object, must provide
|
|
||||||
the following attributes:
|
|
||||||
|
|
||||||
``server_host`` (``str``)
|
|
||||||
hostname of the OpenERP server to dispatch RPC to
|
|
||||||
``server_port`` (``int``)
|
|
||||||
RPC port of the OpenERP server
|
|
||||||
``serve_static`` (``bool | None``)
|
|
||||||
whether this application should serve the various
|
|
||||||
addons's static files
|
|
||||||
``storage_path`` (``str``)
|
|
||||||
filesystem path where HTTP session data will be stored
|
|
||||||
``dbfilter`` (``str``)
|
|
||||||
only used in case the list of databases is requested
|
|
||||||
by the server, will be filtered by this pattern
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, options):
|
def __init__(self):
|
||||||
self.config = options
|
|
||||||
|
|
||||||
if not hasattr(self.config, 'connector'):
|
|
||||||
if self.config.backend == 'local':
|
|
||||||
self.config.connector = session.LocalConnector()
|
|
||||||
else:
|
|
||||||
self.config.connector = openerplib.get_connector(
|
|
||||||
hostname=self.config.server_host, port=self.config.server_port)
|
|
||||||
|
|
||||||
self.httpsession_cookie = 'httpsessionid'
|
self.httpsession_cookie = 'httpsessionid'
|
||||||
self.addons = {}
|
self.addons = {}
|
||||||
|
|
||||||
static_dirs = self._load_addons()
|
static_dirs = self._load_addons()
|
||||||
if options.serve_static:
|
app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs)
|
||||||
app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs)
|
self.dispatch = DisableCacheMiddleware(app)
|
||||||
self.dispatch = DisableCacheMiddleware(app)
|
|
||||||
|
|
||||||
if options.session_storage:
|
try:
|
||||||
if not os.path.exists(options.session_storage):
|
username = getpass.getuser()
|
||||||
os.mkdir(options.session_storage, 0700)
|
except Exception:
|
||||||
self.session_storage = options.session_storage
|
username = "unknown"
|
||||||
|
self.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
|
||||||
|
|
||||||
|
if not os.path.exists(self.session_storage):
|
||||||
|
os.mkdir(self.session_storage, 0700)
|
||||||
_logger.debug('HTTP sessions stored in: %s', self.session_storage)
|
_logger.debug('HTTP sessions stored in: %s', self.session_storage)
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
|
@ -512,7 +484,7 @@ class Root(object):
|
||||||
response = werkzeug.exceptions.NotFound()
|
response = werkzeug.exceptions.NotFound()
|
||||||
else:
|
else:
|
||||||
with session_context(request, self.session_storage, self.httpsession_cookie) as session:
|
with session_context(request, self.session_storage, self.httpsession_cookie) as session:
|
||||||
result = handler( request, self.config)
|
result = handler( request)
|
||||||
|
|
||||||
if isinstance(result, basestring):
|
if isinstance(result, basestring):
|
||||||
headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
|
headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
|
||||||
|
@ -531,7 +503,7 @@ class Root(object):
|
||||||
static URLs to the corresponding directories
|
static URLs to the corresponding directories
|
||||||
"""
|
"""
|
||||||
statics = {}
|
statics = {}
|
||||||
for addons_path in self.config.addons_path:
|
for addons_path in openerp.modules.module.ad_paths:
|
||||||
for module in os.listdir(addons_path):
|
for module in os.listdir(addons_path):
|
||||||
if module not in addons_module:
|
if module not in addons_module:
|
||||||
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
|
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
|
||||||
|
@ -579,4 +551,7 @@ class Root(object):
|
||||||
ps = '/'
|
ps = '/'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def wsgi_postload():
|
||||||
|
openerp.wsgi.register_wsgi_handler(Root())
|
||||||
|
|
||||||
# vim:et:ts=4:sw=4:
|
# vim:et:ts=4:sw=4:
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
"X-Poedit-Language: Czech\n"
|
"X-Poedit-Language: Czech\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -9,13 +9,13 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||||
"PO-Revision-Date: 2012-07-02 14:46+0000\n"
|
"PO-Revision-Date: 2012-07-02 14:46+0000\n"
|
||||||
"Last-Translator: Erwin <Unknown>\n"
|
"Last-Translator: Erwin van der Ploeg (Endian Solutions) <Unknown>\n"
|
||||||
"Language-Team: Dutch <nl@li.org>\n"
|
"Language-Team: Dutch <nl@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -15,8 +15,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web/static/src/js/chrome.js:176
|
#: addons/web/static/src/js/chrome.js:176
|
||||||
|
|
|
@ -4,70 +4,58 @@ import babel
|
||||||
import dateutil.relativedelta
|
import dateutil.relativedelta
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
|
import xmlrpclib
|
||||||
|
|
||||||
import openerplib
|
import openerp
|
||||||
|
|
||||||
from . import nonliterals
|
import nonliterals
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
#----------------------------------------------------------
|
|
||||||
# openerplib local connector
|
|
||||||
#----------------------------------------------------------
|
|
||||||
class LibException(Exception):
|
|
||||||
""" Base of all client lib exceptions """
|
|
||||||
def __init__(self,code=None,message=None):
|
|
||||||
self.code = code
|
|
||||||
self.message = message
|
|
||||||
|
|
||||||
class ApplicationError(LibException):
|
|
||||||
""" maps to code: 1, server side: Exception or openerp.exceptions.DeferredException"""
|
|
||||||
|
|
||||||
class Warning(LibException):
|
|
||||||
""" maps to code: 2, server side: openerp.exceptions.Warning"""
|
|
||||||
|
|
||||||
class AccessError(LibException):
|
|
||||||
""" maps to code: 3, server side: openerp.exceptions.AccessError"""
|
|
||||||
|
|
||||||
class AccessDenied(LibException):
|
|
||||||
""" maps to code: 4, server side: openerp.exceptions.AccessDenied"""
|
|
||||||
|
|
||||||
class LocalConnector(openerplib.Connector):
|
|
||||||
"""
|
|
||||||
A type of connector that uses the XMLRPC protocol.
|
|
||||||
"""
|
|
||||||
PROTOCOL = 'local'
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def send(self, service_name, method, *args):
|
|
||||||
import openerp
|
|
||||||
import traceback
|
|
||||||
import xmlrpclib
|
|
||||||
code_string = "warning -- %s\n\n%s"
|
|
||||||
try:
|
|
||||||
return openerp.netsvc.dispatch_rpc(service_name, method, args)
|
|
||||||
except openerp.osv.osv.except_osv, e:
|
|
||||||
# TODO change the except to raise LibException instead of their emulated xmlrpc fault
|
|
||||||
raise xmlrpclib.Fault(code_string % (e.name, e.value), '')
|
|
||||||
except openerp.exceptions.Warning, e:
|
|
||||||
raise xmlrpclib.Fault(code_string % ("Warning", e), '')
|
|
||||||
except openerp.exceptions.AccessError, e:
|
|
||||||
raise xmlrpclib.Fault(code_string % ("AccessError", e), '')
|
|
||||||
except openerp.exceptions.AccessDenied, e:
|
|
||||||
raise xmlrpclib.Fault('AccessDenied', str(e))
|
|
||||||
except openerp.exceptions.DeferredException, e:
|
|
||||||
formatted_info = "".join(traceback.format_exception(*e.traceback))
|
|
||||||
raise xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info)
|
|
||||||
except Exception, e:
|
|
||||||
formatted_info = "".join(traceback.format_exception(*(sys.exc_info())))
|
|
||||||
raise xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info)
|
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# OpenERPSession RPC openerp backend access
|
# OpenERPSession RPC openerp backend access
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
|
class AuthenticationError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Service(object):
|
||||||
|
def __init__(self, session, service_name):
|
||||||
|
self.session = session
|
||||||
|
self.service_name = service_name
|
||||||
|
|
||||||
|
def __getattr__(self, method):
|
||||||
|
def proxy_method(*args):
|
||||||
|
result = self.session.send(self.service_name, method, *args)
|
||||||
|
return result
|
||||||
|
return proxy_method
|
||||||
|
|
||||||
|
class Model(object):
|
||||||
|
def __init__(self, session, model):
|
||||||
|
self.session = session
|
||||||
|
self.model = model
|
||||||
|
self.proxy = self.session.proxy('object')
|
||||||
|
|
||||||
|
def __getattr__(self, method):
|
||||||
|
def proxy(*args, **kw):
|
||||||
|
result = self.proxy.execute_kw(self.session._db, self.session._uid, self.session._password, self.model, method, args, kw)
|
||||||
|
# reorder read
|
||||||
|
if method == "read":
|
||||||
|
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
|
||||||
|
index = {}
|
||||||
|
for r in result:
|
||||||
|
index[r['id']] = r
|
||||||
|
result = [index[x] for x in args[0] if x in index]
|
||||||
|
return result
|
||||||
|
return proxy
|
||||||
|
|
||||||
|
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
|
||||||
|
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
|
||||||
|
if not record_ids: return []
|
||||||
|
records = self.read(record_ids, fields or [], context or {})
|
||||||
|
return records
|
||||||
|
|
||||||
class OpenERPSession(object):
|
class OpenERPSession(object):
|
||||||
"""
|
"""
|
||||||
An OpenERP RPC session, a given user can own multiple such sessions
|
An OpenERP RPC session, a given user can own multiple such sessions
|
||||||
|
@ -87,7 +75,6 @@ class OpenERPSession(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._creation_time = time.time()
|
self._creation_time = time.time()
|
||||||
self.config = None
|
|
||||||
self._db = False
|
self._db = False
|
||||||
self._uid = False
|
self._uid = False
|
||||||
self._login = False
|
self._login = False
|
||||||
|
@ -98,19 +85,27 @@ class OpenERPSession(object):
|
||||||
self.domains_store = {}
|
self.domains_store = {}
|
||||||
self.jsonp_requests = {} # FIXME use a LRU
|
self.jsonp_requests = {} # FIXME use a LRU
|
||||||
|
|
||||||
def __getstate__(self):
|
def send(self, service_name, method, *args):
|
||||||
state = dict(self.__dict__)
|
code_string = "warning -- %s\n\n%s"
|
||||||
if "config" in state:
|
try:
|
||||||
del state['config']
|
return openerp.netsvc.dispatch_rpc(service_name, method, args)
|
||||||
return state
|
except openerp.osv.osv.except_osv, e:
|
||||||
|
raise xmlrpclib.Fault(code_string % (e.name, e.value), '')
|
||||||
def build_connection(self):
|
except openerp.exceptions.Warning, e:
|
||||||
conn = openerplib.Connection(self.config.connector, database=self._db, login=self._login,
|
raise xmlrpclib.Fault(code_string % ("Warning", e), '')
|
||||||
user_id=self._uid, password=self._password)
|
except openerp.exceptions.AccessError, e:
|
||||||
return conn
|
raise xmlrpclib.Fault(code_string % ("AccessError", e), '')
|
||||||
|
except openerp.exceptions.AccessDenied, e:
|
||||||
|
raise xmlrpclib.Fault('AccessDenied', str(e))
|
||||||
|
except openerp.exceptions.DeferredException, e:
|
||||||
|
formatted_info = "".join(traceback.format_exception(*e.traceback))
|
||||||
|
raise xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info)
|
||||||
|
except Exception, e:
|
||||||
|
formatted_info = "".join(traceback.format_exception(*(sys.exc_info())))
|
||||||
|
raise xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info)
|
||||||
|
|
||||||
def proxy(self, service):
|
def proxy(self, service):
|
||||||
return self.build_connection().get_service(service)
|
return Service(self, service)
|
||||||
|
|
||||||
def bind(self, db, uid, login, password):
|
def bind(self, db, uid, login, password):
|
||||||
self._db = db
|
self._db = db
|
||||||
|
@ -119,7 +114,6 @@ class OpenERPSession(object):
|
||||||
self._password = password
|
self._password = password
|
||||||
|
|
||||||
def authenticate(self, db, login, password, env=None):
|
def authenticate(self, db, login, password, env=None):
|
||||||
# TODO use the openerplib API once it exposes authenticate()
|
|
||||||
uid = self.proxy('common').authenticate(db, login, password, env)
|
uid = self.proxy('common').authenticate(db, login, password, env)
|
||||||
self.bind(db, uid, login, password)
|
self.bind(db, uid, login, password)
|
||||||
|
|
||||||
|
@ -130,7 +124,12 @@ class OpenERPSession(object):
|
||||||
"""
|
"""
|
||||||
Ensures this session is valid (logged into the openerp server)
|
Ensures this session is valid (logged into the openerp server)
|
||||||
"""
|
"""
|
||||||
self.build_connection().check_login(force)
|
if self._uid and not force:
|
||||||
|
return
|
||||||
|
# TODO use authenticate instead of login
|
||||||
|
uid = self.proxy("common").login(self._db, self._login, self._password)
|
||||||
|
if not uid:
|
||||||
|
raise AuthenticationError("Authentication failure")
|
||||||
|
|
||||||
def ensure_valid(self):
|
def ensure_valid(self):
|
||||||
if self._uid:
|
if self._uid:
|
||||||
|
@ -141,7 +140,7 @@ class OpenERPSession(object):
|
||||||
|
|
||||||
def execute(self, model, func, *l, **d):
|
def execute(self, model, func, *l, **d):
|
||||||
self.assert_valid()
|
self.assert_valid()
|
||||||
model = self.build_connection().get_model(model)
|
model = self.model(model)
|
||||||
r = getattr(model, func)(*l, **d)
|
r = getattr(model, func)(*l, **d)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -157,7 +156,8 @@ class OpenERPSession(object):
|
||||||
:type model: str
|
:type model: str
|
||||||
:rtype: a model object
|
:rtype: a model object
|
||||||
"""
|
"""
|
||||||
return self.build_connection().get_model(model)
|
|
||||||
|
return Model(self, model)
|
||||||
|
|
||||||
def get_context(self):
|
def get_context(self):
|
||||||
""" Re-initializes the current user's session context (based on
|
""" Re-initializes the current user's session context (based on
|
||||||
|
@ -167,7 +167,7 @@ class OpenERPSession(object):
|
||||||
:returns: the new context
|
:returns: the new context
|
||||||
"""
|
"""
|
||||||
assert self._uid, "The user needs to be logged-in to initialize his context"
|
assert self._uid, "The user needs to be logged-in to initialize his context"
|
||||||
self.context = self.build_connection().get_user_context() or {}
|
self.context = self.model('res.users').context_get() or {}
|
||||||
self.context['uid'] = self._uid
|
self.context['uid'] = self._uid
|
||||||
self._fix_lang(self.context)
|
self._fix_lang(self.context)
|
||||||
return self.context
|
return self.context
|
|
@ -25,6 +25,7 @@
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp.openerp_webclient_container {
|
.openerp.openerp_webclient_container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1184,7 +1185,7 @@
|
||||||
color: white;
|
color: white;
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
margin: 1px 6px 0 0;
|
margin: 1px 6px 0 0;
|
||||||
border: 1px solid lightgrey;
|
border: 1px solid lightGray;
|
||||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
-moz-border-radius: 4px;
|
-moz-border-radius: 4px;
|
||||||
-webkit-border-radius: 4px;
|
-webkit-border-radius: 4px;
|
||||||
|
@ -1209,7 +1210,7 @@
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
.openerp .oe_secondary_submenu .oe_active {
|
.openerp .oe_secondary_submenu .oe_active {
|
||||||
border-top: 1px solid lightgrey;
|
border-top: 1px solid lightGray;
|
||||||
border-bottom: 1px solid #dedede;
|
border-bottom: 1px solid #dedede;
|
||||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2);
|
-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2);
|
||||||
|
@ -2054,36 +2055,36 @@
|
||||||
width: 400px;
|
width: 400px;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags div.oe_chatter {
|
.openerp .oe_form div.oe_chatter {
|
||||||
min-width: 650px;
|
min-width: 650px;
|
||||||
max-width: 860px;
|
max-width: 860px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 16px 0 48px;
|
padding: 16px 0 48px;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags div.oe_form_configuration p, .openerp .oe_form header .oe_tags div.oe_form_configuration ul, .openerp .oe_form header .oe_tags div.oe_form_configuration ol {
|
.openerp .oe_form div.oe_form_configuration p, .openerp .oe_form div.oe_form_configuration ul, .openerp .oe_form div.oe_form_configuration ol {
|
||||||
color: #aaaaaa;
|
color: #aaaaaa;
|
||||||
max-width: 650px;
|
max-width: 650px;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags div.oe_form_configuration label {
|
.openerp .oe_form div.oe_form_configuration label {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags div.oe_form_configuration .oe_form_group_cell_label {
|
.openerp .oe_form div.oe_form_configuration .oe_form_group_cell_label {
|
||||||
padding: 1px 0;
|
padding: 1px 0;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags div.oe_form_configuration .oe_form_group_cell div div {
|
.openerp .oe_form div.oe_form_configuration .oe_form_group_cell div div {
|
||||||
padding: 1px 0;
|
padding: 1px 0;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer {
|
.openerp .oe_form .oe_subtotal_footer {
|
||||||
width: 1% !important;
|
width: 1% !important;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer td.oe_form_group_cell {
|
.openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer td.oe_form_group_cell_label {
|
.openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell_label {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer .oe_subtotal_footer_separator {
|
.openerp .oe_form .oe_subtotal_footer .oe_subtotal_footer_separator {
|
||||||
width: 108px;
|
width: 108px;
|
||||||
border-top: 1px solid #cacaca;
|
border-top: 1px solid #cacaca;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
@ -2091,14 +2092,14 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer label:after {
|
.openerp .oe_form .oe_subtotal_footer label:after {
|
||||||
content: ":";
|
content: ":";
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer label.oe_subtotal_footer_separator {
|
.openerp .oe_form .oe_subtotal_footer label.oe_subtotal_footer_separator {
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
padding: 2px 11px 2px 0px !important;
|
padding: 2px 11px 2px 0px !important;
|
||||||
}
|
}
|
||||||
.openerp .oe_form header .oe_tags .oe_subtotal_footer label.oe_form_label_help {
|
.openerp .oe_form .oe_subtotal_footer label.oe_form_label_help {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.openerp .oe_form .oe_form_button {
|
.openerp .oe_form .oe_form_button {
|
||||||
|
@ -2130,7 +2131,7 @@
|
||||||
}
|
}
|
||||||
.openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span {
|
.openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: darkgreen;
|
color: darkGreen;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -4px;
|
top: -4px;
|
||||||
|
|
|
@ -1616,16 +1616,18 @@ $sheet-max-width: 860px
|
||||||
ul
|
ul
|
||||||
display: inline-block
|
display: inline-block
|
||||||
float: right
|
float: right
|
||||||
.oe_button,
|
.oe_button
|
||||||
margin: 3px 2px 1px
|
margin: 3px 2px 1px
|
||||||
&:first-child
|
&:first-child
|
||||||
margin-left: 6px
|
margin-left: 6px
|
||||||
// }}}
|
// }}}
|
||||||
// FormView.custom tags and classes {{{
|
// FormView.custom tags and classes {{{
|
||||||
.oe_form header .oe_tags
|
.oe_form
|
||||||
margin: 5px 0 0 5px
|
header
|
||||||
width: 400px
|
.oe_tags
|
||||||
padding-bottom: 0
|
margin: 5px 0 0 5px
|
||||||
|
width: 400px
|
||||||
|
padding-bottom: 0
|
||||||
div.oe_chatter
|
div.oe_chatter
|
||||||
min-width: 650px
|
min-width: 650px
|
||||||
max-width: $sheet-max-width
|
max-width: $sheet-max-width
|
||||||
|
|
|
@ -70,7 +70,7 @@ instance.web.Dialog = instance.web.Widget.extend({
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
position: [false, 40],
|
position: [false, 40],
|
||||||
buttons: {},
|
buttons: {},
|
||||||
beforeClose: function () { self.on_close(); },
|
beforeClose: function () { self.close(); },
|
||||||
resizeStop: this.on_resized
|
resizeStop: this.on_resized
|
||||||
};
|
};
|
||||||
for (var f in this) {
|
for (var f in this) {
|
||||||
|
@ -150,16 +150,14 @@ instance.web.Dialog = instance.web.Widget.extend({
|
||||||
var res = this.start();
|
var res = this.start();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
this.$el.dialog('close');
|
|
||||||
},
|
|
||||||
on_close: function() {
|
|
||||||
if (this.__tmp_dialog_destroying)
|
if (this.__tmp_dialog_destroying)
|
||||||
return;
|
return;
|
||||||
if (this.dialog_options.destroy_on_close) {
|
if (this.dialog_options.destroy_on_close) {
|
||||||
this.__tmp_dialog_closing = true;
|
this.__tmp_dialog_closing = true;
|
||||||
this.destroy();
|
this.destroy();
|
||||||
this.__tmp_dialog_closing = undefined;
|
this.__tmp_dialog_closing = undefined;
|
||||||
|
this.trigger("dialog_close");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_resized: function() {
|
on_resized: function() {
|
||||||
|
@ -181,7 +179,7 @@ instance.web.Dialog = instance.web.Widget.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
||||||
on_rpc_error: function(error) {
|
rpc_error: function(error) {
|
||||||
if (error.data.fault_code) {
|
if (error.data.fault_code) {
|
||||||
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
|
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
|
@ -190,12 +188,12 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error.code === 200 && error.type) {
|
if (error.code === 200 && error.type) {
|
||||||
this.on_managed_error(error);
|
this.show_warning(error);
|
||||||
} else {
|
} else {
|
||||||
this.on_traceback(error);
|
this.show_error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_managed_error: function(error) {
|
show_warning: function(error) {
|
||||||
instance.web.dialog($('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>'), {
|
instance.web.dialog($('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>'), {
|
||||||
title: "OpenERP " + _.str.capitalize(error.type),
|
title: "OpenERP " + _.str.capitalize(error.type),
|
||||||
buttons: [
|
buttons: [
|
||||||
|
@ -203,7 +201,7 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_traceback: function(error) {
|
show_error: function(error) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var buttons = {};
|
var buttons = {};
|
||||||
buttons[_t("Ok")] = function() {
|
buttons[_t("Ok")] = function() {
|
||||||
|
@ -219,8 +217,8 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
||||||
}).open();
|
}).open();
|
||||||
dialog.$el.html(QWeb.render('CrashManager.error', {session: instance.session, error: error}));
|
dialog.$el.html(QWeb.render('CrashManager.error', {session: instance.session, error: error}));
|
||||||
},
|
},
|
||||||
on_javascript_exception: function(exception) {
|
show_message: function(exception) {
|
||||||
this.on_traceback({
|
this.show_error({
|
||||||
type: _t("Client Error"),
|
type: _t("Client Error"),
|
||||||
message: exception,
|
message: exception,
|
||||||
data: {debug: ""}
|
data: {debug: ""}
|
||||||
|
@ -236,7 +234,7 @@ instance.web.Loading = instance.web.Widget.extend({
|
||||||
this.blocked_ui = false;
|
this.blocked_ui = false;
|
||||||
this.session.on("request", this, this.request_call);
|
this.session.on("request", this, this.request_call);
|
||||||
this.session.on("response", this, this.response_call);
|
this.session.on("response", this, this.response_call);
|
||||||
this.session.on("error", this, this.response_call);
|
this.session.on("response_failed", this, this.response_call);
|
||||||
},
|
},
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
this.on_rpc_event(-this.count);
|
this.on_rpc_event(-this.count);
|
||||||
|
@ -627,6 +625,7 @@ instance.web.Reload = function(parent, params) {
|
||||||
hash = "#menu_id=" + menu_id;
|
hash = "#menu_id=" + menu_id;
|
||||||
}
|
}
|
||||||
var url = l.protocol + "//" + l.host + l.pathname + search + hash;
|
var url = l.protocol + "//" + l.host + l.pathname + search + hash;
|
||||||
|
window.onerror = function() {};
|
||||||
window.location = url;
|
window.location = url;
|
||||||
};
|
};
|
||||||
instance.web.client_actions.add("reload", "instance.web.Reload");
|
instance.web.client_actions.add("reload", "instance.web.Reload");
|
||||||
|
@ -878,9 +877,8 @@ instance.web.UserMenu = instance.web.Widget.extend({
|
||||||
};
|
};
|
||||||
this.update_promise = this.update_promise.pipe(fct, fct);
|
this.update_promise = this.update_promise.pipe(fct, fct);
|
||||||
},
|
},
|
||||||
on_action: function() {
|
|
||||||
},
|
|
||||||
on_menu_logout: function() {
|
on_menu_logout: function() {
|
||||||
|
this.trigger('user_logout');
|
||||||
},
|
},
|
||||||
on_menu_settings: function() {
|
on_menu_settings: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -897,8 +895,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
|
||||||
var $help = $(QWeb.render("UserMenu.about", {version_info: res}));
|
var $help = $(QWeb.render("UserMenu.about", {version_info: res}));
|
||||||
$help.find('a.oe_activate_debug_mode').click(function (e) {
|
$help.find('a.oe_activate_debug_mode').click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.location = $.param.querystring(
|
window.location = $.param.querystring( window.location.href, 'debug');
|
||||||
window.location.href, 'debug');
|
|
||||||
});
|
});
|
||||||
instance.web.dialog($help, {autoOpen: true,
|
instance.web.dialog($help, {autoOpen: true,
|
||||||
modal: true, width: 507, height: 290, resizable: false, title: _t("About")});
|
modal: true, width: 507, height: 290, resizable: false, title: _t("About")});
|
||||||
|
@ -957,7 +954,7 @@ instance.web.Client = instance.web.Widget.extend({
|
||||||
show_common: function() {
|
show_common: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.crashmanager = new instance.web.CrashManager();
|
this.crashmanager = new instance.web.CrashManager();
|
||||||
instance.session.on_rpc_error.add(this.crashmanager.on_rpc_error);
|
instance.session.on('error', this.crashmanager, this.crashmanager.rpc_error);
|
||||||
self.notification = new instance.web.Notification(this);
|
self.notification = new instance.web.Notification(this);
|
||||||
self.notification.appendTo(self.$el);
|
self.notification.appendTo(self.$el);
|
||||||
self.loading = new instance.web.Loading(self);
|
self.loading = new instance.web.Loading(self);
|
||||||
|
@ -1007,7 +1004,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||||
var self = this;
|
var self = this;
|
||||||
this._super();
|
this._super();
|
||||||
window.onerror = function (message, file, line) {
|
window.onerror = function (message, file, line) {
|
||||||
self.crashmanager.on_traceback({
|
self.crashmanager.show_error({
|
||||||
type: _t("Client Error"),
|
type: _t("Client Error"),
|
||||||
message: message,
|
message: message,
|
||||||
data: {debug: file + ':' + line}
|
data: {debug: file + ':' + line}
|
||||||
|
@ -1016,20 +1013,16 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||||
},
|
},
|
||||||
show_login: function() {
|
show_login: function() {
|
||||||
this.toggle_bars(false);
|
this.toggle_bars(false);
|
||||||
|
|
||||||
var action = {
|
|
||||||
'type': 'ir.actions.client',
|
|
||||||
'tag': 'login'
|
|
||||||
};
|
|
||||||
var state = $.bbq.getState(true);
|
var state = $.bbq.getState(true);
|
||||||
if (state.action === "login") {
|
var action = {
|
||||||
action.params = state;
|
type: 'ir.actions.client',
|
||||||
}
|
tag: 'login',
|
||||||
|
_push_me: false,
|
||||||
|
};
|
||||||
|
|
||||||
this.action_manager.do_action(action);
|
this.action_manager.do_action(action);
|
||||||
this.action_manager.inner_widget.on('login_successful', this, function() {
|
this.action_manager.inner_widget.on('login_successful', this, function() {
|
||||||
this.do_push_state(state);
|
|
||||||
this._current_state = null; // ensure the state will be loaded
|
|
||||||
this.show_application(); // will load the state we just pushed
|
this.show_application(); // will load the state we just pushed
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1041,8 +1034,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||||
self.menu.on('menu_click', this, this.on_menu_action);
|
self.menu.on('menu_click', this, this.on_menu_action);
|
||||||
self.user_menu = new instance.web.UserMenu(self);
|
self.user_menu = new instance.web.UserMenu(self);
|
||||||
self.user_menu.replace(this.$el.find('.oe_user_menu_placeholder'));
|
self.user_menu.replace(this.$el.find('.oe_user_menu_placeholder'));
|
||||||
self.user_menu.on_menu_logout.add(this.proxy('on_logout'));
|
self.user_menu.on('user_logout', self, self.on_logout);
|
||||||
self.user_menu.on_action.add(this.proxy('on_menu_action'));
|
|
||||||
self.user_menu.do_update();
|
self.user_menu.do_update();
|
||||||
self.bind_hashchange();
|
self.bind_hashchange();
|
||||||
self.set_title();
|
self.set_title();
|
||||||
|
@ -1105,6 +1097,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
state._push_me = false; // no need to push state back...
|
||||||
this.action_manager.do_load_state(state, !!this._current_state);
|
this.action_manager.do_load_state(state, !!this._current_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -980,7 +980,8 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
||||||
triggers: {
|
triggers: {
|
||||||
'request': 'Request sent',
|
'request': 'Request sent',
|
||||||
'response': 'Response received',
|
'response': 'Response received',
|
||||||
'error': 'HTTP Error response or timeout received',
|
'response_failed': 'HTTP Error response or timeout received',
|
||||||
|
'error': 'The received response is an JSON-RPC error',
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @constructs instance.web.JsonRPC
|
* @constructs instance.web.JsonRPC
|
||||||
|
@ -1336,7 +1337,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(jqXHR, textStatus, errorThrown) {
|
function(jqXHR, textStatus, errorThrown) {
|
||||||
self.trigger('error');
|
self.trigger('response_failed', jqXHR);
|
||||||
var error = {
|
var error = {
|
||||||
code: -32098,
|
code: -32098,
|
||||||
message: "XmlHttpRequestError " + errorThrown,
|
message: "XmlHttpRequestError " + errorThrown,
|
||||||
|
@ -1348,7 +1349,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
||||||
deferred.fail(function() {
|
deferred.fail(function() {
|
||||||
deferred.fail(function(error, event) {
|
deferred.fail(function(error, event) {
|
||||||
if (!event.isDefaultPrevented()) {
|
if (!event.isDefaultPrevented()) {
|
||||||
self.on_rpc_error(error, event);
|
self.trigger('error', error, event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1434,13 +1435,15 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
||||||
return deferred;
|
return deferred;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_rpc_error: function(error) {
|
|
||||||
},
|
|
||||||
get_url: function (file) {
|
get_url: function (file) {
|
||||||
return this.prefix + file;
|
return this.prefix + file;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
instance.web.py_eval = function(expr, context) {
|
||||||
|
return py.eval(expr, _.extend({}, context || {}, {"true": true, "false": false, "null": null}));
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||||
|
|
|
@ -280,7 +280,8 @@ instance.web.Model = instance.web.Class.extend({
|
||||||
kwargs = args;
|
kwargs = args;
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
return instance.session.rpc('/web/dataset/call_kw', {
|
var debug = instance.session.debug ? '/'+this.name+':'+method : '';
|
||||||
|
return instance.session.rpc('/web/dataset/call_kw' + debug, {
|
||||||
model: this.name,
|
model: this.name,
|
||||||
method: method,
|
method: method,
|
||||||
args: args,
|
args: args,
|
||||||
|
@ -567,7 +568,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
|
||||||
*/
|
*/
|
||||||
write: function (id, data, options) {
|
write: function (id, data, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
return this._model.call('write', [[id], data], {context: this._model.context(options.context)});
|
return this._model.call('write', [[id], data], {context: this._model.context(options.context)}).then(this.trigger('dataset_changed', id, data, options));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Deletes an existing record from the database
|
* Deletes an existing record from the database
|
||||||
|
@ -575,7 +576,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
|
||||||
* @param {Number|String} ids identifier of the record to delete
|
* @param {Number|String} ids identifier of the record to delete
|
||||||
*/
|
*/
|
||||||
unlink: function(ids) {
|
unlink: function(ids) {
|
||||||
return this._model.call('unlink', [ids], {context: this._model.context()});
|
return this._model.call('unlink', [ids], {context: this._model.context()}).then(this.trigger('dataset_changed', ids));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Calls an arbitrary RPC method
|
* Calls an arbitrary RPC method
|
||||||
|
@ -690,6 +691,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
|
||||||
|
|
||||||
instance.web.DataSetStatic = instance.web.DataSet.extend({
|
instance.web.DataSetStatic = instance.web.DataSet.extend({
|
||||||
init: function(parent, model, context, ids) {
|
init: function(parent, model, context, ids) {
|
||||||
|
var self = this;
|
||||||
this._super(parent, model, context);
|
this._super(parent, model, context);
|
||||||
// all local records
|
// all local records
|
||||||
this.ids = ids || [];
|
this.ids = ids || [];
|
||||||
|
@ -711,12 +713,10 @@ instance.web.DataSetStatic = instance.web.DataSet.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unlink: function(ids) {
|
unlink: function(ids) {
|
||||||
this.on_unlink(ids);
|
this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
|
||||||
|
this.trigger('unlink', ids);
|
||||||
return $.Deferred().resolve({result: true});
|
return $.Deferred().resolve({result: true});
|
||||||
},
|
},
|
||||||
on_unlink: function(ids) {
|
|
||||||
this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.DataSetSearch = instance.web.DataSet.extend({
|
instance.web.DataSetSearch = instance.web.DataSet.extend({
|
||||||
|
@ -778,6 +778,7 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({
|
||||||
self.index = self.index <= self.ids.length - 1 ?
|
self.index = self.index <= self.ids.length - 1 ?
|
||||||
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
|
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
|
||||||
}
|
}
|
||||||
|
this.trigger("dataset_changed", ids, callback, error_callback);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
size: function () {
|
size: function () {
|
||||||
|
@ -834,7 +835,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
||||||
}
|
}
|
||||||
$.extend(cached.values, record.values);
|
$.extend(cached.values, record.values);
|
||||||
if (dirty)
|
if (dirty)
|
||||||
this.on_change();
|
this.trigger("dataset_changed", id, data, options);
|
||||||
return $.Deferred().resolve(true).promise();
|
return $.Deferred().resolve(true).promise();
|
||||||
},
|
},
|
||||||
unlink: function(ids, callback, error_callback) {
|
unlink: function(ids, callback, error_callback) {
|
||||||
|
@ -848,7 +849,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
||||||
this.to_write = _.reject(this.to_write, function(x) { return _.include(ids, x.id);});
|
this.to_write = _.reject(this.to_write, function(x) { return _.include(ids, x.id);});
|
||||||
this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
|
this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
|
||||||
this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
|
this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
|
||||||
this.on_change();
|
this.trigger("dataset_changed", ids, callback, error_callback);
|
||||||
return $.async_when({result: true}).then(callback);
|
return $.async_when({result: true}).then(callback);
|
||||||
},
|
},
|
||||||
reset_ids: function(ids) {
|
reset_ids: function(ids) {
|
||||||
|
@ -859,8 +860,6 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
||||||
this.cache = [];
|
this.cache = [];
|
||||||
this.delete_all = false;
|
this.delete_all = false;
|
||||||
},
|
},
|
||||||
on_change: function() {
|
|
||||||
},
|
|
||||||
read_ids: function (ids, fields, options) {
|
read_ids: function (ids, fields, options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var to_get = [];
|
var to_get = [];
|
||||||
|
@ -947,7 +946,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
||||||
},
|
},
|
||||||
alter_ids: function(n_ids) {
|
alter_ids: function(n_ids) {
|
||||||
this._super(n_ids);
|
this._super(n_ids);
|
||||||
this.on_change();
|
this.trigger("dataset_changed", n_ids);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
instance.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
|
instance.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
|
||||||
|
|
|
@ -173,10 +173,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
} else {
|
} else {
|
||||||
this.$el.find('.oe_form_buttons').replaceWith(this.$buttons);
|
this.$el.find('.oe_form_buttons').replaceWith(this.$buttons);
|
||||||
}
|
}
|
||||||
this.$buttons.on('click','.oe_form_button_create',this.on_button_create);
|
this.$buttons.on('click', '.oe_form_button_create', this.on_button_create);
|
||||||
this.$buttons.on('click','.oe_form_button_edit',this.on_button_edit);
|
this.$buttons.on('click', '.oe_form_button_edit', this.on_button_edit);
|
||||||
this.$buttons.on('click','.oe_form_button_save',this.on_button_save);
|
this.$buttons.on('click', '.oe_form_button_save', this.on_button_save);
|
||||||
this.$buttons.on('click','.oe_form_button_cancel',this.on_button_cancel);
|
this.$buttons.on('click', '.oe_form_button_cancel', this.on_button_cancel);
|
||||||
|
|
||||||
this.$sidebar = this.options.$sidebar || this.$el.find('.oe_form_sidebar');
|
this.$sidebar = this.options.$sidebar || this.$el.find('.oe_form_sidebar');
|
||||||
if (!this.sidebar && this.options.$sidebar) {
|
if (!this.sidebar && this.options.$sidebar) {
|
||||||
|
@ -431,7 +431,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
do_notify_change: function() {
|
do_notify_change: function() {
|
||||||
this.$el.add(this.$buttons).addClass('oe_form_dirty');
|
this.$el.add(this.$buttons).addClass('oe_form_dirty');
|
||||||
},
|
},
|
||||||
on_pager_action: function(action) {
|
execute_pager_action: function(action) {
|
||||||
if (this.can_be_discarded()) {
|
if (this.can_be_discarded()) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'first':
|
case 'first':
|
||||||
|
@ -448,6 +448,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
|
this.trigger('pager_action_executed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init_pager: function() {
|
init_pager: function() {
|
||||||
|
@ -464,7 +465,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
}
|
}
|
||||||
this.$pager.on('click','a[data-pager-action]',function() {
|
this.$pager.on('click','a[data-pager-action]',function() {
|
||||||
var action = $(this).data('pager-action');
|
var action = $(this).data('pager-action');
|
||||||
self.on_pager_action(action);
|
self.execute_pager_action(action);
|
||||||
});
|
});
|
||||||
this.do_update_pager();
|
this.do_update_pager();
|
||||||
},
|
},
|
||||||
|
@ -615,7 +616,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
return self.on_processed_onchange(response, processed);
|
return self.on_processed_onchange(response, processed);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
instance.webclient.crashmanager.on_javascript_exception(e);
|
instance.webclient.crashmanager.show_message(e);
|
||||||
return $.Deferred().reject();
|
return $.Deferred().reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -650,7 +651,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
return $.Deferred().resolve();
|
return $.Deferred().resolve();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
instance.webclient.crashmanager.on_javascript_exception(e);
|
instance.webclient.crashmanager.show_message(e);
|
||||||
return $.Deferred().reject();
|
return $.Deferred().reject();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -747,7 +748,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
},
|
},
|
||||||
on_button_save: function() {
|
on_button_save: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.do_save().then(function(result) {
|
return this.save().then(function(result) {
|
||||||
|
self.trigger("save", result);
|
||||||
self.to_view_mode();
|
self.to_view_mode();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -760,6 +762,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
this.trigger('load_record', this.datarecord);
|
this.trigger('load_record', this.datarecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.trigger('on_button_cancel');
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
on_button_new: function() {
|
on_button_new: function() {
|
||||||
|
@ -783,7 +786,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
var def = $.Deferred();
|
var def = $.Deferred();
|
||||||
$.when(this.has_been_loaded).then(function() {
|
$.when(this.has_been_loaded).then(function() {
|
||||||
self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
|
self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
|
||||||
return self.on_created({ result : new_id });
|
return self.record_created(new_id);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return self.to_edit_mode();
|
return self.to_edit_mode();
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
|
@ -798,7 +801,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
$.when(this.has_been_loaded).then(function() {
|
$.when(this.has_been_loaded).then(function() {
|
||||||
if (self.datarecord.id && confirm(_t("Do you really want to delete this record?"))) {
|
if (self.datarecord.id && confirm(_t("Do you really want to delete this record?"))) {
|
||||||
self.dataset.unlink([self.datarecord.id]).then(function() {
|
self.dataset.unlink([self.datarecord.id]).then(function() {
|
||||||
self.on_pager_action('next');
|
self.execute_pager_action('next');
|
||||||
def.resolve();
|
def.resolve();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -823,11 +826,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
* record or saving an existing one depending on whether the record
|
* record or saving an existing one depending on whether the record
|
||||||
* already has an id property.
|
* already has an id property.
|
||||||
*
|
*
|
||||||
* @param {Boolean} [prepend_on_create=false] if ``do_save`` creates a new
|
* @param {Boolean} [prepend_on_create=false] if ``save`` creates a new
|
||||||
* record, should that record be inserted at the start of the dataset (by
|
* record, should that record be inserted at the start of the dataset (by
|
||||||
* default, records are added at the end)
|
* default, records are added at the end)
|
||||||
*/
|
*/
|
||||||
do_save: function(prepend_on_create) {
|
save: function(prepend_on_create) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
|
return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
|
||||||
try {
|
try {
|
||||||
|
@ -860,7 +863,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
if (!self.datarecord.id) {
|
if (!self.datarecord.id) {
|
||||||
// Creation save
|
// Creation save
|
||||||
save_deferral = self.dataset.create(values).pipe(function(r) {
|
save_deferral = self.dataset.create(values).pipe(function(r) {
|
||||||
return self.on_created(r, prepend_on_create);
|
return self.record_created(r, prepend_on_create);
|
||||||
}, null);
|
}, null);
|
||||||
} else if (_.isEmpty(values) && ! self.force_dirty) {
|
} else if (_.isEmpty(values) && ! self.force_dirty) {
|
||||||
// Not dirty, noop save
|
// Not dirty, noop save
|
||||||
|
@ -869,7 +872,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
self.force_dirty = false;
|
self.force_dirty = false;
|
||||||
// Write save
|
// Write save
|
||||||
save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
|
save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
|
||||||
return self.on_saved(r);
|
return self.record_saved(r);
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
return save_deferral;
|
return save_deferral;
|
||||||
|
@ -896,12 +899,15 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
*
|
*
|
||||||
* @param {Object} r result of the write function.
|
* @param {Object} r result of the write function.
|
||||||
*/
|
*/
|
||||||
on_saved: function(r) {
|
record_saved: function(r) {
|
||||||
|
var self = this;
|
||||||
if (!r) {
|
if (!r) {
|
||||||
// should not happen in the server, but may happen for internal purpose
|
// should not happen in the server, but may happen for internal purpose
|
||||||
|
this.trigger('record_saved', r);
|
||||||
return $.Deferred().reject();
|
return $.Deferred().reject();
|
||||||
} else {
|
} else {
|
||||||
return $.when(this.reload()).pipe(function () {
|
return $.when(this.reload()).pipe(function () {
|
||||||
|
self.trigger('record_saved', r);
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -919,9 +925,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
* @param {Boolean} [prepend_on_create=false] adds the newly created record
|
* @param {Boolean} [prepend_on_create=false] adds the newly created record
|
||||||
* at the beginning of the dataset instead of the end
|
* at the beginning of the dataset instead of the end
|
||||||
*/
|
*/
|
||||||
on_created: function(r, prepend_on_create) {
|
record_created: function(r, prepend_on_create) {
|
||||||
|
var self = this;
|
||||||
if (!r) {
|
if (!r) {
|
||||||
// should not happen in the server, but may happen for internal purpose
|
// should not happen in the server, but may happen for internal purpose
|
||||||
|
this.trigger('record_created', r);
|
||||||
return $.Deferred().reject();
|
return $.Deferred().reject();
|
||||||
} else {
|
} else {
|
||||||
this.datarecord.id = r;
|
this.datarecord.id = r;
|
||||||
|
@ -935,9 +943,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
this.do_update_pager();
|
this.do_update_pager();
|
||||||
if (this.sidebar) {
|
if (this.sidebar) {
|
||||||
this.sidebar.do_attachement_update(this.dataset, this.datarecord.id);
|
this.sidebar.do_attachement_update(this.dataset, this.datarecord.id);
|
||||||
}
|
}
|
||||||
//openerp.log("The record has been created with id #" + this.datarecord.id);
|
//openerp.log("The record has been created with id #" + this.datarecord.id);
|
||||||
return $.when(this.reload()).pipe(function () {
|
return $.when(this.reload()).pipe(function () {
|
||||||
|
self.trigger('record_created', r);
|
||||||
return _.extend(r, {created: true});
|
return _.extend(r, {created: true});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -949,7 +958,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.reload_mutex.exec(function() {
|
return this.reload_mutex.exec(function() {
|
||||||
if (self.dataset.index == null) {
|
if (self.dataset.index == null) {
|
||||||
self.do_prev_view();
|
self.trigger("previous_view");
|
||||||
return $.Deferred().reject().promise();
|
return $.Deferred().reject().promise();
|
||||||
}
|
}
|
||||||
if (self.dataset.index == null || self.dataset.index < 0) {
|
if (self.dataset.index == null || self.dataset.index < 0) {
|
||||||
|
@ -993,7 +1002,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
},
|
},
|
||||||
recursive_save: function() {
|
recursive_save: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
return $.when(this.do_save()).pipe(function(res) {
|
return $.when(this.save()).pipe(function(res) {
|
||||||
if (self.dataset.parent_view)
|
if (self.dataset.parent_view)
|
||||||
return self.dataset.parent_view.recursive_save();
|
return self.dataset.parent_view.recursive_save();
|
||||||
});
|
});
|
||||||
|
@ -1024,7 +1033,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
sidebar_context: function () {
|
sidebar_context: function () {
|
||||||
return this.do_save().pipe(_.bind(function() {return this.get_fields_values();}, this));
|
return this.save().pipe(_.bind(function() {return this.get_fields_values();}, this));
|
||||||
},
|
},
|
||||||
open_defaults_dialog: function () {
|
open_defaults_dialog: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -1089,7 +1098,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||||
field_to_set,
|
field_to_set,
|
||||||
self.fields[field_to_set].get_value(),
|
self.fields[field_to_set].get_value(),
|
||||||
all_users,
|
all_users,
|
||||||
false,
|
true,
|
||||||
condition || false
|
condition || false
|
||||||
]).then(function () { d.close(); });
|
]).then(function () { d.close(); });
|
||||||
}}
|
}}
|
||||||
|
@ -1629,13 +1638,14 @@ instance.web.form.FormDialog = instance.web.Dialog.extend({
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
|
var self = this;
|
||||||
this._super();
|
this._super();
|
||||||
this.form = new instance.web.FormView(this, this.dataset, this.view_id, {
|
this.form = new instance.web.FormView(this, this.dataset, this.view_id, {
|
||||||
pager: false
|
pager: false
|
||||||
});
|
});
|
||||||
this.form.appendTo(this.$el);
|
this.form.appendTo(this.$el);
|
||||||
this.form.on_created.add_last(this.on_form_dialog_saved);
|
this.form.on('record_created', self, this.on_form_dialog_saved);
|
||||||
this.form.on_saved.add_last(this.on_form_dialog_saved);
|
this.form.on('record_saved', this, this.on_form_dialog_saved);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
select_id: function(id) {
|
select_id: function(id) {
|
||||||
|
@ -1652,6 +1662,8 @@ instance.web.form.FormDialog = instance.web.Dialog.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.form.compute_domain = function(expr, fields) {
|
instance.web.form.compute_domain = function(expr, fields) {
|
||||||
|
if (! (expr instanceof Array))
|
||||||
|
return !! expr;
|
||||||
var stack = [];
|
var stack = [];
|
||||||
for (var i = expr.length - 1; i >= 0; i--) {
|
for (var i = expr.length - 1; i >= 0; i--) {
|
||||||
var ex = expr[i];
|
var ex = expr[i];
|
||||||
|
@ -2079,11 +2091,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
|
||||||
this.field = this.field_manager.get_field_desc(this.name);
|
this.field = this.field_manager.get_field_desc(this.name);
|
||||||
this.widget = this.node.attrs.widget;
|
this.widget = this.node.attrs.widget;
|
||||||
this.string = this.node.attrs.string || this.field.string || this.name;
|
this.string = this.node.attrs.string || this.field.string || this.name;
|
||||||
try {
|
this.options = instance.web.py_eval(this.node.attrs.options || '{}');
|
||||||
this.options = JSON.parse(this.node.attrs.options || '{}');
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(_.str.sprintf(_t("Widget options for field '%s' are not valid JSON."), this.name));
|
|
||||||
}
|
|
||||||
this.set({'value': false});
|
this.set({'value': false});
|
||||||
|
|
||||||
this.on("change:value", this, function() {
|
this.on("change:value", this, function() {
|
||||||
|
@ -2371,7 +2379,10 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$input = this.$el.find('input.oe_datepicker_master');
|
this.$input = this.$el.find('input.oe_datepicker_master');
|
||||||
this.$input_picker = this.$el.find('input.oe_datepicker_container');
|
this.$input_picker = this.$el.find('input.oe_datepicker_container');
|
||||||
this.$input.change(this.on_change);
|
this.$input.change(function(){
|
||||||
|
self.change_datetime();
|
||||||
|
});
|
||||||
|
|
||||||
this.picker({
|
this.picker({
|
||||||
onClose: this.on_picker_select,
|
onClose: this.on_picker_select,
|
||||||
onSelect: this.on_picker_select,
|
onSelect: this.on_picker_select,
|
||||||
|
@ -2439,9 +2450,10 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
|
||||||
format_client: function(v) {
|
format_client: function(v) {
|
||||||
return instance.web.format_value(v, {"widget": this.type_of_date});
|
return instance.web.format_value(v, {"widget": this.type_of_date});
|
||||||
},
|
},
|
||||||
on_change: function() {
|
change_datetime: function() {
|
||||||
if (this.is_valid_()) {
|
if (this.is_valid_()) {
|
||||||
this.set_value_from_ui_();
|
this.set_value_from_ui_();
|
||||||
|
this.trigger("datetime_changed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2465,7 +2477,7 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc
|
||||||
initialize_content: function() {
|
initialize_content: function() {
|
||||||
if (!this.get("effective_readonly")) {
|
if (!this.get("effective_readonly")) {
|
||||||
this.datewidget = this.build_widget();
|
this.datewidget = this.build_widget();
|
||||||
this.datewidget.on_change.add_last(_.bind(function() {
|
this.datewidget.on('datetime_changed', this, _.bind(function() {
|
||||||
this.set({'value': this.datewidget.get_value()});
|
this.set({'value': this.datewidget.get_value()});
|
||||||
}, this));
|
}, this));
|
||||||
this.datewidget.appendTo(this.$el);
|
this.datewidget.appendTo(this.$el);
|
||||||
|
@ -2869,7 +2881,7 @@ instance.web.form.CompletionFieldMixin = {
|
||||||
self.build_domain(),
|
self.build_domain(),
|
||||||
new instance.web.CompoundContext(self.build_context(), context || {})
|
new instance.web.CompoundContext(self.build_context(), context || {})
|
||||||
);
|
);
|
||||||
pop.on_select_elements.add(function(element_ids) {
|
pop.on("elements_selected", self, function(element_ids) {
|
||||||
self.add_id(element_ids[0]);
|
self.add_id(element_ids[0]);
|
||||||
self.focus();
|
self.focus();
|
||||||
});
|
});
|
||||||
|
@ -3276,7 +3288,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
||||||
this.dataset.o2m = this;
|
this.dataset.o2m = this;
|
||||||
this.dataset.parent_view = this.view;
|
this.dataset.parent_view = this.view;
|
||||||
this.dataset.child_name = this.name;
|
this.dataset.child_name = this.name;
|
||||||
this.dataset.on_change.add_last(function() {
|
this.dataset.on('dataset_changed', this, function() {
|
||||||
self.trigger_on_change();
|
self.trigger_on_change();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3308,11 +3320,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
||||||
var views = [];
|
var views = [];
|
||||||
_.each(modes, function(mode) {
|
_.each(modes, function(mode) {
|
||||||
if (! _.include(["list", "tree", "graph", "kanban"], mode)) {
|
if (! _.include(["list", "tree", "graph", "kanban"], mode)) {
|
||||||
try {
|
throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode));
|
||||||
throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode));
|
|
||||||
} catch(e) {
|
|
||||||
instance.webclient.crashmanager.on_javascript_exception(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var view = {
|
var view = {
|
||||||
view_id: false,
|
view_id: false,
|
||||||
|
@ -3368,7 +3376,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
||||||
var def = $.Deferred().then(function() {
|
var def = $.Deferred().then(function() {
|
||||||
self.initial_is_loaded.resolve();
|
self.initial_is_loaded.resolve();
|
||||||
});
|
});
|
||||||
this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
|
this.viewmanager.on("controller_inited", self, function(view_type, controller) {
|
||||||
controller.o2m = self;
|
controller.o2m = self;
|
||||||
if (view_type == "list") {
|
if (view_type == "list") {
|
||||||
if (self.get("effective_readonly")) {
|
if (self.get("effective_readonly")) {
|
||||||
|
@ -3383,9 +3391,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
||||||
controller.on("load_record", self, function(){
|
controller.on("load_record", self, function(){
|
||||||
once.resolve();
|
once.resolve();
|
||||||
});
|
});
|
||||||
controller.on_pager_action.add_first(function() {
|
controller.on('pager_action_executed',self,self.save_any_view);
|
||||||
self.save_any_view();
|
|
||||||
});
|
|
||||||
} else if (view_type == "graph") {
|
} else if (view_type == "graph") {
|
||||||
self.reload_current_view()
|
self.reload_current_view()
|
||||||
}
|
}
|
||||||
|
@ -3520,7 +3526,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
||||||
if (!view.is_initialized.isResolved()) {
|
if (!view.is_initialized.isResolved()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var res = $.when(view.do_save());
|
var res = $.when(view.save());
|
||||||
if (!res.isResolved() && !res.isRejected()) {
|
if (!res.isResolved() && !res.isRejected()) {
|
||||||
console.warn("Asynchronous get_value() is not supported in form view.");
|
console.warn("Asynchronous get_value() is not supported in form view.");
|
||||||
}
|
}
|
||||||
|
@ -3565,7 +3571,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
|
||||||
});
|
});
|
||||||
this.__ignore_blur = false;
|
this.__ignore_blur = false;
|
||||||
},
|
},
|
||||||
do_switch_view: function(mode, unused) {
|
switch_mode: function(mode, unused) {
|
||||||
if (mode !== 'form') {
|
if (mode !== 'form') {
|
||||||
return this._super(mode, unused);
|
return this._super(mode, unused);
|
||||||
}
|
}
|
||||||
|
@ -3577,7 +3583,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
|
||||||
create_function: function(data) {
|
create_function: function(data) {
|
||||||
return self.o2m.dataset.create(data).then(function(r) {
|
return self.o2m.dataset.create(data).then(function(r) {
|
||||||
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
|
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
|
||||||
self.o2m.dataset.on_change();
|
self.o2m.dataset.trigger("dataset_changed", r);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
write_function: function(id, data, options) {
|
write_function: function(id, data, options) {
|
||||||
|
@ -3594,7 +3600,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
|
||||||
form_view_options: {'not_interactible_on_create':true},
|
form_view_options: {'not_interactible_on_create':true},
|
||||||
readonly: self.o2m.get("effective_readonly")
|
readonly: self.o2m.get("effective_readonly")
|
||||||
});
|
});
|
||||||
pop.on_select_elements.add_last(function() {
|
pop.on("elements_selected", self, function() {
|
||||||
self.o2m.reload_current_view();
|
self.o2m.reload_current_view();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -3667,7 +3673,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
|
||||||
create_function: function(data, callback, error_callback) {
|
create_function: function(data, callback, error_callback) {
|
||||||
return self.o2m.dataset.create(data).then(function(r) {
|
return self.o2m.dataset.create(data).then(function(r) {
|
||||||
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
|
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
|
||||||
self.o2m.dataset.on_change();
|
self.o2m.dataset.trigger("dataset_changed", r);
|
||||||
}).then(callback, error_callback);
|
}).then(callback, error_callback);
|
||||||
},
|
},
|
||||||
read_function: function() {
|
read_function: function() {
|
||||||
|
@ -3680,7 +3686,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
|
||||||
self.o2m.build_domain(),
|
self.o2m.build_domain(),
|
||||||
self.o2m.build_context()
|
self.o2m.build_context()
|
||||||
);
|
);
|
||||||
pop.on_select_elements.add_last(function() {
|
pop.on("elements_selected", self, function() {
|
||||||
self.o2m.reload_current_view();
|
self.o2m.reload_current_view();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3716,7 +3722,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
|
||||||
var self = this;
|
var self = this;
|
||||||
this.ensure_saved().pipe(function () {
|
this.ensure_saved().pipe(function () {
|
||||||
if (parent_form)
|
if (parent_form)
|
||||||
return parent_form.do_save();
|
return parent_form.save();
|
||||||
else
|
else
|
||||||
return $.when();
|
return $.when();
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
|
@ -3819,7 +3825,7 @@ instance.web.form.One2ManyList = instance.web.ListView.List.extend({
|
||||||
colspan: columns,
|
colspan: columns,
|
||||||
'class': 'oe_form_field_one2many_list_row_add'
|
'class': 'oe_form_field_one2many_list_row_add'
|
||||||
}).append(
|
}).append(
|
||||||
$('<a>', {href: '#'}).text(_t("Add a row"))
|
$('<a>', {href: '#'}).text(_t("Add an item"))
|
||||||
.mousedown(function () {
|
.mousedown(function () {
|
||||||
// FIXME: needs to be an official API somehow
|
// FIXME: needs to be an official API somehow
|
||||||
if (self.view.editor.is_editing()) {
|
if (self.view.editor.is_editing()) {
|
||||||
|
@ -3855,7 +3861,7 @@ instance.web.form.One2ManyFormView = instance.web.FormView.extend({
|
||||||
this._super(data);
|
this._super(data);
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$buttons.find('button.oe_form_button_create').click(function() {
|
this.$buttons.find('button.oe_form_button_create').click(function() {
|
||||||
self.do_save().then(self.on_button_new);
|
self.save().then(self.on_button_new);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
do_notify_change: function() {
|
do_notify_change: function() {
|
||||||
|
@ -4022,7 +4028,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
|
||||||
|
|
||||||
this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
|
this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
|
||||||
this.dataset.m2m = this;
|
this.dataset.m2m = this;
|
||||||
this.dataset.on_unlink.add_last(function(ids) {
|
this.dataset.on('unlink', self, function(ids) {
|
||||||
self.dataset_changed();
|
self.dataset_changed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4117,7 +4123,7 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in
|
||||||
this.m2m_field.build_context()
|
this.m2m_field.build_context()
|
||||||
);
|
);
|
||||||
var self = this;
|
var self = this;
|
||||||
pop.on_select_elements.add(function(element_ids) {
|
pop.on("elements_selected", self, function(element_ids) {
|
||||||
_.each(element_ids, function(one_id) {
|
_.each(element_ids, function(one_id) {
|
||||||
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
|
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
|
||||||
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
|
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
|
||||||
|
@ -4155,7 +4161,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
|
||||||
|
|
||||||
this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
|
this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
|
||||||
this.dataset.m2m = this;
|
this.dataset.m2m = this;
|
||||||
this.dataset.on_unlink.add_last(function(ids) {
|
this.dataset.on('unlink', self, function(ids) {
|
||||||
self.dataset_changed();
|
self.dataset_changed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4203,7 +4209,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
|
||||||
self.initial_is_loaded.resolve();
|
self.initial_is_loaded.resolve();
|
||||||
loaded.resolve();
|
loaded.resolve();
|
||||||
});
|
});
|
||||||
this.kanban_view.do_switch_view.add_last(_.bind(this.open_popup, this));
|
this.kanban_view.on('switch_mode', this, this.open_popup);
|
||||||
$.async_when().then(function () {
|
$.async_when().then(function () {
|
||||||
self.kanban_view.appendTo(self.$el);
|
self.kanban_view.appendTo(self.$el);
|
||||||
});
|
});
|
||||||
|
@ -4232,7 +4238,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
|
||||||
new instance.web.CompoundDomain(this.build_domain(), ["!", ["id", "in", this.dataset.ids]]),
|
new instance.web.CompoundDomain(this.build_domain(), ["!", ["id", "in", this.dataset.ids]]),
|
||||||
this.build_context()
|
this.build_context()
|
||||||
);
|
);
|
||||||
pop.on_select_elements.add(function(element_ids) {
|
pop.on("elements_selected", self, function(element_ids) {
|
||||||
_.each(element_ids, function(one_id) {
|
_.each(element_ids, function(one_id) {
|
||||||
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
|
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
|
||||||
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
|
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
|
||||||
|
@ -4431,7 +4437,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
|
||||||
}));
|
}));
|
||||||
var $snbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save-new");
|
var $snbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save-new");
|
||||||
$snbutton.click(function() {
|
$snbutton.click(function() {
|
||||||
$.when(self.view_form.do_save()).then(function() {
|
$.when(self.view_form.save()).then(function() {
|
||||||
self.view_form.reload_mutex.exec(function() {
|
self.view_form.reload_mutex.exec(function() {
|
||||||
self.view_form.on_button_new();
|
self.view_form.on_button_new();
|
||||||
});
|
});
|
||||||
|
@ -4439,7 +4445,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
|
||||||
});
|
});
|
||||||
var $sbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save");
|
var $sbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save");
|
||||||
$sbutton.click(function() {
|
$sbutton.click(function() {
|
||||||
$.when(self.view_form.do_save()).then(function() {
|
$.when(self.view_form.save()).then(function() {
|
||||||
self.view_form.reload_mutex.exec(function() {
|
self.view_form.reload_mutex.exec(function() {
|
||||||
self.check_exit();
|
self.check_exit();
|
||||||
});
|
});
|
||||||
|
@ -4452,11 +4458,12 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
|
||||||
self.view_form.do_show();
|
self.view_form.do_show();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_select_elements: function(element_ids) {
|
select_elements: function(element_ids) {
|
||||||
|
this.trigger("elements_selected", element_ids);
|
||||||
},
|
},
|
||||||
check_exit: function(no_destroy) {
|
check_exit: function(no_destroy) {
|
||||||
if (this.created_elements.length > 0) {
|
if (this.created_elements.length > 0) {
|
||||||
this.on_select_elements(this.created_elements);
|
this.select_elements(this.created_elements);
|
||||||
this.created_elements = [];
|
this.created_elements = [];
|
||||||
}
|
}
|
||||||
this.destroy();
|
this.destroy();
|
||||||
|
@ -4567,7 +4574,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
|
||||||
});
|
});
|
||||||
var $sbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-select");
|
var $sbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-select");
|
||||||
$sbutton.click(function() {
|
$sbutton.click(function() {
|
||||||
self.on_select_elements(self.selected_ids);
|
self.select_elements(self.selected_ids);
|
||||||
self.destroy();
|
self.destroy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4609,7 +4616,7 @@ instance.web.form.SelectCreateListView = instance.web.ListView.extend({
|
||||||
this.popup.new_object();
|
this.popup.new_object();
|
||||||
},
|
},
|
||||||
select_record: function(index) {
|
select_record: function(index) {
|
||||||
this.popup.on_select_elements([this.dataset.ids[index]]);
|
this.popup.select_elements([this.dataset.ids[index]]);
|
||||||
this.popup.destroy();
|
this.popup.destroy();
|
||||||
},
|
},
|
||||||
do_select: function(ids, records) {
|
do_select: function(ids, records) {
|
||||||
|
@ -4637,6 +4644,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
|
||||||
destroy_content: function() {
|
destroy_content: function() {
|
||||||
if (this.fm) {
|
if (this.fm) {
|
||||||
this.fm.destroy();
|
this.fm.destroy();
|
||||||
|
this.fm = undefined;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initialize_content: function() {
|
initialize_content: function() {
|
||||||
|
@ -4658,9 +4666,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
|
||||||
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
|
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
|
||||||
}});
|
}});
|
||||||
this.selection.on("change:value", this, this.on_selection_changed);
|
this.selection.on("change:value", this, this.on_selection_changed);
|
||||||
this.selection.setElement(this.$(".oe_form_view_reference_selection"));
|
this.selection.appendTo(this.$(".oe_form_view_reference_selection"));
|
||||||
this.selection.renderElement();
|
|
||||||
this.selection.start();
|
|
||||||
this.selection
|
this.selection
|
||||||
.on('focused', null, function () {self.trigger('focused')})
|
.on('focused', null, function () {self.trigger('focused')})
|
||||||
.on('blurred', null, function () {self.trigger('blurred')});
|
.on('blurred', null, function () {self.trigger('blurred')});
|
||||||
|
@ -4670,9 +4676,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
|
||||||
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
|
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
|
||||||
}});
|
}});
|
||||||
this.m2o.on("change:value", this, this.data_changed);
|
this.m2o.on("change:value", this, this.data_changed);
|
||||||
this.m2o.setElement(this.$(".oe_form_view_reference_m2o"));
|
this.m2o.appendTo(this.$(".oe_form_view_reference_m2o"));
|
||||||
this.m2o.renderElement();
|
|
||||||
this.m2o.start();
|
|
||||||
this.m2o
|
this.m2o
|
||||||
.on('focused', null, function () {self.trigger('focused')})
|
.on('focused', null, function () {self.trigger('focused')})
|
||||||
.on('blurred', null, function () {self.trigger('blurred')});
|
.on('blurred', null, function () {self.trigger('blurred')});
|
||||||
|
@ -4816,9 +4820,9 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
|
||||||
this._super();
|
this._super();
|
||||||
if (this.get("effective_readonly")) {
|
if (this.get("effective_readonly")) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$el.find('a').click(function() {
|
this.$el.find('a').click(function(ev) {
|
||||||
if (self.get('value')) {
|
if (self.get('value')) {
|
||||||
self.on_save_as();
|
self.on_save_as(ev);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1321,7 +1321,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
group_label = row_data[group_column.id].value;
|
group_label = row_data[group_column.id].value;
|
||||||
}
|
}
|
||||||
$group_column.text(_.str.sprintf("%s (%d)",
|
$group_column.html(_.str.sprintf("%s (%d)",
|
||||||
group_label, group.length));
|
group_label, group.length));
|
||||||
|
|
||||||
if (group.length && group.openable) {
|
if (group.length && group.openable) {
|
||||||
|
|
|
@ -724,7 +724,7 @@ openerp.web.list_editable = function (instance) {
|
||||||
save: function () {
|
save: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.form
|
return this.form
|
||||||
.do_save(this.delegate.prepends_on_create())
|
.save(this.delegate.prepends_on_create())
|
||||||
.pipe(function (result) {
|
.pipe(function (result) {
|
||||||
var created = result.created && !self.record.id;
|
var created = result.created && !self.record.id;
|
||||||
if (created) {
|
if (created) {
|
||||||
|
|
|
@ -164,6 +164,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
||||||
state = state || {};
|
state = state || {};
|
||||||
if (this.getParent() && this.getParent().do_push_state) {
|
if (this.getParent() && this.getParent().do_push_state) {
|
||||||
if (this.inner_action) {
|
if (this.inner_action) {
|
||||||
|
if (this.inner_action._push_me === false) {
|
||||||
|
// this action has been explicitly marked as not pushable
|
||||||
|
return;
|
||||||
|
}
|
||||||
state['title'] = this.inner_action.name;
|
state['title'] = this.inner_action.name;
|
||||||
if(this.inner_action.type == 'ir.actions.act_window') {
|
if(this.inner_action.type == 'ir.actions.act_window') {
|
||||||
state['model'] = this.inner_action.res_model;
|
state['model'] = this.inner_action.res_model;
|
||||||
|
@ -172,7 +176,13 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
||||||
state['action'] = this.inner_action.id;
|
state['action'] = this.inner_action.id;
|
||||||
} else if (this.inner_action.type == 'ir.actions.client') {
|
} else if (this.inner_action.type == 'ir.actions.client') {
|
||||||
state['action'] = this.inner_action.tag;
|
state['action'] = this.inner_action.tag;
|
||||||
//state = _.extend(this.inner_action.params || {}, state);
|
var params = {};
|
||||||
|
_.each(this.inner_action.params, function(v, k) {
|
||||||
|
if(_.isString(v) || _.isNumber(v)) {
|
||||||
|
params[k] = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state = _.extend(params || {}, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!this.dialog) {
|
if(!this.dialog) {
|
||||||
|
@ -286,8 +296,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
||||||
buttons: { "Close": function() { $(this).dialog("close"); }},
|
buttons: { "Close": function() { $(this).dialog("close"); }},
|
||||||
dialogClass: executor.klass
|
dialogClass: executor.klass
|
||||||
});
|
});
|
||||||
if(on_close)
|
if (on_close) {
|
||||||
this.dialog.on_close.add(on_close);
|
this.dialog.on("dialog_close", this, on_close);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.dialog_widget.destroy();
|
this.dialog_widget.destroy();
|
||||||
}
|
}
|
||||||
|
@ -525,19 +536,19 @@ instance.web.ViewManager = instance.web.Widget.extend({
|
||||||
controller.set_embedded_view(view.embedded_view);
|
controller.set_embedded_view(view.embedded_view);
|
||||||
}
|
}
|
||||||
controller.on('switch_mode', self, this.switch_mode);
|
controller.on('switch_mode', self, this.switch_mode);
|
||||||
|
controller.on('previous_view', self, this.prev_view);
|
||||||
controller.do_prev_view.add_last(this.on_prev_view);
|
|
||||||
var container = this.$el.find(".oe_view_manager_view_" + view_type);
|
var container = this.$el.find(".oe_view_manager_view_" + view_type);
|
||||||
var view_promise = controller.appendTo(container);
|
var view_promise = controller.appendTo(container);
|
||||||
this.views[view_type].controller = controller;
|
this.views[view_type].controller = controller;
|
||||||
this.views[view_type].deferred.resolve(view_type);
|
this.views[view_type].deferred.resolve(view_type);
|
||||||
return $.when(view_promise).then(function() {
|
return $.when(view_promise).then(function() {
|
||||||
self.on_controller_inited(view_type, controller);
|
|
||||||
if (self.searchview
|
if (self.searchview
|
||||||
&& self.flags.auto_search
|
&& self.flags.auto_search
|
||||||
&& view.controller.searchable !== false) {
|
&& view.controller.searchable !== false) {
|
||||||
self.searchview.ready.then(self.searchview.do_search);
|
self.searchview.ready.then(self.searchview.do_search);
|
||||||
}
|
}
|
||||||
|
self.trigger("controller_inited",view_type,controller);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
set_title: function(title) {
|
set_title: function(title) {
|
||||||
|
@ -602,7 +613,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
|
||||||
* @param {String} [options.default=null] view to switch to if no previous view
|
* @param {String} [options.default=null] view to switch to if no previous view
|
||||||
* @returns {$.Deferred} switching end signal
|
* @returns {$.Deferred} switching end signal
|
||||||
*/
|
*/
|
||||||
on_prev_view: function (options) {
|
prev_view: function (options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var current_view = this.views_history.pop();
|
var current_view = this.views_history.pop();
|
||||||
var previous_view = this.views_history[this.views_history.length - 1] || options['default'];
|
var previous_view = this.views_history[this.views_history.length - 1] || options['default'];
|
||||||
|
@ -652,14 +663,6 @@ instance.web.ViewManager = instance.web.Widget.extend({
|
||||||
controller.do_search(results.domain, results.context, groupby || []);
|
controller.do_search(results.domain, results.context, groupby || []);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Event launched when a controller has been inited.
|
|
||||||
*
|
|
||||||
* @param {String} view_type type of view
|
|
||||||
* @param {String} view the inited controller
|
|
||||||
*/
|
|
||||||
on_controller_inited: function(view_type, view) {
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* Called when one of the view want to execute an action
|
* Called when one of the view want to execute an action
|
||||||
*/
|
*/
|
||||||
|
@ -1266,8 +1269,7 @@ instance.web.View = instance.web.Widget.extend({
|
||||||
* @param {Boolean} [options.created=false] resource was created
|
* @param {Boolean} [options.created=false] resource was created
|
||||||
* @param {String} [options.default=null] view to switch to if no previous view
|
* @param {String} [options.default=null] view to switch to if no previous view
|
||||||
*/
|
*/
|
||||||
do_prev_view: function (options) {
|
|
||||||
},
|
|
||||||
do_search: function(view) {
|
do_search: function(view) {
|
||||||
},
|
},
|
||||||
on_sidebar_export: function() {
|
on_sidebar_export: function() {
|
||||||
|
|
|
@ -548,7 +548,7 @@
|
||||||
<a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank">
|
<a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank">
|
||||||
<t t-raw="item.label"/>
|
<t t-raw="item.label"/>
|
||||||
</a>
|
</a>
|
||||||
<a t-if="section.name == 'files'" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a>
|
<a t-if="section.name == 'files' and !item.callback" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a>
|
||||||
</li>
|
</li>
|
||||||
<li t-if="section.name == 'files'" class="oe_sidebar_add_attachment">
|
<li t-if="section.name == 'files'" class="oe_sidebar_add_attachment">
|
||||||
<t t-call="HiddenInputFile">
|
<t t-call="HiddenInputFile">
|
||||||
|
@ -1537,7 +1537,7 @@
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
<label for="import_compat">Export Type:</label>
|
<label for="import_compat">Export Type:</label>
|
||||||
<select id="import_compat" name="import_compat">
|
<select id="import_compat" name="import_compat">
|
||||||
<option value="yes">Import Compatible Export</option>
|
<option value="yes">Import-Compatible Export</option>
|
||||||
<option value="">Export all Data</option>
|
<option value="">Export all Data</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import mock
|
||||||
import unittest2
|
import unittest2
|
||||||
|
|
||||||
from ..controllers import main
|
from ..controllers import main
|
||||||
from ..common.session import OpenERPSession
|
from ..session import OpenERPSession
|
||||||
|
|
||||||
class Placeholder(object):
|
class Placeholder(object):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
|
@ -6,7 +6,7 @@ import unittest2
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
import web.controllers.main
|
import web.controllers.main
|
||||||
from ..common import nonliterals, session as s
|
from .. import nonliterals, session as s
|
||||||
|
|
||||||
def field_attrs(fields_view_get, fieldname):
|
def field_attrs(fields_view_get, fieldname):
|
||||||
(field,) = filter(lambda f: f['attrs'].get('name') == fieldname,
|
(field,) = filter(lambda f: f['attrs'].get('name') == fieldname,
|
||||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
|
"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
|
||||||
"X-Generator: Launchpad (build 16061)\n"
|
"X-Generator: Launchpad (build 16137)\n"
|
||||||
|
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue