summaryrefslogtreecommitdiff
path: root/openerp
diff options
context:
space:
mode:
authorChristophe Simonis <chs@openerp.com>2013-06-13 19:39:00 +0200
committerChristophe Simonis <chs@openerp.com>2013-06-13 19:39:00 +0200
commita61e7cb0c80ae773cab9753bd8a4e7e888bbf415 (patch)
tree019a235869a5e087055700895d4584c80e2f9afb /openerp
parent5ed0ac2614b9430e61dae472d657a21c037d6ee9 (diff)
parent180e6e41d81e28df43b41e3cb6131225d4169a28 (diff)
[MERGE] forward port of branch saas-1 up to revid 4887 chs@openerp.com-20130612153934-qyp6pb3bc4za4taf
bzr revid: chs@openerp.com-20130613172414-dln3g4j0ykcwaa02 bzr revid: chs@openerp.com-20130613173900-xl7rh321nnw2b04b
Diffstat (limited to 'openerp')
-rw-r--r--openerp/__init__.py10
-rw-r--r--openerp/addons/base/base_data.xml6
-rw-r--r--openerp/addons/base/currency_data.xml1
-rw-r--r--openerp/addons/base/res/res_bank_view.xml20
-rw-r--r--openerp/addons/base/res/res_company.py4
-rw-r--r--openerp/addons/base/res/res_partner.py5
-rw-r--r--openerp/addons/base/res/res_partner_view.xml9
-rw-r--r--openerp/addons/base/res/res_users.py2
-rw-r--r--openerp/addons/base/test/test_osv_expression.yml5
-rw-r--r--openerp/cli/server.py22
-rw-r--r--openerp/report/render/rml2pdf/trml2pdf.py15
-rw-r--r--openerp/service/__init__.py7
-rw-r--r--openerp/service/workers.py69
-rw-r--r--openerp/service/wsgi_server.py5
-rw-r--r--openerp/tools/misc.py22
15 files changed, 123 insertions, 79 deletions
diff --git a/openerp/__init__.py b/openerp/__init__.py
index 285c6af85d9..22c8c98256a 100644
--- a/openerp/__init__.py
+++ b/openerp/__init__.py
@@ -23,6 +23,14 @@
"""
+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
# sufficiently deferred so that setting the TZ environment variable
@@ -61,8 +69,6 @@ wsgi.register_wsgi_handler = wsgi.wsgi_server.register_wsgi_handler
# its own copy of the data structure and we don't need to care about
# locks between threads.
multi_process = False
-# Is the server running with gevent.
-evented = False
def registry(database_name):
"""
diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml
index 2922dd82dc4..6a47325db39 100644
--- a/openerp/addons/base/base_data.xml
+++ b/openerp/addons/base/base_data.xml
@@ -49,8 +49,6 @@
<field name="symbol">€</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
- <!-- Company ID will be set later -->
- <field name="company_id" eval="None"/>
</record>
<record id="rateEUR" model="res.currency.rate">
<field name="rate">1.0</field>
@@ -86,10 +84,6 @@ Administrator</field>
<field name="company_id" ref="main_company"/>
</record>
- <record id="EUR" model="res.currency">
- <field name="company_id" ref="main_company"/>
- </record>
-
<record id="ir_mail_server_localhost0" model="ir.mail_server">
<field name="name">localhost</field>
<field name="smtp_host">localhost</field>
diff --git a/openerp/addons/base/currency_data.xml b/openerp/addons/base/currency_data.xml
index 96ff81cc0d1..e38f777d584 100644
--- a/openerp/addons/base/currency_data.xml
+++ b/openerp/addons/base/currency_data.xml
@@ -466,7 +466,6 @@
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field name="symbol">¢</field>
- <field name="company_id" ref="main_company"/>
</record>
<record id="rateCRC" model="res.currency.rate">
<field name="rate">691.3153</field>
diff --git a/openerp/addons/base/res/res_bank_view.xml b/openerp/addons/base/res/res_bank_view.xml
index 1c289d07141..7c1e07e37fb 100644
--- a/openerp/addons/base/res/res_bank_view.xml
+++ b/openerp/addons/base/res/res_bank_view.xml
@@ -53,7 +53,13 @@
<field name="res_model">res.bank</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
- <field name="help">Manage bank records you want to be used in the system.</field>
+ <field name="help">
+ <p class="oe_view_nocontent_create">
+ Click to create a new bank.
+ </p><p>
+ Manage bank records you want to be used in the system.
+ </p>
+ </field>
</record>
<menuitem action="action_res_bank_form" id="menu_action_res_bank_form" parent="base.menu_config_address_book" sequence="11" groups="base.group_no_one"/>
@@ -152,7 +158,17 @@
<field name="res_model">res.partner.bank</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
- <field name="help">Configure your company's bank accounts and select those that must appear on the report footer. You can reorder bank accounts from the list view. If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.</field>
+ <field name="help" type="html">
+ <p class="oe_view_nocontent_create">
+ Click to create a bank account.
+ </p><p>
+ Configure your company's bank accounts and select those that must appear on the report footer.
+ You can reorder bank accounts from the list view.
+ </p>
+ <p>
+ If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.
+ </p>
+ </field>
</record>
<menuitem action="action_res_partner_bank_account_form"
id="menu_action_res_partner_bank_form"
diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py
index 02dfefe1e38..03fcb133d9f 100644
--- a/openerp/addons/base/res/res_company.py
+++ b/openerp/addons/base/res/res_company.py
@@ -280,7 +280,7 @@ class res_company(osv.osv):
<frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
<stylesheet>
<!-- Set here the default font to use for all <para> tags -->
- <parastyle name='Normal' fontName="DejaVu Sans"/>
+ <paraStyle name='Normal' fontName="DejaVu Sans"/>
</stylesheet>
<pageGraphics>
<fill color="black"/>
@@ -318,7 +318,7 @@ class res_company(osv.osv):
<frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
<stylesheet>
<!-- Set here the default font to use for all <para> tags -->
- <parastyle name='Normal' fontName="DejaVu Sans"/>
+ <paraStyle name='Normal' fontName="DejaVu Sans"/>
<paraStyle name="main_footer" fontSize="8.0" alignment="CENTER"/>
<paraStyle name="main_header" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
</stylesheet>
diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py
index 89b9448290e..566ee6066dd 100644
--- a/openerp/addons/base/res/res_partner.py
+++ b/openerp/addons/base/res/res_partner.py
@@ -608,9 +608,8 @@ class res_partner(osv.osv, format_address):
query_args['limit'] = limit
cr.execute('''SELECT partner.id FROM res_partner partner
LEFT JOIN res_partner company ON partner.parent_id = company.id
- WHERE partner.email ''' + operator +''' %(name)s
- OR partner.name || ' (' || COALESCE(company.name,'') || ')'
- ''' + operator + ' %(name)s ' + limit_str, query_args)
+ WHERE partner.email ''' + operator +''' %(name)s OR
+ partner.display_name ''' + operator + ' %(name)s ' + limit_str, query_args)
ids = map(lambda x: x[0], cr.fetchall())
ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
if ids:
diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml
index ccf74206967..2e7b6f0c14d 100644
--- a/openerp/addons/base/res/res_partner_view.xml
+++ b/openerp/addons/base/res/res_partner_view.xml
@@ -580,7 +580,14 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.category</field>
<field name="view_type">form</field>
- <field name="help">Manage the partner tags to better classify them for tracking and analysis purposes. A partner may have several tags and tags have a hierarchical structure: a partner with a tag has also the parent tags.</field>
+ <field name="help" type="html">
+ <p class="oe_view_nocontent_create">
+ Click to create a new partner tags.
+ </p><p>
+ Manage the partner tags to better classify them for tracking and analysis purposes.
+ A partner may have several tags and tags have a hierarchical structure: a partner with a tag has also the parent tags.
+ </p>
+ </field>
</record>
<menuitem action="action_partner_category_form" id="menu_partner_category_form" name="Partner Tags" sequence="4" parent="menu_config_address_book" groups="base.group_no_one"/>
diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py
index 72d9269487b..93d6d307484 100644
--- a/openerp/addons/base/res/res_users.py
+++ b/openerp/addons/base/res/res_users.py
@@ -845,6 +845,7 @@ class users_view(osv.osv):
'string': app and app.name or _('Other'),
'selection': [(False, '')] + [(g.id, g.name) for g in gs],
'help': '\n'.join(tips),
+ 'exportable': False,
}
else:
# boolean group fields
@@ -853,6 +854,7 @@ class users_view(osv.osv):
'type': 'boolean',
'string': g.name,
'help': g.comment,
+ 'exportable': False,
}
return res
diff --git a/openerp/addons/base/test/test_osv_expression.yml b/openerp/addons/base/test/test_osv_expression.yml
index 1516f090e94..111ce40f2ce 100644
--- a/openerp/addons/base/test/test_osv_expression.yml
+++ b/openerp/addons/base/test/test_osv_expression.yml
@@ -375,6 +375,11 @@
currency_ids3 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [])])
assert currency_ids1 == currency_ids2 == currency_ids3, 'All 3 results should have be the same: all currencies'
default_company = self.browse(cr, uid, 1)
+
+ # Due to currency data definition change (in relation with bug 1111298), this test now needs
+ # a manual setup where all currencies are assigned to the default company.
+ self.pool['res.currency'].write(cr, uid, currency_ids1, {'company_id': default_company.id})
+
# one2many towards same model
res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child
res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child
diff --git a/openerp/cli/server.py b/openerp/cli/server.py
index 2ee9e53b3ca..fc1bf61b617 100644
--- a/openerp/cli/server.py
+++ b/openerp/cli/server.py
@@ -221,6 +221,18 @@ def quit_on_signals():
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)
@@ -257,9 +269,15 @@ def main(args):
setup_pid_file()
# Some module register themselves when they are loaded so we need the
# services to be running before loading any registry.
- if config['workers']:
- openerp.service.start_services_workers()
+ 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()
rc = 0
diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py
index 243cc02a0b3..2052b128ad9 100644
--- a/openerp/report/render/rml2pdf/trml2pdf.py
+++ b/openerp/report/render/rml2pdf/trml2pdf.py
@@ -160,7 +160,7 @@ class _rml_styles(object,):
for style in node.findall('paraStyle'):
sname = style.get('name')
self.styles[sname] = self._para_style_update(style)
- if sname in self.default_style:
+ if self.default_style.has_key(sname):
for key, value in self.styles[sname].items():
setattr(self.default_style[sname], key, value)
else:
@@ -277,11 +277,24 @@ class _rml_doc(object):
fname = font.get('fontFile').encode('ascii')
if name not in pdfmetrics._fonts:
pdfmetrics.registerFont(TTFont(name, fname))
+ #by default, we map the fontName to each style (bold, italic, bold and italic), so that
+ #if there isn't any font defined for one of these style (via a font family), the system
+ #will fallback on the normal font.
addMapping(name, 0, 0, name) #normal
addMapping(name, 0, 1, name) #italic
addMapping(name, 1, 0, name) #bold
addMapping(name, 1, 1, name) #italic and bold
+ #if registerFontFamily is defined, we register the mapping of the fontName to use for each style.
+ for font_family in node.findall('registerFontFamily'):
+ family_name = font_family.get('normal').encode('ascii')
+ if font_family.get('italic'):
+ addMapping(family_name, 0, 1, font_family.get('italic').encode('ascii'))
+ if font_family.get('bold'):
+ addMapping(family_name, 1, 0, font_family.get('bold').encode('ascii'))
+ if font_family.get('boldItalic'):
+ addMapping(family_name, 1, 1, font_family.get('boldItalic').encode('ascii'))
+
def setTTFontMapping(self,face, fontname, filename, mode='all'):
from reportlab.lib.fonts import addMapping
from reportlab.pdfbase import pdfmetrics
diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py
index d66904615ba..2c6c80eb80c 100644
--- a/openerp/service/__init__.py
+++ b/openerp/service/__init__.py
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-# Copyright (C) 2010-2012 OpenERP SA (<http://www.openerp.com>)
+# Copyright (C) 2010-2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -37,6 +37,7 @@ 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
@@ -128,9 +129,7 @@ def _reexec():
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)
- strip_args = ['-d', '-u']
- a = sys.argv[:]
- args = [x for i, x in enumerate(a) if x not in strip_args and a[max(i - 1, 0)] not in strip_args]
+ args = stripped_sys_argv()
if not args or args[0] != exe:
args.insert(0, exe)
os.execv(sys.executable, args)
diff --git a/openerp/service/workers.py b/openerp/service/workers.py
index 9a6485b8fd3..1075342919d 100644
--- a/openerp/service/workers.py
+++ b/openerp/service/workers.py
@@ -14,6 +14,8 @@ import signal
import socket
import sys
import time
+import subprocess
+import os.path
import werkzeug.serving
try:
@@ -23,6 +25,7 @@ except ImportError:
import openerp
import openerp.tools.config as config
+from openerp.tools.misc import stripped_sys_argv
_logger = logging.getLogger(__name__)
@@ -35,7 +38,6 @@ class Multicorn(object):
def __init__(self, app):
# config
self.address = (config['xmlrpc_interface'] or '0.0.0.0', config['xmlrpc_port'])
- self.long_polling_address = (config['xmlrpc_interface'] or '0.0.0.0', config['longpolling_port'])
self.population = config['workers']
self.timeout = config['limit_time_real']
self.limit_request = config['limit_request']
@@ -46,10 +48,10 @@ class Multicorn(object):
self.socket = None
self.workers_http = {}
self.workers_cron = {}
- self.workers_longpolling = {}
self.workers = {}
self.generation = 0
self.queue = []
+ self.long_polling_pid = None
def pipe_new(self):
pipe = os.pipe()
@@ -89,6 +91,14 @@ class Multicorn(object):
worker.run()
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
+ popen = subprocess.Popen(nargs)
+ self.long_polling_pid = popen.pid
+
def worker_pop(self, pid):
if pid in self.workers:
_logger.debug("Worker (%s) unregistered",pid)
@@ -143,8 +153,8 @@ class Multicorn(object):
self.worker_spawn(WorkerHTTP, self.workers_http)
while len(self.workers_cron) < config['max_cron_threads']:
self.worker_spawn(WorkerCron, self.workers_cron)
- while len(self.workers_longpolling) < 1:
- self.worker_spawn(WorkerLongPolling, self.workers_longpolling)
+ if not self.long_polling_pid:
+ self.long_polling_spawn()
def sleep(self):
try:
@@ -183,14 +193,11 @@ class Multicorn(object):
self.socket.setblocking(0)
self.socket.bind(self.address)
self.socket.listen(8*self.population)
- # long polling socket
- self.long_polling_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.long_polling_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self.long_polling_socket.setblocking(0)
- self.long_polling_socket.bind(self.long_polling_address)
- self.long_polling_socket.listen(8)
def stop(self, graceful=True):
+ if self.long_polling_pid is not None:
+ self.worker_kill(self.long_polling_pid, signal.SIGTERM)
+ self.long_polling_pid = None
if graceful:
_logger.info("Stopping gracefully")
limit = time.time() + self.timeout
@@ -353,49 +360,8 @@ class WorkerHTTP(Worker):
def start(self):
Worker.start(self)
- self.multi.long_polling_socket.close()
self.server = WorkerBaseWSGIServer(self.multi.app)
-class WorkerLongPolling(Worker):
- """ Long polling workers """
- def __init__(self, multi):
- super(WorkerLongPolling, self).__init__(multi)
- # Disable the watchdog feature for this kind of worker.
- self.watchdog_timeout = None
-
- def watch_parent(self):
- import gevent
- while True:
- if self.ppid != os.getppid():
- _logger.info("WorkerLongPolling (%s) Parent changed", self.pid)
- os.kill(os.getpid(), signal.SIGTERM)
- return
- gevent.sleep(self.multi.beat)
-
- def start(self):
- openerp.evented = True
- _logger.info('Using gevent mode')
- import gevent.monkey
- gevent.monkey.patch_all()
- import gevent_psycopg2
- gevent_psycopg2.monkey_patch()
- from openerp.modules.registry import RegistryManager
- from gevent.coros import RLock
- RegistryManager.registries_lock = RLock()
-
- Worker.start(self)
- self.multi.socket.close()
-
- import gevent
- watcher = gevent.spawn(self.watch_parent)
-
- log = _logger.getChild(self.__class__.__name__)
- log.write = lambda msg: log.info(msg.strip())
-
- from gevent.wsgi import WSGIServer
- self.server = WSGIServer(self.multi.long_polling_socket, self.multi.app, log=log)
- self.server.serve_forever()
-
class WorkerBaseWSGIServer(werkzeug.serving.BaseWSGIServer):
""" werkzeug WSGI Server patched to allow using an external listen socket
"""
@@ -469,7 +435,6 @@ class WorkerCron(Worker):
def start(self):
Worker.start(self)
self.multi.socket.close()
- self.multi.long_polling_socket.close()
openerp.service.start_internal()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py
index df201825d31..acbfc67dd0b 100644
--- a/openerp/service/wsgi_server.py
+++ b/openerp/service/wsgi_server.py
@@ -449,7 +449,10 @@ def start_service():
interface = config['xmlrpc_interface'] or '0.0.0.0'
port = config['xmlrpc_port']
_logger.info('HTTP service (werkzeug) running on %s:%s', interface, port)
- threading.Thread(target=serve, args=(interface, port, True)).start()
+ 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.
diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py
index 1b476fb9b2a..7a54d6b9b6e 100644
--- a/openerp/tools/misc.py
+++ b/openerp/tools/misc.py
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
+# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -37,7 +37,7 @@ import time
import zipfile
from collections import defaultdict
from datetime import datetime
-from itertools import islice, izip
+from itertools import islice, izip, groupby
from lxml import etree
from which import which
from threading import local
@@ -1059,4 +1059,22 @@ class CountingStream(object):
raise StopIteration()
return val
+def stripped_sys_argv(*strip_args):
+ """Return sys.argv with some arguments stripped, suitable for reexecution or subprocesses"""
+ strip_args = sorted(set(strip_args) | set(['-s', '--save', '-d', '--database', '-u', '--update', '-i', '--init']))
+ assert all(config.parser.has_option(s) for s in strip_args)
+ takes_value = dict((s, config.parser.get_option(s).takes_value()) for s in strip_args)
+
+ longs, shorts = list(tuple(y) for _, y in groupby(strip_args, lambda x: x.startswith('--')))
+ longs_eq = tuple(l + '=' for l in longs if takes_value[l])
+
+ args = sys.argv[:]
+
+ def strip(args, i):
+ return args[i].startswith(shorts) \
+ or args[i].startswith(longs_eq) or (args[i] in longs) \
+ or (i >= 1 and (args[i - 1] in strip_args) and takes_value[args[i - 1]])
+
+ return [x for i, x in enumerate(args) if not strip(args, i)]
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: