[Merge] Merge with main server.
bzr revid: mdi@tinyerp.com-20121128042307-b2ukazq07mdzgp02
This commit is contained in:
commit
6b13002e04
266
openerp-server
266
openerp-server
|
@ -1,271 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
OpenERP - Server
|
|
||||||
OpenERP is an ERP+CRM program for small and medium businesses.
|
|
||||||
|
|
||||||
The whole source code is distributed under the terms of the
|
|
||||||
GNU Public Licence.
|
|
||||||
|
|
||||||
(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import signal
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
import traceback
|
|
||||||
import time
|
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
__author__ = openerp.release.author
|
|
||||||
__version__ = openerp.release.version
|
|
||||||
|
|
||||||
# Also use the `openerp` logger for the main script.
|
|
||||||
_logger = logging.getLogger('openerp')
|
|
||||||
|
|
||||||
def check_root_user():
|
|
||||||
""" Exit if the process's user is 'root' (on POSIX system)."""
|
|
||||||
if os.name == 'posix':
|
|
||||||
import pwd
|
|
||||||
if pwd.getpwuid(os.getuid())[0] == 'root' :
|
|
||||||
sys.stderr.write("Running as user 'root' is a security risk, aborting.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def check_postgres_user():
|
|
||||||
""" Exit if the configured database user is 'postgres'.
|
|
||||||
|
|
||||||
This function assumes the configuration has been initialized.
|
|
||||||
"""
|
|
||||||
config = openerp.tools.config
|
|
||||||
if config['db_user'] == 'postgres':
|
|
||||||
sys.stderr.write("Using the database user 'postgres' is a security risk, aborting.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def report_configuration():
|
|
||||||
""" Log the server version and some configuration values.
|
|
||||||
|
|
||||||
This function assumes the configuration has been initialized.
|
|
||||||
"""
|
|
||||||
config = openerp.tools.config
|
|
||||||
_logger.info("OpenERP version %s", __version__)
|
|
||||||
for name, value in [('addons paths', config['addons_path']),
|
|
||||||
('database hostname', config['db_host'] or 'localhost'),
|
|
||||||
('database port', config['db_port'] or '5432'),
|
|
||||||
('database user', config['db_user'])]:
|
|
||||||
_logger.info("%s: %s", name, value)
|
|
||||||
|
|
||||||
def setup_pid_file():
|
|
||||||
""" Create a file with the process id written in it.
|
|
||||||
|
|
||||||
This function assumes the configuration has been initialized.
|
|
||||||
"""
|
|
||||||
config = openerp.tools.config
|
|
||||||
if config['pidfile']:
|
|
||||||
fd = open(config['pidfile'], 'w')
|
|
||||||
pidtext = "%d" % (os.getpid())
|
|
||||||
fd.write(pidtext)
|
|
||||||
fd.close()
|
|
||||||
|
|
||||||
def preload_registry(dbname):
|
|
||||||
""" Preload a registry, and start the cron."""
|
|
||||||
try:
|
|
||||||
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=openerp.tools.config['init'] or openerp.tools.config['update'], pooljobs=False)
|
|
||||||
|
|
||||||
# jobs will start to be processed later, when openerp.cron.start_master_thread() is called by openerp.service.start_services()
|
|
||||||
registry.schedule_cron_jobs()
|
|
||||||
except Exception:
|
|
||||||
_logger.exception('Failed to initialize database `%s`.', dbname)
|
|
||||||
|
|
||||||
def run_test_file(dbname, test_file):
|
|
||||||
""" Preload a registry, possibly run a test file, and start the cron."""
|
|
||||||
try:
|
|
||||||
config = openerp.tools.config
|
|
||||||
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
|
|
||||||
cr = db.cursor()
|
|
||||||
_logger.info('loading test file %s', test_file)
|
|
||||||
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
|
|
||||||
cr.rollback()
|
|
||||||
cr.close()
|
|
||||||
except Exception:
|
|
||||||
_logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
|
|
||||||
|
|
||||||
def export_translation():
|
|
||||||
config = openerp.tools.config
|
|
||||||
dbname = config['db_name']
|
|
||||||
|
|
||||||
if config["language"]:
|
|
||||||
msg = "language %s" % (config["language"],)
|
|
||||||
else:
|
|
||||||
msg = "new language"
|
|
||||||
_logger.info('writing translation file for %s to %s', msg,
|
|
||||||
config["translate_out"])
|
|
||||||
|
|
||||||
fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
|
|
||||||
buf = file(config["translate_out"], "w")
|
|
||||||
cr = openerp.pooler.get_db(dbname).cursor()
|
|
||||||
openerp.tools.trans_export(config["language"],
|
|
||||||
config["translate_modules"] or ["all"], buf, fileformat, cr)
|
|
||||||
cr.close()
|
|
||||||
buf.close()
|
|
||||||
|
|
||||||
_logger.info('translation file written successfully')
|
|
||||||
|
|
||||||
def import_translation():
|
|
||||||
config = openerp.tools.config
|
|
||||||
context = {'overwrite': config["overwrite_existing_translations"]}
|
|
||||||
dbname = config['db_name']
|
|
||||||
|
|
||||||
cr = openerp.pooler.get_db(dbname).cursor()
|
|
||||||
openerp.tools.trans_load( cr, config["translate_in"], config["language"],
|
|
||||||
context=context)
|
|
||||||
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():
|
|
||||||
""" Register the signal handler defined above. """
|
|
||||||
SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
|
|
||||||
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
|
|
||||||
if config['pidfile']:
|
|
||||||
os.unlink(config['pidfile'])
|
|
||||||
|
|
||||||
openerp.service.stop_services()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def configure_babel_localedata_path():
|
|
||||||
# Workaround: py2exe and babel.
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
import babel
|
|
||||||
babel.localedata._dirname = os.path.join(os.path.dirname(sys.executable), 'localedata')
|
|
||||||
|
|
||||||
def main():
|
|
||||||
os.environ["TZ"] = "UTC"
|
|
||||||
|
|
||||||
check_root_user()
|
|
||||||
openerp.tools.config.parse_config(sys.argv[1:])
|
|
||||||
|
|
||||||
check_postgres_user()
|
|
||||||
openerp.netsvc.init_logger()
|
|
||||||
report_configuration()
|
|
||||||
|
|
||||||
config = openerp.tools.config
|
|
||||||
|
|
||||||
configure_babel_localedata_path()
|
|
||||||
|
|
||||||
setup_signal_handlers()
|
|
||||||
|
|
||||||
if config["test_file"]:
|
|
||||||
run_test_file(config['db_name'], config['test_file'])
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if config["translate_out"]:
|
|
||||||
export_translation()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if config["translate_in"]:
|
|
||||||
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 config['workers']:
|
|
||||||
openerp.service.start_services_workers()
|
|
||||||
else:
|
|
||||||
openerp.service.start_services()
|
|
||||||
|
|
||||||
if config['db_name']:
|
|
||||||
for dbname in config['db_name'].split(','):
|
|
||||||
preload_registry(dbname)
|
|
||||||
|
|
||||||
if config["stop_after_init"]:
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
_logger.info('OpenERP server is running, waiting for connections...')
|
|
||||||
quit_on_signals()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
openerp.cli.main()
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
SUPERUSER_ID = 1
|
SUPERUSER_ID = 1
|
||||||
|
|
||||||
import addons
|
import addons
|
||||||
|
import cli
|
||||||
import conf
|
import conf
|
||||||
import loglevels
|
import loglevels
|
||||||
import modules
|
import modules
|
||||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
||||||
"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
|
"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
|
||||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||||
"POT-Creation-Date: 2012-11-24 02:51+0000\n"
|
"POT-Creation-Date: 2012-11-24 02:51+0000\n"
|
||||||
"PO-Revision-Date: 2012-08-20 15:28+0000\n"
|
"PO-Revision-Date: 2012-11-26 17:49+0000\n"
|
||||||
"Last-Translator: Bayuka <bayuka1988@gmail.com>\n"
|
"Last-Translator: gobi <Unknown>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-11-25 05:29+0000\n"
|
"X-Launchpad-Export-Date: 2012-11-27 05:22+0000\n"
|
||||||
"X-Generator: Launchpad (build 16293)\n"
|
"X-Generator: Launchpad (build 16309)\n"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,description:base.module_account_check_writing
|
#: model:ir.module.module,description:base.module_account_check_writing
|
||||||
|
@ -24,6 +24,10 @@ msgid ""
|
||||||
"================================================\n"
|
"================================================\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Чек бичих болон Чек хэвлэх модуль.\n"
|
||||||
|
"================================================\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.country,name:base.sh
|
#: model:res.country,name:base.sh
|
||||||
|
@ -59,7 +63,7 @@ msgstr "Дэлгэцийн архитектур"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,summary:base.module_sale_stock
|
#: model:ir.module.module,summary:base.module_sale_stock
|
||||||
msgid "Quotation, Sale Orders, Delivery & Invoicing Control"
|
msgid "Quotation, Sale Orders, Delivery & Invoicing Control"
|
||||||
msgstr ""
|
msgstr "Үнийн санал, Борлуулалтын захиалга, Хүргэлт & Нэхэмжлэлийн хяналт"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: selection:ir.sequence,implementation:0
|
#: selection:ir.sequence,implementation:0
|
||||||
|
@ -88,12 +92,12 @@ msgstr ""
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,summary:base.module_point_of_sale
|
#: model:ir.module.module,summary:base.module_point_of_sale
|
||||||
msgid "Touchscreen Interface for Shops"
|
msgid "Touchscreen Interface for Shops"
|
||||||
msgstr ""
|
msgstr "Дэлгүүрт зориулагдсан маажих дэлгэц"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
|
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
|
||||||
msgid "Indian Payroll"
|
msgid "Indian Payroll"
|
||||||
msgstr ""
|
msgstr "Энэтхэг Цалин"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:ir.cron,model:0
|
#: help:ir.cron,model:0
|
||||||
|
@ -121,6 +125,17 @@ msgid ""
|
||||||
" * Product Attributes\n"
|
" * Product Attributes\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Барааны маягт дээр үйлдвэрлэгч болон үзүүлэлтүүд нэмдэг модуль.\n"
|
||||||
|
"====================================================================\n"
|
||||||
|
"\n"
|
||||||
|
"Бараанд дараах зүйлсийг тодорхойлох боломжтой болно:\n"
|
||||||
|
"-----------------------------------------------\n"
|
||||||
|
" * Үйлдвэрлэгч\n"
|
||||||
|
" * Барааны Үйлдвэрлэгчийн өгсөн нэр\n"
|
||||||
|
" * Барааны Үйлдвэрлэгчийн өгсөн код\n"
|
||||||
|
" * Барааны үзүүлэлтүүд\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:ir.actions.client,params:0
|
#: field:ir.actions.client,params:0
|
||||||
|
@ -134,11 +149,14 @@ msgid ""
|
||||||
"The module adds google user in res user.\n"
|
"The module adds google user in res user.\n"
|
||||||
"========================================\n"
|
"========================================\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Энэ модуль нь res_user-т google хэрэглэгчийг нэмдэг.\n"
|
||||||
|
"========================================\n"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:res.partner,employee:0
|
#: help:res.partner,employee:0
|
||||||
msgid "Check this box if this contact is an Employee."
|
msgid "Check this box if this contact is an Employee."
|
||||||
msgstr ""
|
msgstr "Хэрэв холбогч нь ажилтан бол үүнийг тэмдэглэ."
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:ir.model.fields,domain:0
|
#: help:ir.model.fields,domain:0
|
||||||
|
@ -168,7 +186,7 @@ msgstr "Ашиглах цонх"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:ir.actions.report.xml,report_rml:0
|
#: field:ir.actions.report.xml,report_rml:0
|
||||||
msgid "Main Report File Path"
|
msgid "Main Report File Path"
|
||||||
msgstr ""
|
msgstr "Тайлангийн Үндсэн Файлын Зам"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,shortdesc:base.module_sale_analytic_plans
|
#: model:ir.module.module,shortdesc:base.module_sale_analytic_plans
|
||||||
|
@ -189,6 +207,14 @@ msgid ""
|
||||||
"revenue\n"
|
"revenue\n"
|
||||||
"reports."
|
"reports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Зардал, Цагийн хуудсын бичилтээс нэхэмжлэлийг үүсгэдэг.\n"
|
||||||
|
"========================================================\n"
|
||||||
|
"\n"
|
||||||
|
"Өртөг (хүний нөөц, зардал, ...) дээр суурилан нэхэмжлэл үүсгэдэг модуль .\n"
|
||||||
|
"\n"
|
||||||
|
"Шинжилгээний данс дээр зарах үнийн хүснэгт үүсгэж орох ашгийн онолийн "
|
||||||
|
"тайланг үүсгэж болно."
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,description:base.module_crm
|
#: model:ir.module.module,description:base.module_crm
|
||||||
|
@ -223,6 +249,33 @@ msgid ""
|
||||||
"* Planned Revenue by Stage and User (graph)\n"
|
"* Planned Revenue by Stage and User (graph)\n"
|
||||||
"* Opportunities by Stage (graph)\n"
|
"* Opportunities by Stage (graph)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"OpenERP-н Захиалагчийн Харилцааны Менежмент (CRM)-н ерөнхий модуль\n"
|
||||||
|
"=====================================================\n"
|
||||||
|
"\n"
|
||||||
|
"Энэ модуль нь хүмүүсийн бүлэгүүд сэжим, боломж, уулзалт, утасны дуудлагыг "
|
||||||
|
"ухаалаг бөгөөд оновчтой зохион байгуулах боломжийг олгодог.\n"
|
||||||
|
"\n"
|
||||||
|
"Түүнчлэн харилцах, олж таних, эрэмбэлэх, оноох, шийдэх, мэдэгдэх гэх мэт "
|
||||||
|
"түлхүүр даалгавруудыг удирддаг.\n"
|
||||||
|
"\n"
|
||||||
|
"OpenERP нь бүх хэрэгүүд хэрэглэгч, захиалагч, нийлүүлэгчээр амжилттай "
|
||||||
|
"хөтлөгдөх баталгааг хангадаг. Автомат сануулга илгээх, хүсэлтийг дээд шат "
|
||||||
|
"рүү хүргэх, байгууллагын дүрэм дээр тулгуурласан маш олон төрлийн "
|
||||||
|
"үйлдлүүдийг гүйцэтгэх боломжтой. \n"
|
||||||
|
"\n"
|
||||||
|
"Системийн гайхалтай тал нь хэрэглэгчид ямар нэг нарийвчилсан ажил хийх "
|
||||||
|
"шаардлагагүй байдаг. CRM модуль нь имэйл болон OpenERP-г хооронд нь холбох "
|
||||||
|
"имэйл үүдтэй. Иймээс зөвхөн имэйл илгээх замаар сэжим үүсгэж боломж "
|
||||||
|
"олгодог.\n"
|
||||||
|
"\n"
|
||||||
|
"OpenERP нь талархлын мессеж илгээгээд имэйлийг харгалзах ажилтан руу илгээж "
|
||||||
|
"цаашид авах бүх арга хэмжээг авч зөв боловсруулалтыг хийлгэдэг.\n"
|
||||||
|
"\n"
|
||||||
|
"CRM-н хянах самбар дараах зүйлсийг агуулдаг:\n"
|
||||||
|
"-------------------------------\n"
|
||||||
|
"* Төлөвлөсөн орлого үеээр болон хэрэглэгчээр (graph)\n"
|
||||||
|
"* Боломж үеээр (график)\n"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: code:addons/base/ir/ir_model.py:394
|
#: code:addons/base/ir/ir_model.py:394
|
||||||
|
@ -266,7 +319,7 @@ msgstr "үүсгэгдсэн."
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:ir.actions.report.xml,report_xsl:0
|
#: field:ir.actions.report.xml,report_xsl:0
|
||||||
msgid "XSL Path"
|
msgid "XSL Path"
|
||||||
msgstr ""
|
msgstr "XSL зам"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,shortdesc:base.module_l10n_tr
|
#: model:ir.module.module,shortdesc:base.module_l10n_tr
|
||||||
|
@ -292,7 +345,7 @@ msgstr "Инуит хэл / ᐃᓄᒃᑎᑐᑦ"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.groups,name:base.group_multi_currency
|
#: model:res.groups,name:base.group_multi_currency
|
||||||
msgid "Multi Currencies"
|
msgid "Multi Currencies"
|
||||||
msgstr ""
|
msgstr "Олон валютууд"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,description:base.module_l10n_cl
|
#: model:ir.module.module,description:base.module_l10n_cl
|
||||||
|
@ -315,7 +368,7 @@ msgstr "Борлуулалтын менежмент"
|
||||||
msgid ""
|
msgid ""
|
||||||
"The internal user that is in charge of communicating with this contact if "
|
"The internal user that is in charge of communicating with this contact if "
|
||||||
"any."
|
"any."
|
||||||
msgstr ""
|
msgstr "Энэ холбогчтой харилцах дотоод хэрэглэгч (хэрэв байгаа бол)."
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: view:res.partner:0
|
#: view:res.partner:0
|
||||||
|
@ -350,6 +403,15 @@ msgid ""
|
||||||
" * Commitment Date\n"
|
" * Commitment Date\n"
|
||||||
" * Effective Date\n"
|
" * Effective Date\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Борлуулалтын захиалгад огнооны нэмэлт мэдээлэл нэмдэг .\n"
|
||||||
|
"===================================================\n"
|
||||||
|
"\n"
|
||||||
|
"Борлуулалтын захиалгад дараах огноонуудыг нэмж болно:\n"
|
||||||
|
"-----------------------------------------------------------\n"
|
||||||
|
" * Хүссэн Огноо\n"
|
||||||
|
" * Амласан Огноо\n"
|
||||||
|
" * Зохистой Огноо\n"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:ir.actions.act_window,res_id:0
|
#: help:ir.actions.act_window,res_id:0
|
||||||
|
@ -357,6 +419,8 @@ msgid ""
|
||||||
"Database ID of record to open in form view, when ``view_mode`` is set to "
|
"Database ID of record to open in form view, when ``view_mode`` is set to "
|
||||||
"'form' only"
|
"'form' only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Форм харагдацийг нээх бичлэгийн өгөгдлийн баазын ID, зөвхөн ``view_mode`` нь "
|
||||||
|
"'form' гэж тохируулагдсан үед."
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:res.partner.address,name:0
|
#: field:res.partner.address,name:0
|
||||||
|
@ -568,7 +632,7 @@ msgstr ""
|
||||||
#. module: base
|
#. module: base
|
||||||
#: view:workflow.transition:0
|
#: view:workflow.transition:0
|
||||||
msgid "Workflow Transition"
|
msgid "Workflow Transition"
|
||||||
msgstr ""
|
msgstr "Ажлын урсгалын шилжилт"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.country,name:base.gf
|
#: model:res.country,name:base.gf
|
||||||
|
@ -578,7 +642,7 @@ msgstr "Франц Гуана"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,summary:base.module_hr
|
#: model:ir.module.module,summary:base.module_hr
|
||||||
msgid "Jobs, Departments, Employees Details"
|
msgid "Jobs, Departments, Employees Details"
|
||||||
msgstr ""
|
msgstr "Ажлууд, Хэлтсүүд, Ажилчдийн дэлгэрэнгүй"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,description:base.module_analytic
|
#: model:ir.module.module,description:base.module_analytic
|
||||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
||||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||||
"POT-Creation-Date: 2012-11-24 02:51+0000\n"
|
"POT-Creation-Date: 2012-11-24 02:51+0000\n"
|
||||||
"PO-Revision-Date: 2012-11-25 09:34+0000\n"
|
"PO-Revision-Date: 2012-11-26 06:49+0000\n"
|
||||||
"Last-Translator: Joshua Jan(SHINEIT) <popkar77@gmail.com>\n"
|
"Last-Translator: Joshua Jan(SHINEIT) <popkar77@gmail.com>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-11-26 04:40+0000\n"
|
"X-Launchpad-Export-Date: 2012-11-27 05:22+0000\n"
|
||||||
"X-Generator: Launchpad (build 16293)\n"
|
"X-Generator: Launchpad (build 16309)\n"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,description:base.module_account_check_writing
|
#: model:ir.module.module,description:base.module_account_check_writing
|
||||||
|
@ -14970,7 +14970,7 @@ msgstr "系统更新"
|
||||||
#: field:ir.actions.report.xml,report_sxw_content:0
|
#: field:ir.actions.report.xml,report_sxw_content:0
|
||||||
#: field:ir.actions.report.xml,report_sxw_content_data:0
|
#: field:ir.actions.report.xml,report_sxw_content_data:0
|
||||||
msgid "SXW Content"
|
msgid "SXW Content"
|
||||||
msgstr ""
|
msgstr "SXW内容"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:ir.sequence,prefix:0
|
#: help:ir.sequence,prefix:0
|
||||||
|
@ -14985,7 +14985,7 @@ msgstr "塞舌尔"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.partner.category,name:base.res_partner_category_4
|
#: model:res.partner.category,name:base.res_partner_category_4
|
||||||
msgid "Gold"
|
msgid "Gold"
|
||||||
msgstr ""
|
msgstr "黄金"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: code:addons/base/res/res_company.py:159
|
#: code:addons/base/res/res_company.py:159
|
||||||
|
@ -15012,7 +15012,7 @@ msgstr "一般信息"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:ir.model.data,complete_name:0
|
#: field:ir.model.data,complete_name:0
|
||||||
msgid "Complete ID"
|
msgid "Complete ID"
|
||||||
msgstr ""
|
msgstr "完整ID"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.country,name:base.tc
|
#: model:res.country,name:base.tc
|
||||||
|
@ -15063,7 +15063,7 @@ msgstr "切换公司警告"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Helps you manage your manufacturing processes and generate reports on those "
|
"Helps you manage your manufacturing processes and generate reports on those "
|
||||||
"processes."
|
"processes."
|
||||||
msgstr ""
|
msgstr "帮助您管理您的生产和其生成的报表。"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: help:ir.sequence,number_increment:0
|
#: help:ir.sequence,number_increment:0
|
||||||
|
@ -15125,12 +15125,12 @@ msgstr "公司"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,shortdesc:base.module_purchase_requisition
|
#: model:ir.module.module,shortdesc:base.module_purchase_requisition
|
||||||
msgid "Purchase Requisitions"
|
msgid "Purchase Requisitions"
|
||||||
msgstr ""
|
msgstr "采购申请"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: selection:ir.actions.act_window,target:0
|
#: selection:ir.actions.act_window,target:0
|
||||||
msgid "Inline Edit"
|
msgid "Inline Edit"
|
||||||
msgstr ""
|
msgstr "行内编辑"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: selection:ir.cron,interval_type:0
|
#: selection:ir.cron,interval_type:0
|
||||||
|
@ -15151,7 +15151,7 @@ msgstr "业务伙伴: "
|
||||||
#. module: base
|
#. module: base
|
||||||
#: view:res.partner:0
|
#: view:res.partner:0
|
||||||
msgid "Is a Company?"
|
msgid "Is a Company?"
|
||||||
msgstr ""
|
msgstr "是一个公司?"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: code:addons/base/res/res_company.py:159
|
#: code:addons/base/res/res_company.py:159
|
||||||
|
@ -15173,7 +15173,7 @@ msgstr "创建对象"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:res.country,name:base.ss
|
#: model:res.country,name:base.ss
|
||||||
msgid "South Sudan"
|
msgid "South Sudan"
|
||||||
msgstr ""
|
msgstr "苏丹南部"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: field:ir.filters,context:0
|
#: field:ir.filters,context:0
|
||||||
|
@ -15206,7 +15206,7 @@ msgstr "潜在客户"
|
||||||
#. module: base
|
#. module: base
|
||||||
#: model:ir.module.module,shortdesc:base.module_stock_invoice_directly
|
#: model:ir.module.module,shortdesc:base.module_stock_invoice_directly
|
||||||
msgid "Invoice Picking Directly"
|
msgid "Invoice Picking Directly"
|
||||||
msgstr ""
|
msgstr "根据装箱单开发票"
|
||||||
|
|
||||||
#. module: base
|
#. module: base
|
||||||
#: selection:base.language.install,lang:0
|
#: selection:base.language.install,lang:0
|
||||||
|
|
|
@ -66,9 +66,11 @@
|
||||||
<field name="name" string="Record Rule"/>
|
<field name="name" string="Record Rule"/>
|
||||||
<filter string="Global" icon="terp-stage" domain="[('global','=',True)]"/>
|
<filter string="Global" icon="terp-stage" domain="[('global','=',True)]"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Full Access" icon="terp-gtk-select-all" domain="[('perm_read','=',True),('perm_write','=',True),('perm_create','=',True),('perm_unlink','=',True)]"/>
|
<filter string="Full Access Right" domain="[('perm_read','=',True),('perm_write','=',True),('perm_create','=',True),('perm_unlink','=',True)]"/>
|
||||||
<filter string="Read Access" icon="terp-stock_align_left_24" domain="[('perm_read','=',True)]"/>
|
<filter string="Read Access Right" domain="[('perm_read','=',True)]"/>
|
||||||
<filter string="Write Access" icon="terp-tools" domain="[('perm_write','=',True)]"/>
|
<filter string="Write Access Right" domain="[('perm_write','=',True)]"/>
|
||||||
|
<filter string="Create Access Right" domain="[('perm_create','=',True)]"/>
|
||||||
|
<filter string="Delete Access Right" domain="[('perm_unlink','=',True)]"/>
|
||||||
<field name="model_id"/>
|
<field name="model_id"/>
|
||||||
<field name="groups"/>
|
<field name="groups"/>
|
||||||
</search>
|
</search>
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from osv import osv, fields
|
||||||
|
from tools.translate import _
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
@ -98,6 +101,8 @@ class ir_sequence(openerp.osv.osv.osv):
|
||||||
|
|
||||||
There is no access rights check.
|
There is no access rights check.
|
||||||
"""
|
"""
|
||||||
|
if number_increment == 0:
|
||||||
|
raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))
|
||||||
assert isinstance(id, (int, long))
|
assert isinstance(id, (int, long))
|
||||||
sql = "CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s" % id
|
sql = "CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s" % id
|
||||||
cr.execute(sql, (number_increment, number_next))
|
cr.execute(sql, (number_increment, number_next))
|
||||||
|
@ -122,6 +127,8 @@ class ir_sequence(openerp.osv.osv.osv):
|
||||||
|
|
||||||
There is no access rights check.
|
There is no access rights check.
|
||||||
"""
|
"""
|
||||||
|
if number_increment == 0:
|
||||||
|
raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))
|
||||||
assert isinstance(id, (int, long))
|
assert isinstance(id, (int, long))
|
||||||
cr.execute("""
|
cr.execute("""
|
||||||
ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s
|
ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s
|
||||||
|
|
|
@ -54,12 +54,12 @@
|
||||||
<record id="view_translation_tree" model="ir.ui.view">
|
<record id="view_translation_tree" model="ir.ui.view">
|
||||||
<field name="model">ir.translation</field>
|
<field name="model">ir.translation</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="Translations" editable="bottom">
|
<tree string="Translations" editable="top">
|
||||||
<field name="src" readonly="True"/>
|
<field name="src"/>
|
||||||
<field name="value"/>
|
<field name="value"/>
|
||||||
<field name="name" readonly="True"/>
|
<field name="name"/>
|
||||||
<field name="lang" readonly="True"/>
|
<field name="lang"/>
|
||||||
<field name="type" readonly="True"/>
|
<field name="type"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<openerp>
|
<openerp>
|
||||||
<data>
|
<data>
|
||||||
<record model="ir.module.category" id="module_category_hidden">
|
<record model="ir.module.category" id="module_category_hidden">
|
||||||
<field name="name">Hidden</field>
|
<field name="name">Technical Settings</field>
|
||||||
<field name="sequence">0</field>
|
<field name="sequence">0</field>
|
||||||
<field name="visible" eval="0" />
|
<field name="visible" eval="0" />
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Company" version="7.0">
|
<form string="Company" version="7.0">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_right oe_avatar">
|
<div>
|
||||||
<field name="logo" nolabel="1" widget="image"/>
|
<field name="logo" nolabel="1" widget="image" class="oe_avatar oe_left"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_right oe_button_box" name="button_box">
|
<div class="oe_right oe_button_box" name="button_box">
|
||||||
<button name="%(preview_report)d" string="Preview Header/Footer" type="action" icon="gtk-print" class="oe_inline oe_right"/>
|
<button name="%(preview_report)d" string="Preview Header/Footer" type="action" icon="gtk-print" class="oe_inline oe_right"/>
|
||||||
|
|
|
@ -508,23 +508,6 @@ class res_partner(osv.osv, format_address):
|
||||||
result[adr] = address_dict.get(adr, default_address)
|
result[adr] = address_dict.get(adr, default_address)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def gen_next_ref(self, cr, uid, ids):
|
|
||||||
if len(ids) != 1:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# compute the next number ref
|
|
||||||
cr.execute("select ref from res_partner where ref is not null order by char_length(ref) desc, ref desc limit 1")
|
|
||||||
res = cr.dictfetchall()
|
|
||||||
ref = res and res[0]['ref'] or '0'
|
|
||||||
try:
|
|
||||||
nextref = int(ref)+1
|
|
||||||
except:
|
|
||||||
raise osv.except_osv(_('Warning'), _("Couldn't generate the next id because some partners have an alphabetic id !"))
|
|
||||||
|
|
||||||
# update the current partner
|
|
||||||
cr.execute("update res_partner set ref=%s where id=%s", (nextref, ids[0]))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def view_header_get(self, cr, uid, view_id, view_type, context):
|
def view_header_get(self, cr, uid, view_id, view_type, context):
|
||||||
res = super(res_partner, self).view_header_get(cr, uid, view_id, view_type, context)
|
res = super(res_partner, self).view_header_get(cr, uid, view_id, view_type, context)
|
||||||
if res: return res
|
if res: return res
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<label for="type" attrs="{'invisible': [('parent_id','=', False)]}"/>
|
<label for="type" attrs="{'invisible': [('parent_id','=', False)]}"/>
|
||||||
<div attrs="{'invisible': [('parent_id','=', False)]}" invisible="1" name="div_type">
|
<div attrs="{'invisible': [('parent_id','=', False)]}" name="div_type">
|
||||||
<field class="oe_inline"
|
<field class="oe_inline"
|
||||||
name="type"/>
|
name="type"/>
|
||||||
<label for="use_parent_address" class="oe_edit_only"/>
|
<label for="use_parent_address" class="oe_edit_only"/>
|
||||||
|
@ -295,7 +295,7 @@
|
||||||
<filter string="Customers" name="customer" icon="terp-personal" domain="[('customer','=',1)]" help="Customer Partners"/>
|
<filter string="Customers" name="customer" icon="terp-personal" domain="[('customer','=',1)]" help="Customer Partners"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Suppliers" name="supplier" icon="terp-personal" domain="[('supplier','=',1)]" help="Supplier Partners"/>
|
<filter string="Suppliers" name="supplier" icon="terp-personal" domain="[('supplier','=',1)]" help="Supplier Partners"/>
|
||||||
<field name="category_id" string="Category" filter_domain="[('category_id','ilike', self)]"/>
|
<field name="category_id" string="Tag" filter_domain="[('category_id','ilike', self)]"/>
|
||||||
<field name="user_id"/>
|
<field name="user_id"/>
|
||||||
<field name="parent_id" filter_domain="[('parent_id','child_of',[self])]"/>
|
<field name="parent_id" filter_domain="[('parent_id','child_of',[self])]"/>
|
||||||
<group expand="0" string="Group By...">
|
<group expand="0" string="Group By...">
|
||||||
|
@ -527,7 +527,7 @@
|
||||||
<field name="help">Manage the partner categories in order to better classify them for tracking and analysis purposes. A partner may belong to several categories and categories have a hierarchy structure: a partner belonging to a category also belong to his parent category.</field>
|
<field name="help">Manage the partner categories in order to better classify them for tracking and analysis purposes. A partner may belong to several categories and categories have a hierarchy structure: a partner belonging to a category also belong to his parent category.</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem action="action_partner_category_form" id="menu_partner_category_form" name="Partner Categories" sequence="4" parent="menu_config_address_book" groups="base.group_no_one"/>
|
<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"/>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
commands = {}
|
||||||
|
|
||||||
|
class CommandType(type):
|
||||||
|
def __init__(cls, name, bases, attrs):
|
||||||
|
super(CommandType, cls).__init__(name, bases, attrs)
|
||||||
|
name = getattr(cls, name, cls.__name__.lower())
|
||||||
|
cls.name = name
|
||||||
|
if name != 'command':
|
||||||
|
commands[name] = cls
|
||||||
|
|
||||||
|
class Command(object):
|
||||||
|
"""Subclass this class to define new openerp subcommands """
|
||||||
|
__metaclass__ = CommandType
|
||||||
|
|
||||||
|
def run(self, args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Help(Command):
|
||||||
|
def run(self, args):
|
||||||
|
print "Available commands:\n"
|
||||||
|
for k, v in commands.items():
|
||||||
|
print " %s" % k
|
||||||
|
|
||||||
|
import server
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = sys.argv[1:]
|
||||||
|
command = "server"
|
||||||
|
if len(args) and not args[0].startswith("-"):
|
||||||
|
command = args[0]
|
||||||
|
args = args[1:]
|
||||||
|
|
||||||
|
if command in commands:
|
||||||
|
o = commands[command]()
|
||||||
|
o.run(args)
|
||||||
|
|
||||||
|
# vim:et:ts=4:sw=4:
|
|
@ -0,0 +1,275 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
OpenERP - Server
|
||||||
|
OpenERP is an ERP+CRM program for small and medium businesses.
|
||||||
|
|
||||||
|
The whole source code is distributed under the terms of the
|
||||||
|
GNU Public Licence.
|
||||||
|
|
||||||
|
(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
import time
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
|
||||||
|
from . import Command
|
||||||
|
|
||||||
|
__author__ = openerp.release.author
|
||||||
|
__version__ = openerp.release.version
|
||||||
|
|
||||||
|
# Also use the `openerp` logger for the main script.
|
||||||
|
_logger = logging.getLogger('openerp')
|
||||||
|
|
||||||
|
def check_root_user():
|
||||||
|
""" Exit if the process's user is 'root' (on POSIX system)."""
|
||||||
|
if os.name == 'posix':
|
||||||
|
import pwd
|
||||||
|
if pwd.getpwuid(os.getuid())[0] == 'root' :
|
||||||
|
sys.stderr.write("Running as user 'root' is a security risk, aborting.\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def check_postgres_user():
|
||||||
|
""" Exit if the configured database user is 'postgres'.
|
||||||
|
|
||||||
|
This function assumes the configuration has been initialized.
|
||||||
|
"""
|
||||||
|
config = openerp.tools.config
|
||||||
|
if config['db_user'] == 'postgres':
|
||||||
|
sys.stderr.write("Using the database user 'postgres' is a security risk, aborting.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def report_configuration():
|
||||||
|
""" Log the server version and some configuration values.
|
||||||
|
|
||||||
|
This function assumes the configuration has been initialized.
|
||||||
|
"""
|
||||||
|
config = openerp.tools.config
|
||||||
|
_logger.info("OpenERP version %s", __version__)
|
||||||
|
for name, value in [('addons paths', config['addons_path']),
|
||||||
|
('database hostname', config['db_host'] or 'localhost'),
|
||||||
|
('database port', config['db_port'] or '5432'),
|
||||||
|
('database user', config['db_user'])]:
|
||||||
|
_logger.info("%s: %s", name, value)
|
||||||
|
|
||||||
|
def setup_pid_file():
|
||||||
|
""" Create a file with the process id written in it.
|
||||||
|
|
||||||
|
This function assumes the configuration has been initialized.
|
||||||
|
"""
|
||||||
|
config = openerp.tools.config
|
||||||
|
if config['pidfile']:
|
||||||
|
fd = open(config['pidfile'], 'w')
|
||||||
|
pidtext = "%d" % (os.getpid())
|
||||||
|
fd.write(pidtext)
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
def preload_registry(dbname):
|
||||||
|
""" Preload a registry, and start the cron."""
|
||||||
|
try:
|
||||||
|
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=openerp.tools.config['init'] or openerp.tools.config['update'], pooljobs=False)
|
||||||
|
|
||||||
|
# jobs will start to be processed later, when openerp.cron.start_master_thread() is called by openerp.service.start_services()
|
||||||
|
registry.schedule_cron_jobs()
|
||||||
|
except Exception:
|
||||||
|
_logger.exception('Failed to initialize database `%s`.', dbname)
|
||||||
|
|
||||||
|
def run_test_file(dbname, test_file):
|
||||||
|
""" Preload a registry, possibly run a test file, and start the cron."""
|
||||||
|
try:
|
||||||
|
config = openerp.tools.config
|
||||||
|
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
|
||||||
|
cr = db.cursor()
|
||||||
|
_logger.info('loading test file %s', test_file)
|
||||||
|
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
|
||||||
|
cr.rollback()
|
||||||
|
cr.close()
|
||||||
|
except Exception:
|
||||||
|
_logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
|
||||||
|
|
||||||
|
def export_translation():
|
||||||
|
config = openerp.tools.config
|
||||||
|
dbname = config['db_name']
|
||||||
|
|
||||||
|
if config["language"]:
|
||||||
|
msg = "language %s" % (config["language"],)
|
||||||
|
else:
|
||||||
|
msg = "new language"
|
||||||
|
_logger.info('writing translation file for %s to %s', msg,
|
||||||
|
config["translate_out"])
|
||||||
|
|
||||||
|
fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
|
||||||
|
buf = file(config["translate_out"], "w")
|
||||||
|
cr = openerp.pooler.get_db(dbname).cursor()
|
||||||
|
openerp.tools.trans_export(config["language"],
|
||||||
|
config["translate_modules"] or ["all"], buf, fileformat, cr)
|
||||||
|
cr.close()
|
||||||
|
buf.close()
|
||||||
|
|
||||||
|
_logger.info('translation file written successfully')
|
||||||
|
|
||||||
|
def import_translation():
|
||||||
|
config = openerp.tools.config
|
||||||
|
context = {'overwrite': config["overwrite_existing_translations"]}
|
||||||
|
dbname = config['db_name']
|
||||||
|
|
||||||
|
cr = openerp.pooler.get_db(dbname).cursor()
|
||||||
|
openerp.tools.trans_load( cr, config["translate_in"], config["language"],
|
||||||
|
context=context)
|
||||||
|
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():
|
||||||
|
""" Register the signal handler defined above. """
|
||||||
|
SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
|
||||||
|
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
|
||||||
|
if config['pidfile']:
|
||||||
|
os.unlink(config['pidfile'])
|
||||||
|
|
||||||
|
openerp.service.stop_services()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def configure_babel_localedata_path():
|
||||||
|
# Workaround: py2exe and babel.
|
||||||
|
if hasattr(sys, 'frozen'):
|
||||||
|
import babel
|
||||||
|
babel.localedata._dirname = os.path.join(os.path.dirname(sys.executable), 'localedata')
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
os.environ["TZ"] = "UTC"
|
||||||
|
|
||||||
|
check_root_user()
|
||||||
|
openerp.tools.config.parse_config(args)
|
||||||
|
|
||||||
|
check_postgres_user()
|
||||||
|
openerp.netsvc.init_logger()
|
||||||
|
report_configuration()
|
||||||
|
|
||||||
|
config = openerp.tools.config
|
||||||
|
|
||||||
|
configure_babel_localedata_path()
|
||||||
|
|
||||||
|
setup_signal_handlers()
|
||||||
|
|
||||||
|
if config["test_file"]:
|
||||||
|
run_test_file(config['db_name'], config['test_file'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if config["translate_out"]:
|
||||||
|
export_translation()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if config["translate_in"]:
|
||||||
|
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 config['workers']:
|
||||||
|
openerp.service.start_services_workers()
|
||||||
|
else:
|
||||||
|
openerp.service.start_services()
|
||||||
|
|
||||||
|
if config['db_name']:
|
||||||
|
for dbname in config['db_name'].split(','):
|
||||||
|
preload_registry(dbname)
|
||||||
|
|
||||||
|
if config["stop_after_init"]:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
_logger.info('OpenERP server is running, waiting for connections...')
|
||||||
|
quit_on_signals()
|
||||||
|
|
||||||
|
class Server(Command):
|
||||||
|
def run(self, args):
|
||||||
|
main(args)
|
||||||
|
|
||||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
Loading…
Reference in New Issue