From 12580e690aea8b9ea3a4862e547cf30e323c683a Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 8 Sep 2013 19:35:35 +0200 Subject: [PATCH 01/37] [IMP] openerp threaded, gevent, prefork service cleanup - unify signal handling - unify start and stop no new feature yet, it paves the way for - developement mode auto reload - graceful restart on HUP - multiprocessing and gevent on windows bzr revid: al@openerp.com-20130908173535-xomt5w7xmqtwkmyy --- openerp-long-polling | 11 -- openerp/__init__.py | 11 +- openerp/cli/server.py | 120 +------------ openerp/service/__init__.py | 116 +------------ openerp/service/cron.py | 76 -------- openerp/service/workers.py | 309 +++++++++++++++++++++++++++++++-- openerp/service/wsgi_server.py | 66 ------- 7 files changed, 317 insertions(+), 392 deletions(-) delete mode 100755 openerp-long-polling delete mode 100644 openerp/service/cron.py diff --git a/openerp-long-polling b/openerp-long-polling deleted file mode 100755 index 304cd01c1ee..00000000000 --- a/openerp-long-polling +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -import gevent.monkey -gevent.monkey.patch_all() -import gevent_psycopg2 -gevent_psycopg2.monkey_patch() - -import openerp - -if __name__ == "__main__": - openerp.cli.main() diff --git a/openerp/__init__.py b/openerp/__init__.py index 22c8c98256a..161b06b0990 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -27,9 +27,16 @@ import sys # Is the server running with gevent. evented = False -if sys.modules.get("gevent") is not None: - evented = True +for i in sys.argv: + if i.startswith('--gevent'): + evented = True + break +if evented: + import gevent.monkey + gevent.monkey.patch_all() + import gevent_psycopg2 + gevent_psycopg2.monkey_patch() # Make sure the OpenERP server runs in UTC. This is especially necessary # under Windows as under Linux it seems the real import of time is diff --git a/openerp/cli/server.py b/openerp/cli/server.py index fc1bf61b617..0c081b6156b 100644 --- a/openerp/cli/server.py +++ b/openerp/cli/server.py @@ -147,112 +147,15 @@ def import_translation(): cr.commit() cr.close() -# Variable keeping track of the number of calls to the signal handler defined -# below. This variable is monitored by ``quit_on_signals()``. -quit_signals_received = 0 - -def signal_handler(sig, frame): - """ Signal handler: exit ungracefully on the second handled signal. - - :param sig: the signal number - :param frame: the interrupted stack frame or None - """ - global quit_signals_received - quit_signals_received += 1 - if quit_signals_received > 1: - # logging.shutdown was already called at this point. - sys.stderr.write("Forced shutdown.\n") - os._exit(0) - -def dumpstacks(sig, frame): - """ Signal handler: dump a stack trace for each existing thread.""" - # code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696 - # modified for python 2.5 compatibility - threads_info = dict([(th.ident, {'name': th.name, - 'uid': getattr(th,'uid','n/a')}) - for th in threading.enumerate()]) - code = [] - for threadId, stack in sys._current_frames().items(): - thread_info = threads_info.get(threadId) - code.append("\n# Thread: %s (id:%s) (uid:%s)" % \ - (thread_info and thread_info['name'] or 'n/a', - threadId, - thread_info and thread_info['uid'] or 'n/a')) - for filename, lineno, name, line in traceback.extract_stack(stack): - code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) - if line: - code.append(" %s" % (line.strip())) - _logger.info("\n".join(code)) - -def setup_signal_handlers(signal_handler): - """ Register the given signal handler. """ - SIGNALS = (signal.SIGINT, signal.SIGTERM) - if os.name == 'posix': - map(lambda sig: signal.signal(sig, signal_handler), SIGNALS) - signal.signal(signal.SIGQUIT, dumpstacks) - elif os.name == 'nt': - import win32api - win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1) - -def quit_on_signals(): - """ Wait for one or two signals then shutdown the server. - - The first SIGINT or SIGTERM signal will initiate a graceful shutdown while - a second one if any will force an immediate exit. - - """ - # Wait for a first signal to be handled. (time.sleep will be interrupted - # by the signal handler.) The try/except is for the win32 case. - try: - while quit_signals_received == 0: - time.sleep(60) - except KeyboardInterrupt: - pass - - config = openerp.tools.config - openerp.service.stop_services() - - if getattr(openerp, 'phoenix', False): - # like the phoenix, reborn from ashes... - openerp.service._reexec() - return - - if config['pidfile']: - os.unlink(config['pidfile']) - sys.exit(0) - -def watch_parent(beat=4): - import gevent - ppid = os.getppid() - while True: - if ppid != os.getppid(): - pid = os.getpid() - _logger.info("LongPolling (%s) Parent changed", pid) - # suicide !! - os.kill(pid, signal.SIGTERM) - return - gevent.sleep(beat) - def main(args): check_root_user() openerp.tools.config.parse_config(args) - - if openerp.tools.config.options["gevent"]: - openerp.evented = True - _logger.info('Using gevent mode') - import gevent.monkey - gevent.monkey.patch_all() - import gevent_psycopg2 - gevent_psycopg2.monkey_patch() - check_postgres_user() openerp.netsvc.init_logger() report_configuration() config = openerp.tools.config - setup_signal_handlers(signal_handler) - if config["test_file"]: run_test_file(config['db_name'], config['test_file']) sys.exit(0) @@ -265,28 +168,19 @@ def main(args): import_translation() sys.exit(0) - if not config["stop_after_init"]: - setup_pid_file() - # Some module register themselves when they are loaded so we need the - # services to be running before loading any registry. - if not openerp.evented: - if config['workers']: - openerp.service.start_services_workers() - else: - openerp.service.start_services() - else: - config['xmlrpc_port'] = config['longpolling_port'] - import gevent - gevent.spawn(watch_parent) - openerp.service.start_services() - + # preload registryies, needed for -u --stop_after_init rc = 0 if config['db_name']: for dbname in config['db_name'].split(','): if not preload_registry(dbname): rc += 1 - if config["stop_after_init"]: + if not config["stop_after_init"]: + setup_pid_file() + openerp.service.workers.start() + if config['pidfile']: + os.unlink(config['pidfile']) + else: sys.exit(rc) _logger.info('OpenERP server is running, waiting for connections...') diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index 2c6c80eb80c..02401d455e1 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -20,29 +20,12 @@ # ############################################################################## -import logging -import os -import signal -import subprocess -import sys -import threading -import time - -import cron -import wsgi_server - -import openerp -import openerp.modules -import openerp.netsvc -import openerp.osv -from openerp.release import nt_service_name -import openerp.tools -from openerp.tools.misc import stripped_sys_argv - import common import db import model import report +import wsgi_server +import workers #.apidoc title: RPC Services @@ -55,100 +38,5 @@ import report low-level behavior of the wire. """ -_logger = logging.getLogger(__name__) - -def load_server_wide_modules(): - for m in openerp.conf.server_wide_modules: - try: - openerp.modules.module.load_openerp_module(m) - except Exception: - msg = '' - if m == 'web': - msg = """ -The `web` module is provided by the addons found in the `openerp-web` project. -Maybe you forgot to add those addons in your addons_path configuration.""" - _logger.exception('Failed to load server-wide module `%s`.%s', m, msg) - -start_internal_done = False -main_thread_id = threading.currentThread().ident - -def start_internal(): - global start_internal_done - if start_internal_done: - return - openerp.netsvc.init_logger() - - load_server_wide_modules() - start_internal_done = True - -def start_services(): - """ Start all services including http, and cron """ - start_internal() - # Start the WSGI server. - wsgi_server.start_service() - # Start the main cron thread. - if not openerp.evented: - cron.start_service() - -def stop_services(): - """ Stop all services. """ - # stop services - if not openerp.evented: - cron.stop_service() - wsgi_server.stop_service() - - _logger.info("Initiating shutdown") - _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") - - # Manually join() all threads before calling sys.exit() to allow a second signal - # to trigger _force_quit() in case some non-daemon threads won't exit cleanly. - # threading.Thread.join() should not mask signals (at least in python 2.5). - me = threading.currentThread() - _logger.debug('current thread: %r', me) - for thread in threading.enumerate(): - _logger.debug('process %r (%r)', thread, thread.isDaemon()) - if thread != me and not thread.isDaemon() and thread.ident != main_thread_id: - while thread.isAlive(): - _logger.debug('join and sleep') - # Need a busyloop here as thread.join() masks signals - # and would prevent the forced shutdown. - thread.join(0.05) - time.sleep(0.05) - - _logger.debug('--') - openerp.modules.registry.RegistryManager.delete_all() - logging.shutdown() - -def start_services_workers(): - import openerp.service.workers - openerp.multi_process = True - openerp.service.workers.Multicorn(openerp.service.wsgi_server.application).run() - -def _reexec(): - """reexecute openerp-server process with (nearly) the same arguments""" - if openerp.tools.osutil.is_running_as_nt_service(): - subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True) - exe = os.path.basename(sys.executable) - args = stripped_sys_argv() - if not args or args[0] != exe: - args.insert(0, exe) - os.execv(sys.executable, args) - -def restart_server(): - if openerp.multi_process: - raise NotImplementedError("Multicorn is not supported (but gunicorn was)") - pid = openerp.wsgi.core.arbiter_pid - os.kill(pid, signal.SIGHUP) - else: - if os.name == 'nt': - def reborn(): - stop_services() - _reexec() - - # run in a thread to let the current thread return response to the caller. - threading.Thread(target=reborn).start() - else: - openerp.phoenix = True - os.kill(os.getpid(), signal.SIGINT) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/cron.py b/openerp/service/cron.py deleted file mode 100644 index f21b27f7fea..00000000000 --- a/openerp/service/cron.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2011 OpenERP SA () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -""" Cron jobs scheduling - -Cron jobs are defined in the ir_cron table/model. This module deals with all -cron jobs, for all databases of a single OpenERP server instance. - -""" - -import logging -import threading -import time -from datetime import datetime - -import openerp - -_logger = logging.getLogger(__name__) - -SLEEP_INTERVAL = 60 # 1 min - -def cron_runner(number): - while True: - time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style - registries = openerp.modules.registry.RegistryManager.registries - _logger.debug('cron%d polling for jobs', number) - for db_name, registry in registries.items(): - while True and registry.ready: - acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) - if not acquired: - break - -def start_service(): - """ Start the above runner function in a daemon thread. - - The thread is a typical daemon thread: it will never quit and must be - terminated when the main process exits - with no consequence (the processing - threads it spawns are not marked daemon). - - """ - - # Force call to strptime just before starting the cron thread - # to prevent time.strptime AttributeError within the thread. - # See: http://bugs.python.org/issue7980 - datetime.strptime('2012-01-01', '%Y-%m-%d') - - for i in range(openerp.tools.config['max_cron_threads']): - def target(): - cron_runner(i) - t = threading.Thread(target=target, name="openerp.service.cron.cron%d" % i) - t.setDaemon(True) - t.start() - _logger.debug("cron%d started!" % i) - -def stop_service(): - pass - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/workers.py b/openerp/service/workers.py index c8b8b84bca2..382d581720f 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -1,7 +1,7 @@ #----------------------------------------------------------- -# Multicorn, multiprocessing inspired by gunicorn -# TODO rename class: Multicorn -> Arbiter ? +# Threaded, Gevent and Prefork Servers #----------------------------------------------------------- +import datetime import errno import fcntl import logging @@ -13,10 +13,14 @@ import select import signal import socket import sys +import threading import time +import traceback import subprocess import os.path +import wsgi_server + import werkzeug.serving try: from setproctitle import setproctitle @@ -25,11 +29,238 @@ except ImportError: import openerp import openerp.tools.config as config +from openerp.release import nt_service_name from openerp.tools.misc import stripped_sys_argv _logger = logging.getLogger(__name__) -class Multicorn(object): +SLEEP_INTERVAL = 60 # 1 min + +#---------------------------------------------------------- +# Common +#---------------------------------------------------------- + +class CommonServer(object): + def __init__(self, app): + # TODO Change the xmlrpc_* options to http_* + self.app = app + # config + self.interface = config['xmlrpc_interface'] or '0.0.0.0' + self.port = config['xmlrpc_port'] + # runtime + self.pid = os.getpid() + + def dumpstacks(self): + """ Signal handler: dump a stack trace for each existing thread.""" + # code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696 + # modified for python 2.5 compatibility + threads_info = dict([(th.ident, {'name': th.name, + 'uid': getattr(th,'uid','n/a')}) + for th in threading.enumerate()]) + code = [] + for threadId, stack in sys._current_frames().items(): + thread_info = threads_info.get(threadId) + code.append("\n# Thread: %s (id:%s) (uid:%s)" % \ + (thread_info and thread_info['name'] or 'n/a', + threadId, + thread_info and thread_info['uid'] or 'n/a')) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) + if line: + code.append(" %s" % (line.strip())) + _logger.info("\n".join(code)) + + def close_socket(self, sock): + """ Closes a socket instance cleanly + :param sock: the network socket to close + :type sock: socket.socket + """ + try: + sock.shutdown(socket.SHUT_RDWR) + except socket.error, e: + # On OSX, socket shutdowns both sides if any side closes it + # causing an error 57 'Socket is not connected' on shutdown + # of the other side (or something), see + # http://bugs.python.org/issue4397 + # note: stdlib fixed test, not behavior + if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']: + raise + sock.close() + +#---------------------------------------------------------- +# Threaded +#---------------------------------------------------------- + +class ThreadedServer(CommonServer): + def __init__(self, app): + super(ThreadedServer, self).__init__(app) + self.main_thread_id = threading.currentThread().ident + # Variable keeping track of the number of calls to the signal handler defined + # below. This variable is monitored by ``quit_on_signals()``. + self.quit_signals_received = 0 + + #self.socket = None + #self.queue = [] + self.httpd = None + + def signal_handler(self, sig, frame): + if sig in [signal.SIGINT,signal.SIGTERM]: + # shutdown on kill -INT or -TERM + self.quit_signals_received += 1 + if self.quit_signals_received > 1: + # logging.shutdown was already called at this point. + sys.stderr.write("Forced shutdown.\n") + os._exit(0) + elif sig == signal.SIGHUP: + # restart on kill -HUP + openerp.phoenix = True + self.quit_signals_received += 1 + elif sig == signal.SIGQUIT: + # dump stacks on kill -3 + self.dumpstacks() + + def cron_thread(self, number): + while True: + time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style + registries = openerp.modules.registry.RegistryManager.registries + _logger.debug('cron%d polling for jobs', number) + for db_name, registry in registries.items(): + while True and registry.ready: + acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) + if not acquired: + break + + def cron_spawn(self): + """ Start the above runner function in a daemon thread. + + The thread is a typical daemon thread: it will never quit and must be + terminated when the main process exits - with no consequence (the processing + threads it spawns are not marked daemon). + + """ + # Force call to strptime just before starting the cron thread + # to prevent time.strptime AttributeError within the thread. + # See: http://bugs.python.org/issue7980 + datetime.datetime.strptime('2012-01-01', '%Y-%m-%d') + for i in range(openerp.tools.config['max_cron_threads']): + def target(): + self.cron_thread(i) + t = threading.Thread(target=target, name="openerp.service.cron.cron%d" % i) + t.setDaemon(True) + t.start() + _logger.debug("cron%d started!" % i) + + def http_thread(self): + self.httpd = werkzeug.serving.make_server(self.interface, self.port, self.app, threaded=True) + self.httpd.serve_forever() + + def http_spawn(self): + threading.Thread(target=self.http_thread).start() + _logger.info('HTTP service (werkzeug) running on %s:%s', self.interface, self.port) + + def start(self): + _logger.debug("Setting signal handlers") + if os.name == 'posix': + signal.signal(signal.SIGINT, self.signal_handler) + signal.signal(signal.SIGTERM, self.signal_handler) + signal.signal(signal.SIGCHLD, self.signal_handler) + signal.signal(signal.SIGHUP, self.signal_handler) + signal.signal(signal.SIGQUIT, self.signal_handler) + elif os.name == 'nt': + import win32api + win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1) + self.cron_spawn() + self.http_spawn() + + def stop(self): + """ Shutdown the WSGI server. Wait for non deamon threads. + """ + _logger.info("Initiating shutdown") + _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") + + self.httpd.shutdown() + self.close_socket(self.httpd.socket) + + # Manually join() all threads before calling sys.exit() to allow a second signal + # to trigger _force_quit() in case some non-daemon threads won't exit cleanly. + # threading.Thread.join() should not mask signals (at least in python 2.5). + me = threading.currentThread() + _logger.debug('current thread: %r', me) + for thread in threading.enumerate(): + _logger.debug('process %r (%r)', thread, thread.isDaemon()) + if thread != me and not thread.isDaemon() and thread.ident != main_thread_id: + while thread.isAlive(): + _logger.debug('join and sleep') + # Need a busyloop here as thread.join() masks signals + # and would prevent the forced shutdown. + thread.join(0.05) + time.sleep(0.05) + + _logger.debug('--') + openerp.modules.registry.RegistryManager.delete_all() + logging.shutdown() + + def run(self): + """ Start the http server and the cron thread then wait for a signal. + + The first SIGINT or SIGTERM signal will initiate a graceful shutdown while + a second one if any will force an immediate exit. + """ + self.start() + + # Wait for a first signal to be handled. (time.sleep will be interrupted + # by the signal handler.) The try/except is for the win32 case. + try: + while self.quit_signals_received == 0: + time.sleep(60) + except KeyboardInterrupt: + pass + + self.stop() + +#---------------------------------------------------------- +# Gevent +#---------------------------------------------------------- + +class GeventServer(CommonServer): + def __init__(self, app): + super(GeventServer, self).__init__(app) + self.port = config['longpolling_port'] + self.httpd = None + + def watch_parent(self, beat=4): + import gevent + ppid = os.getppid() + while True: + if ppid != os.getppid(): + pid = os.getpid() + _logger.info("LongPolling (%s) Parent changed", pid) + # suicide !! + os.kill(pid, signal.SIGTERM) + return + gevent.sleep(beat) + + def start(self): + import gevent + from gevent.wsgi import WSGIServer + gevent.spawn(self.watch_parent) + self.httpd = WSGIServer((self.interface, self.port), self.app) + self.httpd.serve_forever() + + def stop(self): + import gevent + self.httpd.stop() + gevent.shutdown() + + def run(self): + self.start() + self.stop() + +#---------------------------------------------------------- +# Prefork +#---------------------------------------------------------- + +class Multicorn(CommonServer): """ Multiprocessing inspired by (g)unicorn. Multicorn currently uses accept(2) as dispatching method between workers but we plan to replace it by a more intelligent dispatcher to will parse @@ -92,10 +323,8 @@ class Multicorn(object): sys.exit(0) def long_polling_spawn(self): - nargs = stripped_sys_argv('--pidfile') - cmd = nargs[0] - cmd = os.path.join(os.path.dirname(cmd), "openerp-long-polling") - nargs[0] = cmd + nargs = stripped_sys_argv('--pidfile','--workers') + nargs += ['--gevent'] popen = subprocess.Popen(nargs) self.long_polling_pid = popen.pid @@ -122,6 +351,13 @@ class Multicorn(object): sig = self.queue.pop(0) if sig in [signal.SIGINT,signal.SIGTERM]: raise KeyboardInterrupt + elif sig == signal.SIGHUP: + # restart on kill -HUP + openerp.phoenix = True + raise KeyboardInterrupt + elif sig == signal.SIGQUIT: + # dump stacks on kill -3 + self.dumpstacks() def process_zombie(self): # reap dead workers @@ -211,7 +447,6 @@ class Multicorn(object): for pid in self.workers.keys(): self.worker_kill(pid, signal.SIGTERM) self.socket.close() - openerp.cli.server.quit_signals_received = 1 def run(self): self.start() @@ -389,7 +624,7 @@ class WorkerCron(Worker): def sleep(self): # Really sleep once all the databases have been processed. if self.db_index == 0: - interval = 60 + self.pid % 10 # chorus effect + interval = SLEEP_INTERVAL + self.pid % 10 # chorus effect time.sleep(interval) def _db_list(self): @@ -437,12 +672,66 @@ class WorkerCron(Worker): os.nice(10) # mommy always told me to be nice with others... Worker.start(self) self.multi.socket.close() - openerp.service.start_internal() # chorus effect: make cron workers do not all start at first database mct = config['max_cron_threads'] p = float(self.pid % mct) / mct self.db_index = int(len(self._db_list()) * p) +#---------------------------------------------------------- +# start/stop public api +#---------------------------------------------------------- + +server = None + +def load_server_wide_modules(): + for m in openerp.conf.server_wide_modules: + try: + openerp.modules.module.load_openerp_module(m) + except Exception: + msg = '' + if m == 'web': + msg = """ +The `web` module is provided by the addons found in the `openerp-web` project. +Maybe you forgot to add those addons in your addons_path configuration.""" + _logger.exception('Failed to load server-wide module `%s`.%s', m, msg) + +def _reexec(): + """reexecute openerp-server process with (nearly) the same arguments""" + if openerp.tools.osutil.is_running_as_nt_service(): + subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True) + exe = os.path.basename(sys.executable) + args = stripped_sys_argv() + if not args or args[0] != exe: + args.insert(0, exe) + os.execv(sys.executable, args) + +def start(): + """ Start the openerp http server and cron processor. + """ + load_server_wide_modules() + if config['workers']: + openerp.multi_process = True + server = Multicorn(openerp.service.wsgi_server.application) + elif openerp.evented: + server = GeventServer(openerp.service.wsgi_server.application) + else: + server = ThreadedServer(openerp.service.wsgi_server.application) + server.run() + + # like the legend of the phoenix, all ends with beginnings + if getattr(openerp, 'phoenix', False): + _reexec() + sys.exit(0) + +def restart_server(): + """ Restart the server + """ + if os.name == 'nt': + # run in a thread to let the current thread return response to the caller. + threading.Thread(target=_reexec).start() + else: + os.kill(server.pid, signal.SIGHUP) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index acbfc67dd0b..002f8c248b9 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -400,8 +400,6 @@ def application_unproxied(environ, start_response): if hasattr(threading.current_thread(), 'dbname'): del threading.current_thread().dbname - openerp.service.start_internal() - # Try all handlers until one returns some result (i.e. not None). wsgi_handlers = [wsgi_xmlrpc_1, wsgi_xmlrpc, wsgi_xmlrpc_legacy, wsgi_webdav] wsgi_handlers += module_handlers @@ -422,69 +420,5 @@ def application(environ, start_response): else: return application_unproxied(environ, start_response) -# The WSGI server, started by start_server(), stopped by stop_server(). -httpd = None - -def serve(interface, port, threaded): - """ Serve HTTP requests via werkzeug development server. - - Calling this function is blocking, you might want to call it in its own - thread. - """ - - global httpd - if not openerp.evented: - httpd = werkzeug.serving.make_server(interface, port, application, threaded=threaded) - else: - from gevent.wsgi import WSGIServer - httpd = WSGIServer((interface, port), application) - httpd.serve_forever() - -def start_service(): - """ Call serve() in its own thread. - - The WSGI server can be shutdown with stop_server() below. - """ - # TODO Change the xmlrpc_* options to http_* - interface = config['xmlrpc_interface'] or '0.0.0.0' - port = config['xmlrpc_port'] - _logger.info('HTTP service (werkzeug) running on %s:%s', interface, port) - if not openerp.evented: - threading.Thread(target=serve, args=(interface, port, True)).start() - else: - serve(interface, port, True) - -def stop_service(): - """ Initiate the shutdown of the WSGI server. - - The server is supposed to have been started by start_server() above. - """ - if httpd: - if not openerp.evented: - httpd.shutdown() - close_socket(httpd.socket) - else: - import gevent - httpd.stop() - gevent.shutdown() - -def close_socket(sock): - """ Closes a socket instance cleanly - - :param sock: the network socket to close - :type sock: socket.socket - """ - try: - sock.shutdown(socket.SHUT_RDWR) - except socket.error, e: - # On OSX, socket shutdowns both sides if any side closes it - # causing an error 57 'Socket is not connected' on shutdown - # of the other side (or something), see - # http://bugs.python.org/issue4397 - # note: stdlib fixed test, not behavior - if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']: - raise - sock.close() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 093dec2ab01cd5cd8e3f1962cd707f4afdaea17f Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 9 Sep 2013 15:10:24 +0200 Subject: [PATCH 02/37] [FIX] Add the platform lib [IMP] Log when the Long Polling Service is running bzr revid: stw@openerp.com-20130909131024-23an5cvt1qaa90su --- openerp/service/workers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/service/workers.py b/openerp/service/workers.py index 382d581720f..73df8cc5aaf 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -18,6 +18,7 @@ import time import traceback import subprocess import os.path +import platform import wsgi_server @@ -245,6 +246,7 @@ class GeventServer(CommonServer): from gevent.wsgi import WSGIServer gevent.spawn(self.watch_parent) self.httpd = WSGIServer((self.interface, self.port), self.app) + _logger.info('Evented Service (longpolling) running on %s:%s', self.interface, self.port) self.httpd.serve_forever() def stop(self): From f8c0310d8ea8364b13a1a6b7c51862f1760a4ca9 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 9 Sep 2013 15:11:23 +0200 Subject: [PATCH 03/37] [FIX] Use psycogreen instead of gevent-psycopg2 green-psycopg2 has been deprecated by the developer, he asks to use an alternative, in this case, the alternative is psycogreen https://bitbucket.org/dvarrazzo/psycogreen bzr revid: stw@openerp.com-20130909131123-u0gqhvxqwv13yqke --- openerp/__init__.py | 4 ++-- openerpcommand/web.py | 4 ++-- setup.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openerp/__init__.py b/openerp/__init__.py index 161b06b0990..2cb3bce21d6 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -35,8 +35,8 @@ for i in sys.argv: if evented: import gevent.monkey gevent.monkey.patch_all() - import gevent_psycopg2 - gevent_psycopg2.monkey_patch() + import psycogreen.gevent + psycogreen.gevent.patch_psycopg() # Make sure the OpenERP server runs in UTC. This is especially necessary # under Windows as under Linux it seems the real import of time is diff --git a/openerpcommand/web.py b/openerpcommand/web.py index 5875978ad32..5d9d429244b 100644 --- a/openerpcommand/web.py +++ b/openerpcommand/web.py @@ -30,9 +30,9 @@ def run(args): import gevent import gevent.monkey import gevent.wsgi - import gevent_psycopg2 + import psycogreen.gevent gevent.monkey.patch_all() - gevent_psycopg2.monkey_patch() + psycogreen.gevent.patch_psycopg() import threading import openerp import openerp.cli.server diff --git a/setup.py b/setup.py index ff801a97933..4f4ffe6e505 100644 --- a/setup.py +++ b/setup.py @@ -120,7 +120,7 @@ setuptools.setup( 'feedparser', 'gdata', 'gevent', - 'gevent-psycopg2', + 'psycogreen', 'Jinja2', 'lxml', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/ 'mako', From 2a6d0299d97251d93e1a10976096b2354f8f625b Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Mon, 9 Sep 2013 22:08:25 +0200 Subject: [PATCH 04/37] revert to use a separate executable for gevent, add --dev option bzr revid: al@openerp.com-20130909200825-sm5c3invmg7tt70j --- openerp-gevent | 13 +++++++++++++ openerp/__init__.py | 10 ---------- openerp/service/workers.py | 4 +++- openerp/tools/config.py | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) create mode 100755 openerp-gevent diff --git a/openerp-gevent b/openerp-gevent new file mode 100755 index 00000000000..e1c9fa797e1 --- /dev/null +++ b/openerp-gevent @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import gevent.monkey +gevent.monkey.patch_all() +import psycogreen.gevent +psycogreen.gevent.patch_psycopg() + +import openerp + +openerp.evented = True + +if __name__ == "__main__": + openerp.cli.main() diff --git a/openerp/__init__.py b/openerp/__init__.py index 2cb3bce21d6..fe439838497 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -27,16 +27,6 @@ import sys # Is the server running with gevent. evented = False -for i in sys.argv: - if i.startswith('--gevent'): - evented = True - break - -if evented: - import gevent.monkey - gevent.monkey.patch_all() - import psycogreen.gevent - psycogreen.gevent.patch_psycopg() # Make sure the OpenERP server runs in UTC. This is especially necessary # under Windows as under Linux it seems the real import of time is diff --git a/openerp/service/workers.py b/openerp/service/workers.py index 73df8cc5aaf..50aa8f245d0 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -326,7 +326,9 @@ class Multicorn(CommonServer): def long_polling_spawn(self): nargs = stripped_sys_argv('--pidfile','--workers') - nargs += ['--gevent'] + cmd = nargs[0] + cmd = os.path.join(os.path.dirname(cmd), "openerp-gevent") + nargs[0] = cmd popen = subprocess.Popen(nargs) self.long_polling_pid = popen.pid diff --git a/openerp/tools/config.py b/openerp/tools/config.py index cc3c187c775..a399f6d133c 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -106,7 +106,7 @@ class configmanager(object): help="specify additional addons paths (separated by commas).", action="callback", callback=self._check_addons_path, nargs=1, type="string") group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules default=web") - group.add_option("--gevent", dest="gevent", action="store_true", my_default=False, help="Activate the GEvent mode, this also desactivate the cron.") + group.add_option("--dev", dest="dev", action="store_true", my_default=False, help="Activate the developer mode. (code and views auto-reload).") parser.add_option_group(group) # XML-RPC / HTTP @@ -399,7 +399,7 @@ class configmanager(object): 'list_db', 'xmlrpcs', 'proxy_mode', 'test_file', 'test_enable', 'test_commit', 'test_report_directory', 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'unaccent', - 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request', 'gevent' + 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request', 'dev' ] for arg in keys: From 3bc9a499d4e872176db809c80222edd5d6cd6f11 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Mon, 9 Sep 2013 22:17:06 +0200 Subject: [PATCH 05/37] add signals to increase/decrease number of workers bzr revid: al@openerp.com-20130909201706-sllijtol7p6mi5nr --- openerp/service/workers.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/openerp/service/workers.py b/openerp/service/workers.py index 50aa8f245d0..0e7e15fcc39 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -362,6 +362,12 @@ class Multicorn(CommonServer): elif sig == signal.SIGQUIT: # dump stacks on kill -3 self.dumpstacks() + elif sig == signal.SIGTTIN: + # increase number of workers + self.population += 1 + elif sig == signal.SIGTTOUT: + # decrease number of workers + self.population -= 1 def process_zombie(self): # reap dead workers @@ -423,10 +429,14 @@ class Multicorn(CommonServer): # by a signal simulating a pseudo SA_RESTART. We write to a pipe in the # signal handler to overcome this behaviour self.pipe = self.pipe_new() - # set signal + # set signal handlers signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal.SIGTERM, self.signal_handler) + signal.signal(signal.SIGHUP, self.signal_handler) signal.signal(signal.SIGCHLD, self.signal_handler) + signal.signal(signal.SIGQUIT, self.signal_handler) + signal.signal(signal.SIGTTIN, self.signal_handler) + signal.signal(signal.SIGTTOUT, self.signal_handler) # listen to socket self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) From 65c0538a8359c5836a3e42ac6c2c0e739d4d6bff Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Tue, 10 Sep 2013 01:05:53 +0200 Subject: [PATCH 06/37] autoreload, first working version for both python and data, still wip bzr revid: al@openerp.com-20130909230553-jn26ue5qenv0sd3p --- openerp/service/workers.py | 117 +++++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 10 deletions(-) diff --git a/openerp/service/workers.py b/openerp/service/workers.py index 0e7e15fcc39..f2f4c60d5db 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -41,6 +41,97 @@ SLEEP_INTERVAL = 60 # 1 min # Common #---------------------------------------------------------- +class AutoReload(object): + def __init__(self): + self.files = {} + import pyinotify + class EventHandler(pyinotify.ProcessEvent): + def __init__(self, autoreload): + self.autoreload = autoreload + + def process_IN_CREATE(self, event): + _logger.debug('File created: %s', event.pathname) + self.autoreload.files[event.pathname] = 1 + + def process_IN_MODIFY(self, event): + _logger.debug('File modified: %s', event.pathname) + self.autoreload.files[event.pathname] = 1 + + self.wm = pyinotify.WatchManager() + self.handler = EventHandler(self) + self.notifier = pyinotify.Notifier(self.wm, self.handler, timeout=0) + mask = pyinotify.IN_MODIFY | pyinotify.IN_CREATE # IN_MOVED_FROM, IN_MOVED_TO ? + for path in openerp.tools.config.options["addons_path"].split(','): + _logger.info('Watching addons folder %s', path) + self.wm.add_watch(path, mask, rec=True) + + def process_data(self, touched_files): + # pyinotify notifier + fs modiciation tracker + from openerp.modules.module import load_information_from_description_file as load_manifest + addons_path = openerp.tools.config.options["addons_path"].split(',') + registries = openerp.modules.registry.RegistryManager.registries + keys = ['data', 'demo', 'test', 'init_xml', 'update_xml', 'demo_xml'] + # This will only work for loaded registies, so we have to use -d + # al: proposed to move this code in the registry manager so it can be lazy + for db_name, registry in registries.items(): + cr = registry.db.cursor() + try: + for tfile in touched_files: + for path in addons_path: + if tfile.startswith(path): + # find out wich addons path the file belongs to + # and extract it's module name + right = tfile[len(path) + 1:].split('/') + if len(right) < 2: + continue + module = right[0] + relname = "/".join(right[1:]) + domain = [('name', '=', module), ('state', 'in', ['installed', 'to upgrade'])] + if registry.get('ir.module.module').search(cr, openerp.SUPERUSER_ID, domain): + manifest = load_manifest(module) + kind = [key for key in keys if relname in manifest[key]] + if kind: + _logger.info('Updating changed xml file: %s', tfile) + idref = {} + openerp.tools.convert_file(cr, module, relname, idref, mode='update', kind=kind[0]) + cr.commit() + except Exception,e: + _logger.exception(e) + finally: + cr.close() + + def process_python(self, files): + # process python changes + py_files = [i for i in files if i.endswith('.py')] + py_errors = [] + # TODO keep python errors until they are ok + if py_files: + for i in py_files: + try: + source = open(i, 'rb').read() + '\n' + compile(source, i, 'exec') + except SyntaxError: + py_errors.append(i) + if py_errors: + _logger.info('autoreload: python code change detected, errors found') + for i in py_errors: + _logger.info('autoreload: SyntaxError %s',i) + else: + _logger.info('autoreload: python code updated, autoreload activated') + restart_server() + + def check(self): + # Check if some files have been touched in the addons path. + # If true, check if the touched file belongs to an installed module + # in any of the database used in the registry manager. + while self.notifier.check_events(0): + self.notifier.read_events() + self.notifier.process_events() + l = self.files.keys() + self.files.clear() + self.process_data(l) + self.process_python(l) + class CommonServer(object): def __init__(self, app): # TODO Change the xmlrpc_* options to http_* @@ -101,8 +192,8 @@ class ThreadedServer(CommonServer): self.quit_signals_received = 0 #self.socket = None - #self.queue = [] self.httpd = None + self.autoreload = None def signal_handler(self, sig, frame): if sig in [signal.SIGINT,signal.SIGTERM]: @@ -152,7 +243,11 @@ class ThreadedServer(CommonServer): _logger.debug("cron%d started!" % i) def http_thread(self): - self.httpd = werkzeug.serving.make_server(self.interface, self.port, self.app, threaded=True) + def app(e,s): + if self.autoreload: + self.autoreload.check() + return self.app(e,s) + self.httpd = werkzeug.serving.make_server(self.interface, self.port, app, threaded=True) self.httpd.serve_forever() def http_spawn(self): @@ -172,6 +267,7 @@ class ThreadedServer(CommonServer): win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1) self.cron_spawn() self.http_spawn() + self.autoreload = AutoReload() def stop(self): """ Shutdown the WSGI server. Wait for non deamon threads. @@ -189,7 +285,7 @@ class ThreadedServer(CommonServer): _logger.debug('current thread: %r', me) for thread in threading.enumerate(): _logger.debug('process %r (%r)', thread, thread.isDaemon()) - if thread != me and not thread.isDaemon() and thread.ident != main_thread_id: + if thread != me and not thread.isDaemon() and thread.ident != self.main_thread_id: while thread.isAlive(): _logger.debug('join and sleep') # Need a busyloop here as thread.join() masks signals @@ -262,11 +358,11 @@ class GeventServer(CommonServer): # Prefork #---------------------------------------------------------- -class Multicorn(CommonServer): +class PreforkServer(CommonServer): """ Multiprocessing inspired by (g)unicorn. - Multicorn currently uses accept(2) as dispatching method between workers - but we plan to replace it by a more intelligent dispatcher to will parse - the first HTTP request line. + PreforkServer (aka Multicorn) currently uses accept(2) as dispatching + method between workers but we plan to replace it by a more intelligent + dispatcher to will parse the first HTTP request line. """ def __init__(self, app): # config @@ -617,12 +713,12 @@ class WorkerBaseWSGIServer(werkzeug.serving.BaseWSGIServer): def __init__(self, app): werkzeug.serving.BaseWSGIServer.__init__(self, "1", "1", app) def server_bind(self): - # we dont bind beause we use the listen socket of Multicorn#socket + # we dont bind beause we use the listen socket of PreforkServer#socket # instead we close the socket if self.socket: self.socket.close() def server_activate(self): - # dont listen as we use Multicorn#socket + # dont listen as we use PreforkServer#socket pass class WorkerCron(Worker): @@ -723,10 +819,11 @@ def _reexec(): def start(): """ Start the openerp http server and cron processor. """ + global server load_server_wide_modules() if config['workers']: openerp.multi_process = True - server = Multicorn(openerp.service.wsgi_server.application) + server = PreforkServer(openerp.service.wsgi_server.application) elif openerp.evented: server = GeventServer(openerp.service.wsgi_server.application) else: From 082b1dc9fc91200d4eeb9a78c05930dbfac510c6 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Tue, 10 Sep 2013 01:19:46 +0200 Subject: [PATCH 07/37] restore the original gevent detection bzr revid: al@openerp.com-20130909231946-aglho23enxhfwm0i --- openerp-gevent | 2 -- openerp/__init__.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp-gevent b/openerp-gevent index e1c9fa797e1..55044976492 100755 --- a/openerp-gevent +++ b/openerp-gevent @@ -7,7 +7,5 @@ psycogreen.gevent.patch_psycopg() import openerp -openerp.evented = True - if __name__ == "__main__": openerp.cli.main() diff --git a/openerp/__init__.py b/openerp/__init__.py index fe439838497..a06c85d0c21 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -27,6 +27,8 @@ import sys # Is the server running with gevent. evented = False +if sys.modules.get("gevent") is not None: + evented = True # Make sure the OpenERP server runs in UTC. This is especially necessary # under Windows as under Linux it seems the real import of time is From 0afff9aae3497d2621bd9b3d5abd56531f60fb95 Mon Sep 17 00:00:00 2001 From: ima-openerp Date: Wed, 18 Sep 2013 12:28:54 +0530 Subject: [PATCH 08/37] [IMP]removed unused method which is defined only for web shortcuts module. bzr revid: ishwarmalvi13@gmail.com-20130918065854-u0aiyu5e1z7tf09g --- addons/web/controllers/main.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 651e5c42a97..81d37b5aae0 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1010,13 +1010,6 @@ class Menu(http.Controller): """ return request.session.model('ir.ui.menu').get_needaction_data(menu_ids, request.context) - @http.route('/web/menu/action', type='json', auth="user") - def action(self, menu_id): - # still used by web_shortcut - actions = load_actions_from_ir_values('action', 'tree_but_open', - [('ir.ui.menu', menu_id)], False) - return {"action": actions} - class DataSet(http.Controller): @http.route('/web/dataset/search_read', type='json', auth="user") From 76d2e870d6651810914779a486fc851393703d97 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 2 Oct 2013 11:37:30 +0200 Subject: [PATCH 09/37] [FIX] web_kanban: correct css for empty kanban bzr revid: chs@openerp.com-20131002093730-ucn089plydhsl71k --- addons/web_kanban/static/src/css/kanban.css | 4 ---- addons/web_kanban/static/src/css/kanban.sass | 3 --- 2 files changed, 7 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 6f5bf241e17..731fab430b9 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -5,7 +5,6 @@ } .openerp .oe_kanban_view .oe_view_nocontent { position: relative; - z-index: 1; max-width: none; height: 100%; } @@ -91,9 +90,6 @@ .openerp .oe_kanban_view .oe_kanban_groups { height: inherit; } -.openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_groups { - width: 100%; -} .openerp .oe_kanban_view.oe_kanban_grouped_by_m2o .oe_kanban_group_title { cursor: move; } diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index de06990ebb7..dfca3b09d50 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -53,7 +53,6 @@ height: inherit .oe_view_nocontent position: relative - z-index: 1 max-width: none height: 100% .oe_view_nocontent_content @@ -118,8 +117,6 @@ // KanbanGroups {{{ .oe_kanban_groups height: inherit - &.oe_kanban_ungrouped .oe_kanban_groups - width: 100% &.oe_kanban_grouped_by_m2o .oe_kanban_group_title cursor: move .oe_kanban_header From 58281701e99a03b671f60f614a6f1ce0a8f5def7 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 2 Oct 2013 11:46:34 +0200 Subject: [PATCH 10/37] [FIX] web: remove firefox css fix for view switch icons bzr revid: chs@openerp.com-20131002094634-9g7b20vs7n5yw4kh --- addons/web/static/src/css/base.css | 3 --- addons/web/static/src/css/base.sass | 2 -- 2 files changed, 5 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 97bbb2b207c..fe14cc28a62 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -3211,9 +3211,6 @@ } @-moz-document url-prefix() { - .openerp .oe_view_manager .oe_view_manager_switch li { - line-height: 21px; - } .openerp .oe_searchview .oe_searchview_search { top: -1px; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index e41a182407d..5571b5696fc 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -2532,8 +2532,6 @@ $sheet-padding: 16px // }}} @-moz-document url-prefix() .openerp - .oe_view_manager .oe_view_manager_switch li - line-height: 21px .oe_searchview .oe_searchview_search top: -1px .oe_form_field_many2one .oe_m2o_cm_button From f2e1240522bd7eb5fbd8bf32d3865dd35ddc3644 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 2 Oct 2013 14:07:33 +0200 Subject: [PATCH 11/37] [FIX] mail: correct button on "Suggested Groups" bzr revid: chs@openerp.com-20131002120733-6hsz0ugl3ir2gwfp --- addons/mail/static/src/js/suggestions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/suggestions.js b/addons/mail/static/src/js/suggestions.js index 4d0fcec32bf..47a5bcf625c 100644 --- a/addons/mail/static/src/js/suggestions.js +++ b/addons/mail/static/src/js/suggestions.js @@ -48,7 +48,8 @@ openerp.mail.suggestions = function(session, mail) { join_group: function (event) { var self = this; - return this.mail_group.call('message_subscribe_users', [[$(event.currentTarget).attr('id')],[this.session.uid]]).then(function(res) { + var group_id = parseInt($(event.currentTarget).attr('id'), 10); + return this.mail_group.call('message_subscribe_users', [[group_id], [this.session.uid]]).then(function(res) { self.fetch_suggested_groups(); }); }, From fc13b6e3722e13d3457b4b41b7fbb825e3423b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 09:58:36 +0200 Subject: [PATCH 12/37] [IMP] web_kanban_sparkline: always begin y range at 0 instead of minimum value bzr revid: tde@openerp.com-20131003075836-qffb91gxe8uk4k0n --- addons/web_kanban_sparkline/static/src/js/kanban_sparkline.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/web_kanban_sparkline/static/src/js/kanban_sparkline.js b/addons/web_kanban_sparkline/static/src/js/kanban_sparkline.js index de21cbba945..5335599478f 100644 --- a/addons/web_kanban_sparkline/static/src/js/kanban_sparkline.js +++ b/addons/web_kanban_sparkline/static/src/js/kanban_sparkline.js @@ -20,6 +20,7 @@ instance.web_kanban.SparklineBarWidget = instance.web_kanban.AbstractField.exten barWidth: 4, barSpacing: 1, barColor: '#96d854', + chartRangeMin: 0, tooltipFormat: '{{offset:offset}} {{value}}', tooltipValueLookups: { 'offset': tooltips From f72927123e4fb68fe3bb00c48ddddc1cf058ad7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 10:27:36 +0200 Subject: [PATCH 13/37] [FIX] crm, sale_crm, mass_mailin: fixed computation for sparkline widgets. Added an end date in the read_group domain. Indeed having results outside the date range made the result computation crash because of list limits. There is now a begin and end date for groupby domain. bzr revid: tde@openerp.com-20131003082736-tw50xk2vmhpjh1e5 --- addons/crm/crm.py | 15 +++++++++------ addons/mass_mailing/mass_mailing.py | 11 +++++++---- addons/sale_crm/sale_crm.py | 8 +++++--- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 932fa998d0a..dc7ebf3ca95 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -19,6 +19,7 @@ # ############################################################################## +import calendar from datetime import date, datetime from dateutil import relativedelta @@ -117,9 +118,9 @@ class crm_case_section(osv.osv): """ month_begin = date.today().replace(day=1) section_result = [{ - 'value': 0, - 'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'), - } for i in range(self._period_number - 1, -1, -1)] + 'value': 0, + 'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'), + } for i in range(self._period_number - 1, -1, -1)] group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context) for group in group_obj: group_begin_date = datetime.strptime(group['__domain'][0][2], tools.DEFAULT_SERVER_DATE_FORMAT) @@ -135,12 +136,14 @@ class crm_case_section(osv.osv): obj = self.pool.get('crm.lead') res = dict.fromkeys(ids, False) month_begin = date.today().replace(day=1) - groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1) + date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1]) + date_domain = [('create_date', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)), ('create_date', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] for id in ids: res[id] = dict() - lead_domain = [('type', '=', 'lead'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)] + lead_domain = date_domain + [('type', '=', 'lead'), ('section_id', '=', id)] res[id]['monthly_open_leads'] = self.__get_bar_values(cr, uid, obj, lead_domain, ['create_date'], 'create_date_count', 'create_date', context=context) - opp_domain = [('type', '=', 'opportunity'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)] + opp_domain = date_domain + [('type', '=', 'opportunity'), ('section_id', '=', id)] res[id]['monthly_planned_revenue'] = self.__get_bar_values(cr, uid, obj, opp_domain, ['planned_revenue', 'create_date'], 'planned_revenue', 'create_date', context=context) return res diff --git a/addons/mass_mailing/mass_mailing.py b/addons/mass_mailing/mass_mailing.py index 49ee106bc69..4f59994d4a6 100644 --- a/addons/mass_mailing/mass_mailing.py +++ b/addons/mass_mailing/mass_mailing.py @@ -194,10 +194,13 @@ class MassMailing(osv.Model): } for id in ids: res[id] = {} - date_begin = self.browse(cr, uid, id, context=context).date - domain = [('mass_mailing_id', '=', id), ('opened', '>=', date_begin)] + date_begin = datetime.strptime(self.browse(cr, uid, id, context=context).date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_end = date_begin + relativedelta.relativedelta(days=self._period_number - 1) + date_begin_str = date_begin.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_end_str = date_end.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) + domain = [('mass_mailing_id', '=', id), ('opened', '>=', date_begin_str), ('opened', '<=', date_end_str)] res[id]['opened_monthly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['opened'], 'opened_count', 'opened', context=context) - domain = [('mass_mailing_id', '=', id), ('replied', '>=', date_begin)] + domain = [('mass_mailing_id', '=', id), ('replied', '>=', date_begin_str), ('replied', '<=', date_end_str)] res[id]['replied_monthly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['replied'], 'replied_count', 'replied', context=context) return res @@ -274,7 +277,7 @@ class MassMailing(osv.Model): } _defaults = { - 'date': fields.datetime.now(), + 'date': fields.datetime.now, } diff --git a/addons/sale_crm/sale_crm.py b/addons/sale_crm/sale_crm.py index d6413c994e7..47caad79c26 100644 --- a/addons/sale_crm/sale_crm.py +++ b/addons/sale_crm/sale_crm.py @@ -19,6 +19,7 @@ # ############################################################################## +import calendar from datetime import date from dateutil import relativedelta @@ -48,12 +49,13 @@ class crm_case_section(osv.osv): obj = self.pool.get('sale.order') res = dict.fromkeys(ids, False) month_begin = date.today().replace(day=1) - groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1]).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) for id in ids: res[id] = dict() - created_domain = [('section_id', '=', id), ('state', 'in', ['draft', 'sent']), ('date_order', '>=', groupby_begin)] + created_domain = [('section_id', '=', id), ('state', 'in', ['draft', 'sent']), ('date_order', '>=', date_begin), ('date_order', '<=', date_end)] res[id]['monthly_quoted'] = self.__get_bar_values(cr, uid, obj, created_domain, ['amount_total', 'date_order'], 'amount_total', 'date_order', context=context) - validated_domain = [('section_id', '=', id), ('state', 'not in', ['draft', 'sent']), ('date_confirm', '>=', groupby_begin)] + validated_domain = [('section_id', '=', id), ('state', 'not in', ['draft', 'sent']), ('date_confirm', '>=', date_begin), ('date_order', '<=', date_end)] res[id]['monthly_confirmed'] = self.__get_bar_values(cr, uid, obj, validated_domain, ['amount_total', 'date_confirm'], 'amount_total', 'date_confirm', context=context) return res From 6e6977e0f24fdf273f43b5d8a5a9a6aa4a22c007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 11:00:49 +0200 Subject: [PATCH 14/37] [FIX] web: form_view: FieldStatus widget: fixed hidden states/stages not appearing because behind displayed sheet. bzr revid: tde@openerp.com-20131003090049-88q0o69970eahb2h --- addons/web/static/src/css/base.css | 1 + addons/web/static/src/css/base.sass | 1 + 2 files changed, 2 insertions(+) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index fe14cc28a62..51c3fd30f3c 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -2741,6 +2741,7 @@ } .openerp ul.oe_form_status .oe_folded ul, .openerp ul.oe_form_status_clickable .oe_folded ul { position: absolute; + z-index: 1000; border-top: 1px solid #cacaca; float: none; top: 30px; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 5571b5696fc..a0231387e7f 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -2179,6 +2179,7 @@ $sheet-padding: 16px padding-bottom: 8px ul position: absolute + z-index: 1000 border-top: 1px solid #cacaca float: none top: 30px From 187c9454d76ada420eb7ab8e66894732a4192bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 11:56:26 +0200 Subject: [PATCH 15/37] [FIX] sale_crm: fixed previous fix + forgot to complete domain on invoices, added an end date for invoice sparklines bzr revid: tde@openerp.com-20131003095626-dckhvcvi935fdgzf --- addons/sale_crm/sale_crm.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/sale_crm/sale_crm.py b/addons/sale_crm/sale_crm.py index 47caad79c26..e5695daab09 100644 --- a/addons/sale_crm/sale_crm.py +++ b/addons/sale_crm/sale_crm.py @@ -49,7 +49,7 @@ class crm_case_section(osv.osv): obj = self.pool.get('sale.order') res = dict.fromkeys(ids, False) month_begin = date.today().replace(day=1) - date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_begin = (month_begin - relativedelta.relativedelta(months=self._period_number - 1)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1]).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) for id in ids: res[id] = dict() @@ -63,9 +63,10 @@ class crm_case_section(osv.osv): obj = self.pool.get('account.invoice.report') res = dict.fromkeys(ids, False) month_begin = date.today().replace(day=1) - groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_begin = (month_begin - relativedelta.relativedelta(months=self._period_number - 1)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1]).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) for id in ids: - created_domain = [('section_id', '=', id), ('state', 'not in', ['draft', 'cancel']), ('date', '>=', groupby_begin)] + created_domain = [('section_id', '=', id), ('state', 'not in', ['draft', 'cancel']), ('date', '>=', date_begin), ('date', '<=', date_end)] res[id] = self.__get_bar_values(cr, uid, obj, created_domain, ['price_total', 'date'], 'price_total', 'date', context=context) return res From ace96e02df9c9593d4479220fe19f0339392266e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 11:57:03 +0200 Subject: [PATCH 16/37] [FIX] sale_crm: fixed kanban view: correct groups on the whole div containing invoice data, not only on the label bzr revid: tde@openerp.com-20131003095703-zoqvii3nzmb2j024 --- addons/sale_crm/sale_crm_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/sale_crm/sale_crm_view.xml b/addons/sale_crm/sale_crm_view.xml index a1e201d9b7f..34f32e0b58b 100644 --- a/addons/sale_crm/sale_crm_view.xml +++ b/addons/sale_crm/sale_crm_view.xml @@ -249,8 +249,8 @@ -
- Invoices +
+ Invoices Revenue of sent invoices per month.
Click to see a detailed analysis of invoices. From fed1b1e91c221d751b4f2b259463727f1e5b1dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 15:33:57 +0200 Subject: [PATCH 17/37] [REF] ir_actions in email_template: strange implementation of displaying template values based on copying fields replaced by a standard related fields + using an onchange on the template. bzr revid: tde@openerp.com-20131003133357-hbs35e3h4mleg9v5 --- addons/email_template/ir_actions.py | 54 +++++++++++++---------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/addons/email_template/ir_actions.py b/addons/email_template/ir_actions.py index bd860785da4..64c50651f11 100644 --- a/addons/email_template/ir_actions.py +++ b/addons/email_template/ir_actions.py @@ -33,48 +33,44 @@ class actions_server(osv.Model): return res _columns = { - 'email_from': fields.char('From', - help="Sender address; define the template to see its value. If not set, the default " - "value will be the author's email alias if configured, or email address."), - 'email_to': fields.char('To (Emails)', - help="Comma-separated recipient addresses; define the template to see its value"), - 'partner_to': fields.char('To (Partners)', - help="Comma-separated ids of recipient partners; define the template to see its value"), - 'subject': fields.char('Subject', - help="Email subject; define the template to see its value"), - 'body_html': fields.text('Body', - help="Rich-text/HTML version of the message; define the template to see its value"), - 'template_id': fields.many2one('email.template', 'Email Template', ondelete='set null', - help="Define the email template to use for the email to send.") + 'email_from': fields.related( + 'template_id', 'email_from', type='char', + readonly=True, string='From' + ), + 'email_to': fields.related( + 'template_id', 'email_to', type='char', + readonly=True, string='To (Emails)' + ), + 'partner_to': fields.related( + 'template_id', 'partner_to', type='char', + readonly=True, string='To (Partners)' + ), + 'subject': fields.related( + 'template_id', 'subject', type='char', + readonly=True, string='Subject' + ), + 'body_html': fields.related( + 'template_id', 'body_html', type='text', + readonly=True, string='Body' + ), + 'template_id': fields.many2one( + 'email.template', 'Email Template', ondelete='set null' + ), } def on_change_template_id(self, cr, uid, ids, template_id, context=None): """ Render the raw template in the server action fields. """ + fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to'] if template_id: - fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids'] template_values = self.pool.get('email.template').read(cr, uid, template_id, fields, context) values = dict((field, template_values[field]) for field in fields if template_values.get(field)) if not values.get('email_from'): return {'warning': {'title': 'Incomplete template', 'message': 'Your template should define email_from'}, 'value': values} else: - values = self.default_get(cr, uid, ['subject', 'body_html', 'email_from', 'email_to', 'partner_to'], context=context) + values = dict.fromkeys(fields, False) return {'value': values} - def create(self, cr, uid, values, context=None): - if values.get('template_id'): - fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids'] - template_values = self.pool.get('email.template').read(cr, uid, values.get('template_id'), fields, context) - values.update(dict((field, template_values[field]) for field in fields if template_values.get(field))) - return super(actions_server, self).create(cr, uid, values, context=context) - - def write(self, cr, uid, ids, values, context=None): - if values.get('template_id'): - fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids'] - template_values = self.pool.get('email.template').read(cr, uid, values.get('template_id'), fields, context) - values.update(dict((field, template_values[field]) for field in fields if template_values.get(field))) - return super(actions_server, self).write(cr, uid, ids, values, context=context) - def run_action_email(self, cr, uid, action, eval_context=None, context=None): if not action.template_id or not context.get('active_id'): return False From bdd86a831f026c0a99dd5f71e772488f2bea4eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 3 Oct 2013 16:04:58 +0200 Subject: [PATCH 18/37] [IMP] ir_actions in email_template: template_id domain not only on view, directly on field bzr revid: tde@openerp.com-20131003140458-ztnd9taih2rcq8ty --- addons/email_template/ir_actions.py | 3 ++- addons/email_template/ir_actions_view.xml | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/email_template/ir_actions.py b/addons/email_template/ir_actions.py index 64c50651f11..ae2395e3b81 100644 --- a/addons/email_template/ir_actions.py +++ b/addons/email_template/ir_actions.py @@ -54,7 +54,8 @@ class actions_server(osv.Model): readonly=True, string='Body' ), 'template_id': fields.many2one( - 'email.template', 'Email Template', ondelete='set null' + 'email.template', 'Email Template', ondelete='set null', + domain="[('model_id', '=', model_id)]", ), } diff --git a/addons/email_template/ir_actions_view.xml b/addons/email_template/ir_actions_view.xml index fae9c364312..8f5875257aa 100644 --- a/addons/email_template/ir_actions_view.xml +++ b/addons/email_template/ir_actions_view.xml @@ -16,7 +16,6 @@

Choose a template to display its values. From 0a75a6b5ff175feef9348cdbbc4ab2d90f686304 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sat, 5 Oct 2013 23:22:40 +0200 Subject: [PATCH 19/37] simplier autoreload working bzr revid: al@openerp.com-20131005212240-5lp8tgwukeg5wwdq --- openerp/addons/base/module/module.py | 2 +- openerp/service/workers.py | 185 +++++++++++++++------------ openerp/tools/config.py | 3 +- 3 files changed, 103 insertions(+), 87 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 39d59a4ab2c..32306fbd0ff 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -726,7 +726,7 @@ class module(osv.osv): if already_installed: # in this case, force server restart to reload python code... cr.commit() - openerp.service.restart_server() + openerp.service.restart() return { 'type': 'ir.actions.client', 'tag': 'home', diff --git a/openerp/service/workers.py b/openerp/service/workers.py index f2f4c60d5db..f7d6f97b85b 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -6,21 +6,19 @@ import errno import fcntl import logging import os +import os.path +import platform import psutil import random import resource import select import signal import socket +import subprocess import sys import threading import time import traceback -import subprocess -import os.path -import platform - -import wsgi_server import werkzeug.serving try: @@ -33,17 +31,60 @@ import openerp.tools.config as config from openerp.release import nt_service_name from openerp.tools.misc import stripped_sys_argv +import wsgi_server + _logger = logging.getLogger(__name__) SLEEP_INTERVAL = 60 # 1 min #---------------------------------------------------------- -# Common +# Werkzeug WSGI servers patched +#---------------------------------------------------------- + +class BaseWSGIServerNoBind(werkzeug.serving.BaseWSGIServer): + """ werkzeug Base WSGI Server patched to skip socket binding. PreforkServer + use this class, sets the socket and calls the process_request() manually + """ + def __init__(self, app): + werkzeug.serving.BaseWSGIServer.__init__(self, "1", "1", app) + def server_bind(self): + # we dont bind beause we use the listen socket of PreforkServer#socket + # instead we close the socket + if self.socket: + self.socket.close() + def server_activate(self): + # dont listen as we use PreforkServer#socket + pass + +# MAybe NOT useful BECAUSE of SOCKET_REUSE, need to test + +class ThreadedWSGIServerReloadable(werkzeug.serving.ThreadedWSGIServer): + """ werkzeug Threaded WSGI Server patched to allow reusing a listen socket + given by the environement, this is used by autoreload to keep the listen + socket open when a reload happens. + """ + def server_bind(self): + envfd = os.environ.get('OPENERP_AUTO_RELOAD_FD') + if envfd: + self.reload_socket = socket.fromfd + # close os.close()fd if fd has been diplucated ?! + else: + self.reload_socket = False + super(ThreadedWSGIServerReloadable, self).server_bind() + + def server_activate(self): + if not self.reload_socket: + super(ThreadedWSGIServerReloadable, self).server_activate() + +#---------------------------------------------------------- +# AutoReload watcher #---------------------------------------------------------- class AutoReload(object): - def __init__(self): + def __init__(self, server): + self.server = server self.files = {} + self.modules = {} import pyinotify class EventHandler(pyinotify.ProcessEvent): def __init__(self, autoreload): @@ -65,40 +106,22 @@ class AutoReload(object): _logger.info('Watching addons folder %s', path) self.wm.add_watch(path, mask, rec=True) - def process_data(self, touched_files): - # pyinotify notifier + fs modiciation tracker - from openerp.modules.module import load_information_from_description_file as load_manifest + def process_data(self, files): + xml_files = [i for i in files if i.endswith('.xml')] addons_path = openerp.tools.config.options["addons_path"].split(',') - registries = openerp.modules.registry.RegistryManager.registries - keys = ['data', 'demo', 'test', 'init_xml', 'update_xml', 'demo_xml'] - # This will only work for loaded registies, so we have to use -d - # al: proposed to move this code in the registry manager so it can be lazy - for db_name, registry in registries.items(): - cr = registry.db.cursor() - try: - for tfile in touched_files: - for path in addons_path: - if tfile.startswith(path): - # find out wich addons path the file belongs to - # and extract it's module name - right = tfile[len(path) + 1:].split('/') - if len(right) < 2: - continue - module = right[0] - relname = "/".join(right[1:]) - domain = [('name', '=', module), ('state', 'in', ['installed', 'to upgrade'])] - if registry.get('ir.module.module').search(cr, openerp.SUPERUSER_ID, domain): - manifest = load_manifest(module) - kind = [key for key in keys if relname in manifest[key]] - if kind: - _logger.info('Updating changed xml file: %s', tfile) - idref = {} - openerp.tools.convert_file(cr, module, relname, idref, mode='update', kind=kind[0]) - cr.commit() - except Exception,e: - _logger.exception(e) - finally: - cr.close() + for i in xml_files: + for path in addons_path: + if i.startswith(path): + # find out wich addons path the file belongs to + # and extract it's module name + right = i[len(path) + 1:].split('/') + if len(right) < 2: + continue + module = right[0] + self.modules[module]=1 + if self.modules: + _logger.info('autoreload: xml change detected, autoreload activated') + restart() def process_python(self, files): # process python changes @@ -118,19 +141,30 @@ class AutoReload(object): _logger.info('autoreload: SyntaxError %s',i) else: _logger.info('autoreload: python code updated, autoreload activated') - restart_server() + restart() - def check(self): + def check_thread(self): # Check if some files have been touched in the addons path. # If true, check if the touched file belongs to an installed module # in any of the database used in the registry manager. - while self.notifier.check_events(0): - self.notifier.read_events() - self.notifier.process_events() - l = self.files.keys() - self.files.clear() - self.process_data(l) - self.process_python(l) + while 1: + while self.notifier.check_events(1000): + self.notifier.read_events() + self.notifier.process_events() + l = self.files.keys() + self.files.clear() + self.process_data(l) + self.process_python(l) + + def run(self): + t = threading.Thread(target=self.check_thread) + t.setDaemon(True) + t.start() + _logger.info('AutoReload watcher running') + +#---------------------------------------------------------- +# Servers: Threaded, Gevented and Prefork +#---------------------------------------------------------- class CommonServer(object): def __init__(self, app): @@ -179,10 +213,6 @@ class CommonServer(object): raise sock.close() -#---------------------------------------------------------- -# Threaded -#---------------------------------------------------------- - class ThreadedServer(CommonServer): def __init__(self, app): super(ThreadedServer, self).__init__(app) @@ -193,7 +223,6 @@ class ThreadedServer(CommonServer): #self.socket = None self.httpd = None - self.autoreload = None def signal_handler(self, sig, frame): if sig in [signal.SIGINT,signal.SIGTERM]: @@ -244,10 +273,8 @@ class ThreadedServer(CommonServer): def http_thread(self): def app(e,s): - if self.autoreload: - self.autoreload.check() return self.app(e,s) - self.httpd = werkzeug.serving.make_server(self.interface, self.port, app, threaded=True) + self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, app) self.httpd.serve_forever() def http_spawn(self): @@ -267,7 +294,6 @@ class ThreadedServer(CommonServer): win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1) self.cron_spawn() self.http_spawn() - self.autoreload = AutoReload() def stop(self): """ Shutdown the WSGI server. Wait for non deamon threads. @@ -315,9 +341,8 @@ class ThreadedServer(CommonServer): self.stop() -#---------------------------------------------------------- -# Gevent -#---------------------------------------------------------- + def reload(self): + os.kill(self.pid, signal.SIGHUP) class GeventServer(CommonServer): def __init__(self, app): @@ -354,10 +379,6 @@ class GeventServer(CommonServer): self.start() self.stop() -#---------------------------------------------------------- -# Prefork -#---------------------------------------------------------- - class PreforkServer(CommonServer): """ Multiprocessing inspired by (g)unicorn. PreforkServer (aka Multicorn) currently uses accept(2) as dispatching @@ -684,7 +705,7 @@ class WorkerHTTP(Worker): # Prevent fd inherientence close_on_exec flags = fcntl.fcntl(client, fcntl.F_GETFD) | fcntl.FD_CLOEXEC fcntl.fcntl(client, fcntl.F_SETFD, flags) - # do request using WorkerBaseWSGIServer monkey patched with socket + # do request using BaseWSGIServerNoBind monkey patched with socket self.server.socket = client # tolerate broken pipe when the http client closes the socket before # receiving the full reply @@ -705,21 +726,7 @@ class WorkerHTTP(Worker): def start(self): Worker.start(self) - self.server = WorkerBaseWSGIServer(self.multi.app) - -class WorkerBaseWSGIServer(werkzeug.serving.BaseWSGIServer): - """ werkzeug WSGI Server patched to allow using an external listen socket - """ - def __init__(self, app): - werkzeug.serving.BaseWSGIServer.__init__(self, "1", "1", app) - def server_bind(self): - # we dont bind beause we use the listen socket of PreforkServer#socket - # instead we close the socket - if self.socket: - self.socket.close() - def server_activate(self): - # dont listen as we use PreforkServer#socket - pass + self.server = BaseWSGIServerNoBind(self.multi.app) class WorkerCron(Worker): """ Cron workers """ @@ -806,12 +813,13 @@ The `web` module is provided by the addons found in the `openerp-web` project. Maybe you forgot to add those addons in your addons_path configuration.""" _logger.exception('Failed to load server-wide module `%s`.%s', m, msg) -def _reexec(): +def _reexec(updated_modules=None): """reexecute openerp-server process with (nearly) the same arguments""" if openerp.tools.osutil.is_running_as_nt_service(): subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True) exe = os.path.basename(sys.executable) args = stripped_sys_argv() + args += ["-u", ','.join(updated_modules)] if not args or args[0] != exe: args.insert(0, exe) os.execv(sys.executable, args) @@ -828,14 +836,22 @@ def start(): server = GeventServer(openerp.service.wsgi_server.application) else: server = ThreadedServer(openerp.service.wsgi_server.application) + + if config['auto_reload']: + autoreload = AutoReload(server) + autoreload.run() + server.run() # like the legend of the phoenix, all ends with beginnings if getattr(openerp, 'phoenix', False): - _reexec() + modules = [] + if config['auto_reload']: + modules = autoreload.modules.keys() + _reexec(modules) sys.exit(0) -def restart_server(): +def restart(): """ Restart the server """ if os.name == 'nt': @@ -844,5 +860,4 @@ def restart_server(): else: os.kill(server.pid, signal.SIGHUP) - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tools/config.py b/openerp/tools/config.py index a399f6d133c..05242b538c2 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -246,6 +246,7 @@ class configmanager(object): # Advanced options group = optparse.OptionGroup(parser, "Advanced options") + group.add_option('--auto-reload', dest='auto_reload', action='store_true', my_default=False, help='enable auto reload') group.add_option('--debug', dest='debug_mode', action='store_true', my_default=False, help='enable debug mode') group.add_option("--stop-after-init", action="store_true", dest="stop_after_init", my_default=False, help="stop the server after its initialization") @@ -399,7 +400,7 @@ class configmanager(object): 'list_db', 'xmlrpcs', 'proxy_mode', 'test_file', 'test_enable', 'test_commit', 'test_report_directory', 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'unaccent', - 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request', 'dev' + 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request', 'dev', 'auto_reload' ] for arg in keys: From c52df72706844589ca8bc4c3fac3fe8550612c23 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sat, 5 Oct 2013 23:58:21 +0200 Subject: [PATCH 20/37] fix signal name bzr revid: al@openerp.com-20131005215821-r60pgkgsrp1lo2ug --- openerp/service/workers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/service/workers.py b/openerp/service/workers.py index f7d6f97b85b..e9b0615e70c 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -482,7 +482,7 @@ class PreforkServer(CommonServer): elif sig == signal.SIGTTIN: # increase number of workers self.population += 1 - elif sig == signal.SIGTTOUT: + elif sig == signal.SIGTTOU: # decrease number of workers self.population -= 1 @@ -553,7 +553,7 @@ class PreforkServer(CommonServer): signal.signal(signal.SIGCHLD, self.signal_handler) signal.signal(signal.SIGQUIT, self.signal_handler) signal.signal(signal.SIGTTIN, self.signal_handler) - signal.signal(signal.SIGTTOUT, self.signal_handler) + signal.signal(signal.SIGTTOU, self.signal_handler) # listen to socket self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) From e6b18fc7aac067d6e905a0f1a68d89670e959fc3 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 00:18:29 +0200 Subject: [PATCH 21/37] rename server bzr revid: al@openerp.com-20131005221829-a18vx5ag6ef4ufee --- openerp/addons/base/module/module.py | 2 +- openerp/cli/server.py | 2 +- openerp/service/__init__.py | 2 +- openerp/service/{workers.py => server.py} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename openerp/service/{workers.py => server.py} (100%) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 6f986ac01b3..6279a5fe6ae 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -716,7 +716,7 @@ class module(osv.osv): if already_installed: # in this case, force server restart to reload python code... cr.commit() - openerp.service.restart() + openerp.service.server.restart() return { 'type': 'ir.actions.client', 'tag': 'home', diff --git a/openerp/cli/server.py b/openerp/cli/server.py index 0c081b6156b..24987c098e4 100644 --- a/openerp/cli/server.py +++ b/openerp/cli/server.py @@ -177,7 +177,7 @@ def main(args): if not config["stop_after_init"]: setup_pid_file() - openerp.service.workers.start() + openerp.service.server.start() if config['pidfile']: os.unlink(config['pidfile']) else: diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index 02401d455e1..6e3ae985fab 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -25,7 +25,7 @@ import db import model import report import wsgi_server -import workers +import server #.apidoc title: RPC Services diff --git a/openerp/service/workers.py b/openerp/service/server.py similarity index 100% rename from openerp/service/workers.py rename to openerp/service/server.py From 156094df3deb1f8779eeff1cc1f8a3597fcea530 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 01:56:39 +0200 Subject: [PATCH 22/37] [FIX] preliminary code for socket activation, to avoid connection refused during restart bzr revid: al@openerp.com-20131005235639-vifvbhu4o17lf780 --- openerp/service/server.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openerp/service/server.py b/openerp/service/server.py index e9b0615e70c..cddb0bee444 100644 --- a/openerp/service/server.py +++ b/openerp/service/server.py @@ -56,7 +56,9 @@ class BaseWSGIServerNoBind(werkzeug.serving.BaseWSGIServer): # dont listen as we use PreforkServer#socket pass -# MAybe NOT useful BECAUSE of SOCKET_REUSE, need to test +# _reexec() should set LISTEN_* to avoid connection refused during reload time. It +# should also work with systemd socket activation. This is currently untested +# and not yet used. class ThreadedWSGIServerReloadable(werkzeug.serving.ThreadedWSGIServer): """ werkzeug Threaded WSGI Server patched to allow reusing a listen socket @@ -64,10 +66,11 @@ class ThreadedWSGIServerReloadable(werkzeug.serving.ThreadedWSGIServer): socket open when a reload happens. """ def server_bind(self): - envfd = os.environ.get('OPENERP_AUTO_RELOAD_FD') - if envfd: - self.reload_socket = socket.fromfd - # close os.close()fd if fd has been diplucated ?! + envfd = os.environ.get('LISTEN_FDS') + if envfd and os.environ.get('LISTEN_PID') == str(os.getpid()): + self.reload_socket = True + self.socket = socket.fromfd(int(envfd), socket.AF_INET, socket.SOCK_STREAM) + # should we os.close(int(envfd)) ? it seem python duplicate the fd. else: self.reload_socket = False super(ThreadedWSGIServerReloadable, self).server_bind() From 780ae0829472ea777a002de9279d658c311e6683 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 12:21:31 +0200 Subject: [PATCH 23/37] [IMP] add an easier to use XML-RPC faultCode compliant protocol remove the /openerp/* routes, they were never used because the protocol was too different from the historical /xmlrpc/ routes. Instead we introduce a /xmlrpc/2/ route identical to /xmlrpc/ with the only difference that it returns int faultCodes making it compliant with the XML-RPC specification. bzr revid: al@openerp.com-20131006102131-707kxc9zyd1mvlps --- openerp/service/wsgi_server.py | 103 +++++++-------------------------- openerp/tests/common.py | 10 ++-- openerp/tests/test_xmlrpc.py | 17 +++--- 3 files changed, 34 insertions(+), 96 deletions(-) diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index 002f8c248b9..506a07d0295 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -57,13 +57,7 @@ RPC_FAULT_CODE_WARNING = 2 RPC_FAULT_CODE_ACCESS_DENIED = 3 RPC_FAULT_CODE_ACCESS_ERROR = 4 -# The new (6.1) versioned RPC paths. -XML_RPC_PATH = '/openerp/xmlrpc' -XML_RPC_PATH_1 = '/openerp/xmlrpc/1' -JSON_RPC_PATH = '/openerp/jsonrpc' -JSON_RPC_PATH_1 = '/openerp/jsonrpc/1' - -def xmlrpc_return(start_response, service, method, params, legacy_exceptions=False): +def xmlrpc_return(start_response, service, method, params, string_faultcode=False): """ Helper to call a service's method with some params, using a wsgi-supplied ``start_response`` callback. @@ -81,14 +75,14 @@ def xmlrpc_return(start_response, service, method, params, legacy_exceptions=Fal result = openerp.netsvc.dispatch_rpc(service, method, params) response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None) except Exception, e: - if legacy_exceptions: - response = xmlrpc_handle_exception_legacy(e) + if string_faultcode: + response = xmlrpc_handle_exception_string(e) else: - response = xmlrpc_handle_exception(e) + response = xmlrpc_handle_exception_int(e) start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))]) return [response] -def xmlrpc_handle_exception(e): +def xmlrpc_handle_exception_int(e): if isinstance(e, openerp.osv.orm.except_orm): # legacy fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, openerp.tools.ustr(e.value)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) @@ -121,7 +115,7 @@ def xmlrpc_handle_exception(e): response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) return response -def xmlrpc_handle_exception_legacy(e): +def xmlrpc_handle_exception_string(e): if isinstance(e, openerp.osv.orm.except_orm): fault = xmlrpclib.Fault('warning -- ' + e.name + '\n\n' + e.value, '') response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) @@ -146,82 +140,29 @@ def xmlrpc_handle_exception_legacy(e): response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) return response -def wsgi_xmlrpc_1(environ, start_response): - """ The main OpenERP WSGI handler.""" - if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith(XML_RPC_PATH_1): - length = int(environ['CONTENT_LENGTH']) - data = environ['wsgi.input'].read(length) - - params, method = xmlrpclib.loads(data) - - path = environ['PATH_INFO'][len(XML_RPC_PATH_1):] - if path.startswith('/'): path = path[1:] - if path.endswith('/'): path = path[:-1] - path = path.split('/') - - # All routes are hard-coded. - - # No need for a db segment. - if len(path) == 1: - service = path[0] - - if service == 'common': - if method in ('server_version',): - service = 'db' - return xmlrpc_return(start_response, service, method, params) - - # A db segment must be given. - elif len(path) == 2: - service, db_name = path - params = (db_name,) + params - - return xmlrpc_return(start_response, service, method, params) - - # A db segment and a model segment must be given. - elif len(path) == 3 and path[0] == 'model': - service, db_name, model_name = path - params = (db_name,) + params[:2] + (model_name,) + params[2:] - service = 'object' - return xmlrpc_return(start_response, service, method, params) - - # The body has been read, need to raise an exception (not return None). - fault = xmlrpclib.Fault(RPC_FAULT_CODE_CLIENT_ERROR, '') - response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) - start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))]) - return [response] - def wsgi_xmlrpc(environ, start_response): - """ WSGI handler to return the versions.""" - if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith(XML_RPC_PATH): - length = int(environ['CONTENT_LENGTH']) - data = environ['wsgi.input'].read(length) + """ Two routes are available for XML-RPC - params, method = xmlrpclib.loads(data) + /xmlrpc/ route returns faultCode as strings. This is a historic + violation of the protocol kept for compatibility. - path = environ['PATH_INFO'][len(XML_RPC_PATH):] - if path.startswith('/'): path = path[1:] - if path.endswith('/'): path = path[:-1] - path = path.split('/') - - # All routes are hard-coded. - - if len(path) == 1 and path[0] == '' and method in ('version',): - return xmlrpc_return(start_response, 'common', method, ()) - - # The body has been read, need to raise an exception (not return None). - fault = xmlrpclib.Fault(RPC_FAULT_CODE_CLIENT_ERROR, '') - response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) - start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))]) - return [response] - -def wsgi_xmlrpc_legacy(environ, start_response): + /xmlrpc/2/ is a new route that returns faultCode as int and is + therefore fully compliant. + """ if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'): length = int(environ['CONTENT_LENGTH']) data = environ['wsgi.input'].read(length) - path = environ['PATH_INFO'][len('/xmlrpc/'):] # expected to be one of db, object, ... + + # Distinguish betweed the 2 faultCode modes + string_faultcode = True + if environ['PATH_INFO'].startswith('/xmlrpc/2/'): + service = environ['PATH_INFO'][len('/xmlrpc/2/'):] + string_faultcode = False + else: + service = environ['PATH_INFO'][len('/xmlrpc/'):] params, method = xmlrpclib.loads(data) - return xmlrpc_return(start_response, path, method, params, True) + return xmlrpc_return(start_response, service, method, params, string_faultcode) def wsgi_webdav(environ, start_response): pi = environ['PATH_INFO'] @@ -401,7 +342,7 @@ def application_unproxied(environ, start_response): del threading.current_thread().dbname # Try all handlers until one returns some result (i.e. not None). - wsgi_handlers = [wsgi_xmlrpc_1, wsgi_xmlrpc, wsgi_xmlrpc_legacy, wsgi_webdav] + wsgi_handlers = [wsgi_xmlrpc, wsgi_webdav] wsgi_handlers += module_handlers for handler in wsgi_handlers: result = handler(environ, start_response) diff --git a/openerp/tests/common.py b/openerp/tests/common.py index f8472e81fcf..df00e61f140 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -135,11 +135,11 @@ class RpcCase(unittest2.TestCase): self.proxy.object_60 = xmlrpclib.ServerProxy(url_60 + 'object') #self.proxy.edi_60 = xmlrpclib.ServerProxy(url_60 + 'edi') - # Use the new (6.1) API. - self.proxy.url_61 = url_61 = 'http://%s:%d/openerp/xmlrpc/1/' % (HOST, PORT) - self.proxy.common_61 = xmlrpclib.ServerProxy(url_61 + 'common') - self.proxy.db_61 = xmlrpclib.ServerProxy(url_61 + 'db') - self.proxy.model_61 = xmlrpclib.ServerProxy(url_61 + 'model/' + DB) + # Use the new (8) API. + self.proxy.url_8 = url_8 = 'http://%s:%d/xmlrpc/2/' % (HOST, PORT) + self.proxy.common_8 = xmlrpclib.ServerProxy(url_8 + 'common') + self.proxy.db_8 = xmlrpclib.ServerProxy(url_8 + 'db') + self.proxy.object_8 = xmlrpclib.ServerProxy(url_8 + 'object') @classmethod def generate_database_name(cls): diff --git a/openerp/tests/test_xmlrpc.py b/openerp/tests/test_xmlrpc.py index 8c9d6911e7b..12bc828cb29 100644 --- a/openerp/tests/test_xmlrpc.py +++ b/openerp/tests/test_xmlrpc.py @@ -47,21 +47,18 @@ class test_xmlrpc(common.RpcCase): def test_xmlrpc_ir_model_search(self): """ Try a search on the object service. """ - ids = self.proxy.object_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, - 'ir.model', 'search', []) + o = self.proxy.object_60 + ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', []) assert ids - ids = self.proxy.object_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, - 'ir.model', 'search', [], {}) + ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {}) assert ids - def test_xmlrpc_61_ir_model_search(self): + def test_xmlrpc_8_ir_model_search(self): """ Try a search on the object service. """ - - proxy = xmlrpclib.ServerProxy(self.proxy.url_61 + 'model/' + DB + - '/ir.model') - ids = proxy.execute(ADMIN_USER_ID, ADMIN_PASSWORD, 'search', []) + o = self.proxy.object_8 + ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', []) assert ids - ids = proxy.execute(ADMIN_USER_ID, ADMIN_PASSWORD, 'search', [], {}) + ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {}) assert ids # This test was written to test the creation of a new RPC endpoint, not From a32bf724f2d4495844765f22c9b80a2134dd3eb6 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 12:24:04 +0200 Subject: [PATCH 24/37] [IMP] ir_actions cleanups. Remove deprecated old style wizards. Remove unsed get_model() function. Move crons into Actions menuitem. Move todos into Actions menuitem. bzr revid: al@openerp.com-20131006102404-s46md70ahydihiih --- openerp/addons/base/ir/ir_actions.py | 120 +++++------------- openerp/addons/base/ir/ir_actions.xml | 84 ++---------- openerp/addons/base/ir/ir_cron_view.xml | 3 +- openerp/addons/base/ir/ir_model.py | 2 + openerp/addons/base/ir/ir_rule_view.xml | 10 ++ .../addons/base/security/ir.model.access.csv | 2 - 6 files changed, 56 insertions(+), 165 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index e13602d6a77..d8198f7270a 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -54,10 +54,9 @@ class actions(osv.osv): _defaults = { 'usage': lambda *a: False, } -actions() -class report_xml(osv.osv): +class ir_actions_report_xml(osv.osv): def _report_content(self, cursor, user, ids, name, arg, context=None): res = {} @@ -174,9 +173,8 @@ class report_xml(osv.osv): 'attachment': False, } -report_xml() -class act_window(osv.osv): +class ir_actions_act_window(osv.osv): _name = 'ir.actions.act_window' _table = 'ir_act_window' _inherit = 'ir.actions.actions' @@ -291,7 +289,7 @@ class act_window(osv.osv): ids_int = isinstance(ids, (int, long)) if ids_int: ids = [ids] - results = super(act_window, self).read(cr, uid, ids, fields=fields, context=context, load=load) + results = super(ir_actions_act_window, self).read(cr, uid, ids, fields=fields, context=context, load=load) if not fields or 'help' in fields: context = dict(context or {}) @@ -328,8 +326,6 @@ class act_window(osv.osv): res_id = dataobj.browse(cr, uid, data_id, context).res_id return self.read(cr, uid, res_id, [], context) -act_window() - VIEW_TYPES = [ ('tree', 'Tree'), ('form', 'Form'), @@ -337,7 +333,7 @@ VIEW_TYPES = [ ('calendar', 'Calendar'), ('gantt', 'Gantt'), ('kanban', 'Kanban')] -class act_window_view(osv.osv): +class ir_actions_act_window_view(osv.osv): _name = 'ir.actions.act_window.view' _table = 'ir_act_window_view' _rec_name = 'view_id' @@ -354,33 +350,22 @@ class act_window_view(osv.osv): 'multi': False, } def _auto_init(self, cr, context=None): - super(act_window_view, self)._auto_init(cr, context) + super(ir_actions_act_window_view, self)._auto_init(cr, context) cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'act_window_view_unique_mode_per_action\'') if not cr.fetchone(): cr.execute('CREATE UNIQUE INDEX act_window_view_unique_mode_per_action ON ir_act_window_view (act_window_id, view_mode)') -act_window_view() -class act_wizard(osv.osv): - _name = 'ir.actions.wizard' + +class ir_actions_act_window_close(osv.osv): + _name = 'ir.actions.act_window_close' _inherit = 'ir.actions.actions' - _table = 'ir_act_wizard' - _sequence = 'ir_actions_id_seq' - _order = 'name' - _columns = { - 'name': fields.char('Wizard Info', size=64, required=True, translate=True), - 'type': fields.char('Action Type', size=32, required=True), - 'wiz_name': fields.char('Wizard Name', size=64, required=True), - 'multi': fields.boolean('Action on Multiple Doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form view."), - 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups'), - 'model': fields.char('Object', size=64), - } + _table = 'ir_actions' _defaults = { - 'type': 'ir.actions.wizard', - 'multi': False, + 'type': 'ir.actions.act_window_close', } -act_wizard() -class act_url(osv.osv): + +class ir_actions_act_url(osv.osv): _name = 'ir.actions.act_url' _table = 'ir_act_url' _inherit = 'ir.actions.actions' @@ -400,55 +385,9 @@ class act_url(osv.osv): 'type': 'ir.actions.act_url', 'target': 'new' } -act_url() - -def model_get(self, cr, uid, context=None): - wkf_pool = self.pool.get('workflow') - ids = wkf_pool.search(cr, uid, []) - osvs = wkf_pool.read(cr, uid, ids, ['osv']) - - res = [] - mpool = self.pool.get('ir.model') - for osv in osvs: - model = osv.get('osv') - id = mpool.search(cr, uid, [('model','=',model)]) - name = mpool.read(cr, uid, id)[0]['name'] - res.append((model, name)) - - return res - -class ir_model_fields(osv.osv): - _inherit = 'ir.model.fields' - _rec_name = 'field_description' - _columns = { - 'complete_name': fields.char('Complete Name', size=64, select=1), - } -ir_model_fields() - -class server_object_lines(osv.osv): - _name = 'ir.server.object.lines' - _sequence = 'ir_actions_id_seq' - _columns = { - 'server_id': fields.many2one('ir.actions.server', 'Related Server Action'), - 'col1': fields.many2one('ir.model.fields', 'Field', required=True), - 'value': fields.text('Value', required=True, help="Expression containing a value specification. \n" - "When Formula type is selected, this field may be a Python expression " - " that can use the same values as for the condition field on the server action.\n" - "If Value type is selected, the value will be used directly without evaluation."), - 'type': fields.selection([ - ('value', 'Value'), - ('equation', 'Python expression') - ], 'Evaluation Type', required=True, change_default=True), - } - _defaults = { - 'type': 'value', - } -## -# Actions that are run on the server side -# -class actions_server(osv.osv): +class ir_actions_server(osv.osv): """ Server actions model. Server action work on a base model and offer various type of actions that can be executed automatically, for example using base action rules, of manually, by adding the action in the 'More' contextual @@ -1029,16 +968,26 @@ class actions_server(osv.osv): return res -class act_window_close(osv.osv): - _name = 'ir.actions.act_window_close' - _inherit = 'ir.actions.actions' - _table = 'ir_actions' - _defaults = { - 'type': 'ir.actions.act_window_close', +class ir_server_object_lines(osv.osv): + _name = 'ir.server.object.lines' + _sequence = 'ir_actions_id_seq' + _columns = { + 'server_id': fields.many2one('ir.actions.server', 'Related Server Action'), + 'col1': fields.many2one('ir.model.fields', 'Field', required=True), + 'value': fields.text('Value', required=True, help="Expression containing a value specification. \n" + "When Formula type is selected, this field may be a Python expression " + " that can use the same values as for the condition field on the server action.\n" + "If Value type is selected, the value will be used directly without evaluation."), + 'type': fields.selection([ + ('value', 'Value'), + ('equation', 'Python expression') + ], 'Evaluation Type', required=True, change_default=True), + } + _defaults = { + 'type': 'value', } -act_window_close() -# This model use to register action services. + TODO_STATES = [('open', 'To Do'), ('done', 'Done')] TODO_TYPES = [('manual', 'Launch Manually'),('once', 'Launch Manually Once'), @@ -1139,9 +1088,8 @@ Launch Manually Once: after having been launched manually, it sets automatically 'todo': len(total) - len(done) } -ir_actions_todo() -class act_client(osv.osv): +class ir_actions_act_client(osv.osv): _name = 'ir.actions.client' _inherit = 'ir.actions.actions' _table = 'ir_act_client' @@ -1182,6 +1130,8 @@ class act_client(osv.osv): 'context': '{}', } -act_client() + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/openerp/addons/base/ir/ir_actions.xml b/openerp/addons/base/ir/ir_actions.xml index db5beff5e0f..843dc5df35b 100644 --- a/openerp/addons/base/ir/ir_actions.xml +++ b/openerp/addons/base/ir/ir_actions.xml @@ -1,7 +1,9 @@ - + + + ir.actions.actions ir.actions.actions @@ -34,7 +36,6 @@ - Actions ir.actions.act_window @@ -46,7 +47,7 @@ - + ir.actions.report.xml @@ -121,7 +122,6 @@ - Reports ir.actions.act_window @@ -132,6 +132,8 @@ + + ir.actions.windows.tree ir.actions.act_window @@ -145,7 +147,6 @@ - ir.actions.windows.form ir.actions.act_window @@ -221,7 +222,6 @@ - Window Actions ir.actions.act_window @@ -243,66 +243,7 @@ - - ir.actions.wizard.tree - ir.actions.wizard - - - - - - - - - - - ir.actions.wizard - ir.actions.wizard - -

- - - - - - -
- Server Actions ir.actions.server @@ -527,7 +467,6 @@
- ir.actions.server.search ir.actions.server @@ -542,7 +481,6 @@ - Server Actions ir.actions.act_window @@ -573,7 +511,6 @@ - ir.actions.todo Config Wizard Steps @@ -602,7 +539,6 @@ - ir.actions.todo ir.actions.todo.select @@ -614,7 +550,6 @@ - Configuration Wizards ir.actions.todo @@ -622,9 +557,7 @@ form The configuration wizards are used to help you configure a new instance of OpenERP. They are launched during the installation of new modules, but you can choose to restart some wizards manually from this menu. - - - + Run Remaining Action Todo True @@ -638,6 +571,5 @@ if config.get('type') not in ('ir.actions.act_window_close',): - diff --git a/openerp/addons/base/ir/ir_cron_view.xml b/openerp/addons/base/ir/ir_cron_view.xml index edbc2d74b86..63c8994b48b 100644 --- a/openerp/addons/base/ir/ir_cron_view.xml +++ b/openerp/addons/base/ir/ir_cron_view.xml @@ -86,8 +86,7 @@ {'active_test': False} - - + diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 3b709934a27..6630251d2fb 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -219,9 +219,11 @@ class ir_model(osv.osv): class ir_model_fields(osv.osv): _name = 'ir.model.fields' _description = "Fields" + _rec_name = 'field_description' _columns = { 'name': fields.char('Name', required=True, size=64, select=1), + 'complete_name': fields.char('Complete Name', size=64, select=1), 'model': fields.char('Object Name', size=64, required=True, select=1, help="The technical name of the model this field belongs to"), 'relation': fields.char('Object Relation', size=64, diff --git a/openerp/addons/base/ir/ir_rule_view.xml b/openerp/addons/base/ir/ir_rule_view.xml index 9448af058ea..6a1e3aead43 100644 --- a/openerp/addons/base/ir/ir_rule_view.xml +++ b/openerp/addons/base/ir/ir_rule_view.xml @@ -85,5 +85,15 @@ + + + + Property multi-company + + + ['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)] + + + diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index fe5d622ca82..9783d37874f 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -85,8 +85,6 @@ "access_ir_actions_act_window_close_group_system","ir_actions_act_window_close_group_system","model_ir_actions_act_window_close","group_system",1,1,1,1 "access_ir_actions_report_xml_all","ir_actions_report_xml","model_ir_actions_report_xml",,1,0,0,0 "access_ir_actions_report_xml_group_system","ir_actions_report_xml_group_system","model_ir_actions_report_xml","group_system",1,1,1,1 -"access_ir_actions_wizard_all","ir_actions_wizard","model_ir_actions_wizard",,1,0,0,0 -"access_ir_actions_wizard_group_system","ir_actions_wizard_group_system","model_ir_actions_wizard","group_system",1,1,1,1 "access_ir_actions_todo_group_system","ir_actions_todo group system","model_ir_actions_todo","group_system",1,1,1,1 "access_workflow_all","workflow_all","model_workflow",,1,0,0,0 "access_workflow_group_system","workflow_group_system","model_workflow","group_system",1,1,1,1 From 881a76dbcf47c877feb5efa14943010309d22eaf Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 13:26:08 +0200 Subject: [PATCH 25/37] [IMP] Technical menu reorg, remove depreacted requests. Moved low levels object to database structure. Removed res.request models bu keep res.request.link, res.request.link is used to flag models worth to be linked by references fields. Moved currency and state to the approriate directory. bzr revid: al@openerp.com-20131006112608-3qucrevmkf43kq20 --- openerp/addons/base/__openerp__.py | 6 +- openerp/addons/base/base_menu.xml | 1 - .../addons/base/data/administration-hover.png | Bin 2119 -> 0 bytes openerp/addons/base/data/administration.png | Bin 1252 -> 0 bytes openerp/addons/base/data/sales-hover.png | Bin 2324 -> 0 bytes openerp/addons/base/data/sales.png | Bin 1234 -> 0 bytes openerp/addons/base/ir/ir_attachment_view.xml | 2 +- .../base/{data => res}/res.country.state.csv | 0 .../res_currency_data.xml} | 0 openerp/addons/base/res/res_partner_demo.xml | 8 -- openerp/addons/base/res/res_request.py | 76 ------------------ openerp/addons/base/res/res_request_view.xml | 5 +- .../addons/base/security/ir.model.access.csv | 4 - 13 files changed, 6 insertions(+), 96 deletions(-) delete mode 100644 openerp/addons/base/data/administration-hover.png delete mode 100644 openerp/addons/base/data/administration.png delete mode 100644 openerp/addons/base/data/sales-hover.png delete mode 100644 openerp/addons/base/data/sales.png rename openerp/addons/base/{data => res}/res.country.state.csv (100%) rename openerp/addons/base/{currency_data.xml => res/res_currency_data.xml} (100%) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index f2df88506f5..fd2d514791b 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -35,21 +35,21 @@ The kernel of OpenERP, needed for all installation. 'depends': [], 'data': [ 'base_data.xml', - 'currency_data.xml', + 'res/res_currency_data.xml', 'res/res_country_data.xml', 'security/base_security.xml', 'base_menu.xml', 'res/res_security.xml', 'res/res_config.xml', - 'data/res.country.state.csv', + 'res/res.country.state.csv', 'ir/wizard/wizard_menu_view.xml', 'ir/ir_actions.xml', - 'ir/ir_attachment_view.xml', 'ir/ir_config_parameter_view.xml', 'ir/ir_cron_view.xml', 'ir/ir_filters.xml', 'ir/ir_mail_server_view.xml', 'ir/ir_model_view.xml', + 'ir/ir_attachment_view.xml', 'ir/ir_rule_view.xml', 'ir/ir_sequence_view.xml', 'ir/ir_translation_view.xml', diff --git a/openerp/addons/base/base_menu.xml b/openerp/addons/base/base_menu.xml index 2e6a6d3a27f..19f1e8465e2 100644 --- a/openerp/addons/base/base_menu.xml +++ b/openerp/addons/base/base_menu.xml @@ -27,7 +27,6 @@ - Open Settings Menu diff --git a/openerp/addons/base/data/administration-hover.png b/openerp/addons/base/data/administration-hover.png deleted file mode 100644 index 5d10833d2e45ea8d9017861fe3c38e03a1cdb5ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2119 zcmV-N2)Or&P)n!doG!o{XjAE#d` zsZ$iGTNSEA2C7{etj5W%OAoG+YOhrhvQ87Sva+*L5wxtOwO$pqY&W(|3ARufxX#YF z)6=^a8@yf-y<`}_wy(fk8^c^3!-`VGRu;ry6U1v2#aI@_S`Efw zAjV`I$Z8(RUmM9{AIW4N%3&JHW*N$K8OvrN%witRWgpFIBF)Xs&R!DEXdlmO9nWti z&|wwOa3RrbBhhgt(R&)v<>b*ncb8crV#{DA{`}*?cJ3gfH2KA=!;J+I%S5f-Bp6D%*T6+kPn9ek$94 zE8BlC+leyVek$C5F5HVI-GD3If-K#GEZu`I-i9vTh%erzP~V9!-;FWgiZS4hGT@Uo z;KHrph%e!fGvSXl;*mAtlP%(tHsayoI^&!>Iapd*%<(xj{o;>BAKINZ2=AJ_4pg-oLLFcYd=gqk2rbXze zMd-X}=-ScgpEv2JOX;XZ>8VHQtVik5z3Qn?>aI!ZzK!dwPwTHs>$Onpx`FH2$?ULA z?6OPjvrO%&OYN^y?X^wq?d|TYOzyZ=@6D(1zF6?Zj_}#S@wiLzcZf4~`u3kZ-9AaQ{cw_S+?0)aRn?eMW! z_y7mQ&Vm_#Oiy=pRb^#naHw`qujN5gqvclbq19QHk#9!C8_}VL0RsjM7%*VKfB^&g zK+eDQ=ihjq)(f-uod^F1lAnG3qkE^{-aoIYJvYf;4ogY#1^n~6{PV{i*Mlp?_1~W^ zzj>v&er{WL=ArZQBf)tu@_O^m>3Y2I?@Z?#J0{b6y-7a!$>&GJ7cq@D|5SPZuYa#! z-%vk3xHemF*_!?1i+w#gD1Z9p%T&Zw+P0s(yX$u^U0!c!t}gQ*eUBO-g5`~!-~IY5 zU(Qh1dq4cbo?F`0H5F+dy-nEKP|Do#*Uw^!Hj+Tpzw!Qq`@KBT=_ejH6GTBkk?k)j zt0YAWHE&sNA2aG4QK)w(huSwMIA3q-{3xT%I@cp))OAKiY%@h6U{CUS-^9$&)mc{Yhe_DN#D` z+Coy$&>5H)4GhRJc_#5f#aO1$G}>sJ5RwV&VEC6bX$+E^%x;nD-ky}R#%oYWpr8nA zBH4()h{0Qv)!gmvNv$)DDQ&9ym0wX!J`WOHs$yS~ST~}2j^^iq7*&eu z>}Vy&gE~6hY6^z1sCtL%WEoz%Z|;@WBPt4#nMAa0TR@ZHbB}-4U&4#=DS=XW>foc+ z7;wSaz$HOFC0HL>iiY|E5^hHADm{QNsH-O01_F-U=BBEf?)d%L==R-1q_|xK*pt=f}HhMlaUGfXm&pd$BO??`}YyG9~d7C_#zMQbk6e@vzJNwb;&5Lampnv%81w>GBoB zv|WE>Eu$N0@yWg<*W{0%d+^Vf9)`1RZa@CR?we;ek5@nb<-rfeHGQz{i?7_<@8!w< x!LR<-i-UQ(y?>7Z0|pEjFkrxd0Ruh`{1?h5tE%|~;HLlp002ovPDHLkV1g)CBk%wK diff --git a/openerp/addons/base/data/administration.png b/openerp/addons/base/data/administration.png deleted file mode 100644 index ba4e403ff33c19d3c8c553453a692905a535a827..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1252 zcmVlarU1mzbEC zo12@Rot>YbpP-z`(%9 z#>UOf&C}D<+S=OU;o<4&>Fw?9@9*#P^Yi=r`WJoAD*ylh0d!JMQvg8b*k%9#1Jy}H zK~!ko?O08(+e8#S=h}{wyp~piif-8;Au0r@sQ-V-3f64-5<&v;9_`DA?>#KWV>{&K zDPzjcM^>UqX6DTOzGGm)f&~i}ELgB$!GaQ0*H8U&C#y2*=b!!hKOE<)O>=_n>#LX6 zSI@lL!&>FhUcP((g1l*L^UXN?y0M%8F3Fo+$H~y{T-(DdCQ&GF-|k*nj1$zf-xia+ z`*~X{Ylmv?f!*I-{+HDOx^0f=Sz*5a_@X4d@cS3Pe9%HrKZpKD{ciK2#s$Cm8qWv{ z5CFsd?&bG|Brl#e5FkQ?z=$AR(%@U_F|EGGQ$d zO0qDlI+of*`2hq9@?LdG8X*J_0ur+r-W8L$n-HT`lR2_v5Cz$EMU=a6q*WTV-hcB{ z+`+CkBTh6bOasM3enS8TA}&w594CSlgTlmrZ7~&y0U9rJJR->vlhZNI9pgkC0V=Fz|RV0db`EC!S77WGM;N1gOjb0uc^)2w+Fa01O+mFE(X0{?nhf z(-faFzDHj+B&&$==p?{slTPMK%UImV1{;FtTFfbwzi-X(}k+bBgeB}sj7NVGno40C6Y z5C|JuIw^njoG>RjBrndq&MB;eY0@j?&KOE9CfNr&5E9G#E+`Z!A1U8K2Dep!0TH7b+fC;Z{mgwYN{7_?2%Q2-SZ3 zY*pOVzx@5LqSqp}{iyh2+N@tlyp|yhWZf)p_7*HyuwcQ01q&9uAN&IZR3T!09?22_ O0000MUZEbCGWjS(jZF6c)d3bn-hlh-I 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 - + diff --git a/openerp/addons/base/data/res.country.state.csv b/openerp/addons/base/res/res.country.state.csv similarity index 100% rename from openerp/addons/base/data/res.country.state.csv rename to openerp/addons/base/res/res.country.state.csv diff --git a/openerp/addons/base/currency_data.xml b/openerp/addons/base/res/res_currency_data.xml similarity index 100% rename from openerp/addons/base/currency_data.xml rename to openerp/addons/base/res/res_currency_data.xml diff --git a/openerp/addons/base/res/res_partner_demo.xml b/openerp/addons/base/res/res_partner_demo.xml index a8f0aa4eec7..3f5d50efa27 100644 --- a/openerp/addons/base/res/res_partner_demo.xml +++ b/openerp/addons/base/res/res_partner_demo.xml @@ -410,15 +410,7 @@ vauxoo.com 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 - - - ASUSTEK-Subject - - - diff --git a/openerp/addons/base/res/res_request.py b/openerp/addons/base/res/res_request.py index e91ebacbe2a..5a01f146d97 100644 --- a/openerp/addons/base/res/res_request.py +++ b/openerp/addons/base/res/res_request.py @@ -29,64 +29,6 @@ def _links_get(self, cr, uid, context=None): res = obj.read(cr, uid, ids, ['object', 'name'], context) return [(r['object'], r['name']) for r in res] -class res_request(osv.osv): - _name = 'res.request' - - def request_send(self, cr, uid, ids, *args): - for id in ids: - cr.execute('update res_request set state=%s,date_sent=%s where id=%s', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id)) - cr.execute('select act_from,act_to,body,date_sent from res_request where id=%s', (id,)) - values = cr.dictfetchone() - if values['body'] and (len(values['body']) > 128): - values['name'] = values['body'][:125] + '...' - else: - values['name'] = values['body'] or '/' - values['req_id'] = id - self.pool.get('res.request.history').create(cr, uid, values) - return True - - def request_reply(self, cr, uid, ids, *args): - for id in ids: - cr.execute("update res_request set state='active', act_from=%s, act_to=act_from, trigger_date=NULL, body='' where id=%s", (uid,id)) - return True - - def request_close(self, cr, uid, ids, *args): - self.write(cr, uid, ids, {'state':'closed'}) - return True - - def request_get(self, cr, uid): - cr.execute('select id from res_request where act_to=%s and (trigger_date<=%s or trigger_date is null) and active=True and state != %s', (uid,time.strftime('%Y-%m-%d'), 'closed')) - ids = map(lambda x:x[0], cr.fetchall()) - cr.execute('select id from res_request where act_from=%s and (act_to<>%s) and (trigger_date<=%s or trigger_date is null) and active=True and state != %s', (uid,uid,time.strftime('%Y-%m-%d'), 'closed')) - ids2 = map(lambda x:x[0], cr.fetchall()) - return ids, ids2 - - _columns = { - 'create_date': fields.datetime('Created Date', readonly=True), - 'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128), - 'active': fields.boolean('Active'), - 'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True), - 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}, select=1), - 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1), - 'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}), - 'date_sent': fields.datetime('Date', readonly=True), - 'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1), - 'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}), - 'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}), - 'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}), - 'state': fields.selection([('draft','draft'),('waiting','waiting'),('active','active'),('closed','closed')], 'Status', required=True, readonly=True), - 'history': fields.one2many('res.request.history','req_id', 'History') - } - _defaults = { - 'act_from': lambda obj,cr,uid,context=None: uid, - 'state': 'draft', - 'active': True, - 'priority': '1', - } - _order = 'priority desc, trigger_date, create_date desc' - _table = 'res_request' -res_request() - class res_request_link(osv.osv): _name = 'res.request.link' _columns = { @@ -98,25 +40,7 @@ class res_request_link(osv.osv): 'priority': 5, } _order = 'priority' -res_request_link() -class res_request_history(osv.osv): - _name = 'res.request.history' - _columns = { - 'name': fields.char('Summary', size=128, states={'active':[('readonly',True)],'waiting':[('readonly',True)]}, required=True), - 'req_id': fields.many2one('res.request', 'Request', required=True, ondelete='cascade', select=True), - 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True), - 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)]}), - 'body': fields.text('Body', states={'waiting':[('readonly',True)]}), - 'date_sent': fields.datetime('Date sent', states={'waiting':[('readonly',True)]}, required=True) - } - _defaults = { - 'name': 'NoName', - 'act_from': lambda obj,cr,uid,context=None: uid, - 'act_to': lambda obj,cr,uid,context=None: uid, - 'date_sent': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), - } -res_request_history() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_request_view.xml b/openerp/addons/base/res/res_request_view.xml index 7ad47a53c2e..03713f79926 100644 --- a/openerp/addons/base/res/res_request_view.xml +++ b/openerp/addons/base/res/res_request_view.xml @@ -35,16 +35,15 @@ - - Request Reference Types + Referencable Models ir.actions.act_window res.request.link form - + diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 9783d37874f..1efd28b9afa 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -69,10 +69,6 @@ "access_res_partner_category_group_partner_manager","res_partner_category group_partner_manager","model_res_partner_category","group_partner_manager",1,1,1,1 "access_res_partner_title_group_user","res_partner_title group_user","model_res_partner_title","group_partner_manager",1,1,1,1 "access_res_partner_title_group_partner_manager","res_partner_title group_partner_manager","model_res_partner_title",,1,0,0,0 -"access_res_request_group_user","res_request group_user","model_res_request","base.group_user",1,1,1,1 -"access_res_request_history_group_user","res_request_history group_user","model_res_request_history","base.group_user",1,1,1,1 -"access_res_request_group_user_all","res_request group_user all","model_res_request",,1,0,0,0 -"access_res_request_history_group_user_all","res_request_history group_user all","model_res_request_history",,1,0,0,0 "access_res_request_link_group_system","res_request_link group_system","model_res_request_link","group_system",1,1,1,1 "access_res_request_link_group_user","res_request_link group_user","model_res_request_link",,1,0,0,0 "access_res_users_all","res_users all","model_res_users",,1,0,0,0 From f1faa55cb6e3f77588ce6e0a431d7a376c883738 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 13:47:04 +0200 Subject: [PATCH 26/37] rename links get, allow reference fields without size. bzr revid: al@openerp.com-20131006114704-mkbheq3l355u21jb --- openerp/addons/base/res/res_request.py | 6 +----- openerp/osv/fields.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/res/res_request.py b/openerp/addons/base/res/res_request.py index 5a01f146d97..a565f3c7844 100644 --- a/openerp/addons/base/res/res_request.py +++ b/openerp/addons/base/res/res_request.py @@ -19,11 +19,9 @@ # ############################################################################## -import time - from openerp.osv import osv, fields -def _links_get(self, cr, uid, context=None): +def referencable_models(self, cr, uid, context=None): obj = self.pool.get('res.request.link') ids = obj.search(cr, uid, [], context=context) res = obj.read(cr, uid, ids, ['object', 'name'], context) @@ -41,7 +39,5 @@ class res_request_link(osv.osv): } _order = 'priority' - - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 3f0642c9229..372d7e463aa 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -182,7 +182,7 @@ class reference(_column): _type = 'reference' _classic_read = False # post-process to handle missing target - def __init__(self, string, selection, size, **args): + def __init__(self, string, selection, size=None, **args): _column.__init__(self, string=string, size=size, selection=selection, **args) def get(self, cr, obj, ids, name, uid=None, context=None, values=None): From 9757c088729d4b0f182f87522e36007836fa788f Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 13:58:08 +0200 Subject: [PATCH 27/37] use referencable models instead of _get_links bzr revid: al@openerp.com-20131006115808-etkyq34ar1pqh2pb --- addons/base_calendar/base_calendar.py | 28 +-------------------------- addons/crm/crm.py | 7 ------- addons/crm/crm_lead.py | 5 +++-- addons/crm_claim/crm_claim.py | 3 ++- addons/crm_helpdesk/crm_helpdesk.py | 5 +++-- addons/resource/resource_view.xml | 2 +- 6 files changed, 10 insertions(+), 40 deletions(-) diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 6194324e183..397bd193757 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -114,19 +114,6 @@ def real_id2base_calendar_id(real_id, recurrent_date): return '%d-%s' % (real_id, recurrent_date) return real_id -def _links_get(self, cr, uid, context=None): - """ - Get request link. - @param cr: the current row, from the database cursor - @param uid: the current user's ID for security checks - @param context: a standard dictionary for contextual values - @return: list of dictionary which contain object and name and id - """ - obj = self.pool.get('res.request.link') - ids = obj.search(cr, uid, []) - res = obj.read(cr, uid, ids, ['object', 'name'], context=context) - return [(r['object'], r['name']) for r in res] - html_invitation = """ @@ -307,19 +294,6 @@ class calendar_attendee(osv.osv): return result - def _links_get(self, cr, uid, context=None): - """ - Get request link for ref field in calendar attendee. - @param cr: the current row, from the database cursor - @param uid: the current user's id for security checks - @param context: A standard dictionary for contextual values - @return: list of dictionary which contain object and name and id - """ - obj = self.pool.get('res.request.link') - ids = obj.search(cr, uid, []) - res = obj.read(cr, uid, ids, ['object', 'name'], context=context) - return [(r['object'], r['name']) for r in res] - def _lang_get(self, cr, uid, context=None): """ Get language for language selection field. @@ -385,7 +359,7 @@ property or property parameter."), 'event_end_date': fields.function(_compute_data, \ string='Event End Date', type="datetime", \ multi='event_end_date'), - 'ref': fields.reference('Event Ref', selection=_links_get, size=128), + 'ref': fields.reference('Event Ref', selection=openerp.addons.base.res.res_request.referencable_models, size=128), 'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"), } _defaults = { diff --git a/addons/crm/crm.py b/addons/crm/crm.py index dc7ebf3ca95..98581b91666 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -258,13 +258,6 @@ class crm_case_resource_type(osv.osv): 'section_id': fields.many2one('crm.case.section', 'Sales Team'), } -def _links_get(self, cr, uid, context=None): - """Gets links value for reference field""" - obj = self.pool.get('res.request.link') - ids = obj.search(cr, uid, []) - res = obj.read(cr, uid, ids, ['object', 'name'], context) - return [(r['object'], r['name']) for r in res] - class crm_payment_mode(osv.osv): """ Payment Mode for Fund """ _name = "crm.payment.mode" diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index fcfec50d344..bb080a95399 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -23,6 +23,7 @@ import crm from datetime import datetime from operator import itemgetter +import openerp from openerp import SUPERUSER_ID from openerp import tools from openerp.addons.base.res.res_partner import format_address @@ -258,8 +259,8 @@ class crm_lead(format_address, osv.osv): # Only used for type opportunity 'probability': fields.float('Success Rate (%)', group_operator="avg"), 'planned_revenue': fields.float('Expected Revenue', track_visibility='always'), - 'ref': fields.reference('Reference', selection=crm._links_get, size=128), - 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128), + 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models), + 'ref2': fields.reference('Reference 2', selection=openerp.addons.base.res.res_request.referencable_models), 'phone': fields.char("Phone", size=64), 'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."), 'date_action': fields.date('Next Action Date', select=True), diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py index a3b09c272f6..1b9cb0b0c50 100644 --- a/addons/crm_claim/crm_claim.py +++ b/addons/crm_claim/crm_claim.py @@ -19,6 +19,7 @@ # ############################################################################## +import openerp from openerp.addons.crm import crm from openerp.osv import fields, osv from openerp import tools @@ -83,7 +84,7 @@ class crm_claim(osv.osv): 'date_deadline': fields.date('Deadline'), 'date_closed': fields.datetime('Closed', readonly=True), 'date': fields.datetime('Claim Date', select=True), - 'ref' : fields.reference('Reference', selection=crm._links_get, size=128), + 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models), 'categ_id': fields.many2one('crm.case.categ', 'Category', \ domain="[('section_id','=',section_id),\ ('object_id.model', '=', 'crm.claim')]"), diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py index 80a86c87c7c..5f84d45f974 100644 --- a/addons/crm_helpdesk/crm_helpdesk.py +++ b/addons/crm_helpdesk/crm_helpdesk.py @@ -19,6 +19,7 @@ # ############################################################################## +import openerp from openerp.addons.crm import crm from openerp.osv import fields, osv from openerp import tools @@ -53,8 +54,8 @@ class crm_helpdesk(osv.osv): 'email_cc': fields.text('Watchers Emails', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"), 'email_from': fields.char('Email', size=128, help="Destination email for email gateway"), 'date': fields.datetime('Date'), - 'ref' : fields.reference('Reference', selection=crm._links_get, size=128), - 'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128), + 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models), + 'ref2': fields.reference('Reference 2', selection=openerp.addons.base.res.res_request.referencable_models), 'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel."), 'planned_revenue': fields.float('Planned Revenue'), 'planned_cost': fields.float('Planned Costs'), diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml index 5d573214187..8954adae80a 100644 --- a/addons/resource/resource_view.xml +++ b/addons/resource/resource_view.xml @@ -251,7 +251,7 @@ tree,form,calendar - + From 80df504ed1372cc5eb9432649897815059bfcc03 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 14:46:55 +0200 Subject: [PATCH 28/37] [REM] web_shortcut bzr revid: al@openerp.com-20131006124655-kxjp9kbzc07j9584 --- addons/web_shortcuts/LICENSE | 15 -- addons/web_shortcuts/__init__.py | 21 --- addons/web_shortcuts/__openerp__.py | 44 ------ addons/web_shortcuts/i18n/cs.po | 25 --- addons/web_shortcuts/i18n/da.po | 25 --- addons/web_shortcuts/i18n/de.po | 25 --- addons/web_shortcuts/i18n/el.po | 25 --- addons/web_shortcuts/i18n/en_GB.po | 25 --- addons/web_shortcuts/i18n/es.po | 25 --- addons/web_shortcuts/i18n/fr.po | 25 --- addons/web_shortcuts/i18n/hr.po | 25 --- addons/web_shortcuts/i18n/hu.po | 25 --- addons/web_shortcuts/i18n/it.po | 25 --- addons/web_shortcuts/i18n/lt.po | 25 --- addons/web_shortcuts/i18n/mk.po | 25 --- addons/web_shortcuts/i18n/mn.po | 25 --- addons/web_shortcuts/i18n/nl.po | 25 --- addons/web_shortcuts/i18n/pl.po | 25 --- addons/web_shortcuts/i18n/pt.po | 25 --- addons/web_shortcuts/i18n/pt_BR.po | 25 --- addons/web_shortcuts/i18n/ro.po | 25 --- addons/web_shortcuts/i18n/ru.po | 25 --- addons/web_shortcuts/i18n/sl.po | 25 --- addons/web_shortcuts/i18n/sv.po | 25 --- addons/web_shortcuts/i18n/th.po | 25 --- addons/web_shortcuts/i18n/tr.po | 25 --- addons/web_shortcuts/i18n/vi.po | 25 --- addons/web_shortcuts/i18n/web_shortcuts.pot | 24 --- addons/web_shortcuts/i18n/zh_CN.po | 25 --- addons/web_shortcuts/i18n/zh_TW.po | 25 --- .../web_shortcuts/static/description/icon.png | Bin 5369 -> 0 bytes .../static/src/css/web_shortcuts.css | 60 ------- .../static/src/js/web_shortcuts.js | 149 ------------------ .../static/src/xml/web_shortcuts.xml | 24 --- 34 files changed, 987 deletions(-) delete mode 100644 addons/web_shortcuts/LICENSE delete mode 100644 addons/web_shortcuts/__init__.py delete mode 100644 addons/web_shortcuts/__openerp__.py delete mode 100644 addons/web_shortcuts/i18n/cs.po delete mode 100644 addons/web_shortcuts/i18n/da.po delete mode 100644 addons/web_shortcuts/i18n/de.po delete mode 100644 addons/web_shortcuts/i18n/el.po delete mode 100644 addons/web_shortcuts/i18n/en_GB.po delete mode 100644 addons/web_shortcuts/i18n/es.po delete mode 100644 addons/web_shortcuts/i18n/fr.po delete mode 100644 addons/web_shortcuts/i18n/hr.po delete mode 100644 addons/web_shortcuts/i18n/hu.po delete mode 100644 addons/web_shortcuts/i18n/it.po delete mode 100644 addons/web_shortcuts/i18n/lt.po delete mode 100644 addons/web_shortcuts/i18n/mk.po delete mode 100644 addons/web_shortcuts/i18n/mn.po delete mode 100644 addons/web_shortcuts/i18n/nl.po delete mode 100644 addons/web_shortcuts/i18n/pl.po delete mode 100644 addons/web_shortcuts/i18n/pt.po delete mode 100644 addons/web_shortcuts/i18n/pt_BR.po delete mode 100644 addons/web_shortcuts/i18n/ro.po delete mode 100644 addons/web_shortcuts/i18n/ru.po delete mode 100644 addons/web_shortcuts/i18n/sl.po delete mode 100644 addons/web_shortcuts/i18n/sv.po delete mode 100644 addons/web_shortcuts/i18n/th.po delete mode 100644 addons/web_shortcuts/i18n/tr.po delete mode 100644 addons/web_shortcuts/i18n/vi.po delete mode 100644 addons/web_shortcuts/i18n/web_shortcuts.pot delete mode 100644 addons/web_shortcuts/i18n/zh_CN.po delete mode 100644 addons/web_shortcuts/i18n/zh_TW.po delete mode 100644 addons/web_shortcuts/static/description/icon.png delete mode 100644 addons/web_shortcuts/static/src/css/web_shortcuts.css delete mode 100644 addons/web_shortcuts/static/src/js/web_shortcuts.js delete mode 100644 addons/web_shortcuts/static/src/xml/web_shortcuts.xml diff --git a/addons/web_shortcuts/LICENSE b/addons/web_shortcuts/LICENSE deleted file mode 100644 index ff64be448e9..00000000000 --- a/addons/web_shortcuts/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -OpenERP, Open Source Management Solution -Copyright © 2010-2011 OpenERP SA (). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public Lice -along with this program. If not, see . diff --git a/addons/web_shortcuts/__init__.py b/addons/web_shortcuts/__init__.py deleted file mode 100644 index 99b6a1491e8..00000000000 --- a/addons/web_shortcuts/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2010 OpenERP s.a. (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/web_shortcuts/__openerp__.py b/addons/web_shortcuts/__openerp__.py deleted file mode 100644 index aa23ed2bfa6..00000000000 --- a/addons/web_shortcuts/__openerp__.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2010-2011 OpenERP s.a. (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -{ - 'name': 'Web Shortcuts', - 'version': '1.0', - 'category': 'Tools', - 'description': """ -Enable shortcuts feature in the web client. -=========================================== - -Add a Shortcut icon in the systray in order to access the user's shortcuts (if any). - -Add a Shortcut icon besides the views title in order to add/remove a shortcut. - """, - 'author': 'OpenERP SA', - 'website': 'http://openerp.com', - 'depends': ['base'], - 'data': [], - 'js' : ['static/src/js/web_shortcuts.js'], - 'css' : ['static/src/css/web_shortcuts.css'], - 'qweb' : ['static/src/xml/*.xml'], - 'installable': True, - 'auto_install': False, -} - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/web_shortcuts/i18n/cs.po b/addons/web_shortcuts/i18n/cs.po deleted file mode 100644 index fe42953dceb..00000000000 --- a/addons/web_shortcuts/i18n/cs.po +++ /dev/null @@ -1,25 +0,0 @@ -# Czech translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-02-20 13:43+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Czech \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Přidat / Odebrat zkratku..." diff --git a/addons/web_shortcuts/i18n/da.po b/addons/web_shortcuts/i18n/da.po deleted file mode 100644 index 3cbeed065b5..00000000000 --- a/addons/web_shortcuts/i18n/da.po +++ /dev/null @@ -1,25 +0,0 @@ -# Danish translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-09-15 20:22+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Danish \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-16 05:42+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Tilføj/fjern genvej ..." diff --git a/addons/web_shortcuts/i18n/de.po b/addons/web_shortcuts/i18n/de.po deleted file mode 100644 index c6e3f2ba0d8..00000000000 --- a/addons/web_shortcuts/i18n/de.po +++ /dev/null @@ -1,25 +0,0 @@ -# German translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-04 07:22+0000\n" -"Last-Translator: Ferdinand @ Camptocamp \n" -"Language-Team: German \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Hinzufügen/Entfernen Lesezeichen ..." diff --git a/addons/web_shortcuts/i18n/el.po b/addons/web_shortcuts/i18n/el.po deleted file mode 100644 index d8ee859a736..00000000000 --- a/addons/web_shortcuts/i18n/el.po +++ /dev/null @@ -1,25 +0,0 @@ -# Greek translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-09-30 20:14+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Greek \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-10-01 05:18+0000\n" -"X-Generator: Launchpad (build 16774)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "" diff --git a/addons/web_shortcuts/i18n/en_GB.po b/addons/web_shortcuts/i18n/en_GB.po deleted file mode 100644 index b80ba0e48f7..00000000000 --- a/addons/web_shortcuts/i18n/en_GB.po +++ /dev/null @@ -1,25 +0,0 @@ -# English (United Kingdom) translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-08-23 16:45+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: English (United Kingdom) \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Add / Remove Shortcut..." diff --git a/addons/web_shortcuts/i18n/es.po b/addons/web_shortcuts/i18n/es.po deleted file mode 100644 index bb120c90dd6..00000000000 --- a/addons/web_shortcuts/i18n/es.po +++ /dev/null @@ -1,25 +0,0 @@ -# Spanish translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-12 12:54+0000\n" -"Last-Translator: Pedro Manuel Baeza \n" -"Language-Team: Spanish \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Añadir / Eliminar acceso directo..." diff --git a/addons/web_shortcuts/i18n/fr.po b/addons/web_shortcuts/i18n/fr.po deleted file mode 100644 index 1a2a90becc1..00000000000 --- a/addons/web_shortcuts/i18n/fr.po +++ /dev/null @@ -1,25 +0,0 @@ -# French translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-01 08:11+0000\n" -"Last-Translator: WANTELLET Sylvain \n" -"Language-Team: French \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Ajouter / supprimer un raccourci..." diff --git a/addons/web_shortcuts/i18n/hr.po b/addons/web_shortcuts/i18n/hr.po deleted file mode 100644 index 47a0f8f35cd..00000000000 --- a/addons/web_shortcuts/i18n/hr.po +++ /dev/null @@ -1,25 +0,0 @@ -# Croatian translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-10 06:51+0000\n" -"Last-Translator: Goran Kliska \n" -"Language-Team: Croatian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Dodaj / ukloni prečac..." diff --git a/addons/web_shortcuts/i18n/hu.po b/addons/web_shortcuts/i18n/hu.po deleted file mode 100644 index c91a6c93d36..00000000000 --- a/addons/web_shortcuts/i18n/hu.po +++ /dev/null @@ -1,25 +0,0 @@ -# Hungarian translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-01-04 12:01+0000\n" -"Last-Translator: krnkris \n" -"Language-Team: Hungarian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Billentyűkombináció hozzáadása/eltávolítása" diff --git a/addons/web_shortcuts/i18n/it.po b/addons/web_shortcuts/i18n/it.po deleted file mode 100644 index e08a8ad8ca2..00000000000 --- a/addons/web_shortcuts/i18n/it.po +++ /dev/null @@ -1,25 +0,0 @@ -# Italian translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-11-29 07:33+0000\n" -"Last-Translator: Davide Corio \n" -"Language-Team: Italian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Aggiungi / Rimuovi Scorciatoia..." diff --git a/addons/web_shortcuts/i18n/lt.po b/addons/web_shortcuts/i18n/lt.po deleted file mode 100644 index 9f564849598..00000000000 --- a/addons/web_shortcuts/i18n/lt.po +++ /dev/null @@ -1,25 +0,0 @@ -# Lithuanian translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-04-24 18:29+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Lithuanian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Pridėti / pašalinti trumpinį..." diff --git a/addons/web_shortcuts/i18n/mk.po b/addons/web_shortcuts/i18n/mk.po deleted file mode 100644 index 21e7f37e589..00000000000 --- a/addons/web_shortcuts/i18n/mk.po +++ /dev/null @@ -1,25 +0,0 @@ -# Macedonian translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-03-01 14:20+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Macedonian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Додади / Отстрани кратенка" diff --git a/addons/web_shortcuts/i18n/mn.po b/addons/web_shortcuts/i18n/mn.po deleted file mode 100644 index ffded75a811..00000000000 --- a/addons/web_shortcuts/i18n/mn.po +++ /dev/null @@ -1,25 +0,0 @@ -# Mongolian translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-02-07 11:26+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Mongolian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Шуут холбоосыг Нэмэх / Устгах ..." diff --git a/addons/web_shortcuts/i18n/nl.po b/addons/web_shortcuts/i18n/nl.po deleted file mode 100644 index 0f542966caf..00000000000 --- a/addons/web_shortcuts/i18n/nl.po +++ /dev/null @@ -1,25 +0,0 @@ -# Dutch translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-11-27 19:29+0000\n" -"Last-Translator: Erwin van der Ploeg (BAS Solutions) \n" -"Language-Team: Dutch \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Toevoegen/verwijderen snelkoppeling" diff --git a/addons/web_shortcuts/i18n/pl.po b/addons/web_shortcuts/i18n/pl.po deleted file mode 100644 index 54553cf463d..00000000000 --- a/addons/web_shortcuts/i18n/pl.po +++ /dev/null @@ -1,25 +0,0 @@ -# Polish translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-17 10:08+0000\n" -"Last-Translator: Grzegorz Grzelak (OpenGLOBE.pl) \n" -"Language-Team: Polish \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Dodaj / Usuń skrót" diff --git a/addons/web_shortcuts/i18n/pt.po b/addons/web_shortcuts/i18n/pt.po deleted file mode 100644 index c7cf8d637b2..00000000000 --- a/addons/web_shortcuts/i18n/pt.po +++ /dev/null @@ -1,25 +0,0 @@ -# Portuguese translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-05 10:09+0000\n" -"Last-Translator: Andrei Talpa (multibase.pt) \n" -"Language-Team: Portuguese \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Adicionar / Remover atalho..." diff --git a/addons/web_shortcuts/i18n/pt_BR.po b/addons/web_shortcuts/i18n/pt_BR.po deleted file mode 100644 index 63e42f4c0b1..00000000000 --- a/addons/web_shortcuts/i18n/pt_BR.po +++ /dev/null @@ -1,25 +0,0 @@ -# Brazilian Portuguese translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-11-29 23:53+0000\n" -"Last-Translator: Luiz Fernando M.França (Sig Informática) \n" -"Language-Team: Brazilian Portuguese \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Adicionar / Remover atalho ..." diff --git a/addons/web_shortcuts/i18n/ro.po b/addons/web_shortcuts/i18n/ro.po deleted file mode 100644 index 350c9fe7522..00000000000 --- a/addons/web_shortcuts/i18n/ro.po +++ /dev/null @@ -1,25 +0,0 @@ -# Romanian translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-10 07:32+0000\n" -"Last-Translator: ERPSystems.ro \n" -"Language-Team: Romanian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Adauga / Sterge Shortcut..." diff --git a/addons/web_shortcuts/i18n/ru.po b/addons/web_shortcuts/i18n/ru.po deleted file mode 100644 index d7d092ab708..00000000000 --- a/addons/web_shortcuts/i18n/ru.po +++ /dev/null @@ -1,25 +0,0 @@ -# Russian translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-25 12:18+0000\n" -"Last-Translator: Chertykov Denis \n" -"Language-Team: Russian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Добавить / Удалить ярлык..." diff --git a/addons/web_shortcuts/i18n/sl.po b/addons/web_shortcuts/i18n/sl.po deleted file mode 100644 index 480bf6e1f04..00000000000 --- a/addons/web_shortcuts/i18n/sl.po +++ /dev/null @@ -1,25 +0,0 @@ -# Slovenian translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-18 22:32+0000\n" -"Last-Translator: Dušan Laznik (Mentis) \n" -"Language-Team: Slovenian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Dodaj / Odstrani bližnjico..." diff --git a/addons/web_shortcuts/i18n/sv.po b/addons/web_shortcuts/i18n/sv.po deleted file mode 100644 index 51d285d148d..00000000000 --- a/addons/web_shortcuts/i18n/sv.po +++ /dev/null @@ -1,25 +0,0 @@ -# Swedish translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-01-26 15:07+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Swedish \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Lägg till/ta bort genväg..." diff --git a/addons/web_shortcuts/i18n/th.po b/addons/web_shortcuts/i18n/th.po deleted file mode 100644 index 87ee37b52cc..00000000000 --- a/addons/web_shortcuts/i18n/th.po +++ /dev/null @@ -1,25 +0,0 @@ -# Thai translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-06-17 05:48+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Thai \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "เพิ่ม / ลบ ทางลัด ..." diff --git a/addons/web_shortcuts/i18n/tr.po b/addons/web_shortcuts/i18n/tr.po deleted file mode 100644 index 077c845c317..00000000000 --- a/addons/web_shortcuts/i18n/tr.po +++ /dev/null @@ -1,25 +0,0 @@ -# Turkish translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-02-04 14:33+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Turkish \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Kısayol Ekle/Kaldır..." diff --git a/addons/web_shortcuts/i18n/vi.po b/addons/web_shortcuts/i18n/vi.po deleted file mode 100644 index 4f6227de670..00000000000 --- a/addons/web_shortcuts/i18n/vi.po +++ /dev/null @@ -1,25 +0,0 @@ -# Vietnamese translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-06-27 16:15+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Vietnamese \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "Thêm / Xóa đường dẫn ...." diff --git a/addons/web_shortcuts/i18n/web_shortcuts.pot b/addons/web_shortcuts/i18n/web_shortcuts.pot deleted file mode 100644 index 2babdff3864..00000000000 --- a/addons/web_shortcuts/i18n/web_shortcuts.pot +++ /dev/null @@ -1,24 +0,0 @@ -# Translation of OpenERP Server. -# This file contains the translation of the following modules: -# * web_shortcuts -# -msgid "" -msgstr "" -"Project-Id-Version: OpenERP Server 7.0alpha\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-12-21 17:06+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "" - diff --git a/addons/web_shortcuts/i18n/zh_CN.po b/addons/web_shortcuts/i18n/zh_CN.po deleted file mode 100644 index 2c125e77d74..00000000000 --- a/addons/web_shortcuts/i18n/zh_CN.po +++ /dev/null @@ -1,25 +0,0 @@ -# Chinese (Simplified) translation for openobject-addons -# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2012-11-27 14:18+0000\n" -"Last-Translator: 盈通 ccdos \n" -"Language-Team: Chinese (Simplified) \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "添加/删除快捷方式..." diff --git a/addons/web_shortcuts/i18n/zh_TW.po b/addons/web_shortcuts/i18n/zh_TW.po deleted file mode 100644 index b7c58ae4c93..00000000000 --- a/addons/web_shortcuts/i18n/zh_TW.po +++ /dev/null @@ -1,25 +0,0 @@ -# Chinese (Traditional) translation for openobject-addons -# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 -# This file is distributed under the same license as the openobject-addons package. -# FIRST AUTHOR , 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: openobject-addons\n" -"Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-12-21 17:06+0000\n" -"PO-Revision-Date: 2013-01-31 03:39+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Chinese (Traditional) \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:37+0000\n" -"X-Generator: Launchpad (build 16761)\n" - -#. module: web_shortcuts -#. openerp-web -#: code:addons/web_shortcuts/static/src/xml/web_shortcuts.xml:21 -#, python-format -msgid "Add / Remove Shortcut..." -msgstr "新增/移除 捷徑..." diff --git a/addons/web_shortcuts/static/description/icon.png b/addons/web_shortcuts/static/description/icon.png deleted file mode 100644 index 44347e95f4586548085405afc3960bf9f3be042e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5369 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
_BCl2Uf| zqcAyzl(I<(@tYMNFni1`v^@F^&Yd#Y8GrLhhc>olrN*oYeC1W% zx@eA^(OTwUCLk41>p0tX()f*=cxKH;T2Yf!FGwk~YM`@4=0!a(gxGSyoy2ZDpDo`z zhq-c}>(|@VK*er@v_tyt*LgQ{Syo9WS>?tEAv9g*%4Z+s+Ovjpx}jsVMTsnbjkmA6 zg*O}r3G6~iwj~?Gas?qo5wKu%4MXp`g!6{=p-u?z03PZriTt?r zcOyTr5V)qOfbjUyl)U^Jdp&h~3H%lKb9XbJa)nF=*>qq+MHt`c{uI6R{-Kq*Bq|~} zm{r}~%nvLDPDh0SIx0MQzbh%SrxKYI<>4rMU6j4+rIgKC*V)^COaJqRUXTU;`NsbN X7N_QJWu=O_00000NkvXXu0mjfz5O5B diff --git a/addons/web_shortcuts/static/src/css/web_shortcuts.css b/addons/web_shortcuts/static/src/css/web_shortcuts.css deleted file mode 100644 index 5d4e34f53b9..00000000000 --- a/addons/web_shortcuts/static/src/css/web_shortcuts.css +++ /dev/null @@ -1,60 +0,0 @@ -/* Shortcuts*/ -.oe_systray_shortcuts .oe_star_off { - color: #eee; -} -.oe_shortcuts_toggle { - height: 20px; - margin-top: 3px; - padding: 0; - width: 24px; - cursor: pointer; - display: block; - background: url(/web/static/src/img/add-shortcut.png) no-repeat center center; - float: left; -} -.oe_shortcuts_remove{ - background: url(/web/static/src/img/remove-shortcut.png) no-repeat center center; -} -.oe_shortcuts { - position: absolute; - margin: 0; - padding: 6px 15px; - top: 37px; - left: 197px; - right: 0; - height: 17px; - line-height: 1.2; -} -.oe_shortcuts ul { - display: block; - overflow: hidden; - list-style: none; - white-space: nowrap; - padding: 0; - margin: 0; -} -.oe_shortcuts li { - cursor: pointer; - display: -moz-inline-stack; - display: inline-block; - display: inline; /*IE7 */ - color: #fff; - text-align: center; - border-left: 1px solid #909090; - padding: 0 4px; - font-size: 80%; - font-weight: normal; - vertical-align: top; -} - -.oe_shortcuts li:hover { - background-color: #666; -} -.oe_shortcuts li:first-child { - border-left: none; - padding-left: 0; -} -.oe_systray_shortcuts_items > li > a:hover { - overflow:visible; - white-space: normal; -} \ No newline at end of file diff --git a/addons/web_shortcuts/static/src/js/web_shortcuts.js b/addons/web_shortcuts/static/src/js/web_shortcuts.js deleted file mode 100644 index 045bc5b5ae6..00000000000 --- a/addons/web_shortcuts/static/src/js/web_shortcuts.js +++ /dev/null @@ -1,149 +0,0 @@ -/*############################################################################ -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011-2012 OpenERP SA (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################*/ - -openerp.web_shortcuts = function (instance) { - -var QWeb = instance.web.qweb, - _t = instance.web._t; - -instance.web_shortcuts.Shortcuts = instance.web.Widget.extend({ - template: 'Systray.Shortcuts', - - init: function() { - this._super(); - this.on('load', this, this.load); - this.on('add', this, this.add); - this.on('display', this, this.display); - this.on('remove', this, this.remove); - this.on('click', this, this.click); - this.model = new instance.web.Model('ir.ui.view_sc'); - }, - start: function() { - var self = this; - this._super(); - this.trigger('load'); - this.$el.on('click', '.oe_systray_shortcuts_items a', function() { - self.trigger('click', $(this)); - }); - }, - load: function() { - var self = this; - this.$el.find('.oe_systray_shortcuts_items').empty(); - return this.model.call('get_sc', [ - instance.session.uid, - 'ir.ui.menu', - instance.web.pyeval.eval('context', {}) - ]).done(function(shortcuts) { - _.each(shortcuts, function(sc) { - self.trigger('display', sc); - }); - }); - }, - add: function (sc) { - var self = this; - this.model.call('create', [sc]).then(function(out){ - self.trigger('load'); - }); - }, - display: function(sc) { - var self = this; - this.$el.find('.oe_systray_shortcuts_items').append(); - var $sc = $(QWeb.render('Systray.Shortcuts.Item', {'shortcut': sc})); - $sc.appendTo(self.$el.find('.oe_systray_shortcuts_items')); - }, - remove: function (menu_id) { - var menu_id = this.session.active_id; - var $shortcut = this.$el.find('.oe_systray_shortcuts_items li a[data-id=' + menu_id + ']'); - var shortcut_id = $shortcut.data('shortcut-id'); - $shortcut.remove(); - this.model.call('unlink', [shortcut_id]); - }, - click: function($link) { - var self = this, - id = $link.data('id'); - self.session.active_id = id; - // TODO: Use do_action({menu_id: id, type: 'ir.actions.menu'}) - self.rpc('/web/menu/action', {'menu_id': id}).done(function(ir_menu_data) { - if (ir_menu_data.action.length){ - instance.webclient.on_menu_action({action_id: ir_menu_data.action[0][2].id}); - } - }); - this.$el.find('.oe_systray_shortcuts').trigger('mouseout'); - }, - has: function(menu_id) { - return !!this.$el.find('a[data-id=' + menu_id + ']').length; - } -}); - -instance.web.UserMenu.include({ - do_update: function() { - var self = this; - this._super.apply(this, arguments); - this.update_promise.done(function() { - if (self.shortcuts) { - self.shortcuts.trigger('load'); - } else { - self.shortcuts = new instance.web_shortcuts.Shortcuts(self); - self.shortcuts.appendTo(instance.webclient.$el.find('.oe_systray')); - } - }); - }, -}); - -instance.web.ViewManagerAction.include({ - switch_mode: function (view_type, no_store) { - var self = this; - this._super.apply(this, arguments).done(function() { - self.shortcut_check(self.views[view_type]); - }); - }, - shortcut_check : function(view) { - var self = this; - var shortcuts_menu = instance.webclient.user_menu.shortcuts; - var grandparent = this.getParent() && this.getParent().getParent(); - // display shortcuts if on the first view for the action - var $shortcut_toggle = this.$el.find('.oe_shortcuts_toggle'); - if (!this.action.name || - !(view.view_type === this.views_src[0].view_type - && view.view_id === this.views_src[0].view_id)) { - $shortcut_toggle.hide(); - return; - } - // Anonymous users don't have user_menu - if (shortcuts_menu) { - $shortcut_toggle.toggleClass('oe_shortcuts_remove', shortcuts_menu.has(self.session.active_id)); - $shortcut_toggle.unbind("click").click(function() { - if ($shortcut_toggle.hasClass("oe_shortcuts_remove")) { - shortcuts_menu.trigger('remove', self.session.active_id); - } else { - shortcuts_menu.trigger('add', { - 'user_id': self.session.uid, - 'res_id': self.session.active_id, - 'resource': 'ir.ui.menu', - 'name': self.action.name - }); - } - $shortcut_toggle.toggleClass("oe_shortcuts_remove"); - }); - } - } -}); - -}; diff --git a/addons/web_shortcuts/static/src/xml/web_shortcuts.xml b/addons/web_shortcuts/static/src/xml/web_shortcuts.xml deleted file mode 100644 index 0b9701f9f1a..00000000000 --- a/addons/web_shortcuts/static/src/xml/web_shortcuts.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - -
- 7 -
    -
-
- -
- - - - - - - From 4c84a49afea4b7178f3c9b1ae9cc74fe225601d2 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 15:12:25 +0200 Subject: [PATCH 29/37] [REM] shortcuts, deprecated by browser bookmarks bzr revid: al@openerp.com-20131006131225-jguvkys2ngwsd6er --- addons/hr/hr.py | 19 +------------------ addons/hr/hr_view.xml | 7 ------- addons/product/__openerp__.py | 1 - addons/product/product_shortcut_data.xml | 13 ------------- addons/share/wizard/share_wizard.py | 22 ++-------------------- 5 files changed, 3 insertions(+), 59 deletions(-) delete mode 100644 addons/product/product_shortcut_data.xml diff --git a/addons/hr/hr.py b/addons/hr/hr.py index d19f1f7de8b..bf58fdd76f8 100644 --- a/addons/hr/hr.py +++ b/addons/hr/hr.py @@ -346,26 +346,9 @@ class res_users(osv.osv): _name = 'res.users' _inherit = 'res.users' - def create(self, cr, uid, data, context=None): - user_id = super(res_users, self).create(cr, uid, data, context=context) - - # add shortcut unless 'noshortcut' is True in context - if not(context and context.get('noshortcut', False)): - data_obj = self.pool.get('ir.model.data') - try: - data_id = data_obj._get_id(cr, uid, 'hr', 'ir_ui_view_sc_employee') - view_id = data_obj.browse(cr, uid, data_id, context=context).res_id - self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = { - 'user_id': user_id}, context=context) - except: - # Tolerate a missing shortcut. See product/product.py for similar code. - _logger.debug('Skipped meetings shortcut for user "%s".', data.get('name',' - - Employees - ir.ui.menu - - - - hr.employee.tree diff --git a/addons/product/__openerp__.py b/addons/product/__openerp__.py index fdadda2e4d4..da17f7d8f6a 100644 --- a/addons/product/__openerp__.py +++ b/addons/product/__openerp__.py @@ -54,7 +54,6 @@ Print product labels with barcode. 'product_data.xml', 'product_report.xml', 'product_view.xml', - 'product_shortcut_data.xml', 'pricelist_view.xml', 'partner_view.xml', 'process/product_process.xml' diff --git a/addons/product/product_shortcut_data.xml b/addons/product/product_shortcut_data.xml deleted file mode 100644 index 4f48445a197..00000000000 --- a/addons/product/product_shortcut_data.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Products - ir.ui.menu - - - - - - diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py index f6ee6379ef1..2e8d4d9373e 100644 --- a/addons/share/wizard/share_wizard.py +++ b/addons/share/wizard/share_wizard.py @@ -289,32 +289,14 @@ class share_wizard(osv.TransientModel): return created_ids, existing_ids - def _create_shortcut(self, cr, uid, values, context=None): + def _create_action(self, cr, uid, values, context=None): if context is None: context = {} new_context = context.copy() for key in context: if key.startswith('default_'): del new_context[key] - - dataobj = self.pool.get('ir.model.data') - menu_id = dataobj._get_id(cr, uid, 'base', 'menu_administration_shortcut') - shortcut_menu_id = int(dataobj.read(cr, uid, menu_id, ['res_id'], new_context)['res_id']) action_id = self.pool.get('ir.actions.act_window').create(cr, UID_ROOT, values, new_context) - menu_data = {'name': values['name'], - 'sequence': 10, - 'action': 'ir.actions.act_window,'+str(action_id), - 'parent_id': shortcut_menu_id, - 'icon': 'STOCK_JUSTIFY_FILL'} - menu_obj = self.pool.get('ir.ui.menu') - menu_id = menu_obj.create(cr, UID_ROOT, menu_data) - sc_data = {'name': values['name'], 'sequence': UID_ROOT,'res_id': menu_id } - self.pool.get('ir.ui.view_sc').create(cr, uid, sc_data, new_context) - - # update menu cache - user_groups = set(self.pool.get('res.users').read(cr, UID_ROOT, uid, ['groups_id'])['groups_id']) - key = (cr.dbname, shortcut_menu_id, tuple(user_groups)) - menu_obj._cache[key] = True return action_id def _cleanup_action_context(self, context_str, user_id): @@ -383,7 +365,7 @@ class share_wizard(osv.TransientModel): values = self._shared_action_def(cr, uid, wizard_data, context=None) user_obj = self.pool.get('res.users') for user_id in user_ids: - action_id = self._create_shortcut(cr, user_id, values) + action_id = self._create_action(cr, user_id, values) if make_home: # We do this only for new share users, as existing ones already have their initial home # action. Resetting to the default menu does not work well as the menu is rather empty From 097dc15ded1ebeef88047009dd41c62dacfdf6ed Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 15:23:10 +0200 Subject: [PATCH 30/37] [REM] shortcuts, deprecated by bookmarks bzr revid: al@openerp.com-20131006132310-rrycbi10x441i2ef --- addons/web/controllers/main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 0e519b1c899..9ac4877d3d4 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -866,11 +866,6 @@ class Session(http.Controller): return {'error': _('The old password you provided is incorrect, your password was not changed.'), 'title': _('Change Password')} return {'error': _('Error, password not changed !'), 'title': _('Change Password')} - @http.route('/web/session/sc_list', type='json', auth="user") - def sc_list(self): - return request.session.model('ir.ui.view_sc').get_sc( - request.session.uid, "ir.ui.menu", request.context) - @http.route('/web/session/get_lang_list', type='json', auth="none") def get_lang_list(self): try: From 31a8dc36e50cece53930d11791ef089dbdeb931c Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 15:24:24 +0200 Subject: [PATCH 31/37] [REM] shortcuts, deprecated by bookmarks bzr revid: al@openerp.com-20131006132424-bpd8w0zzuf42s55l --- openerp/addons/base/__openerp__.py | 1 - openerp/addons/base/ir/ir_ui_menu.py | 8 ----- openerp/addons/base/ir/ir_ui_view.py | 36 ------------------- openerp/addons/base/ir/ir_ui_view_view.xml | 22 ------------ .../base/res/res_partner_shortcut_data.xml | 13 ------- .../addons/base/security/ir.model.access.csv | 1 - 6 files changed, 81 deletions(-) delete mode 100644 openerp/addons/base/res/res_partner_shortcut_data.xml diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index fd2d514791b..c797d3cf47e 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -76,7 +76,6 @@ The kernel of OpenERP, needed for all installation. 'res/res_lang_view.xml', 'res/res_partner_report.xml', 'res/res_partner_view.xml', - 'res/res_partner_shortcut_data.xml', 'res/res_bank_view.xml', 'res/res_country_view.xml', 'res/res_currency_view.xml', diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index c23d0e08be8..f01ce54bfc2 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -32,14 +32,6 @@ from openerp import SUPERUSER_ID MENU_ITEM_SEPARATOR = "/" -def one_in(setA, setB): - """Check the presence of an element of setA in setB - """ - for x in setA: - if x in setB: - return True - return False - class ir_ui_menu(osv.osv): _name = 'ir.ui.menu' diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index 794f3fcd826..123b20db15f 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -305,41 +305,5 @@ class view(osv.osv): ids = map(itemgetter(0), cr.fetchall()) return self._check_xml(cr, uid, ids) - -class view_sc(osv.osv): - _name = 'ir.ui.view_sc' - _columns = { - 'name': fields.char('Shortcut Name', size=64), # Kept for backwards compatibility only - resource name used instead (translatable) - 'res_id': fields.integer('Resource Ref.', help="Reference of the target resource, whose model/table depends on the 'Resource Name' field."), - 'sequence': fields.integer('Sequence'), - 'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade', select=True), - 'resource': fields.char('Resource Name', size=64, required=True, select=True) - } - - def _auto_init(self, cr, context=None): - super(view_sc, self)._auto_init(cr, context) - cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_ui_view_sc_user_id_resource\'') - if not cr.fetchone(): - cr.execute('CREATE INDEX ir_ui_view_sc_user_id_resource ON ir_ui_view_sc (user_id, resource)') - - def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context=None): - ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context) - results = self.read(cr, uid, ids, ['res_id'], context=context) - name_map = dict(self.pool[model].name_get(cr, uid, [x['res_id'] for x in results], context=context)) - # Make sure to return only shortcuts pointing to exisintg menu items. - filtered_results = filter(lambda result: result['res_id'] in name_map, results) - for result in filtered_results: - result.update(name=name_map[result['res_id']]) - return filtered_results - - _order = 'sequence,name' - _defaults = { - 'resource': 'ir.ui.menu', - 'user_id': lambda obj, cr, uid, context: uid, - } - _sql_constraints = [ - ('shortcut_unique', 'unique(res_id, resource, user_id)', 'Shortcut for this menu already exists!'), - ] - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_ui_view_view.xml b/openerp/addons/base/ir/ir_ui_view_view.xml index 44594c1e616..82a7db2c723 100644 --- a/openerp/addons/base/ir/ir_ui_view_view.xml +++ b/openerp/addons/base/ir/ir_ui_view_view.xml @@ -114,27 +114,5 @@ - - - ir.ui.view_sc - -
- - - - -
-
-
- - ir.ui.view_sc - - - - - - - - diff --git a/openerp/addons/base/res/res_partner_shortcut_data.xml b/openerp/addons/base/res/res_partner_shortcut_data.xml deleted file mode 100644 index ee534a2ff6b..00000000000 --- a/openerp/addons/base/res/res_partner_shortcut_data.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Customers - ir.ui.menu - - - - - - diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 1efd28b9afa..167c18ae884 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -40,7 +40,6 @@ "access_ir_ui_view_group_user","ir_ui_view group_user","model_ir_ui_view",,1,0,0,0 "access_ir_ui_view_group_system","ir_ui_view group_system","model_ir_ui_view","group_system",1,1,1,1 "access_ir_ui_view_custom_group_user","ir_ui_view_custom_group_user","model_ir_ui_view_custom",,1,1,1,1 -"access_ir_ui_view_sc_group_user","ir_ui_view_sc group_user","model_ir_ui_view_sc",,1,1,1,1 "access_ir_values_group_all","ir_values group_all","model_ir_values",,1,1,1,1 "access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1 "access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0 From 6488849191593e2ee9f736317bf1537372f80462 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 16:40:20 +0200 Subject: [PATCH 32/37] [REM] res.config and res.users cleanups. removed deprecated configuration wizards removed deprecated busniess card report moved change password wizard to res_users.py bzr revid: al@openerp.com-20131006144020-zyp2jz5vy28m9q3f --- openerp/addons/base/__openerp__.py | 1 - openerp/addons/base/res/__init__.py | 3 - openerp/addons/base/res/config_pixmaps/1.png | Bin 19440 -> 0 bytes openerp/addons/base/res/config_pixmaps/2.png | Bin 16139 -> 0 bytes openerp/addons/base/res/config_pixmaps/3.png | Bin 13916 -> 0 bytes openerp/addons/base/res/report/__init__.py | 28 ------ .../addons/base/res/report/business_card.xml | 15 --- .../addons/base/res/report/business_card.xsl | 80 ---------------- openerp/addons/base/res/res_config.py | 44 +-------- openerp/addons/base/res/res_config.xml | 17 ---- .../addons/base/res/res_partner_report.xml | 12 ++- ...ess.xml => res_partner_report_address.xml} | 0 ...ess.xsl => res_partner_report_address.xsl} | 0 openerp/addons/base/res/res_users.py | 87 ++++++++++++++++-- openerp/addons/base/res/res_users_view.xml | 38 ++++++++ openerp/addons/base/res/wizard/__init__.py | 22 ----- .../base/res/wizard/change_password_wizard.py | 81 ---------------- .../wizard/change_password_wizard_view.xml | 44 --------- 18 files changed, 125 insertions(+), 347 deletions(-) delete mode 100755 openerp/addons/base/res/config_pixmaps/1.png delete mode 100755 openerp/addons/base/res/config_pixmaps/2.png delete mode 100755 openerp/addons/base/res/config_pixmaps/3.png delete mode 100644 openerp/addons/base/res/report/__init__.py delete mode 100644 openerp/addons/base/res/report/business_card.xml delete mode 100644 openerp/addons/base/res/report/business_card.xsl rename openerp/addons/base/res/{report/partner_address.xml => res_partner_report_address.xml} (100%) rename openerp/addons/base/res/{report/partner_address.xsl => res_partner_report_address.xsl} (100%) delete mode 100644 openerp/addons/base/res/wizard/__init__.py delete mode 100644 openerp/addons/base/res/wizard/change_password_wizard.py delete mode 100644 openerp/addons/base/res/wizard/change_password_wizard_view.xml diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index c797d3cf47e..a26def920f4 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -79,7 +79,6 @@ The kernel of OpenERP, needed for all installation. 'res/res_bank_view.xml', 'res/res_country_view.xml', 'res/res_currency_view.xml', - 'res/wizard/change_password_wizard_view.xml', 'res/res_users_view.xml', 'res/res_partner_data.xml', 'res/ir_property_view.xml', diff --git a/openerp/addons/base/res/__init__.py b/openerp/addons/base/res/__init__.py index 59403545112..50807e20116 100644 --- a/openerp/addons/base/res/__init__.py +++ b/openerp/addons/base/res/__init__.py @@ -31,8 +31,5 @@ import res_request import res_lang import ir_property -import report -import wizard - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/config_pixmaps/1.png b/openerp/addons/base/res/config_pixmaps/1.png deleted file mode 100755 index 63bd433736949dd5330d1564b328bec375eda385..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19440 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 TX)}PwaWQzh`njxgN@xNAEPOV! diff --git a/openerp/addons/base/res/config_pixmaps/2.png b/openerp/addons/base/res/config_pixmaps/2.png deleted file mode 100755 index 80d4e3602bb89af22f10004de25dd71316b81962..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16139 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 diff --git a/openerp/addons/base/res/config_pixmaps/3.png b/openerp/addons/base/res/config_pixmaps/3.png deleted file mode 100755 index 63acab34263b1398ca18b253454e0ef8587bf392..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13916 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 q5B;D0$V4-gS diff --git a/openerp/addons/base/res/report/__init__.py b/openerp/addons/base/res/report/__init__.py deleted file mode 100644 index 0a7dcc8620f..00000000000 --- a/openerp/addons/base/res/report/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -#from report import report_sxw -#report_sxw.report_sxw('report.partner.list', 'res.partner', 'addons/base/res/partner/report/partner_list.rml') - - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/addons/base/res/report/business_card.xml b/openerp/addons/base/res/report/business_card.xml deleted file mode 100644 index c4695ffa020..00000000000 --- a/openerp/addons/base/res/report/business_card.xml +++ /dev/null @@ -1,15 +0,0 @@ - - -
- - - - - - Tiny sprl - Rue du Vieux Chateau, 21 - BE-1457 - Walhain - http://tiny.be -
-
diff --git a/openerp/addons/base/res/report/business_card.xsl b/openerp/addons/base/res/report/business_card.xsl deleted file mode 100644 index f274d9437f6..00000000000 --- a/openerp/addons/base/res/report/business_card.xsl +++ /dev/null @@ -1,80 +0,0 @@ - - - -20.5 -0.5 -5.5 -8.5 -5.5cm -8.5cm -3 -8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - cm - - - - cm - - - - - - - - PACKINGLIST - - - - Logo - - - - - - - - - - - - - - - - - - diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index abfe8df7268..c59f56d9fa6 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -131,6 +131,7 @@ class res_config_configurable(osv.osv_memory): """ raise NotImplementedError( 'Configuration items need to implement execute') + def cancel(self, cr, uid, ids, context=None): """ Method called when the user click on the ``Skip`` button. @@ -184,8 +185,6 @@ class res_config_configurable(osv.osv_memory): if next: return next return self.next(cr, uid, ids, context=context) -res_config_configurable() - class res_config_installer(osv.osv_memory, res_config_module_installation_mixin): """ New-style configuration base specialized for addons selection and installation. @@ -314,7 +313,6 @@ class res_config_installer(osv.osv_memory, res_config_module_installation_mixin) context=context), context=context) - def modules_to_install(self, cr, uid, ids, context=None): """ selects all modules to install: @@ -397,45 +395,6 @@ class res_config_installer(osv.osv_memory, res_config_module_installation_mixin) return self._install_modules(cr, uid, modules, context=context) -res_config_installer() - -DEPRECATION_MESSAGE = 'You are using an addon using old-style configuration '\ - 'wizards (ir.actions.configuration.wizard). Old-style configuration '\ - 'wizards have been deprecated.\n'\ - 'The addon should be migrated to res.config objects.' -class ir_actions_configuration_wizard(osv.osv_memory): - ''' Compatibility configuration wizard - - The old configuration wizard has been replaced by res.config, but in order - not to break existing but not-yet-migrated addons, the old wizard was - reintegrated and gutted. - ''' - _name='ir.actions.configuration.wizard' - _inherit = 'res.config' - - def _next_action_note(self, cr, uid, ids, context=None): - next = self._next_action(cr, uid) - if next: - # if the next one is also an old-style extension, you never know... - if next.note: - return next.note - return _("Click 'Continue' to configure the next addon...") - return _("Your database is now fully configured.\n\n"\ - "Click 'Continue' and enjoy your OpenERP experience...") - - _columns = { - 'note': fields.text('Next Wizard', readonly=True), - } - _defaults = { - 'note': _next_action_note, - } - - def execute(self, cr, uid, ids, context=None): - _logger.warning(DEPRECATION_MESSAGE) - -ir_actions_configuration_wizard() - - class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): """ Base configuration wizard for application settings. It provides support for setting default values, assigning groups to employee users, and installing modules. @@ -694,4 +653,5 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): if (action_id): return exceptions.RedirectWarning(msg % values, action_id, _('Go to the configuration panel')) return exceptions.Warning(msg % values) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_config.xml b/openerp/addons/base/res/res_config.xml index 342aeaa6e0f..066f9435434 100644 --- a/openerp/addons/base/res/res_config.xml +++ b/openerp/addons/base/res/res_config.xml @@ -17,23 +17,6 @@ - - Compabitiliby configuration wizard - ir.actions.configuration.wizard - -
- - - -
-
-
-
-
- Inheritable view for installer objects res.config.installer diff --git a/openerp/addons/base/res/res_partner_report.xml b/openerp/addons/base/res/res_partner_report.xml index 80ab161e62c..00b8a84608e 100644 --- a/openerp/addons/base/res/res_partner_report.xml +++ b/openerp/addons/base/res/res_partner_report.xml @@ -1,9 +1,13 @@ - - + diff --git a/openerp/addons/base/res/report/partner_address.xml b/openerp/addons/base/res/res_partner_report_address.xml similarity index 100% rename from openerp/addons/base/res/report/partner_address.xml rename to openerp/addons/base/res/res_partner_report_address.xml diff --git a/openerp/addons/base/res/report/partner_address.xsl b/openerp/addons/base/res/res_partner_report_address.xsl similarity index 100% rename from openerp/addons/base/res/report/partner_address.xsl rename to openerp/addons/base/res/res_partner_report_address.xsl diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index ba709a48175..30a63d6a3e8 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -34,7 +34,11 @@ from openerp.tools.translate import _ _logger = logging.getLogger(__name__) -class groups(osv.osv): +#---------------------------------------------------------- +# Basic res.groups and res.users +#---------------------------------------------------------- + +class res_groups(osv.osv): _name = "res.groups" _description = "Access Groups" _rec_name = 'full_name' @@ -102,8 +106,6 @@ class groups(osv.osv): self.pool['ir.model.access'].call_cache_clearing_methods(cr) return res -groups() - class res_users(osv.osv): """ User class. A res.users record models an OpenERP user and is different from an employee. @@ -516,12 +518,13 @@ class res_users(osv.osv): (uid, module, ext_id)) return bool(cr.fetchone()) - -# -# Extension of res.groups and res.users with a relation for "implied" or -# "inherited" groups. Once a user belongs to a group, it automatically belongs -# to the implied groups (transitively). +#---------------------------------------------------------- +# Implied groups # +# Extension of res.groups and res.users with a relation for "implied" +# or "inherited" groups. Once a user belongs to a group, it +# automatically belongs to the implied groups (transitively). +#---------------------------------------------------------- class cset(object): """ A cset (constrained set) is a set of elements that may be constrained to @@ -551,7 +554,6 @@ def concat(ls): return res - class groups_implied(osv.osv): _inherit = 'res.groups' @@ -618,6 +620,8 @@ class users_implied(osv.osv): super(users_implied, self).write(cr, uid, [user.id], vals, context) return res +#---------------------------------------------------------- +# Vitrual checkbox and selection for res.user form view # # Extension of res.groups and res.users for the special groups view in the users # form. This extension presents groups with selection and boolean widgets: @@ -638,6 +642,7 @@ class users_implied(osv.osv): # any of ID1, ..., IDk is in 'groups_id' # - selection field 'sel_groups_ID1_..._IDk' is ID iff # ID is in 'groups_id' and ID is maximal in the set {ID1, ..., IDk} +#---------------------------------------------------------- def name_boolean_group(id): return 'in_group_' + str(id) def name_boolean_groups(ids): return 'in_groups_' + '_'.join(map(str, ids)) @@ -661,7 +666,6 @@ def partition(f, xs): return yes, nos - class groups_view(osv.osv): _inherit = 'res.groups' @@ -869,4 +873,67 @@ class users_view(osv.osv): } return res +#---------------------------------------------------------- +# change password wizard +#---------------------------------------------------------- + +class change_password_wizard(osv.TransientModel): + """ + A wizard to manage the change of users' passwords + """ + + _name = "change.password.wizard" + _description = "Change Password Wizard" + _columns = { + 'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'), + } + + def default_get(self, cr, uid, fields, context=None): + if context == None: + context = {} + user_ids = context.get('active_ids', []) + wiz_id = context.get('active_id', None) + res = [] + users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context) + for user in users: + res.append((0, 0, { + 'wizard_id': wiz_id, + 'user_id': user.id, + 'user_login': user.login, + })) + return {'user_ids': res} + + + def change_password_button(self, cr, uid, id, context=None): + wizard = self.browse(cr, uid, id, context=context)[0] + user_ids = [] + for user in wizard.user_ids: + user_ids.append(user.id) + self.pool.get('change.password.user').change_password_button(cr, uid, user_ids, context=context) + return { + 'type': 'ir.actions.act_window_close', + } + +class change_password_user(osv.TransientModel): + """ + A model to configure users in the change password wizard + """ + + _name = 'change.password.user' + _description = 'Change Password Wizard User' + _columns = { + 'wizard_id': fields.many2one('change.password.wizard', string='Wizard', required=True), + 'user_id': fields.many2one('res.users', string='User', required=True), + 'user_login': fields.char('User Login', readonly=True), + 'new_passwd': fields.char('New Password'), + } + _defaults = { + 'new_passwd': '', + } + + def change_password_button(self, cr, uid, ids, context=None): + for user in self.browse(cr, uid, ids, context=context): + self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd}) + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_users_view.xml b/openerp/addons/base/res/res_users_view.xml index 770cb45149b..f741a7925bc 100644 --- a/openerp/addons/base/res/res_users_view.xml +++ b/openerp/addons/base/res/res_users_view.xml @@ -277,5 +277,43 @@ + + + + + + Change Password + change.password.wizard + +
+ +
+
+ +
+
+ + + + Change Password Users + change.password.user + + + + + + + + + diff --git a/openerp/addons/base/res/wizard/__init__.py b/openerp/addons/base/res/wizard/__init__.py deleted file mode 100644 index f572814a2cf..00000000000 --- a/openerp/addons/base/res/wizard/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2011 OpenERP S.A (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import change_password_wizard \ No newline at end of file diff --git a/openerp/addons/base/res/wizard/change_password_wizard.py b/openerp/addons/base/res/wizard/change_password_wizard.py deleted file mode 100644 index 4d1bfe67fce..00000000000 --- a/openerp/addons/base/res/wizard/change_password_wizard.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2011 OpenERP S.A (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv - -class change_password_wizard(osv.TransientModel): - """ - A wizard to manage the change of users' passwords - """ - - _name = "change.password.wizard" - _description = "Change Password Wizard" - _columns = { - 'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'), - } - - def default_get(self, cr, uid, fields, context=None): - if context == None: - context = {} - user_ids = context.get('active_ids', []) - wiz_id = context.get('active_id', None) - res = [] - users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context) - for user in users: - res.append((0, 0, { - 'wizard_id': wiz_id, - 'user_id': user.id, - 'user_login': user.login, - })) - return {'user_ids': res} - - - def change_password_button(self, cr, uid, id, context=None): - wizard = self.browse(cr, uid, id, context=context)[0] - user_ids = [] - for user in wizard.user_ids: - user_ids.append(user.id) - self.pool.get('change.password.user').change_password_button(cr, uid, user_ids, context=context) - return { - 'type': 'ir.actions.act_window_close', - } - -class change_password_user(osv.TransientModel): - """ - A model to configure users in the change password wizard - """ - - _name = 'change.password.user' - _description = 'Change Password Wizard User' - _columns = { - 'wizard_id': fields.many2one('change.password.wizard', string='Wizard', required=True), - 'user_id': fields.many2one('res.users', string='User', required=True), - 'user_login': fields.char('User Login', readonly=True), - 'new_passwd': fields.char('New Password'), - } - _defaults = { - 'new_passwd': '', - } - - def change_password_button(self, cr, uid, ids, context=None): - for user in self.browse(cr, uid, ids, context=context): - self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd}) - diff --git a/openerp/addons/base/res/wizard/change_password_wizard_view.xml b/openerp/addons/base/res/wizard/change_password_wizard_view.xml deleted file mode 100644 index cc190c1525a..00000000000 --- a/openerp/addons/base/res/wizard/change_password_wizard_view.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - Change Password - change.password.wizard - -
- -
-
- -
-
- - - - Change Password Users - change.password.user - - - - - - - - - -
-
From 6e2e77beec69ed16f67ad7dc837d4303d77a799d Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 17:03:09 +0200 Subject: [PATCH 33/37] fix res_group rename, move files to clean up res bzr revid: al@openerp.com-20131006150309-fg8vuvaq9hmvi9oh --- openerp/addons/base/__openerp__.py | 4 +- openerp/addons/base/ir/__init__.py | 1 + openerp/addons/base/ir/ir_model.py | 28 +++++++++ .../modeloverview.sxw => ir_model_report.sxw} | Bin .../ir_report.xml => ir_model_report.xml} | 2 +- openerp/addons/base/ir/ir_model_view.xml | 21 +++++++ openerp/addons/base/ir/wizard/__init__.py | 23 -------- openerp/addons/base/ir/wizard/wizard_menu.py | 54 ------------------ .../base/ir/wizard/wizard_menu_view.xml | 23 -------- .../addons/base/ir/{workflow => }/workflow.py | 0 openerp/addons/base/ir/workflow/__init__.py | 25 -------- .../print_instance.py => workflow_report.py} | 0 .../base/ir/{workflow => }/workflow_view.xml | 0 openerp/addons/base/res/res_users.py | 8 +-- 14 files changed, 57 insertions(+), 132 deletions(-) rename openerp/addons/base/ir/{report/modeloverview.sxw => ir_model_report.sxw} (100%) rename openerp/addons/base/ir/{report/ir_report.xml => ir_model_report.xml} (84%) delete mode 100644 openerp/addons/base/ir/wizard/__init__.py delete mode 100644 openerp/addons/base/ir/wizard/wizard_menu.py delete mode 100644 openerp/addons/base/ir/wizard/wizard_menu_view.xml rename openerp/addons/base/ir/{workflow => }/workflow.py (100%) delete mode 100644 openerp/addons/base/ir/workflow/__init__.py rename openerp/addons/base/ir/{workflow/print_instance.py => workflow_report.py} (100%) rename openerp/addons/base/ir/{workflow => }/workflow_view.xml (100%) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index a26def920f4..5fe452e7490 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -57,8 +57,8 @@ The kernel of OpenERP, needed for all installation. 'ir/ir_ui_view_view.xml', 'ir/ir_values_view.xml', 'ir/osv_memory_autovacuum.xml', - 'ir/report/ir_report.xml', - 'ir/workflow/workflow_view.xml', + 'ir/ir_model_report.xml', + 'ir/workflow_view.xml', 'module/module_view.xml', 'module/module_data.xml', 'module/module_report.xml', diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index c6034e0f7ee..3a7843d2e02 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -33,6 +33,7 @@ import ir_values import ir_translation import ir_exports import workflow +import workflow_report import ir_rule import wizard import ir_config_parameter diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 6630251d2fb..396de27903e 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -1136,4 +1136,32 @@ class ir_model_data(osv.osv): _logger.info('Deleting %s@%s', res_id, model) self.pool[model].unlink(cr, uid, [res_id]) +class wizard_model_menu(osv.osv_memory): + _name = 'wizard.ir.model.menu.create' + _columns = { + 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True), + 'name': fields.char('Menu Name', size=64, required=True), + } + + def menu_create(self, cr, uid, ids, context=None): + if not context: + context = {} + model_pool = self.pool.get('ir.model') + for menu in self.browse(cr, uid, ids, context): + model = model_pool.browse(cr, uid, context.get('model_id'), context=context) + val = { + 'name': menu.name, + 'res_model': model.model, + 'view_type': 'form', + 'view_mode': 'tree,form' + } + action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val) + self.pool.get('ir.ui.menu').create(cr, uid, { + 'name': menu.name, + 'parent_id': menu.menu_id.id, + 'action': 'ir.actions.act_window,%d' % (action_id,), + 'icon': 'STOCK_INDENT' + }, context) + return {'type':'ir.actions.act_window_close'} + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/report/modeloverview.sxw b/openerp/addons/base/ir/ir_model_report.sxw similarity index 100% rename from openerp/addons/base/ir/report/modeloverview.sxw rename to openerp/addons/base/ir/ir_model_report.sxw diff --git a/openerp/addons/base/ir/report/ir_report.xml b/openerp/addons/base/ir/ir_model_report.xml similarity index 84% rename from openerp/addons/base/ir/report/ir_report.xml rename to openerp/addons/base/ir/ir_model_report.xml index 3d077f453c8..9fcf97b6c49 100644 --- a/openerp/addons/base/ir/report/ir_report.xml +++ b/openerp/addons/base/ir/ir_model_report.xml @@ -7,7 +7,7 @@ model="ir.model" name="ir.model.overview" report_type="sxw" - file="base/ir/report/modeloverview.sxw" + file="base/ir/ir_model_report.sxw" header="False" /> diff --git a/openerp/addons/base/ir/ir_model_view.xml b/openerp/addons/base/ir/ir_model_view.xml index 537c046f95d..fb68df9b5ff 100644 --- a/openerp/addons/base/ir/ir_model_view.xml +++ b/openerp/addons/base/ir/ir_model_view.xml @@ -1,6 +1,27 @@ + + + + Create Menu + wizard.ir.model.menu.create + +
+ + + + +
+
+
+
+
+ + ir.model diff --git a/openerp/addons/base/ir/wizard/__init__.py b/openerp/addons/base/ir/wizard/__init__.py deleted file mode 100644 index 23cc77e8c15..00000000000 --- a/openerp/addons/base/ir/wizard/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -import wizard_menu -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/addons/base/ir/wizard/wizard_menu.py b/openerp/addons/base/ir/wizard/wizard_menu.py deleted file mode 100644 index a374b3dad2d..00000000000 --- a/openerp/addons/base/ir/wizard/wizard_menu.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv - -class wizard_model_menu(osv.osv_memory): - _name = 'wizard.ir.model.menu.create' - _columns = { - 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True), - 'name': fields.char('Menu Name', size=64, required=True), - } - - def menu_create(self, cr, uid, ids, context=None): - if not context: - context = {} - model_pool = self.pool.get('ir.model') - for menu in self.browse(cr, uid, ids, context): - model = model_pool.browse(cr, uid, context.get('model_id'), context=context) - val = { - 'name': menu.name, - 'res_model': model.model, - 'view_type': 'form', - 'view_mode': 'tree,form' - } - action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val) - self.pool.get('ir.ui.menu').create(cr, uid, { - 'name': menu.name, - 'parent_id': menu.menu_id.id, - 'action': 'ir.actions.act_window,%d' % (action_id,), - 'icon': 'STOCK_INDENT' - }, context) - return {'type':'ir.actions.act_window_close'} - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/addons/base/ir/wizard/wizard_menu_view.xml b/openerp/addons/base/ir/wizard/wizard_menu_view.xml deleted file mode 100644 index 7fd32b256e2..00000000000 --- a/openerp/addons/base/ir/wizard/wizard_menu_view.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Create Menu - wizard.ir.model.menu.create - -
- - - - -
-
-
-
-
- -
-
diff --git a/openerp/addons/base/ir/workflow/workflow.py b/openerp/addons/base/ir/workflow.py similarity index 100% rename from openerp/addons/base/ir/workflow/workflow.py rename to openerp/addons/base/ir/workflow.py diff --git a/openerp/addons/base/ir/workflow/__init__.py b/openerp/addons/base/ir/workflow/__init__.py deleted file mode 100644 index daa5bb1d29a..00000000000 --- a/openerp/addons/base/ir/workflow/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -import workflow -import print_instance - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/addons/base/ir/workflow/print_instance.py b/openerp/addons/base/ir/workflow_report.py similarity index 100% rename from openerp/addons/base/ir/workflow/print_instance.py rename to openerp/addons/base/ir/workflow_report.py diff --git a/openerp/addons/base/ir/workflow/workflow_view.xml b/openerp/addons/base/ir/workflow_view.xml similarity index 100% rename from openerp/addons/base/ir/workflow/workflow_view.xml rename to openerp/addons/base/ir/workflow_view.xml diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 30a63d6a3e8..beb0018dc8d 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -85,24 +85,24 @@ class res_groups(osv.osv): def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): # add explicit ordering if search is sorted on full_name if order and order.startswith('full_name'): - ids = super(groups, self).search(cr, uid, args, context=context) + ids = super(res_groups, self).search(cr, uid, args, context=context) gs = self.browse(cr, uid, ids, context) gs.sort(key=lambda g: g.full_name, reverse=order.endswith('DESC')) gs = gs[offset:offset+limit] if limit else gs[offset:] return map(int, gs) - return super(groups, self).search(cr, uid, args, offset, limit, order, context, count) + return super(res_groups, self).search(cr, uid, args, offset, limit, order, context, count) def copy(self, cr, uid, id, default=None, context=None): group_name = self.read(cr, uid, [id], ['name'])[0]['name'] default.update({'name': _('%s (copy)')%group_name}) - return super(groups, self).copy(cr, uid, id, default, context) + return super(res_groups, self).copy(cr, uid, id, default, context) def write(self, cr, uid, ids, vals, context=None): if 'name' in vals: if vals['name'].startswith('-'): raise osv.except_osv(_('Error'), _('The name of the group can not start with "-"')) - res = super(groups, self).write(cr, uid, ids, vals, context=context) + res = super(res_groups, self).write(cr, uid, ids, vals, context=context) self.pool['ir.model.access'].call_cache_clearing_methods(cr) return res From 8e688b8ac6f889514185e1dee98eb83a3a5b9c04 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 17:04:25 +0200 Subject: [PATCH 34/37] missing import bzr revid: al@openerp.com-20131006150425-m7xjwji6xncxdum3 --- openerp/addons/base/ir/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index 3a7843d2e02..df6e0ac645c 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -35,7 +35,6 @@ import ir_exports import workflow import workflow_report import ir_rule -import wizard import ir_config_parameter import osv_memory_autovacuum import ir_mail_server From 08c2fe46f1efe32b9eaf908f61fd6bafa26ef187 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 17:05:25 +0200 Subject: [PATCH 35/37] fix manifest bzr revid: al@openerp.com-20131006150525-stso6goforsxsnjl --- openerp/addons/base/__openerp__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 5fe452e7490..a3d630439e7 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -42,7 +42,6 @@ The kernel of OpenERP, needed for all installation. 'res/res_security.xml', 'res/res_config.xml', 'res/res.country.state.csv', - 'ir/wizard/wizard_menu_view.xml', 'ir/ir_actions.xml', 'ir/ir_config_parameter_view.xml', 'ir/ir_cron_view.xml', From e14ec807d2c28250d4446f7d7ee6a3ee5b20403b Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 17:08:57 +0200 Subject: [PATCH 36/37] fix xml order for change password wizard bzr revid: al@openerp.com-20131006150857-6jm5jpjl1u4p0vo7 --- openerp/addons/base/res/res_users_view.xml | 72 +++++++++++----------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/openerp/addons/base/res/res_users_view.xml b/openerp/addons/base/res/res_users_view.xml index f741a7925bc..628cfc4f858 100644 --- a/openerp/addons/base/res/res_users_view.xml +++ b/openerp/addons/base/res/res_users_view.xml @@ -1,6 +1,41 @@ + + + + Change Password + change.password.wizard + +
+ +
+
+ +
+
+ + Change Password Users + change.password.user + + + + + + + + + + res.groups.search @@ -277,43 +312,6 @@ - - - - - - Change Password - change.password.wizard - -
- -
-
- -
-
- - - - Change Password Users - change.password.user - - - - - - - -
From df230e07e4829bc66ae1ce6827f689988ff38d6d Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 6 Oct 2013 17:18:27 +0200 Subject: [PATCH 37/37] move workflow bzr revid: al@openerp.com-20131006151827-oevn6uuv005qbsu8 --- openerp/addons/base/__init__.py | 1 + openerp/addons/base/__openerp__.py | 2 +- openerp/addons/base/ir/__init__.py | 2 -- openerp/addons/base/workflow/__init__.py | 7 +++++++ openerp/addons/base/{ir => workflow}/workflow.py | 0 openerp/addons/base/{ir => workflow}/workflow_report.py | 0 openerp/addons/base/{ir => workflow}/workflow_view.xml | 0 7 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 openerp/addons/base/workflow/__init__.py rename openerp/addons/base/{ir => workflow}/workflow.py (100%) rename openerp/addons/base/{ir => workflow}/workflow_report.py (100%) rename openerp/addons/base/{ir => workflow}/workflow_view.xml (100%) diff --git a/openerp/addons/base/__init__.py b/openerp/addons/base/__init__.py index d666a6abbf7..a5bc4c59484 100644 --- a/openerp/addons/base/__init__.py +++ b/openerp/addons/base/__init__.py @@ -20,6 +20,7 @@ ############################################################################## import ir +import workflow import module import res import report diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index a3d630439e7..808dd18d3e5 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -57,7 +57,7 @@ The kernel of OpenERP, needed for all installation. 'ir/ir_values_view.xml', 'ir/osv_memory_autovacuum.xml', 'ir/ir_model_report.xml', - 'ir/workflow_view.xml', + 'workflow/workflow_view.xml', 'module/module_view.xml', 'module/module_data.xml', 'module/module_report.xml', diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index df6e0ac645c..35184f7a565 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -32,8 +32,6 @@ import ir_filters import ir_values import ir_translation import ir_exports -import workflow -import workflow_report import ir_rule import ir_config_parameter import osv_memory_autovacuum diff --git a/openerp/addons/base/workflow/__init__.py b/openerp/addons/base/workflow/__init__.py new file mode 100644 index 00000000000..45a9f36fa36 --- /dev/null +++ b/openerp/addons/base/workflow/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +import workflow +import workflow_report + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/openerp/addons/base/ir/workflow.py b/openerp/addons/base/workflow/workflow.py similarity index 100% rename from openerp/addons/base/ir/workflow.py rename to openerp/addons/base/workflow/workflow.py diff --git a/openerp/addons/base/ir/workflow_report.py b/openerp/addons/base/workflow/workflow_report.py similarity index 100% rename from openerp/addons/base/ir/workflow_report.py rename to openerp/addons/base/workflow/workflow_report.py diff --git a/openerp/addons/base/ir/workflow_view.xml b/openerp/addons/base/workflow/workflow_view.xml similarity index 100% rename from openerp/addons/base/ir/workflow_view.xml rename to openerp/addons/base/workflow/workflow_view.xml
  • - - - -