diff --git a/MANIFEST.in b/MANIFEST.in index 6cd10b511cf..70715f18bc2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,18 +1,12 @@ -include rpminstall_sh.txt # TODO do we need this file ? include README include LICENSE include MANIFEST.in include setup.nsi include setup.cfg -#include openerp/server.cert -#include openerp/server.pkey -#include openerp/gpl.txt -include man/openerp-server.1 -include man/openerp_serverrc.5 -recursive-include pixmaps *bmp *ico *png +include setup_rpm.sh recursive-include win32 *.py *.bat -recursive-include openerp *css *csv *html *png *po *pot -recursive-include openerp *rml *rng *sql *sxw *xml *xsl *yml +recursive-include openerp *css *csv *html *png *po *pot *rml *rng *sql *sxw *xml *xsl *yml +graft install graft debian graft doc global-exclude *pyc *~ # Exclude possible garbage from previous graft. diff --git a/README b/README index 5725ce9f866..a6fe10c8ffb 100644 --- a/README +++ b/README @@ -1,17 +1,138 @@ -About OpenERP ---------------- - -OpenERP is a free Enterprise Resource Planning and Customer Relationship -Management software. It is mainly developed to meet changing needs. - -The main functional features are: CRM & SRM, analytic and financial accounting, -double-entry stock management, sales and purchases management, tasks automation, -help desk, marketing campaign, ... and vertical modules for very specific -businesses. - -Technical features include a distributed server, flexible workflows, an object -database, dynamic GUIs, customizable reports, NET-RPC and XML-RPC interfaces, ... - -For more information, please visit: -http://www.openerp.com - +About OpenERP +------------- + +OpenERP is a free Enterprise Resource Planning and Customer Relationship +Management software. It is mainly developed to meet changing needs. + +The main functional features are: CRM & SRM, analytic and financial accounting, +double-entry stock management, sales and purchases management, tasks automation, +help desk, marketing campaign, ... and vertical modules for very specific +businesses. + +Technical features include a distributed server, flexible workflows, an object +database, dynamic GUIs, customizable reports, NET-RPC and XML-RPC interfaces, ... + +For more information, please visit: +http://www.openerp.com + +OpenERP Quick Installation Guide +--------------------------------- + +This file contains a quick guide to configure and install the OpenERP server. + +Required dependencies: +--------------------- + +You need the following software installed: + + * Python 2.5 or 2.6 + * Postgresql 8.2 or above + * Psycopg2 python module + * Reportlab pdf generation library for python + * lxml python module + * pytz python module + * PyYaml python module (install with: easy_install PyYaml) + +Some dependencies are only required for specific purposes: + +for rendering workflows graphs, you need: + * graphviz + * pyparsing + +For Luxembourg localization, you also need: + * pdftk (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/) + +for generating reports using non .jpg images, you need: + * Python Imaging Library for python + +For Debian-based distributions, the required packages can be installed with the +following command: + + #> apt-get install -y postgresql graphviz python-psycopg2 python-lxml python-tz python-imaging + +For Fedora +if they are not installed, install: +python and postgresql + +uses yum or you can recover required packages on fedora web site in "core" or "extra" repository : +postgresql-python +python-lxml +python-imaging +python-psycopg2 +python-reportlab +graphviz +You can find pyparsing at http://pyparsing.sourceforge.net/ + +1. Check that all the required dependencies are installed. + +2. Launch the program "python ./bin/openerp-server.py -r db_user -w db_password --db_host 127.0.0.1". +See the man page for more information about options. + +3. Connect to the server using the GUI client. And follow the instructions to create a new database. + +Installation Steps +------------------ + +1. Check that all the required dependencies are installed. + +2. Create a postgresql database. + +The default database name is "terp". If you want to use another name, you +will need to provide it when launching the server (by using the commandline +option --database). + +To create a postgresql database named "terp" using the following command: + $ createdb --encoding=UNICODE terp + +If it is the first time you use postgresql you might need to create a new user +to the postgres system using the following commands (where myusername is your +unix user name): + + $ su - + # su - postgres + $ createuser openerp + Shall the new user be allowed to create databases? (y/n) y + Shall the new user be allowed to create more new users? (y/n) y + CREATE USER + $ logout + # logout + +3. Launch service daemon by "service openerp-server start". + +The first time it is run, the server will initialise the database with all the default values. + +4. Connect to the server using the GUI client. + +There are two accounts by default: + * login: admin, password:admin + * login: demo, password:demo + +Some instructions to use setup.py for a user-install. +This file should/will be moved on a proper documentation place later. + + +- Possibly clean any left-over of the previous build. + > rm -rf dist openerp_server.egg-info + +- Possibly copy the addons in the server if we want them to be packaged + together: + > rsync -av --delete \ + --exclude .bzr/ \ + --exclude .bzrignore \ + --exclude /__init__.py \ + --exclude /base \ + --exclude /base_quality_interrogation.py \ + openerp/addons + +- Create the user-local directory where we want the package to be installed: + > mkdir -p /home/openerp/openerp-tmp/lib/python2.6/site-packages/ + +- Use --prefix to specify where the package is installed and include that + place in PYTHONPATH: + > PYTHONPATH=/home/openerp/openerp-tmp/lib/python2.6/site-packages/ \ + python setup.py install --prefix=/home/openerp/openerp-tmp + +- Run the main script, again specifying the PYTHONPATH: + > PYTHONPATH=/home/openerp/openerp-tmp/lib/python2.6/site-packages/ \ + /home/openerp/openerp-tmp/bin/openerp-server + diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 00000000000..7b117c040f6 --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,17 @@ +import openerp +# Standard OpenERP XML-RPC port. +bind = '127.0.0.1:8069' +pidfile = '.gunicorn.pid' +# This is the big TODO: safely use more than a single worker. +workers = 1 +# Some application-wide initialization is needed. +on_starting = openerp.wsgi.on_starting +when_ready = openerp.wsgi.when_ready +timeout = 240 # openerp request-response cycle can be quite long + +# Setting openerp.conf.xxx will be better than setting +# openerp.tools.config['xxx'] +conf = openerp.tools.config +conf['addons_path'] = '/home/openerp/repos/addons/trunk-xmlrpc' +conf['static_http_document_root'] = '/tmp' +#conf['log_level'] = 10 # 10 is DEBUG diff --git a/doc/Changelog b/history/Changelog similarity index 100% rename from doc/Changelog rename to history/Changelog diff --git a/doc/Changelog-4.x b/history/Changelog-4.x similarity index 100% rename from doc/Changelog-4.x rename to history/Changelog-4.x diff --git a/doc/Changelog-6.x b/history/Changelog-6.x similarity index 100% rename from doc/Changelog-6.x rename to history/Changelog-6.x diff --git a/doc/INSTALL b/history/INSTALL similarity index 100% rename from doc/INSTALL rename to history/INSTALL diff --git a/doc/README.urpmi b/history/README.urpmi similarity index 100% rename from doc/README.urpmi rename to history/README.urpmi diff --git a/doc/README.userchange b/history/README.userchange similarity index 100% rename from doc/README.userchange rename to history/README.userchange diff --git a/tools/change-loglevel.sh b/history/change-loglevel.sh similarity index 100% rename from tools/change-loglevel.sh rename to history/change-loglevel.sh diff --git a/doc/tests/check_profile_l10n_all.py b/history/check_profile_l10n_all.py similarity index 100% rename from doc/tests/check_profile_l10n_all.py rename to history/check_profile_l10n_all.py diff --git a/sql/clean-model.sql b/history/clean-model.sql similarity index 100% rename from sql/clean-model.sql rename to history/clean-model.sql diff --git a/tools/gen_graph.sh b/history/gen_graph.sh similarity index 100% rename from tools/gen_graph.sh rename to history/gen_graph.sh diff --git a/tools/get-srvstats.sh b/history/get-srvstats.sh similarity index 100% rename from tools/get-srvstats.sh rename to history/get-srvstats.sh diff --git a/tools/list-services.sh b/history/list-services.sh similarity index 100% rename from tools/list-services.sh rename to history/list-services.sh diff --git a/doc/migrate/3.3.0-3.4.0/README b/history/migrate/3.3.0-3.4.0/README similarity index 100% rename from doc/migrate/3.3.0-3.4.0/README rename to history/migrate/3.3.0-3.4.0/README diff --git a/doc/migrate/3.3.0-3.4.0/post.py b/history/migrate/3.3.0-3.4.0/post.py similarity index 100% rename from doc/migrate/3.3.0-3.4.0/post.py rename to history/migrate/3.3.0-3.4.0/post.py diff --git a/doc/migrate/3.3.0-3.4.0/pre.py b/history/migrate/3.3.0-3.4.0/pre.py similarity index 100% rename from doc/migrate/3.3.0-3.4.0/pre.py rename to history/migrate/3.3.0-3.4.0/pre.py diff --git a/doc/migrate/3.4.0-4.0.0/README b/history/migrate/3.4.0-4.0.0/README similarity index 100% rename from doc/migrate/3.4.0-4.0.0/README rename to history/migrate/3.4.0-4.0.0/README diff --git a/doc/migrate/3.4.0-4.0.0/post-tiny.py b/history/migrate/3.4.0-4.0.0/post-tiny.py similarity index 100% rename from doc/migrate/3.4.0-4.0.0/post-tiny.py rename to history/migrate/3.4.0-4.0.0/post-tiny.py diff --git a/doc/migrate/3.4.0-4.0.0/post.py b/history/migrate/3.4.0-4.0.0/post.py similarity index 100% rename from doc/migrate/3.4.0-4.0.0/post.py rename to history/migrate/3.4.0-4.0.0/post.py diff --git a/doc/migrate/3.4.0-4.0.0/pre-tiny.py b/history/migrate/3.4.0-4.0.0/pre-tiny.py similarity index 100% rename from doc/migrate/3.4.0-4.0.0/pre-tiny.py rename to history/migrate/3.4.0-4.0.0/pre-tiny.py diff --git a/doc/migrate/3.4.0-4.0.0/pre.py b/history/migrate/3.4.0-4.0.0/pre.py similarity index 100% rename from doc/migrate/3.4.0-4.0.0/pre.py rename to history/migrate/3.4.0-4.0.0/pre.py diff --git a/doc/migrate/4.0.0-4.2.0/pre.py b/history/migrate/4.0.0-4.2.0/pre.py similarity index 100% rename from doc/migrate/4.0.0-4.2.0/pre.py rename to history/migrate/4.0.0-4.2.0/pre.py diff --git a/doc/migrate/4.0.0-4.2.0/tiny/README b/history/migrate/4.0.0-4.2.0/tiny/README similarity index 100% rename from doc/migrate/4.0.0-4.2.0/tiny/README rename to history/migrate/4.0.0-4.2.0/tiny/README diff --git a/doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py b/history/migrate/4.0.0-4.2.0/tiny/pre-tiny.py similarity index 100% rename from doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py rename to history/migrate/4.0.0-4.2.0/tiny/pre-tiny.py diff --git a/doc/migrate/4.2.0-4.4.0/pre.py b/history/migrate/4.2.0-4.4.0/pre.py similarity index 100% rename from doc/migrate/4.2.0-4.4.0/pre.py rename to history/migrate/4.2.0-4.4.0/pre.py diff --git a/tools/module_graph.py b/history/module_graph.py similarity index 100% rename from tools/module_graph.py rename to history/module_graph.py diff --git a/tools/xml2yml.py b/history/xml2yml.py similarity index 100% rename from tools/xml2yml.py rename to history/xml2yml.py diff --git a/pixmaps/openerp-header.bmp b/install/openerp-header.bmp similarity index 100% rename from pixmaps/openerp-header.bmp rename to install/openerp-header.bmp diff --git a/pixmaps/openerp-header.png b/install/openerp-header.png similarity index 100% rename from pixmaps/openerp-header.png rename to install/openerp-header.png diff --git a/pixmaps/openerp-icon.ico b/install/openerp-icon.ico similarity index 100% rename from pixmaps/openerp-icon.ico rename to install/openerp-icon.ico diff --git a/pixmaps/openerp-icon.png b/install/openerp-icon.png similarity index 100% rename from pixmaps/openerp-icon.png rename to install/openerp-icon.png diff --git a/man/openerp-server.1 b/install/openerp-server.1 similarity index 100% rename from man/openerp-server.1 rename to install/openerp-server.1 diff --git a/doc/openerp-server.conf b/install/openerp-server.conf similarity index 100% rename from doc/openerp-server.conf rename to install/openerp-server.conf diff --git a/doc/openerp-server.init b/install/openerp-server.init similarity index 100% rename from doc/openerp-server.init rename to install/openerp-server.init diff --git a/doc/openerp-server.logrotate b/install/openerp-server.logrotate similarity index 100% rename from doc/openerp-server.logrotate rename to install/openerp-server.logrotate diff --git a/pixmaps/openerp.ico b/install/openerp.ico similarity index 100% rename from pixmaps/openerp.ico rename to install/openerp.ico diff --git a/pixmaps/openerp.png b/install/openerp.png similarity index 100% rename from pixmaps/openerp.png rename to install/openerp.png diff --git a/man/openerp_serverrc.5 b/install/openerp_serverrc.5 similarity index 100% rename from man/openerp_serverrc.5 rename to install/openerp_serverrc.5 diff --git a/ssl-cert.cfg b/install/ssl-cert.cfg similarity index 100% rename from ssl-cert.cfg rename to install/ssl-cert.cfg diff --git a/openerp-server b/openerp-server index 5fdbb28eeb6..60eccd777bc 100755 --- a/openerp-server +++ b/openerp-server @@ -96,14 +96,17 @@ def preload_registry(dbname): def run_test_file(dbname, test_file): """ Preload a registry, possibly run a test file, and start the cron.""" - db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) + try: + db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) + cr = db.cursor() + logger = logging.getLogger('server') + logger.info('loading test file %s', test_file) + openerp.tools.convert_yaml_import(cr, 'base', file(test_file), {}, 'test', True) + cr.rollback() + cr.close() + except Exception: + logging.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file) - cr = db.cursor() - logger = logging.getLogger('server') - logger.info('loading test file %s', test_file) - openerp.tools.convert_yaml_import(cr, 'base', file(test_file), {}, 'test', True) - cr.rollback() - cr.close() def export_translation(): config = openerp.tools.config @@ -139,27 +142,6 @@ def import_translation(): cr.commit() cr.close() -def start_services(): - http_server = openerp.service.http_server - netrpc_server = openerp.service.netrpc_server - - # Instantiate local services (this is a legacy design). - openerp.osv.osv.start_object_proxy() - # Export (for RPC) services. - openerp.service.web_services.start_web_services() - - # Initialize the HTTP stack. - http_server.init_servers() - http_server.init_xmlrpc() - http_server.init_static_http() - netrpc_server.init_servers() - - # Start the main cron thread. - openerp.netsvc.start_agent() - - # Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC). - openerp.netsvc.Server.startAll() - # 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 @@ -211,26 +193,10 @@ def quit_on_signals(): while quit_signals_received == 0: time.sleep(60) - openerp.netsvc.Agent.quit() - openerp.netsvc.Server.quitAll() - config = openerp.tools.config if config['pidfile']: os.unlink(config['pidfile']) - logger = logging.getLogger('server') - logger.info("Initiating shutdown") - logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") - logging.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) - for thread in threading.enumerate(): - if thread != threading.currentThread() and not thread.isDaemon(): - while thread.isAlive(): - # need a busyloop here as thread.join() masks signals - # and would present the forced shutdown - thread.join(0.05) - time.sleep(0.05) + openerp.service.stop_services() sys.exit(0) if __name__ == "__main__": @@ -262,7 +228,7 @@ if __name__ == "__main__": if not config["stop_after_init"]: # Some module register themselves when they are loaded so we need the # services to be running before loading any registry. - start_services() + openerp.service.start_services() if config['db_name']: for dbname in config['db_name'].split(','): @@ -271,6 +237,16 @@ if __name__ == "__main__": if config["stop_after_init"]: sys.exit(0) + for m in openerp.conf.server_wide_modules: + try: + __import__(m) + # Call any post_load hook. + info = openerp.modules.module.load_information_from_description_file(m) + if info['post_load']: + getattr(sys.modules[m], info['post_load'])() + except Exception: + logging.exception('Failed to load server-wide module `%s`', m) + setup_pid_file() logger = logging.getLogger('server') logger.info('OpenERP server is running, waiting for connections...') diff --git a/openerp/__init__.py b/openerp/__init__.py index 919dc4d9816..7e723c41f9d 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -43,6 +43,7 @@ import tiny_socket import tools import wizard import workflow +import wsgi # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/__init__.py b/openerp/addons/__init__.py index 88a0d113151..1f863eca509 100644 --- a/openerp/addons/__init__.py +++ b/openerp/addons/__init__.py @@ -22,10 +22,15 @@ """ Addons module. -This module only serves to contain OpenERP addons. For the code to -manage those addons, see openerp.modules. This module conveniently -reexports some symbols from openerp.modules. Importing them from here -is deprecated. +This module serves to contain all OpenERP addons, across all configured addons +paths. For the code to manage those addons, see openerp.modules. + +Addons are made available here (i.e. under openerp.addons) after +openerp.tools.config.parse_config() is called (so that the addons paths +are known). + +This module also conveniently reexports some symbols from openerp.modules. +Importing them from here is deprecated. """ diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po index da07b07a1e9..2fa355ab21a 100644 --- a/openerp/addons/base/i18n/da.po +++ b/openerp/addons/base/i18n/da.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" -"PO-Revision-Date: 2010-02-07 05:09+0000\n" -"Last-Translator: Fabien (Open ERP) \n" +"PO-Revision-Date: 2011-09-24 16:40+0000\n" +"Last-Translator: John Mertens Pallesen \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: 2011-09-01 04:40+0000\n" -"X-Generator: Launchpad (build 13827)\n" +"X-Launchpad-Export-Date: 2011-09-25 04:40+0000\n" +"X-Generator: Launchpad (build 14012)\n" #. module: base #: view:ir.filters:0 @@ -141,7 +141,7 @@ msgstr "" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Advarsel!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -196,7 +196,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_res_company_tree #: model:ir.ui.menu,name:base.menu_action_res_company_tree msgid "Company's Structure" -msgstr "" +msgstr "Virksomhedens struktur" #. module: base #: selection:base.language.install,lang:0 @@ -277,7 +277,7 @@ msgstr "" #. module: base #: field:res.partner,credit_limit:0 msgid "Credit Limit" -msgstr "" +msgstr "Kreditgrænse" #. module: base #: field:ir.model.data,date_update:0 @@ -372,7 +372,7 @@ msgstr "Fransk Guyana" #. module: base #: selection:base.language.install,lang:0 msgid "Greek / Ελληνικά" -msgstr "" +msgstr "Græsk / Greek" #. module: base #: selection:base.language.install,lang:0 @@ -483,7 +483,7 @@ msgstr "" #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "Ny bruger" #. module: base #: view:base.language.export:0 @@ -525,7 +525,7 @@ msgstr "Eritrea" #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "Beskrivelse" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule @@ -563,7 +563,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Swedish / svenska" -msgstr "" +msgstr "Svensk / Swedish" #. module: base #: model:res.country,name:base.rs @@ -601,7 +601,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Albanian / Shqip" -msgstr "" +msgstr "Albanien" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity @@ -651,7 +651,7 @@ msgstr "Spanien" #. module: base #: model:ir.ui.menu,name:base.menu_translation_export msgid "Import / Export" -msgstr "" +msgstr "Import / Eksport" #. module: base #: help:ir.actions.act_window,domain:0 @@ -692,7 +692,7 @@ msgstr "Oman" #: model:ir.actions.act_window,name:base.action_payterm_form #: model:ir.model,name:base.model_res_payterm msgid "Payment term" -msgstr "" +msgstr "Betalingsbetingelse" #. module: base #: model:res.country,name:base.nu @@ -859,7 +859,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract msgid "Contracts" -msgstr "" +msgstr "Kontrakter" #. module: base #: selection:base.language.install,lang:0 @@ -884,12 +884,12 @@ msgstr "Niger" #. module: base #: selection:base.language.install,lang:0 msgid "Chinese (HK)" -msgstr "" +msgstr "Kinesisk (HK)" #. module: base #: model:res.country,name:base.ba msgid "Bosnia-Herzegovina" -msgstr "" +msgstr "Bosnien-Hercegovina" #. module: base #: view:base.language.export:0 @@ -931,7 +931,7 @@ msgstr "" #. module: base #: field:base.module.import,module_name:0 msgid "Module Name" -msgstr "" +msgstr "Modulnavn" #. module: base #: model:res.country,name:base.mh @@ -990,7 +990,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_hr_dasboard msgid "Dashboard" -msgstr "" +msgstr "Oversigt" #. module: base #: model:ir.ui.menu,name:base.menu_purchase_root @@ -1011,7 +1011,7 @@ msgstr "Funktioner" #: view:ir.module.module:0 #: report:ir.module.reference.graph:0 msgid "Version" -msgstr "" +msgstr "Version" #. module: base #: view:ir.model.access:0 @@ -1382,7 +1382,7 @@ msgstr "" #. module: base #: model:res.country,name:base.fi msgid "Finland" -msgstr "" +msgstr "Finland" #. module: base #: selection:ir.actions.act_window,view_type:0 @@ -1407,7 +1407,7 @@ msgstr "" #. module: base #: view:base.language.export:0 msgid "https://help.launchpad.net/Translations" -msgstr "" +msgstr "https://help.launchpad.net/Translations" #. module: base #: field:ir.actions.act_window,view_mode:0 @@ -1430,7 +1430,7 @@ msgstr "" #. module: base #: view:res.log:0 msgid "Logs" -msgstr "" +msgstr "Logfiler" #. module: base #: selection:base.language.install,lang:0 @@ -1613,7 +1613,7 @@ msgstr "" #: selection:ir.translation,type:0 #: field:multi_company.default,field_id:0 msgid "Field" -msgstr "" +msgstr "Felt" #. module: base #: view:ir.rule:0 @@ -1623,14 +1623,14 @@ msgstr "" #. module: base #: model:res.country,name:base.fo msgid "Faroe Islands" -msgstr "" +msgstr "Færøerne" #. module: base #: selection:res.config.users,view:0 #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Simplified" -msgstr "" +msgstr "Forenklet" #. module: base #: model:res.country,name:base.st @@ -1640,7 +1640,7 @@ msgstr "" #. module: base #: selection:res.partner.address,type:0 msgid "Invoice" -msgstr "" +msgstr "Faktura" #. module: base #: selection:base.language.install,lang:0 @@ -1650,12 +1650,12 @@ msgstr "" #. module: base #: model:res.country,name:base.bb msgid "Barbados" -msgstr "" +msgstr "Barbados" #. module: base #: model:res.country,name:base.mg msgid "Madagascar" -msgstr "" +msgstr "Madagaskar" #. module: base #: code:addons/base/ir/ir_model.py:96 @@ -1674,12 +1674,12 @@ msgstr "" #: view:ir.ui.menu:0 #: field:ir.ui.menu,name:0 msgid "Menu" -msgstr "" +msgstr "Menu" #. module: base #: field:res.currency,rate:0 msgid "Current Rate" -msgstr "" +msgstr "Aktuel kurs" #. module: base #: field:ir.ui.view.custom,ref_id:0 @@ -1721,7 +1721,7 @@ msgstr "" #. module: base #: model:res.country,name:base.zw msgid "Zimbabwe" -msgstr "" +msgstr "Zimbabwe" #. module: base #: view:base.module.update:0 @@ -1736,7 +1736,7 @@ msgstr "" #. module: base #: field:ir.actions.server,email:0 msgid "Email Address" -msgstr "" +msgstr "E-mail adresse" #. module: base #: selection:base.language.install,lang:0 @@ -1752,12 +1752,12 @@ msgstr "" #. module: base #: model:res.country,name:base.tt msgid "Trinidad and Tobago" -msgstr "" +msgstr "Trinidad og Tobago" #. module: base #: model:res.country,name:base.lv msgid "Latvia" -msgstr "" +msgstr "Letland" #. module: base #: view:ir.values:0 @@ -1782,7 +1782,7 @@ msgstr "" #. module: base #: model:res.country,name:base.py msgid "Paraguay" -msgstr "" +msgstr "Paraguay" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window_close @@ -1797,7 +1797,7 @@ msgstr "" #. module: base #: model:res.country,name:base.lt msgid "Lithuania" -msgstr "" +msgstr "Litauen" #. module: base #: model:ir.actions.act_window,name:base.action_view_partner_clear_ids @@ -1827,12 +1827,12 @@ msgstr "" #. module: base #: model:res.country,name:base.si msgid "Slovenia" -msgstr "" +msgstr "Slovenien" #. module: base #: model:res.country,name:base.pk msgid "Pakistan" -msgstr "" +msgstr "Pakistan" #. module: base #: code:addons/orm.py:1350 @@ -1843,7 +1843,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_email_gateway_form msgid "Messages" -msgstr "" +msgstr "Meddelelser" #. module: base #: code:addons/base/ir/ir_model.py:303 @@ -1855,7 +1855,7 @@ msgstr "" #: code:addons/base/module/wizard/base_update_translations.py:38 #, python-format msgid "Error!" -msgstr "" +msgstr "Fejl!" #. module: base #: view:res.lang:0 @@ -1880,7 +1880,7 @@ msgstr "" #. module: base #: model:res.country,name:base.nz msgid "New Zealand" -msgstr "" +msgstr "New Zealand" #. module: base #: code:addons/orm.py:3366 @@ -1927,7 +1927,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bd msgid "Bangladesh" -msgstr "" +msgstr "Bangladesh" #. module: base #: constraint:res.company:0 @@ -1953,7 +1953,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cu msgid "Cuba" -msgstr "" +msgstr "Cuba" #. module: base #: model:ir.model,name:base.model_res_partner_event @@ -1963,12 +1963,12 @@ msgstr "" #. module: base #: model:res.widget,title:base.facebook_widget msgid "Facebook" -msgstr "" +msgstr "Facebook" #. module: base #: model:res.country,name:base.am msgid "Armenia" -msgstr "" +msgstr "Armenien" #. module: base #: model:ir.actions.act_window,name:base.ir_property_form @@ -1984,14 +1984,14 @@ msgstr "" #. module: base #: model:res.country,name:base.se msgid "Sweden" -msgstr "" +msgstr "Sverige" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Gantt" -msgstr "" +msgstr "Gantt" #. module: base #: view:ir.property:0 @@ -2002,7 +2002,7 @@ msgstr "" #: model:ir.model,name:base.model_res_partner_bank_type #: view:res.partner.bank.type:0 msgid "Bank Account Type" -msgstr "" +msgstr "Bank Kontotype" #. module: base #: field:base.language.export,config_logo:0 @@ -2019,7 +2019,7 @@ msgstr "" #: field:res.config.users,config_logo:0 #: field:res.config.view,config_logo:0 msgid "Image" -msgstr "" +msgstr "Billede" #. module: base #: view:ir.actions.server:0 @@ -2034,7 +2034,7 @@ msgstr "" #. module: base #: model:res.country,name:base.at msgid "Austria" -msgstr "" +msgstr "Østrig" #. module: base #: selection:base.language.install,state:0 @@ -2049,7 +2049,7 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Calendar" -msgstr "" +msgstr "Kalender" #. module: base #: field:res.partner.address,partner_id:0 @@ -2143,7 +2143,7 @@ msgstr "" #. module: base #: field:res.partner.address,birthdate:0 msgid "Birthdate" -msgstr "" +msgstr "Fødselsdato" #. module: base #: model:ir.actions.act_window,name:base.action_partner_title_contact @@ -2183,12 +2183,12 @@ msgstr "" #. module: base #: model:res.country,name:base.uy msgid "Uruguay" -msgstr "" +msgstr "Uruguay" #. module: base #: selection:base.language.install,lang:0 msgid "Finnish / Suomi" -msgstr "" +msgstr "Finsk / Suomi" #. module: base #: field:ir.rule,perm_write:0 @@ -2203,7 +2203,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "German / Deutsch" -msgstr "" +msgstr "Tysk / Deutsch" #. module: base #: help:ir.actions.server,trigger_name:0 @@ -2218,7 +2218,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese / Português" -msgstr "" +msgstr "Portugisisk / Português" #. module: base #: model:res.partner.title,name:base.res_partner_title_sir @@ -2245,7 +2245,7 @@ msgstr "" #. module: base #: model:res.country,name:base.mt msgid "Malta" -msgstr "" +msgstr "Malta" #. module: base #: field:ir.actions.server,fields_lines:0 @@ -2261,7 +2261,7 @@ msgstr "" #: report:ir.module.reference.graph:0 #: field:ir.translation,module:0 msgid "Module" -msgstr "" +msgstr "Modul" #. module: base #: field:ir.attachment,description:0 @@ -2272,7 +2272,7 @@ msgstr "" #: field:res.partner.event,description:0 #: view:res.request:0 msgid "Description" -msgstr "" +msgstr "Beskrivelse" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_instance_form @@ -2283,7 +2283,7 @@ msgstr "" #. module: base #: model:res.country,name:base.aq msgid "Antarctica" -msgstr "" +msgstr "Antarktis" #. module: base #: field:ir.actions.report.xml,auto:0 @@ -2336,7 +2336,7 @@ msgstr "" #. module: base #: view:res.payterm:0 msgid "Payment Term" -msgstr "" +msgstr "Betalingsbetingelse" #. module: base #: selection:res.lang,direction:0 @@ -2417,7 +2417,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ru msgid "Russian Federation" -msgstr "" +msgstr "Rusland" #. module: base #: selection:base.language.install,lang:0 @@ -2427,13 +2427,13 @@ msgstr "" #. module: base #: field:res.company,name:0 msgid "Company Name" -msgstr "" +msgstr "Virksomhedsnavn" #. module: base #: model:ir.actions.act_window,name:base.action_country #: model:ir.ui.menu,name:base.menu_country_partner msgid "Countries" -msgstr "" +msgstr "Lande" #. module: base #: selection:ir.translation,type:0 @@ -2448,7 +2448,7 @@ msgstr "" #. module: base #: view:ir.property:0 msgid "Field Information" -msgstr "" +msgstr "Feltinformation" #. module: base #: view:ir.actions.todo:0 @@ -2464,7 +2464,7 @@ msgstr "" #. module: base #: field:res.partner,vat:0 msgid "VAT" -msgstr "" +msgstr "Moms" #. module: base #: view:res.lang:0 @@ -2545,7 +2545,7 @@ msgstr "" #. module: base #: model:res.country,name:base.me msgid "Montenegro" -msgstr "" +msgstr "Montenegro" #. module: base #: view:ir.cron:0 @@ -2556,7 +2556,7 @@ msgstr "" #: view:res.partner:0 #: field:res.partner,category_id:0 msgid "Categories" -msgstr "" +msgstr "Kategorier" #. module: base #: view:base.language.import:0 @@ -2576,7 +2576,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ly msgid "Libya" -msgstr "" +msgstr "Libyen" #. module: base #: model:res.country,name:base.cf @@ -2586,18 +2586,18 @@ msgstr "" #. module: base #: model:res.country,name:base.li msgid "Liechtenstein" -msgstr "" +msgstr "Liechtenstein" #. module: base #: model:ir.model,name:base.model_partner_sms_send #: view:partner.sms.send:0 msgid "Send SMS" -msgstr "" +msgstr "Send SMS" #. module: base #: field:res.partner,ean13:0 msgid "EAN13" -msgstr "" +msgstr "EAN13" #. module: base #: code:addons/orm.py:1622 @@ -2608,7 +2608,7 @@ msgstr "" #. module: base #: model:res.country,name:base.pt msgid "Portugal" -msgstr "" +msgstr "Portugal" #. module: base #: sql_constraint:ir.model.data:0 @@ -2648,7 +2648,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_res_lang_act_window #: view:res.lang:0 msgid "Languages" -msgstr "" +msgstr "Sprog" #. module: base #: selection:workflow.activity,join_mode:0 @@ -2659,7 +2659,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ec msgid "Ecuador" -msgstr "" +msgstr "Equador" #. module: base #: code:addons/base/module/wizard/base_export_language.py:52 @@ -2676,12 +2676,12 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_partner_form #: view:res.partner:0 msgid "Customers" -msgstr "" +msgstr "Kunder" #. module: base #: model:res.country,name:base.au msgid "Australia" -msgstr "" +msgstr "Australien" #. module: base #: help:res.partner,lang:0 @@ -2693,7 +2693,7 @@ msgstr "" #. module: base #: report:ir.module.reference.graph:0 msgid "Menu :" -msgstr "" +msgstr "Menu:" #. module: base #: selection:ir.model.fields,state:0 @@ -2708,7 +2708,7 @@ msgstr "" #. module: base #: field:ir.actions.todo,restart:0 msgid "Restart" -msgstr "" +msgstr "Genstart" #. module: base #: field:ir.actions.report.xml,report_sxw_content:0 @@ -2776,7 +2776,7 @@ msgstr "" #. module: base #: view:res.company:0 msgid "Header/Footer" -msgstr "" +msgstr "Sidehoved/sidefod" #. module: base #: help:ir.actions.act_window,help:0 @@ -2829,13 +2829,13 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.marketing_menu msgid "Marketing" -msgstr "" +msgstr "Markedsføring" #. module: base #: view:res.partner.bank:0 #: model:res.partner.bank.type,name:base.bank_normal msgid "Bank account" -msgstr "" +msgstr "Bank konto" #. module: base #: selection:base.language.install,lang:0 @@ -2855,17 +2855,17 @@ msgstr "" #. module: base #: field:ir.module.module,license:0 msgid "License" -msgstr "" +msgstr "Licens" #. module: base #: field:ir.attachment,url:0 msgid "Url" -msgstr "" +msgstr "Adresse" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Always" -msgstr "" +msgstr "Altid" #. module: base #: selection:ir.translation,type:0 @@ -2876,7 +2876,7 @@ msgstr "" #: field:ir.actions.server,srcmodel_id:0 #: field:ir.model.fields,model_id:0 msgid "Model" -msgstr "" +msgstr "Model" #. module: base #: view:base.language.install:0 @@ -2911,7 +2911,7 @@ msgstr "" #: field:res.partner.address,zip:0 #: field:res.partner.bank,zip:0 msgid "Zip" -msgstr "" +msgstr "Postnummer" #. module: base #: view:ir.module.module:0 @@ -2946,12 +2946,12 @@ msgstr "" #. module: base #: model:res.country,name:base.bo msgid "Bolivia" -msgstr "" +msgstr "Bolivia" #. module: base #: model:res.country,name:base.gh msgid "Ghana" -msgstr "" +msgstr "Ghana" #. module: base #: field:res.lang,direction:0 @@ -2973,7 +2973,7 @@ msgstr "" #: view:res.groups:0 #: field:res.groups,rule_groups:0 msgid "Rules" -msgstr "" +msgstr "Regler" #. module: base #: code:addons/base/module/module.py:216 @@ -3040,7 +3040,7 @@ msgstr "" #: view:res.config:0 #: view:res.config.installer:0 msgid "Skip" -msgstr "" +msgstr "Spring over" #. module: base #: model:res.country,name:base.ls @@ -3056,7 +3056,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ke msgid "Kenya" -msgstr "" +msgstr "Kenya" #. module: base #: view:res.partner.event:0 @@ -3092,17 +3092,17 @@ msgstr "" #. module: base #: model:res.country,name:base.sm msgid "San Marino" -msgstr "" +msgstr "San Marino" #. module: base #: model:res.country,name:base.bm msgid "Bermuda" -msgstr "" +msgstr "Bermuda" #. module: base #: model:res.country,name:base.pe msgid "Peru" -msgstr "" +msgstr "Peru" #. module: base #: selection:ir.model.fields,on_delete:0 @@ -3162,7 +3162,7 @@ msgstr "" #: view:ir.model.access:0 #: view:ir.rule:0 msgid "Full Access" -msgstr "" +msgstr "Fuld adgang" #. module: base #: view:ir.actions.act_window:0 @@ -3171,7 +3171,7 @@ msgstr "" #: view:ir.model.fields:0 #: model:ir.ui.menu,name:base.menu_security msgid "Security" -msgstr "" +msgstr "Sikkerhed" #. module: base #: model:res.widget,title:base.openerp_favorites_twitter_widget @@ -3181,14 +3181,14 @@ msgstr "" #. module: base #: model:res.country,name:base.za msgid "South Africa" -msgstr "" +msgstr "Sydafrika" #. module: base #: view:ir.module.module:0 #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "Installed" -msgstr "" +msgstr "Installeret" #. module: base #: selection:base.language.install,lang:0 @@ -3204,12 +3204,12 @@ msgstr "" #. module: base #: model:res.country,name:base.sn msgid "Senegal" -msgstr "" +msgstr "Senegal" #. module: base #: model:res.country,name:base.hu msgid "Hungary" -msgstr "" +msgstr "Ungarn" #. module: base #: model:ir.model,name:base.model_res_groups @@ -3219,7 +3219,7 @@ msgstr "" #. module: base #: model:res.country,name:base.br msgid "Brazil" -msgstr "" +msgstr "Brasilien" #. module: base #: view:res.lang:0 @@ -3234,7 +3234,7 @@ msgstr "" #. module: base #: field:ir.sequence,number_next:0 msgid "Next Number" -msgstr "" +msgstr "Næste nummer" #. module: base #: help:workflow.transition,condition:0 @@ -3255,12 +3255,12 @@ msgstr "" #. module: base #: model:res.country,name:base.sy msgid "Syria" -msgstr "" +msgstr "Syrien" #. module: base #: view:res.lang:0 msgid "======================================================" -msgstr "" +msgstr "======================================================" #. module: base #: help:ir.actions.server,mobile:0 @@ -3288,7 +3288,7 @@ msgstr "" #: field:res.partner.event,date:0 #: field:res.request,date_sent:0 msgid "Date" -msgstr "" +msgstr "Dato" #. module: base #: field:ir.actions.report.xml,report_sxw:0 @@ -3298,7 +3298,7 @@ msgstr "" #. module: base #: view:ir.attachment:0 msgid "Data" -msgstr "" +msgstr "Data" #. module: base #: field:ir.ui.menu,parent_id:0 @@ -3364,7 +3364,7 @@ msgstr "" #. module: base #: model:res.country,name:base.mx msgid "Mexico" -msgstr "" +msgstr "Mexico" #. module: base #: model:ir.ui.menu,name:base.menu_base_config_plugins @@ -3384,7 +3384,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ni msgid "Nicaragua" -msgstr "" +msgstr "Nicaragua" #. module: base #: code:addons/orm.py:1046 @@ -3416,7 +3416,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ve msgid "Venezuela" -msgstr "" +msgstr "Venezuela" #. module: base #: view:res.lang:0 @@ -3426,7 +3426,7 @@ msgstr "" #. module: base #: model:res.country,name:base.zm msgid "Zambia" -msgstr "" +msgstr "Zambia" #. module: base #: help:res.partner,user_id:0 @@ -3453,7 +3453,7 @@ msgstr "" #. module: base #: model:res.country,name:base.kz msgid "Kazakhstan" -msgstr "" +msgstr "Kazakstan" #. module: base #: view:res.lang:0 @@ -3536,17 +3536,17 @@ msgstr "" #. module: base #: field:ir.module.module,demo:0 msgid "Demo data" -msgstr "" +msgstr "Demostrations data" #. module: base #: selection:base.language.install,lang:0 msgid "English (UK)" -msgstr "" +msgstr "Engelsk (UK)" #. module: base #: selection:base.language.install,lang:0 msgid "Japanese / 日本語" -msgstr "" +msgstr "Japansk / 日本語" #. module: base #: help:workflow.transition,act_from:0 @@ -3580,7 +3580,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "English (CA)" -msgstr "" +msgstr "Engelsk (CA)" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract @@ -3590,7 +3590,7 @@ msgstr "" #. module: base #: model:res.country,name:base.et msgid "Ethiopia" -msgstr "" +msgstr "Etiopien" #. module: base #: help:res.country.state,code:0 @@ -3631,7 +3631,7 @@ msgstr "" #. module: base #: view:ir.translation:0 msgid "Translation" -msgstr "" +msgstr "Oversættelse" #. module: base #: selection:res.request,state:0 @@ -3689,7 +3689,7 @@ msgstr "" #: field:res.partner.bank,state:0 #: field:res.partner.bank.type.field,bank_type_id:0 msgid "Bank Type" -msgstr "" +msgstr "Bank type" #. module: base #: code:addons/base/res/res_user.py:58 @@ -3757,7 +3757,7 @@ msgstr "" #. module: base #: selection:ir.cron,interval_type:0 msgid "Hours" -msgstr "" +msgstr "Timer" #. module: base #: model:res.country,name:base.gp @@ -3770,7 +3770,7 @@ msgstr "" #: code:addons/base/res/res_lang.py:161 #, python-format msgid "User Error" -msgstr "" +msgstr "Bruger fejl!" #. module: base #: help:workflow.transition,signal:0 @@ -3803,18 +3803,18 @@ msgstr "" #. module: base #: view:ir.attachment:0 msgid "Month" -msgstr "" +msgstr "Måned" #. module: base #: model:res.country,name:base.my msgid "Malaysia" -msgstr "" +msgstr "Malaysien" #. module: base #: view:base.language.install:0 #: model:ir.actions.act_window,name:base.action_view_base_language_install msgid "Load Official Translation" -msgstr "" +msgstr "Hent den officielle oversættelse" #. module: base #: model:ir.model,name:base.model_res_request_history @@ -3893,7 +3893,7 @@ msgstr "" #. module: base #: view:res.currency:0 msgid "Price Accuracy" -msgstr "" +msgstr "Pris nøjagtighed" #. module: base #: selection:base.language.install,lang:0 @@ -3909,7 +3909,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "French / Français" -msgstr "" +msgstr "Fransk / Français" #. module: base #: code:addons/orm.py:1049 @@ -3971,7 +3971,7 @@ msgstr "" #. module: base #: model:res.country,name:base.fj msgid "Fiji" -msgstr "" +msgstr "Fiji" #. module: base #: field:ir.model.fields,size:0 @@ -3981,12 +3981,12 @@ msgstr "" #. module: base #: model:res.country,name:base.sd msgid "Sudan" -msgstr "" +msgstr "Sudan" #. module: base #: model:res.country,name:base.fm msgid "Micronesia" -msgstr "" +msgstr "Mikronesien" #. module: base #: view:res.request.history:0 @@ -3998,7 +3998,7 @@ msgstr "" #: field:ir.module.module,menus_by_module:0 #: view:res.groups:0 msgid "Menus" -msgstr "" +msgstr "Menuer" #. module: base #: selection:base.language.install,lang:0 @@ -4008,7 +4008,7 @@ msgstr "" #. module: base #: model:res.country,name:base.il msgid "Israel" -msgstr "" +msgstr "Israel" #. module: base #: model:ir.actions.wizard,name:base.wizard_server_action_create @@ -4025,7 +4025,7 @@ msgstr "" #. module: base #: field:res.lang,time_format:0 msgid "Time Format" -msgstr "" +msgstr "Tidsformat" #. module: base #: view:ir.module.module:0 @@ -4045,7 +4045,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_management #: model:ir.ui.menu,name:base.menu_module_tree msgid "Modules" -msgstr "" +msgstr "Moduler" #. module: base #: view:workflow.activity:0 @@ -4071,12 +4071,12 @@ msgstr "" #: view:res.bank:0 #: field:res.partner,bank_ids:0 msgid "Banks" -msgstr "" +msgstr "Banker" #. module: base #: view:res.log:0 msgid "Unread" -msgstr "" +msgstr "Ulæst" #. module: base #: field:ir.cron,doall:0 @@ -4102,7 +4102,7 @@ msgstr "" #. module: base #: model:res.country,name:base.uk msgid "United Kingdom" -msgstr "" +msgstr "Storbritannien" #. module: base #: view:res.config:0 @@ -4124,7 +4124,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bw msgid "Botswana" -msgstr "" +msgstr "Botswana" #. module: base #: model:ir.actions.act_window,name:base.action_partner_title_partner @@ -4213,7 +4213,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_main_pm msgid "Project" -msgstr "" +msgstr "Projekt" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 @@ -4274,7 +4274,7 @@ msgstr "" #. module: base #: field:res.partner,employee:0 msgid "Employee" -msgstr "" +msgstr "Ansat" #. module: base #: field:ir.model.access,perm_create:0 @@ -4289,7 +4289,7 @@ msgstr "" #. module: base #: field:ir.actions.server,copy_object:0 msgid "Copy Of" -msgstr "" +msgstr "Kopi af" #. module: base #: field:ir.model,osv_memory:0 @@ -4327,7 +4327,7 @@ msgstr "" #: view:ir.model:0 #: field:ir.model.fields,ttype:0 msgid "Field Type" -msgstr "" +msgstr "Felttype" #. module: base #: field:res.country.state,code:0 @@ -4353,14 +4353,14 @@ msgstr "" #. module: base #: model:res.country,name:base.vn msgid "Vietnam" -msgstr "" +msgstr "Vietnam" #. module: base #: field:res.config.users,signature:0 #: view:res.users:0 #: field:res.users,signature:0 msgid "Signature" -msgstr "" +msgstr "Signatur" #. module: base #: code:addons/fields.py:456 @@ -4372,7 +4372,7 @@ msgstr "" #: code:addons/fields.py:664 #, python-format msgid "Not Implemented" -msgstr "" +msgstr "Ikke implementeret" #. module: base #: model:ir.model,name:base.model_res_widget_user @@ -4382,7 +4382,7 @@ msgstr "" #. module: base #: field:res.partner.category,complete_name:0 msgid "Full Name" -msgstr "" +msgstr "Fulde navn" #. module: base #: view:base.module.configuration:0 @@ -4427,7 +4427,7 @@ msgstr "" #: view:res.partner:0 #: field:res.partner,user_id:0 msgid "Salesman" -msgstr "" +msgstr "Sælger" #. module: base #: field:res.partner,address:0 @@ -4462,7 +4462,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cz msgid "Czech Republic" -msgstr "" +msgstr "Tjekkiet" #. module: base #: view:res.widget.wizard:0 @@ -4527,12 +4527,12 @@ msgstr "" #. module: base #: model:res.country,name:base.na msgid "Namibia" -msgstr "" +msgstr "Namibia" #. module: base #: model:res.country,name:base.mn msgid "Mongolia" -msgstr "" +msgstr "Mongoliet" #. module: base #: view:ir.module.module:0 @@ -4547,7 +4547,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bi msgid "Burundi" -msgstr "" +msgstr "Burundi" #. module: base #: view:base.language.install:0 @@ -4568,12 +4568,12 @@ msgstr "" #. module: base #: view:res.log:0 msgid "My Logs" -msgstr "" +msgstr "Mine logfiler" #. module: base #: model:res.country,name:base.bt msgid "Bhutan" -msgstr "" +msgstr "Bhutan" #. module: base #: help:ir.sequence,number_next:0 @@ -4603,7 +4603,7 @@ msgstr "" #. module: base #: field:base.language.export,format:0 msgid "File Format" -msgstr "" +msgstr "Filformat" #. module: base #: field:res.lang,iso_code:0 @@ -4619,7 +4619,7 @@ msgstr "" #: view:res.log:0 #: field:res.log,read:0 msgid "Read" -msgstr "" +msgstr "Læst" #. module: base #: sql_constraint:res.country:0 @@ -4649,7 +4649,7 @@ msgstr "" #: field:res.config.users,password:0 #: field:res.users,password:0 msgid "Password" -msgstr "" +msgstr "Adgangskode" #. module: base #: model:ir.actions.act_window,name:base.action_model_fields @@ -4659,12 +4659,12 @@ msgstr "" #: view:ir.model.fields:0 #: model:ir.ui.menu,name:base.ir_model_model_fields msgid "Fields" -msgstr "" +msgstr "Felter" #. module: base #: model:ir.actions.act_window,name:base.action_partner_employee_form msgid "Employees" -msgstr "" +msgstr "Ansatte" #. module: base #: help:res.log,read:0 @@ -4705,12 +4705,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_partner_address_form #: model:ir.ui.menu,name:base.menu_partner_address_form msgid "Addresses" -msgstr "" +msgstr "Adresser" #. module: base #: model:res.country,name:base.mm msgid "Myanmar" -msgstr "" +msgstr "Myanmar (Burma)" #. module: base #: selection:base.language.install,lang:0 @@ -4722,12 +4722,12 @@ msgstr "" #: field:res.partner.address,street:0 #: field:res.partner.bank,street:0 msgid "Street" -msgstr "" +msgstr "Vej" #. module: base #: model:res.country,name:base.yu msgid "Yugoslavia" -msgstr "" +msgstr "Jugoslavien" #. module: base #: field:ir.model.data,name:0 @@ -4737,12 +4737,12 @@ msgstr "" #. module: base #: model:res.country,name:base.ca msgid "Canada" -msgstr "" +msgstr "Canada" #. module: base #: selection:ir.module.module.dependency,state:0 msgid "Unknown" -msgstr "" +msgstr "Ukendt" #. module: base #: model:ir.actions.act_window,name:base.action_res_users_my @@ -4758,17 +4758,17 @@ msgstr "" #. module: base #: field:partner.sms.send,text:0 msgid "SMS Message" -msgstr "" +msgstr "SMS besked" #. module: base #: model:res.country,name:base.cm msgid "Cameroon" -msgstr "" +msgstr "Cameroun" #. module: base #: model:res.country,name:base.bf msgid "Burkina Faso" -msgstr "" +msgstr "Burkina Faso" #. module: base #: selection:ir.actions.todo,state:0 @@ -4835,7 +4835,7 @@ msgstr "" #. module: base #: report:ir.module.reference.graph:0 msgid "1cm 28cm 20cm 28cm" -msgstr "" +msgstr "1cm 28cm 20cm 28cm" #. module: base #: field:ir.module.module,maintainer:0 @@ -4855,7 +4855,7 @@ msgstr "" #. module: base #: model:ir.actions.report.xml,name:base.res_partner_address_report msgid "Labels" -msgstr "" +msgstr "Etiketter" #. module: base #: field:partner.wizard.spam,email_from:0 @@ -4945,7 +4945,7 @@ msgstr "" #. module: base #: model:res.country,name:base.us msgid "United States" -msgstr "" +msgstr "USA" #. module: base #: view:ir.module.module:0 @@ -4978,7 +4978,7 @@ msgstr "" #. module: base #: model:res.country,name:base.kw msgid "Kuwait" -msgstr "" +msgstr "Kuwait" #. module: base #: field:workflow.workitem,inst_id:0 @@ -5001,7 +5001,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ng msgid "Nigeria" -msgstr "" +msgstr "Nigeria" #. module: base #: code:addons/base/ir/ir_model.py:250 @@ -5012,7 +5012,7 @@ msgstr "" #. module: base #: model:ir.actions.act_window,name:base.action_partner_sms_send msgid "SMS Send" -msgstr "" +msgstr "SMS sendt" #. module: base #: field:res.company,user_ids:0 @@ -5037,7 +5037,7 @@ msgstr "" #. module: base #: model:res.country,name:base.hk msgid "Hong Kong" -msgstr "" +msgstr "Hong Kong" #. module: base #: help:ir.actions.server,name:0 @@ -5059,12 +5059,12 @@ msgstr "" #. module: base #: model:res.country,name:base.ph msgid "Philippines" -msgstr "" +msgstr "Filippinerne" #. module: base #: model:res.country,name:base.ma msgid "Morocco" -msgstr "" +msgstr "Marokko" #. module: base #: view:res.lang:0 @@ -5084,7 +5084,7 @@ msgstr "" #. module: base #: model:res.country,name:base.td msgid "Chad" -msgstr "" +msgstr "Tchad" #. module: base #: model:ir.model,name:base.model_workflow_transition @@ -5131,7 +5131,7 @@ msgstr "" #. module: base #: model:res.country,name:base.np msgid "Nepal" -msgstr "" +msgstr "Nepal" #. module: base #: code:addons/orm.py:2307 @@ -5233,12 +5233,12 @@ msgstr "" #: field:base.language.export,data:0 #: field:base.language.import,data:0 msgid "File" -msgstr "" +msgstr "Fil" #. module: base #: view:res.config.users:0 msgid "Add User" -msgstr "" +msgstr "Tilføj bruger" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_install @@ -5261,7 +5261,7 @@ msgstr "" #: field:res.partner.address,is_supplier_add:0 #: model:res.partner.category,name:base.res_partner_category_8 msgid "Supplier" -msgstr "" +msgstr "Leverandør" #. module: base #: view:ir.actions.server:0 @@ -5349,7 +5349,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ae msgid "United Arab Emirates" -msgstr "" +msgstr "De Forenede Arabiske Emirater" #. module: base #: model:ir.ui.menu,name:base.menu_crm_case_job_req_main @@ -5373,7 +5373,7 @@ msgstr "" #: view:ir.rule:0 #: field:ir.rule,global:0 msgid "Global" -msgstr "" +msgstr "Globalt" #. module: base #: model:res.country,name:base.mp @@ -5427,7 +5427,7 @@ msgstr "" #: view:ir.translation:0 #: model:ir.ui.menu,name:base.menu_translation msgid "Translations" -msgstr "" +msgstr "Oversættelser" #. module: base #: field:ir.sequence,padding:0 @@ -5437,12 +5437,12 @@ msgstr "" #. module: base #: view:ir.actions.report.xml:0 msgid "Report" -msgstr "" +msgstr "Rapport" #. module: base #: model:res.country,name:base.ua msgid "Ukraine" -msgstr "" +msgstr "Ukraine" #. module: base #: model:res.country,name:base.to @@ -5558,12 +5558,12 @@ msgstr "" #. module: base #: model:res.country,name:base.dz msgid "Algeria" -msgstr "" +msgstr "Algeriet" #. module: base #: model:res.country,name:base.be msgid "Belgium" -msgstr "" +msgstr "Belgien" #. module: base #: model:ir.model,name:base.model_osv_memory_autovacuum @@ -5579,12 +5579,12 @@ msgstr "" #: field:res.partner,lang:0 #: field:res.users,context_lang:0 msgid "Language" -msgstr "" +msgstr "Sprog" #. module: base #: model:res.country,name:base.gm msgid "Gambia" -msgstr "" +msgstr "Gambia" #. module: base #: model:ir.actions.act_window,name:base.action_res_company_form @@ -5596,7 +5596,7 @@ msgstr "" #: view:res.users:0 #: field:res.users,company_ids:0 msgid "Companies" -msgstr "" +msgstr "Virksomheder" #. module: base #: view:res.lang:0 @@ -5661,12 +5661,12 @@ msgstr "" #. module: base #: selection:base.language.export,format:0 msgid "PO File" -msgstr "" +msgstr "PO fil" #. module: base #: model:res.country,name:base.nt msgid "Neutral Zone" -msgstr "" +msgstr "Neutral Zone" #. module: base #: selection:base.language.install,lang:0 @@ -5686,7 +5686,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_9 msgid "Components Supplier" -msgstr "" +msgstr "Komponent leverandør" #. module: base #: model:ir.actions.act_window,name:base.action_res_users @@ -5697,7 +5697,7 @@ msgstr "" #: field:res.groups,users:0 #: view:res.users:0 msgid "Users" -msgstr "" +msgstr "Brugere" #. module: base #: field:ir.module.module,published_version:0 @@ -5707,7 +5707,7 @@ msgstr "" #. module: base #: model:res.country,name:base.is msgid "Iceland" -msgstr "" +msgstr "Island" #. module: base #: model:ir.actions.act_window,name:base.ir_action_window @@ -5728,7 +5728,7 @@ msgstr "" #. module: base #: model:res.country,name:base.de msgid "Germany" -msgstr "" +msgstr "Tyskland" #. module: base #: view:ir.sequence:0 @@ -5738,7 +5738,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_14 msgid "Bad customers" -msgstr "" +msgstr "Dårlige kunder" #. module: base #: report:ir.module.reference.graph:0 @@ -5748,7 +5748,7 @@ msgstr "" #. module: base #: model:res.country,name:base.gy msgid "Guyana" -msgstr "" +msgstr "Guyana" #. module: base #: help:ir.actions.act_window,view_type:0 @@ -5771,7 +5771,7 @@ msgstr "" #. module: base #: model:res.country,name:base.hn msgid "Honduras" -msgstr "" +msgstr "Honduras" #. module: base #: help:res.config.users,menu_tips:0 @@ -5783,7 +5783,7 @@ msgstr "" #. module: base #: model:res.country,name:base.eg msgid "Egypt" -msgstr "" +msgstr "Ægypten" #. module: base #: field:ir.rule,perm_read:0 @@ -5805,7 +5805,7 @@ msgstr "" #. module: base #: field:base.language.import,name:0 msgid "Language Name" -msgstr "" +msgstr "Sprog navn" #. module: base #: selection:ir.property,type:0 @@ -5886,7 +5886,7 @@ msgstr "" #: field:res.partner,comment:0 #: model:res.widget,title:base.note_widget msgid "Notes" -msgstr "" +msgstr "Noter" #. module: base #: field:ir.config_parameter,value:0 @@ -5911,7 +5911,7 @@ msgstr "" #: field:res.bank,code:0 #: field:res.partner.bank.type,code:0 msgid "Code" -msgstr "" +msgstr "Kode" #. module: base #: model:ir.model,name:base.model_res_config_installer @@ -5921,17 +5921,17 @@ msgstr "" #. module: base #: model:res.country,name:base.mc msgid "Monaco" -msgstr "" +msgstr "Monaco" #. module: base #: selection:ir.cron,interval_type:0 msgid "Minutes" -msgstr "" +msgstr "Minutter" #. module: base #: selection:ir.translation,type:0 msgid "Help" -msgstr "" +msgstr "Hjælp" #. module: base #: help:res.config.users,menu_id:0 @@ -5986,7 +5986,7 @@ msgstr "" #. module: base #: model:res.country,name:base.fr msgid "France" -msgstr "" +msgstr "Frankrig" #. module: base #: model:ir.model,name:base.model_res_log @@ -6008,7 +6008,7 @@ msgstr "" #. module: base #: selection:ir.cron,interval_type:0 msgid "Weeks" -msgstr "" +msgstr "Uger" #. module: base #: model:res.country,name:base.af @@ -6019,7 +6019,7 @@ msgstr "" #: code:addons/base/module/wizard/base_module_import.py:67 #, python-format msgid "Error !" -msgstr "" +msgstr "Fejl!" #. module: base #: model:res.partner.bank.type.field,name:base.bank_normal_field_contry @@ -6047,7 +6047,7 @@ msgstr "" #: field:res.bank,fax:0 #: field:res.partner.address,fax:0 msgid "Fax" -msgstr "" +msgstr "Fax" #. module: base #: field:res.lang,thousands_sep:0 @@ -6094,7 +6094,7 @@ msgstr "" #. module: base #: model:res.country,name:base.pa msgid "Panama" -msgstr "" +msgstr "Panama" #. module: base #: model:res.partner.title,name:base.res_partner_title_ltd @@ -6116,7 +6116,7 @@ msgstr "" #. module: base #: model:res.country,name:base.gi msgid "Gibraltar" -msgstr "" +msgstr "Gibraltar" #. module: base #: field:ir.actions.report.xml,report_name:0 @@ -6144,7 +6144,7 @@ msgstr "" #: field:res.config.users,name:0 #: field:res.users,name:0 msgid "User Name" -msgstr "" +msgstr "Brugernavn" #. module: base #: view:ir.sequence:0 @@ -6173,7 +6173,7 @@ msgstr "" #. module: base #: selection:ir.cron,interval_type:0 msgid "Months" -msgstr "" +msgstr "Måneder" #. module: base #: field:ir.actions.act_window,search_view:0 @@ -6198,7 +6198,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_sale_config_sales #: model:ir.ui.menu,name:base.menu_sales msgid "Sales" -msgstr "" +msgstr "Salg" #. module: base #: field:ir.actions.server,child_ids:0 @@ -6234,17 +6234,17 @@ msgstr "" #: field:res.partner.address,city:0 #: field:res.partner.bank,city:0 msgid "City" -msgstr "" +msgstr "By" #. module: base #: model:res.country,name:base.qa msgid "Qatar" -msgstr "" +msgstr "Qatar" #. module: base #: model:res.country,name:base.it msgid "Italy" -msgstr "" +msgstr "Italien" #. module: base #: view:ir.actions.todo:0 @@ -6262,12 +6262,12 @@ msgstr "" #: field:res.partner,email:0 #: field:res.users,email:0 msgid "E-mail" -msgstr "" +msgstr "E-mail" #. module: base #: selection:ir.module.module,license:0 msgid "GPL-3 or later version" -msgstr "" +msgstr "GPL-3 eller senere version" #. module: base #: field:workflow.activity,action:0 @@ -6277,7 +6277,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "English (US)" -msgstr "" +msgstr "Engelsk (US)" #. module: base #: model:ir.actions.act_window,name:base.action_model_data @@ -6313,12 +6313,12 @@ msgstr "" #: view:res.users:0 #: field:res.users,address_id:0 msgid "Address" -msgstr "" +msgstr "Adresse" #. module: base #: field:ir.module.module,latest_version:0 msgid "Installed version" -msgstr "" +msgstr "Installeret version" #. module: base #: selection:base.language.install,lang:0 @@ -6328,7 +6328,7 @@ msgstr "" #. module: base #: model:res.country,name:base.mr msgid "Mauritania" -msgstr "" +msgstr "Mauretanien" #. module: base #: model:ir.model,name:base.model_ir_translation @@ -6344,7 +6344,7 @@ msgstr "" #: view:workflow.activity:0 #: field:workflow.workitem,act_id:0 msgid "Activity" -msgstr "" +msgstr "Aktivitet" #. module: base #: view:res.partner:0 @@ -6370,7 +6370,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cg msgid "Congo" -msgstr "" +msgstr "Congo" #. module: base #: view:res.lang:0 @@ -6385,7 +6385,7 @@ msgstr "Standardværdi" #. module: base #: model:ir.ui.menu,name:base.menu_tools msgid "Tools" -msgstr "" +msgstr "Værktøj" #. module: base #: model:res.country,name:base.kn @@ -6427,7 +6427,7 @@ msgstr "" #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "Not Installed" -msgstr "" +msgstr "Ikke installeret" #. module: base #: view:workflow.activity:0 @@ -6438,7 +6438,7 @@ msgstr "" #. module: base #: field:ir.ui.menu,icon:0 msgid "Icon" -msgstr "" +msgstr "Ikon" #. module: base #: help:ir.model.fields,model_id:0 @@ -6466,12 +6466,12 @@ msgstr "" #. module: base #: model:res.country,name:base.ye msgid "Yemen" -msgstr "" +msgstr "Yemen" #. module: base #: selection:workflow.activity,split_mode:0 msgid "Or" -msgstr "" +msgstr "Eller" #. module: base #: model:ir.actions.act_window,name:base.res_log_act_window @@ -6482,12 +6482,12 @@ msgstr "" #. module: base #: model:res.country,name:base.al msgid "Albania" -msgstr "" +msgstr "Albanien" #. module: base #: model:res.country,name:base.ws msgid "Samoa" -msgstr "" +msgstr "Samoa" #. module: base #: code:addons/base/res/res_lang.py:161 @@ -6555,14 +6555,14 @@ msgstr "" #. module: base #: model:res.country,name:base.la msgid "Laos" -msgstr "" +msgstr "Laos" #. module: base #: selection:ir.actions.server,state:0 #: field:res.config.users,user_email:0 #: field:res.users,user_email:0 msgid "Email" -msgstr "" +msgstr "E-mail" #. module: base #: field:res.config.users,action_id:0 @@ -6593,7 +6593,7 @@ msgstr "" #. module: base #: model:res.country,name:base.tg msgid "Togo" -msgstr "" +msgstr "Togo" #. module: base #: selection:ir.module.module,license:0 @@ -6603,7 +6603,7 @@ msgstr "" #. module: base #: selection:workflow.activity,kind:0 msgid "Stop All" -msgstr "" +msgstr "Stop alle" #. module: base #: code:addons/orm.py:412 @@ -6644,7 +6644,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ro msgid "Romania" -msgstr "" +msgstr "Rumænien" #. module: base #: help:ir.cron,doall:0 @@ -6678,7 +6678,7 @@ msgstr "" #: field:res.config.users,context_tz:0 #: field:res.users,context_tz:0 msgid "Timezone" -msgstr "" +msgstr "Tidszone" #. module: base #: model:ir.model,name:base.model_ir_actions_report_xml @@ -6731,7 +6731,7 @@ msgstr "" #. module: base #: model:res.country,name:base.by msgid "Belarus" -msgstr "" +msgstr "Hviderusland" #. module: base #: field:ir.actions.act_window,name:0 @@ -6755,7 +6755,7 @@ msgstr "" #. module: base #: selection:res.request,priority:0 msgid "Normal" -msgstr "" +msgstr "Normal" #. module: base #: field:res.bank,street2:0 @@ -6786,12 +6786,12 @@ msgstr "" #: view:res.users:0 #: field:res.widget.user,user_id:0 msgid "User" -msgstr "" +msgstr "Bruger" #. module: base #: model:res.country,name:base.pr msgid "Puerto Rico" -msgstr "" +msgstr "Puerto Rico" #. module: base #: view:ir.actions.act_window:0 @@ -6816,7 +6816,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ch msgid "Switzerland" -msgstr "" +msgstr "Schweiz" #. module: base #: model:res.country,name:base.gd @@ -6841,7 +6841,7 @@ msgstr "" #. module: base #: view:base.language.install:0 msgid "Load" -msgstr "" +msgstr "Indlæs" #. module: base #: help:res.config.users,name:0 @@ -6870,7 +6870,7 @@ msgstr "" #. module: base #: model:res.country,name:base.so msgid "Somalia" -msgstr "" +msgstr "Somalia" #. module: base #: selection:publisher_warranty.contract,state:0 @@ -6892,7 +6892,7 @@ msgstr "" #: field:res.request,act_to:0 #: field:res.request.history,act_to:0 msgid "To" -msgstr "" +msgstr "Til" #. module: base #: view:ir.cron:0 @@ -6909,12 +6909,12 @@ msgstr "" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 2" -msgstr "" +msgstr "GPL Version 2" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 3" -msgstr "" +msgstr "GPL Version 3" #. module: base #: code:addons/orm.py:836 @@ -6939,7 +6939,7 @@ msgstr "" #: field:res.partner.address,is_customer_add:0 #: model:res.partner.category,name:base.res_partner_category_0 msgid "Customer" -msgstr "" +msgstr "Kunde" #. module: base #: selection:base.language.install,lang:0 @@ -6949,7 +6949,7 @@ msgstr "" #. module: base #: field:ir.module.module,shortdesc:0 msgid "Short Description" -msgstr "" +msgstr "Kort beskrivelse" #. module: base #: field:ir.actions.act_window,context:0 @@ -6975,7 +6975,7 @@ msgstr "" #. module: base #: field:res.request.history,date_sent:0 msgid "Date sent" -msgstr "" +msgstr "Dato sendt" #. module: base #: view:ir.sequence:0 @@ -7002,12 +7002,12 @@ msgstr "" #. module: base #: model:res.country,name:base.tn msgid "Tunisia" -msgstr "" +msgstr "Tunesien" #. module: base #: model:ir.ui.menu,name:base.menu_mrp_root msgid "Manufacturing" -msgstr "" +msgstr "Produktion" #. module: base #: model:res.country,name:base.km @@ -7153,12 +7153,12 @@ msgstr "" #: code:addons/base/res/res_user.py:580 #, python-format msgid "Warning !" -msgstr "" +msgstr "Advarsel!" #. module: base #: model:res.widget,title:base.google_maps_widget msgid "Google Maps" -msgstr "" +msgstr "Google Maps" #. module: base #: model:ir.ui.menu,name:base.menu_base_config @@ -7210,17 +7210,17 @@ msgstr "" #. module: base #: model:res.country,name:base.tr msgid "Turkey" -msgstr "" +msgstr "Tyrkiet" #. module: base #: model:res.country,name:base.fk msgid "Falkland Islands" -msgstr "" +msgstr "Falklandsøerne" #. module: base #: model:res.country,name:base.lb msgid "Lebanon" -msgstr "" +msgstr "Libanon" #. module: base #: view:ir.actions.report.xml:0 @@ -7263,7 +7263,7 @@ msgstr "" #: view:base.language.install:0 #: model:ir.ui.menu,name:base.menu_view_base_language_install msgid "Load an Official Translation" -msgstr "" +msgstr "Hent en officiel oversættelse" #. module: base #: view:res.currency:0 @@ -7375,7 +7375,7 @@ msgstr "" #: view:ir.module.module:0 #: field:ir.module.module,category_id:0 msgid "Category" -msgstr "" +msgstr "Kategori" #. module: base #: view:ir.attachment:0 @@ -7388,17 +7388,17 @@ msgstr "" #: field:ir.actions.server,sms:0 #: selection:ir.actions.server,state:0 msgid "SMS" -msgstr "" +msgstr "SMS" #. module: base #: model:res.country,name:base.cr msgid "Costa Rica" -msgstr "" +msgstr "Costa Rica" #. module: base #: view:workflow.activity:0 msgid "Conditions" -msgstr "" +msgstr "Betingelser" #. module: base #: model:ir.actions.act_window,name:base.action_partner_other_form @@ -7410,7 +7410,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_action_currency_form #: view:res.currency:0 msgid "Currencies" -msgstr "" +msgstr "Valutaer" #. module: base #: sql_constraint:res.groups:0 @@ -7435,12 +7435,12 @@ msgstr "" #. module: base #: model:res.country,name:base.dk msgid "Denmark" -msgstr "" +msgstr "Danmark" #. module: base #: field:res.country,code:0 msgid "Country Code" -msgstr "" +msgstr "Lande kode" #. module: base #: model:ir.model,name:base.model_workflow_instance @@ -7485,7 +7485,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ee msgid "Estonia" -msgstr "" +msgstr "Estland" #. module: base #: model:ir.ui.menu,name:base.dashboard @@ -7506,7 +7506,7 @@ msgstr "" #. module: base #: model:res.country,name:base.nl msgid "Netherlands" -msgstr "" +msgstr "Holland" #. module: base #: model:ir.ui.menu,name:base.next_id_4 @@ -7541,7 +7541,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_emails #: model:ir.ui.menu,name:base.menu_mail_gateway msgid "Emails" -msgstr "" +msgstr "E-mails" #. module: base #: model:res.country,name:base.cd @@ -7563,7 +7563,7 @@ msgstr "" #. module: base #: model:res.country,name:base.jp msgid "Japan" -msgstr "" +msgstr "Japan" #. module: base #: field:ir.cron,numbercall:0 @@ -7591,7 +7591,7 @@ msgstr "" #. module: base #: model:res.country,name:base.gr msgid "Greece" -msgstr "" +msgstr "Grækenland" #. module: base #: field:res.request,trigger_date:0 @@ -7643,7 +7643,7 @@ msgstr "" #: view:ir.model.fields:0 #: field:ir.model.fields,translate:0 msgid "Translate" -msgstr "" +msgstr "Oversæt" #. module: base #: field:res.request.history,body:0 @@ -7653,7 +7653,7 @@ msgstr "" #. module: base #: view:partner.wizard.spam:0 msgid "Send Email" -msgstr "" +msgstr "Send e-mail" #. module: base #: field:res.config.users,menu_id:0 @@ -7692,7 +7692,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_procurement_management_supplier_name #: view:res.partner:0 msgid "Suppliers" -msgstr "" +msgstr "Leverandører" #. module: base #: view:publisher_warranty.contract.wizard:0 @@ -7729,12 +7729,12 @@ msgstr "" #. module: base #: model:res.country,name:base.gl msgid "Greenland" -msgstr "" +msgstr "Grønland" #. module: base #: field:res.partner.bank,acc_number:0 msgid "Account Number" -msgstr "" +msgstr "Kontonummer" #. module: base #: view:res.lang:0 @@ -7749,7 +7749,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cy msgid "Cyprus" -msgstr "" +msgstr "Cypern" #. module: base #: view:base.module.import:0 @@ -7764,13 +7764,13 @@ msgstr "" #: field:partner.wizard.spam,subject:0 #: field:res.request,name:0 msgid "Subject" -msgstr "" +msgstr "Emne" #. module: base #: field:res.request,act_from:0 #: field:res.request.history,act_from:0 msgid "From" -msgstr "" +msgstr "Fra" #. module: base #: view:res.users:0 @@ -7811,7 +7811,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cn msgid "China" -msgstr "" +msgstr "Kina" #. module: base #: code:addons/base/res/res_user.py:516 @@ -7841,7 +7841,7 @@ msgstr "" #. module: base #: model:res.country,name:base.id msgid "Indonesia" -msgstr "" +msgstr "Indonesien" #. module: base #: view:base.update.translations:0 @@ -7861,7 +7861,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bg msgid "Bulgaria" -msgstr "" +msgstr "Bulgarien" #. module: base #: view:publisher_warranty.contract.wizard:0 @@ -7871,7 +7871,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ao msgid "Angola" -msgstr "" +msgstr "Angola" #. module: base #: model:res.country,name:base.tf @@ -7886,7 +7886,7 @@ msgstr "" #: field:res.currency,name:0 #: field:res.currency.rate,currency_id:0 msgid "Currency" -msgstr "" +msgstr "Valuta" #. module: base #: field:res.partner.canal,name:0 @@ -7917,7 +7917,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_administration msgid "Administration" -msgstr "" +msgstr "Administration" #. module: base #: view:base.module.update:0 @@ -7971,12 +7971,12 @@ msgstr "" #. module: base #: model:res.country,name:base.ki msgid "Kiribati" -msgstr "" +msgstr "Kiribati" #. module: base #: model:res.country,name:base.iq msgid "Iraq" -msgstr "" +msgstr "Irak" #. module: base #: model:ir.ui.menu,name:base.menu_association @@ -7986,14 +7986,14 @@ msgstr "" #. module: base #: model:res.country,name:base.cl msgid "Chile" -msgstr "" +msgstr "Chile" #. module: base #: model:ir.ui.menu,name:base.menu_address_book #: model:ir.ui.menu,name:base.menu_config_address_book #: model:ir.ui.menu,name:base.menu_procurement_management_supplier msgid "Address Book" -msgstr "" +msgstr "Adressebog" #. module: base #: model:ir.model,name:base.model_ir_sequence_type @@ -8003,12 +8003,12 @@ msgstr "" #. module: base #: selection:base.language.export,format:0 msgid "CSV File" -msgstr "" +msgstr "CSV fil" #. module: base #: field:res.company,account_no:0 msgid "Account No." -msgstr "" +msgstr "Konto nummer" #. module: base #: code:addons/base/res/res_lang.py:157 @@ -8034,7 +8034,7 @@ msgstr "" #. module: base #: model:res.country,name:base.dj msgid "Djibouti" -msgstr "" +msgstr "Djibouti" #. module: base #: field:ir.translation,value:0 @@ -8044,7 +8044,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ag msgid "Antigua and Barbuda" -msgstr "" +msgstr "Antigua og Barbuda" #. module: base #: code:addons/orm.py:3166 @@ -8057,7 +8057,7 @@ msgstr "" #. module: base #: model:res.country,name:base.zr msgid "Zaire" -msgstr "" +msgstr "Zaire" #. module: base #: field:ir.model.data,res_id:0 @@ -8091,7 +8091,7 @@ msgstr "" #. module: base #: view:res.request:0 msgid "Reply" -msgstr "" +msgstr "Svar" #. module: base #: selection:base.language.install,lang:0 @@ -8166,7 +8166,7 @@ msgstr "" #. module: base #: model:res.country,name:base.hr msgid "Croatia" -msgstr "" +msgstr "Kroatien" #. module: base #: help:res.bank,bic:0 @@ -8176,7 +8176,7 @@ msgstr "" #. module: base #: model:res.country,name:base.tm msgid "Turkmenistan" -msgstr "" +msgstr "Turkmenistan" #. module: base #: code:addons/base/ir/ir_actions.py:597 @@ -8208,7 +8208,7 @@ msgstr "" #: code:addons/orm.py:3199 #, python-format msgid "Error" -msgstr "" +msgstr "Fejl!" #. module: base #: model:res.country,name:base.pm @@ -8239,12 +8239,12 @@ msgstr "" #. module: base #: model:res.country,name:base.tz msgid "Tanzania" -msgstr "" +msgstr "Tanzania" #. module: base #: selection:base.language.install,lang:0 msgid "Danish / Dansk" -msgstr "" +msgstr "Danish / Dansk" #. module: base #: selection:ir.model.fields,select_level:0 @@ -8309,7 +8309,7 @@ msgstr "" #. module: base #: view:res.request:0 msgid "Send" -msgstr "" +msgstr "Send" #. module: base #: field:res.config.users,menu_tips:0 @@ -8370,7 +8370,7 @@ msgstr "" #. module: base #: model:res.country,name:base.do msgid "Dominican Republic" -msgstr "" +msgstr "Den Dominikanske Republik" #. module: base #: selection:base.language.install,lang:0 @@ -8388,7 +8388,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sa msgid "Saudi Arabia" -msgstr "" +msgstr "Saudi-Arabien" #. module: base #: help:res.partner,supplier:0 @@ -8432,7 +8432,7 @@ msgstr "" #. module: base #: field:ir.actions.report.xml,report_xml:0 msgid "XML path" -msgstr "" +msgstr "XML sti" #. module: base #: selection:ir.actions.todo,restart:0 @@ -8442,12 +8442,12 @@ msgstr "" #. module: base #: model:res.country,name:base.gn msgid "Guinea" -msgstr "" +msgstr "Guinea" #. module: base #: model:res.country,name:base.lu msgid "Luxembourg" -msgstr "" +msgstr "Luxembourg" #. module: base #: help:ir.values,key2:0 @@ -8484,14 +8484,14 @@ msgstr "" #. module: base #: model:res.country,name:base.sv msgid "El Salvador" -msgstr "" +msgstr "El Salvador" #. module: base #: field:res.bank,phone:0 #: field:res.partner,phone:0 #: field:res.partner.address,phone:0 msgid "Phone" -msgstr "" +msgstr "Telefon" #. module: base #: field:ir.cron,active:0 @@ -8509,12 +8509,12 @@ msgstr "" #: view:workflow.instance:0 #: view:workflow.workitem:0 msgid "Active" -msgstr "" +msgstr "Aktiv" #. module: base #: model:res.country,name:base.th msgid "Thailand" -msgstr "" +msgstr "Thailand" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_lead @@ -8535,7 +8535,7 @@ msgstr "" #: selection:workflow.activity,join_mode:0 #: selection:workflow.activity,split_mode:0 msgid "And" -msgstr "" +msgstr "Og" #. module: base #: field:ir.model.fields,relation:0 @@ -8551,7 +8551,7 @@ msgstr "" #. module: base #: model:res.country,name:base.uz msgid "Uzbekistan" -msgstr "" +msgstr "Usbekistan" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window @@ -8572,7 +8572,7 @@ msgstr "" #. module: base #: model:res.country,name:base.tw msgid "Taiwan" -msgstr "" +msgstr "Taiwan" #. module: base #: model:ir.model,name:base.model_res_currency_rate @@ -8682,7 +8682,7 @@ msgstr "" #: field:base.language.export,name:0 #: field:ir.attachment,datas_fname:0 msgid "Filename" -msgstr "" +msgstr "Filnavn" #. module: base #: field:ir.model,access_ids:0 @@ -8693,7 +8693,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sk msgid "Slovak Republic" -msgstr "" +msgstr "Slovakiet" #. module: base #: model:ir.ui.menu,name:base.publisher_warranty @@ -8708,7 +8708,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ar msgid "Argentina" -msgstr "" +msgstr "Argentina" #. module: base #: field:res.groups,name:0 @@ -8718,7 +8718,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bh msgid "Bahrain" -msgstr "" +msgstr "Bahrain" #. module: base #: model:res.partner.category,name:base.res_partner_category_12 @@ -8740,7 +8740,7 @@ msgstr "" #: view:res.users:0 #: field:res.users,company_id:0 msgid "Company" -msgstr "" +msgstr "Virksomhed" #. module: base #: view:res.users:0 @@ -8780,7 +8780,7 @@ msgstr "" #. module: base #: model:res.country,name:base.jm msgid "Jamaica" -msgstr "" +msgstr "Jamaica" #. module: base #: model:ir.actions.act_window,help:base.action_partner_category_form @@ -8800,7 +8800,7 @@ msgstr "" #: code:addons/base/res/partner/partner.py:250 #, python-format msgid "Warning" -msgstr "" +msgstr "Advarsel!" #. module: base #: selection:base.language.install,lang:0 @@ -8840,7 +8840,7 @@ msgstr "" #. module: base #: model:res.country,name:base.rw msgid "Rwanda" -msgstr "" +msgstr "Rwanda" #. module: base #: view:ir.sequence:0 @@ -8865,7 +8865,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sg msgid "Singapore" -msgstr "" +msgstr "Singapore" #. module: base #: selection:ir.actions.act_window,target:0 @@ -8895,7 +8895,7 @@ msgstr "" #: field:res.partner.address,country_id:0 #: field:res.partner.bank,country_id:0 msgid "Country" -msgstr "" +msgstr "Land" #. module: base #: field:ir.model.fields,complete_name:0 @@ -8918,12 +8918,12 @@ msgstr "" #. module: base #: field:res.partner.category,name:0 msgid "Category Name" -msgstr "" +msgstr "Kategori Navn" #. module: base #: model:res.partner.category,name:base.res_partner_category_15 msgid "IT sector" -msgstr "" +msgstr "IT sektor" #. module: base #: view:ir.actions.act_window:0 @@ -8975,7 +8975,7 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Graph" -msgstr "" +msgstr "Graf" #. module: base #: model:ir.model,name:base.model_ir_actions_server @@ -9017,7 +9017,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_localisation msgid "Localisation" -msgstr "" +msgstr "Lokalisering" #. module: base #: view:ir.actions.server:0 @@ -9070,7 +9070,7 @@ msgstr "" #. module: base #: field:ir.actions.server,mobile:0 msgid "Mobile No" -msgstr "" +msgstr "Mobil nr." #. module: base #: model:ir.actions.act_window,name:base.action_partner_by_category @@ -9084,7 +9084,7 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "System Update" -msgstr "" +msgstr "Systemopdatering" #. module: base #: selection:ir.translation,type:0 @@ -9099,18 +9099,18 @@ msgstr "" #. module: base #: model:res.country,name:base.sc msgid "Seychelles" -msgstr "" +msgstr "Seychellerne" #. module: base #: model:ir.model,name:base.model_res_partner_bank #: view:res.partner.bank:0 msgid "Bank Accounts" -msgstr "" +msgstr "Bankkonti" #. module: base #: model:res.country,name:base.sl msgid "Sierra Leone" -msgstr "" +msgstr "Sierra Leone" #. module: base #: view:res.company:0 @@ -9126,7 +9126,7 @@ msgstr "" #. module: base #: field:res.partner.bank,owner_name:0 msgid "Account Owner" -msgstr "" +msgstr "Konto ejer" #. module: base #: code:addons/base/res/res_user.py:256 @@ -9155,7 +9155,7 @@ msgstr "" #: field:res.partner.address,function:0 #: selection:workflow.activity,kind:0 msgid "Function" -msgstr "" +msgstr "Funktion" #. module: base #: view:res.widget:0 @@ -9165,12 +9165,12 @@ msgstr "" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Never" -msgstr "" +msgstr "Aldrig" #. module: base #: selection:res.partner.address,type:0 msgid "Delivery" -msgstr "" +msgstr "Levering" #. module: base #: model:res.partner.title,name:base.res_partner_title_pvt_ltd @@ -9197,7 +9197,7 @@ msgstr "" #. module: base #: model:res.country,name:base.kp msgid "North Korea" -msgstr "" +msgstr "Nordkorea" #. module: base #: selection:ir.actions.server,state:0 @@ -9240,7 +9240,7 @@ msgstr "" #. module: base #: model:res.country,name:base.lk msgid "Sri Lanka" -msgstr "" +msgstr "Sri Lanka" #. module: base #: selection:base.language.install,lang:0 diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po index fc0c7518e38..22d06500f88 100644 --- a/openerp/addons/base/i18n/sl.po +++ b/openerp/addons/base/i18n/sl.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" -"PO-Revision-Date: 2010-12-01 06:59+0000\n" -"Last-Translator: OpenERP Administrators \n" +"PO-Revision-Date: 2011-09-26 18:06+0000\n" +"Last-Translator: Simon Vidmar \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-09-01 04:43+0000\n" -"X-Generator: Launchpad (build 13827)\n" +"X-Launchpad-Export-Date: 2011-09-27 04:47+0000\n" +"X-Generator: Launchpad (build 14028)\n" #. module: base #: view:ir.filters:0 @@ -33,12 +33,12 @@ msgstr "Sveta Helena" #. module: base #: view:ir.actions.report.xml:0 msgid "Other Configuration" -msgstr "" +msgstr "Ostale nastavitve" #. module: base #: selection:ir.property,type:0 msgid "DateTime" -msgstr "" +msgstr "DatumČas" #. module: base #: code:addons/fields.py:534 @@ -47,12 +47,14 @@ msgid "" "The second argument of the many2many field %s must be a SQL table !You used " "%s, which is not a valid SQL table name." msgstr "" +"Drugi argument od polja many2many %s mora biti SQL tabela! Uporabili ste %s, " +"ki ni veljavno ime SQL tabele." #. module: base #: view:ir.values:0 #: field:ir.values,meta_unpickle:0 msgid "Metadata" -msgstr "Metapodatki" +msgstr "Meta podatki" #. module: base #: field:ir.ui.view,arch:0 @@ -73,7 +75,7 @@ msgstr "Oznaka (n.pr.: sl_SI)" #: field:workflow.transition,wkf_id:0 #: field:workflow.workitem,wkf_id:0 msgid "Workflow" -msgstr "Potek dela" +msgstr "Delovni proces" #. module: base #: view:partner.sms.send:0 @@ -98,12 +100,12 @@ msgstr "Špansko" #. module: base #: field:ir.actions.server,wkf_model_id:0 msgid "Workflow On" -msgstr "Vklopi potek dela" +msgstr "Vklopi delovni proces" #. module: base #: field:ir.actions.act_window,display_menu_tip:0 msgid "Display Menu Tips" -msgstr "Prikaži tip menija" +msgstr "Prikaži namige menija" #. module: base #: view:ir.module.module:0 @@ -117,6 +119,8 @@ msgid "" "You can not write in this document (%s) ! Be sure your user belongs to one " "of these groups: %s." msgstr "" +"Ne morete pisati v ta dokument (%s)! Bodite prepričani, da vaš uporabnik " +"sodi v eno od teh skupin: %s." #. module: base #: help:ir.model.fields,domain:0 @@ -125,11 +129,14 @@ msgid "" "specified as a Python expression defining a list of triplets. For example: " "[('color','=','red')]" msgstr "" +"Opcijska domena, ki omeji možne vrednosti za sorodna polja, navedena kot " +"Python izrazi, ki opredeljujejo seznam trojčkov. Kot npr: " +"[('color','=','red')]" #. module: base #: field:res.partner,ref:0 msgid "Reference" -msgstr "Referenca" +msgstr "Sklic" #. module: base #: field:ir.actions.act_window,target:0 @@ -140,7 +147,7 @@ msgstr "Ciljno okno" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Opozorilo!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -149,12 +156,14 @@ msgid "" "Properties of base fields cannot be altered in this manner! Please modify " "them through Python code, preferably through a custom addon!" msgstr "" +"Lastnosti baze polj ni mogoče spremeniti na ta način! Prosimo, da jih " +"spremenite preko kode Python, po možnosti z dodatkom po meri!" #. module: base #: code:addons/osv.py:133 #, python-format msgid "Constraint Error" -msgstr "" +msgstr "Napaka omejitve" #. module: base #: model:ir.model,name:base.model_ir_ui_view_custom @@ -164,14 +173,14 @@ msgstr "ir.ui.view.custom" #. module: base #: model:res.country,name:base.sz msgid "Swaziland" -msgstr "Svazi" +msgstr "Švica" #. module: base #: code:addons/orm.py:1993 #: code:addons/orm.py:3653 #, python-format msgid "created." -msgstr "" +msgstr "ustvarjeno." #. module: base #: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 @@ -185,17 +194,19 @@ msgid "" "Some installed modules depend on the module you plan to Uninstall :\n" " %s" msgstr "" +"Nekateri nameščeni moduli so odvisni od modula, ki ga želite odstraniti:\n" +" %s" #. module: base #: field:ir.sequence,number_increment:0 msgid "Increment Number" -msgstr "Prirastek zaporedja" +msgstr "Dobiček" #. module: base #: model:ir.actions.act_window,name:base.action_res_company_tree #: model:ir.ui.menu,name:base.menu_action_res_company_tree msgid "Company's Structure" -msgstr "Struktura družbe" +msgstr "Struktura podjetja" #. module: base #: selection:base.language.install,lang:0 @@ -205,13 +216,15 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Search Partner" -msgstr "" +msgstr "Iskanje partnerja" #. module: base #: code:addons/base/res/res_user.py:132 #, python-format msgid "\"smtp_server\" needs to be set to send mails to users" msgstr "" +"\"smtp strežnik\" mora biti nastavljen, da se lahko pošilja e-pošto " +"uporabnikom" #. module: base #: code:addons/base/module/wizard/base_export_language.py:60 @@ -232,7 +245,7 @@ msgstr "Število modulov" #. module: base #: help:multi_company.default,company_dest_id:0 msgid "Company to store the current record" -msgstr "" +msgstr "Podjetje za shranjevanje trenutnega zapisa" #. module: base #: field:res.partner.bank.type.field,size:0 @@ -242,7 +255,7 @@ msgstr "Maksimalna velikost" #. module: base #: field:res.partner.address,name:0 msgid "Contact Name" -msgstr "Naziv stika" +msgstr "Ime stika" #. module: base #: code:addons/base/module/wizard/base_export_language.py:56 @@ -252,12 +265,12 @@ msgid "" "text editor. The file encoding is UTF-8." msgstr "" "Shrani ta dokument v datoteko %s in ga uredi z ustreznim urejevalnikom. " -"Kodni tabela je UTF-8." +"Kodni nabor je UTF-8." #. module: base #: sql_constraint:res.lang:0 msgid "The name of the language must be unique !" -msgstr "" +msgstr "Ime jezika mora biti edinstven!" #. module: base #: selection:res.request,state:0 @@ -273,12 +286,12 @@ msgstr "Ime čarovnika" #: code:addons/orm.py:2160 #, python-format msgid "Invalid group_by" -msgstr "" +msgstr "Neveljavna skupina_z" #. module: base #: field:res.partner,credit_limit:0 msgid "Credit Limit" -msgstr "" +msgstr "Meja posojila" #. module: base #: field:ir.model.data,date_update:0 @@ -288,12 +301,12 @@ msgstr "Datum posodobitve" #. module: base #: view:ir.attachment:0 msgid "Owner" -msgstr "" +msgstr "Lastnik" #. module: base #: field:ir.actions.act_window,src_model:0 msgid "Source Object" -msgstr "Izvorni objekt" +msgstr "Izvorni predmet" #. module: base #: view:ir.actions.todo:0 @@ -309,7 +322,7 @@ msgstr "ir.ui.view_sc" #: field:res.widget.user,widget_id:0 #: field:res.widget.wizard,widgets_list:0 msgid "Widget" -msgstr "" +msgstr "Gradnik" #. module: base #: view:ir.model.access:0 @@ -323,23 +336,23 @@ msgstr "Skupina" #: field:ir.translation,name:0 #: field:res.partner.bank.type.field,name:0 msgid "Field Name" -msgstr "Naziv polja" +msgstr "Ime polja" #. module: base #: wizard_view:server.action.create,init:0 #: wizard_field:server.action.create,init,type:0 msgid "Select Action Type" -msgstr "" +msgstr "Izberi tip dejanja" #. module: base #: model:res.country,name:base.tv msgid "Tuvalu" -msgstr "tuvalujščina" +msgstr "Tuvalu" #. module: base #: selection:ir.model,state:0 msgid "Custom Object" -msgstr "Objekt po meri" +msgstr "Predmet po meri" #. module: base #: field:res.lang,date_format:0 @@ -375,7 +388,7 @@ msgstr "Francoska Gvajana" #. module: base #: selection:base.language.install,lang:0 msgid "Greek / Ελληνικά" -msgstr "" +msgstr "Grški / Ελληνικά" #. module: base #: selection:base.language.install,lang:0 @@ -388,22 +401,24 @@ msgid "" "If you check this, then the second time the user prints with same attachment " "name, it returns the previous report." msgstr "" +"Če označite to, potem bo drugič ko uporabnik natisne z enakim imenom " +"prilogo, se vrne v prejšnje poročilo." #. module: base #: code:addons/orm.py:904 #, python-format msgid "The read method is not implemented on this object !" -msgstr "Metoda 'read' ni implementirana za ta objekt." +msgstr "Metoa 'read' ni implementirana za ta predmet." #. module: base #: help:res.lang,iso_code:0 msgid "This ISO code is the name of po files to use for translations" -msgstr "" +msgstr "ISO koda je ime po datotek za uporabo prevodov." #. module: base #: view:base.module.upgrade:0 msgid "Your system will be updated." -msgstr "" +msgstr "Vaš sistem bo posodobljen." #. module: base #: field:ir.actions.todo,note:0 @@ -414,7 +429,7 @@ msgstr "Besedilo" #. module: base #: field:res.country,name:0 msgid "Country Name" -msgstr "Naziv države" +msgstr "Ime države" #. module: base #: model:res.country,name:base.co @@ -430,7 +445,7 @@ msgstr "Razporedi nadgradnjo" #: code:addons/orm.py:838 #, python-format msgid "Key/value '%s' not found in selection field '%s'" -msgstr "" +msgstr "Ključ/vrednost '%s' ni mogoče najti v izbranem polju '%s'" #. module: base #: help:res.country,code:0 @@ -449,18 +464,18 @@ msgstr "Palau" #. module: base #: view:res.partner:0 msgid "Sales & Purchases" -msgstr "Prodaja in nabava" +msgstr "Prodaja & Nabava" #. module: base #: view:ir.translation:0 msgid "Untranslated" -msgstr "" +msgstr "Ni prevedeno" #. module: base #: help:ir.actions.act_window,context:0 msgid "" "Context dictionary as Python expression, empty by default (Default: {})" -msgstr "" +msgstr "Kontekst slovar kot izraz Python, prazno privzeto (privzeto: {})" #. module: base #: model:ir.actions.act_window,name:base.ir_action_wizard @@ -472,7 +487,7 @@ msgstr "Čarovniki" #. module: base #: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 msgid "Miscellaneous Suppliers" -msgstr "" +msgstr "Razni dobavitelji" #. module: base #: code:addons/base/ir/ir_model.py:255 @@ -483,12 +498,12 @@ msgstr "Nazivi polj po meri se morajo začeti z 'x_'." #. module: base #: help:ir.actions.server,action_id:0 msgid "Select the Action Window, Report, Wizard to be executed." -msgstr "" +msgstr "Izberite okno dejanja, poročila, čarovnika, ki naj bo izvršeno." #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "Nov uporabnik" #. module: base #: view:base.language.export:0 @@ -504,7 +519,7 @@ msgstr "Opis modela" #: help:ir.actions.act_window,src_model:0 msgid "" "Optional model name of the objects on which this action should be visible" -msgstr "" +msgstr "Ime opcijskega modula predmeta na katerem bo to dejanje vidno" #. module: base #: field:workflow.transition,trigger_expr_id:0 @@ -519,7 +534,7 @@ msgstr "Jordanija" #. module: base #: view:ir.module.module:0 msgid "Certified" -msgstr "" +msgstr "Preverjeno" #. module: base #: model:res.country,name:base.er @@ -530,12 +545,12 @@ msgstr "Eritreja" #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "opis" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule msgid "Automated Actions" -msgstr "" +msgstr "Avtomatska dejanja" #. module: base #: model:ir.model,name:base.model_ir_actions_actions @@ -545,7 +560,7 @@ msgstr "ir.actions.actions" #. module: base #: view:partner.wizard.ean.check:0 msgid "Want to check Ean ? " -msgstr "" +msgstr "Ali želite preveriti Ean? " #. module: base #: field:ir.values,key2:0 @@ -559,16 +574,19 @@ msgid "" "Launchpad.net, our open source project management facility. We use their " "online interface to synchronize all translations efforts." msgstr "" +"OpenERP prevodi (jedro, moduli, klienti) se upravljajp skoz Launchpad.net, " +"ki je naš odprto kodni objekt za upravljanje. Uporabljamo njihov spletni " +"vmesnik za sinhronizacijo vseh prevodov." #. module: base #: field:res.partner,title:0 msgid "Partner Form" -msgstr "" +msgstr "Obrazec partnerja" #. module: base #: selection:base.language.install,lang:0 msgid "Swedish / svenska" -msgstr "Švedsko" +msgstr "Švedsko / svenska" #. module: base #: model:res.country,name:base.rs @@ -596,27 +614,27 @@ msgstr "Zaporedja" #. module: base #: model:ir.model,name:base.model_base_language_import msgid "Language Import" -msgstr "" +msgstr "Uvoz jezika" #. module: base #: model:ir.model,name:base.model_res_config_users msgid "res.config.users" -msgstr "" +msgstr "Copy text \t res.config.users" #. module: base #: selection:base.language.install,lang:0 msgid "Albanian / Shqip" -msgstr "" +msgstr "Albansko /Shqip" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "Priložnosti" #. module: base #: model:ir.model,name:base.model_base_language_export msgid "base.language.export" -msgstr "" +msgstr "base.language.export" #. module: base #: model:res.country,name:base.pg @@ -627,6 +645,7 @@ msgstr "Papua Nova Gvineja" #: help:ir.actions.report.xml,report_type:0 msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..." msgstr "" +"Tip poročila, npr. pdf, html, raw, sxw, odt, html2html, mako2html, ..." #. module: base #: model:res.partner.category,name:base.res_partner_category_4 @@ -641,12 +660,12 @@ msgstr "," #. module: base #: view:res.partner:0 msgid "My Partners" -msgstr "" +msgstr "Moji partnerji" #. module: base #: view:ir.actions.report.xml:0 msgid "XML Report" -msgstr "" +msgstr "XML poročilo" #. module: base #: model:res.country,name:base.es @@ -662,13 +681,13 @@ msgstr "Uvoz / Izvoz" #: help:ir.actions.act_window,domain:0 msgid "" "Optional domain filtering of the destination data, as a Python expression" -msgstr "" +msgstr "Dodatna domena filtriranje za destinacije podatkov, kot izraz Python" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #: model:ir.model,name:base.model_base_module_upgrade msgid "Module Upgrade" -msgstr "" +msgstr "Posodobitev modula" #. module: base #: view:res.config.users:0 @@ -676,11 +695,13 @@ msgid "" "Groups are used to define access rights on objects and the visibility of " "screens and menus" msgstr "" +"Skupine se uporablja za opredelitev pravice dostopa do predmetov, ter za " +"vidnost zaslonov in menijev" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (UY) / Español (UY)" -msgstr "" +msgstr "Špansko (UY) / Español (UY)" #. module: base #: field:res.partner,mobile:0 @@ -697,7 +718,7 @@ msgstr "Oman" #: model:ir.actions.act_window,name:base.action_payterm_form #: model:ir.model,name:base.model_res_payterm msgid "Payment term" -msgstr "Plačilni pogoj" +msgstr "" #. module: base #: model:res.country,name:base.nu @@ -712,7 +733,7 @@ msgstr "Delovni dnevi" #. module: base #: selection:ir.module.module,license:0 msgid "Other OSI Approved Licence" -msgstr "" +msgstr "Ostale OSI dvoljene licence" #. module: base #: help:res.config.users,context_lang:0 @@ -721,12 +742,13 @@ msgid "" "Sets the language for the user's user interface, when UI translations are " "available" msgstr "" +"Nastavi jezik za uporabniški vmesnik uporabnika, ko so prevodi UI na voljo" #. module: base #: code:addons/orm.py:1043 #, python-format msgid "The unlink method is not implemented on this object !" -msgstr "Metoda 'unlink' ni implementirana za ta objekt." +msgstr "Metoda 'unlink' ni implementirana za ta predmet." #. module: base #: model:ir.actions.act_window,name:base.act_menu_create @@ -743,12 +765,12 @@ msgstr "Indija" #: model:ir.actions.act_window,name:base.res_request_link-act #: model:ir.ui.menu,name:base.menu_res_request_link_act msgid "Request Reference Types" -msgstr "" +msgstr "Zahtevaj tipe sklicov" #. module: base #: view:ir.values:0 msgid "client_action_multi, client_action_relate" -msgstr "" +msgstr "client_action_multi, client_action_relate" #. module: base #: model:res.country,name:base.ad @@ -759,12 +781,12 @@ msgstr "Andora, Principat" #: field:ir.module.category,child_ids:0 #: field:res.partner.category,child_ids:0 msgid "Child Categories" -msgstr "Kategorije otrok" +msgstr "Kategorije podrejenih" #. module: base #: model:ir.model,name:base.model_ir_config_parameter msgid "ir.config_parameter" -msgstr "" +msgstr "ir.config_parameter" #. module: base #: selection:base.language.export,format:0 @@ -799,6 +821,8 @@ msgid "" "Language with code \"%s\" is not defined in your system !\n" "Define it through the Administration menu." msgstr "" +"Jezik s kodo \"%s\" ni določen na vašem sistemu!\n" +"Določite ga v Administracijskem meniju." #. module: base #: model:res.country,name:base.gu @@ -808,13 +832,13 @@ msgstr "Guam (USA)" #. module: base #: model:ir.ui.menu,name:base.menu_hr_project msgid "Human Resources Dashboard" -msgstr "" +msgstr "Nadzorna plošča človeških virov" #. module: base #: code:addons/base/res/res_user.py:507 #, python-format msgid "Setting empty passwords is not allowed for security reasons!" -msgstr "" +msgstr "Nastavitev brez gesla ni dovoljeno zaradi varnostnih razlogov!" #. module: base #: selection:ir.actions.server,state:0 @@ -825,7 +849,7 @@ msgstr "Začasno" #. module: base #: constraint:ir.ui.view:0 msgid "Invalid XML for View Architecture!" -msgstr "Neveljaven XML za arhitekturo pogleda." +msgstr "Neveljaven XML za arhitekturo pogleda!" #. module: base #: model:res.country,name:base.ky @@ -848,28 +872,28 @@ msgstr "Prehodi" #: code:addons/orm.py:4020 #, python-format msgid "Record #%d of %s not found, cannot copy!" -msgstr "" +msgstr "Zapisa #%d od %s ni mogoče najti. Ne morem kopirati!" #. module: base #: field:ir.module.module,contributors:0 msgid "Contributors" -msgstr "" +msgstr "Sodelavci" #. module: base #: selection:ir.property,type:0 msgid "Char" -msgstr "" +msgstr "Znak" #. module: base #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract msgid "Contracts" -msgstr "" +msgstr "Pogodbe" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (AR) / Español (AR)" -msgstr "Špansko" +msgstr "Špansko (AR) / Español (AR)" #. module: base #: model:res.country,name:base.ug @@ -879,17 +903,17 @@ msgstr "Uganda" #. module: base #: field:ir.model.access,perm_unlink:0 msgid "Delete Access" -msgstr "" +msgstr "Izbriši dostop" #. module: base #: model:res.country,name:base.ne msgid "Niger" -msgstr "Niger" +msgstr "Nigerija" #. module: base #: selection:base.language.install,lang:0 msgid "Chinese (HK)" -msgstr "" +msgstr "Kitajsko (HK)" #. module: base #: model:res.country,name:base.ba @@ -903,11 +927,14 @@ msgid "" "Lauchpad's web interface (Rosetta). If you need to perform mass translation, " "Launchpad also allows uploading full .po files at once" msgstr "" +"Če želite izboljšati ali razširiti uradne prevode, morate uporabljati " +"neposredno Lauchpad spletni vmesnik (Rosetta). Če morate opraviti množično " +"prevod, Launchpad tudi omogoča tudi nalaganje polno. PO datotek hkrati" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (GT) / Español (GT)" -msgstr "" +msgstr "Špansko (GT) / Español (GT)" #. module: base #: view:res.lang:0 @@ -916,12 +943,15 @@ msgid "" "decimal number [00,53]. All days in a new year preceding the first Monday " "are considered to be in week 0." msgstr "" +"%W - Številka tedna v letu (ponedeljek kot prvi dan v tednu), kot decimalno " +"število [00,53]. Vse dni v novem letu pred prvim ponedeljekom se šteje, da " +"je v tednu 0." #. module: base #: field:ir.module.module,website:0 #: field:res.partner,website:0 msgid "Website" -msgstr "Spletno mesto" +msgstr "Spletna stran" #. module: base #: model:res.country,name:base.gs @@ -931,7 +961,7 @@ msgstr "" #. module: base #: field:ir.actions.url,url:0 msgid "Action URL" -msgstr "" +msgstr "URL dejanja" #. module: base #: field:base.module.import,module_name:0 @@ -941,13 +971,13 @@ msgstr "Ime modula" #. module: base #: model:res.country,name:base.mh msgid "Marshall Islands" -msgstr "Marshallovi otoki" +msgstr "Maršalovi otoki" #. module: base #: code:addons/base/ir/ir_model.py:328 #, python-format msgid "Changing the model of a field is forbidden!" -msgstr "" +msgstr "Spreminjanje modela polja ni dovoljeno!" #. module: base #: model:res.country,name:base.ht @@ -958,7 +988,7 @@ msgstr "Haiti" #: view:ir.ui.view:0 #: selection:ir.ui.view,type:0 msgid "Search" -msgstr "" +msgstr "Iskanje" #. module: base #: code:addons/osv.py:136 @@ -969,38 +999,43 @@ msgid "" "reference it\n" "- creation/update: a mandatory field is not correctly set" msgstr "" +"Operacije ni mogoče zaključiti zaradi naslednjih zadev:\n" +"- izbris: poizkušate izbrisati zapis med tem, ko drug zapis še vedno kaže " +"nanj\n" +"- ustvariti/posodobiti: obvezno polje ni pravilno nastavljeno" #. module: base #: view:ir.rule:0 msgid "" "2. Group-specific rules are combined together with a logical AND operator" msgstr "" +"Skupinsko-specifična pravila so združena skupaj z logičnim operatorjem AND" #. module: base #: code:addons/base/res/res_user.py:206 #, python-format msgid "Operation Canceled" -msgstr "" +msgstr "Operacija preklicana" #. module: base #: help:base.language.export,lang:0 msgid "To export a new language, do not select a language." -msgstr "Jezika ne izbirajte za izvoz novega jezika." +msgstr "Ne izbirajte jezika za izvoz novega jezika." #. module: base #: view:res.request:0 msgid "Request Date" -msgstr "" +msgstr "Datum zahtevka" #. module: base #: model:ir.ui.menu,name:base.menu_hr_dasboard msgid "Dashboard" -msgstr "" +msgstr "Nadzorna plošča" #. module: base #: model:ir.ui.menu,name:base.menu_purchase_root msgid "Purchases" -msgstr "" +msgstr "Nabave" #. module: base #: model:res.country,name:base.md @@ -1034,13 +1069,13 @@ msgstr "ir.exports" #: code:addons/base/module/wizard/base_update_translations.py:38 #, python-format msgid "No language with code \"%s\" exists" -msgstr "" +msgstr "Ne obstaja jezik s kodo \"%s\"" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:163 #, python-format msgid "Error during communication with the publisher warranty server." -msgstr "" +msgstr "Napaka pri komuniciranju s strežnikom založniške garancije." #. module: base #: help:ir.actions.server,email:0 @@ -1049,11 +1084,14 @@ msgid "" "you select the invoice, then `object.invoice_address_id.email` is the field " "which gives the correct address" msgstr "" +"Zagotavlja polja, ki se bodo uporabljala za pridobivanje e-poštnih naslovov, " +"npr. ko izberete račun, nato pa polje `object.invoice_address_id.email`, ki " +"daje pravi naslov" #. module: base #: view:res.lang:0 msgid "%Y - Year with century." -msgstr "" +msgstr "%Y - leto s stoletji" #. module: base #: report:ir.module.reference.graph:0 @@ -1067,22 +1105,25 @@ msgid "" "system. After the contract has been registered, you will be able to send " "issues directly to OpenERP." msgstr "" +"Ta čarovnik vam pomaga registrirati pogodbo garancije založnika v vašem " +"OpenERP sistemu. Ko je pogodba registrirana, boste lahko poslali vprašanja " +"direktno na OpenERP." #. module: base #: code:addons/orm.py:1744 #, python-format msgid "The search method is not implemented on this object !" -msgstr "Metoda 'search' ni implementirana za ta objekt." +msgstr "Metoda 'search' ni implementira v predmet." #. module: base #: view:wizard.ir.model.menu.create:0 msgid "Create _Menu" -msgstr "" +msgstr "Ustvari_meni" #. module: base #: field:res.payterm,name:0 msgid "Payment Term (short name)" -msgstr "" +msgstr "Plačilni pogoj (kratko ime)" #. module: base #: model:ir.model,name:base.model_res_bank @@ -1102,11 +1143,13 @@ msgid "" "If you check this box, your customized translations will be overwritten and " "replaced by the official ones." msgstr "" +"Če označite to polje, bodo prilagojeni prevodi prepisani in zamenjani z " +"uradnimi." #. module: base #: field:ir.actions.report.xml,report_rml:0 msgid "Main report file path" -msgstr "" +msgstr "Pot datoteke glavnega poročila" #. module: base #: model:ir.actions.act_window,name:base.ir_action_report_xml @@ -1122,6 +1165,8 @@ msgid "" "If set to true, the action will not be displayed on the right toolbar of a " "form view." msgstr "" +"Če je nastavljeno na true, potem to dejanje ne bo prikazano v desni orodni " +"vrstici pogleda obrazca." #. module: base #: field:workflow,on_create:0 @@ -1135,6 +1180,8 @@ msgid "" "'%s' contains too many dots. XML ids should not contain dots ! These are " "used to refer to other modules data, as in module.reference_id" msgstr "" +"'%s' vsebuje preveč pik. XML id-ki ne smejo vsebovati pik! To se uporablja " +"za nanašanje na druge podatke modulov, kot je module.reference_id" #. module: base #: field:partner.sms.send,user:0 @@ -1149,6 +1196,8 @@ msgid "" "Access all the fields related to the current object using expressions, i.e. " "object.partner_id.name " msgstr "" +"Dostop do vseh polj, povezanih s trenutnim predmetom s pomočjo izrazov, npr. " +"object.partner_id.name " #. module: base #: model:ir.model,name:base.model_res_country_state @@ -1158,7 +1207,7 @@ msgstr "Zvezna država" #. module: base #: selection:ir.property,type:0 msgid "Float" -msgstr "" +msgstr "Plavajoče" #. module: base #: model:ir.model,name:base.model_res_request_link @@ -1168,14 +1217,14 @@ msgstr "res.request.link" #. module: base #: field:ir.actions.wizard,name:0 msgid "Wizard Info" -msgstr "" +msgstr "Info čarovnika" #. module: base #: view:base.language.export:0 #: model:ir.actions.act_window,name:base.action_wizard_lang_export #: model:ir.ui.menu,name:base.menu_wizard_lang_export msgid "Export Translation" -msgstr "" +msgstr "Izvoz prevoda" #. module: base #: help:res.log,secondary:0 @@ -1183,6 +1232,7 @@ msgid "" "Do not display this log if it belongs to the same object the user is working " "on" msgstr "" +"Ne prikaži dnevnika, če pripada na istem predmetu na katerem dela uporabnik" #. module: base #: model:res.country,name:base.tp @@ -1206,6 +1256,19 @@ msgid "" "%(user_signature)s\n" "%(company_name)s" msgstr "" +"Datum: %(date)s\n" +"\n" +"Spoštovani %(partner_name)s,\n" +"\n" +"Prosimo, najdete v priponki opomnik vseh vaših neplačanih računov, skupni " +"znesek:\n" +"\n" +"%(followup_amount).2f %(company_currency)s\n" +"\n" +"Hvala,\n" +"--\n" +"%(user_signature)s\n" +"%(company_name)s" #. module: base #: field:res.currency,accuracy:0 @@ -1225,7 +1288,7 @@ msgstr "wizard.ir.model.menu.create.line" #. module: base #: field:ir.attachment,res_id:0 msgid "Attached ID" -msgstr "" +msgstr "ID pripetja" #. module: base #: view:ir.sequence:0 @@ -1240,7 +1303,7 @@ msgstr "Maldivi" #. module: base #: help:ir.values,res_id:0 msgid "Keep 0 if the action must appear on all resources." -msgstr "" +msgstr "Obdržite 0, če se mora dejanje pojaviti v vseh virih." #. module: base #: model:ir.model,name:base.model_ir_rule @@ -1258,13 +1321,15 @@ msgid "" "Condition that is to be tested before action is executed, e.g. " "object.list_price > object.cost_price" msgstr "" +"Pogoj, ki ga je treba preskusiti, preden se dejanje izvede, npr. " +"object.list_price > object.cost_price" #. module: base #: code:addons/base/res/partner/partner.py:155 #: code:addons/base/res/res_company.py:66 #, python-format msgid " (copy)" -msgstr "" +msgstr " (kopija)" #. module: base #: view:res.lang:0 @@ -1281,13 +1346,13 @@ msgstr "Partnerji" #. module: base #: field:res.partner.category,parent_left:0 msgid "Left parent" -msgstr "" +msgstr "Levi izvor" #. module: base #: model:ir.actions.act_window,name:base.res_widget_act_window #: model:ir.ui.menu,name:base.menu_res_widget_act_window msgid "Homepage Widgets" -msgstr "" +msgstr "Gradnik domače strani" #. module: base #: help:ir.actions.server,message:0 @@ -1295,16 +1360,18 @@ msgid "" "Specify the message. You can use the fields from the object. e.g. `Dear [[ " "object.partner_id.name ]]`" msgstr "" +"Navedite sporočilo. Lahko uporabite polja iz predmeta. npr. 'Spoštovani " +"[[object.partner_id.name]]'" #. module: base #: field:ir.attachment,res_model:0 msgid "Attached Model" -msgstr "" +msgstr "Pripeti model" #. module: base #: view:ir.rule:0 msgid "Domain Setup" -msgstr "" +msgstr "Namestitev domene" #. module: base #: field:ir.actions.server,trigger_name:0 @@ -1342,7 +1409,7 @@ msgstr "Formula" #: code:addons/base/res/res_user.py:389 #, python-format msgid "Can not remove root user!" -msgstr "Ne morete odstaniti uporabnika 'root'." +msgstr "Ne morete odstaniti uporabnika 'root'!" #. module: base #: model:res.country,name:base.mw @@ -1354,7 +1421,7 @@ msgstr "Malavi" #: code:addons/base/res/res_user.py:413 #, python-format msgid "%s (copy)" -msgstr "" +msgstr "%s (kopija)" #. module: base #: field:res.partner.address,type:0 @@ -1364,7 +1431,7 @@ msgstr "Vrsta naslova" #. module: base #: view:ir.ui.menu:0 msgid "Full Path" -msgstr "" +msgstr "Celotna pot" #. module: base #: view:res.request:0 @@ -1378,11 +1445,14 @@ msgid "" "decimal number [00,53]. All days in a new year preceding the first Sunday " "are considered to be in week 0." msgstr "" +"%U - številka tedna v letu (nedelja kot prvi dan tedna) je decimalno " +"število[00,53]. Vse dnevi v novem letu pred prvo nedeljo se šteje, da je v 0 " +"tednu." #. module: base #: view:ir.ui.view:0 msgid "Advanced" -msgstr "" +msgstr "Napredno" #. module: base #: model:res.country,name:base.fi @@ -1396,23 +1466,23 @@ msgstr "Finska" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Tree" -msgstr "Drevo" +msgstr "Drevesni prikaz" #. module: base #: help:res.config.users,password:0 msgid "" "Keep empty if you don't want the user to be able to connect on the system." -msgstr "" +msgstr "Obdržite prazno, če ne želite, da se uporabnik poveže na sistem." #. module: base #: view:ir.actions.server:0 msgid "Create / Write / Copy" -msgstr "" +msgstr "Ustvari / Zapiši / Kopiraj" #. module: base #: view:base.language.export:0 msgid "https://help.launchpad.net/Translations" -msgstr "" +msgstr "https://help.launchpad.net/Translations" #. module: base #: field:ir.actions.act_window,view_mode:0 @@ -1425,27 +1495,29 @@ msgid "" "When using CSV format, please also check that the first line of your file is " "one of the following:" msgstr "" +"Ko uporabljate CSV format, prosim preverite tudi prve vrstice vaše datoteke " +"ena od naslednje:" #. module: base #: code:addons/fields.py:114 #, python-format msgid "Not implemented search_memory method !" -msgstr "Metoda 'search_memory' ni implementirana." +msgstr "Metoda 'search_memory' ni implementirana!" #. module: base #: view:res.log:0 msgid "Logs" -msgstr "" +msgstr "Dnevniki" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish / Español" -msgstr "Špansko" +msgstr "Špansko / Español" #. module: base #: selection:base.language.install,lang:0 msgid "Korean (KP) / 한국어 (KP)" -msgstr "" +msgstr "Korejsko (KP) / 한국어 (KP)" #. module: base #: view:base.module.update:0 @@ -1453,6 +1525,8 @@ msgid "" "This wizard will scan all module repositories on the server side to detect " "newly added modules as well as any change to existing modules." msgstr "" +"Ta čarovnik po pregledal vse skladišča modulov na strani strežnik za " +"odkrivanje novo dodanih modulov kot tudi vse spremembe na obstoječih modulih." #. module: base #: field:res.company,logo:0 @@ -1462,7 +1536,7 @@ msgstr "Logotip" #. module: base #: view:res.partner.address:0 msgid "Search Contact" -msgstr "" +msgstr "Išči po stikih" #. module: base #: view:ir.module.module:0 @@ -1486,13 +1560,13 @@ msgstr "Bahami" msgid "" "Couldn't generate the next id because some partners have an alphabetic id !" msgstr "" -"Ni bilo možno ustvariti naslednjega IDja, saj imajo nekateri partnerji " -"črkovni ID." +"Ni bilo možno ustvariti sledečega IDja, ker imajo nekateri partnerji črkovni " +"ID!" #. module: base #: view:ir.attachment:0 msgid "Attachment" -msgstr "Priponke" +msgstr "Priponka" #. module: base #: model:res.country,name:base.ie @@ -1508,12 +1582,12 @@ msgstr "Število osveženih modulov" #: code:addons/fields.py:100 #, python-format msgid "Not implemented set_memory method !" -msgstr "Metoda 'set_memory' ni implementirana." +msgstr "Metoda 'set_memory' ni implementirana!" #. module: base #: view:workflow.activity:0 msgid "Workflow Activity" -msgstr "" +msgstr "Aktivnost delovnega procesa" #. module: base #: view:ir.rule:0 @@ -1521,6 +1595,8 @@ msgid "" "Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND " "GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )" msgstr "" +"Primer: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND " +"GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )" #. module: base #: model:ir.actions.act_window,help:base.action_ui_view @@ -1528,6 +1604,9 @@ msgid "" "Views allows you to personalize each view of OpenERP. You can add new " "fields, move fields, rename them or delete the ones that you do not need." msgstr "" +"Pogledi vam dovolijo prilagoditev vsak pogled OpenERP. Dodate lahko nova " +"polja, premaknite polja, jih preimenujete ali izbrišete tiste, ki jih ne " +"potrebujete." #. module: base #: field:ir.actions.act_window,groups_id:0 @@ -1553,7 +1632,7 @@ msgstr "Skupine" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CL) / Español (CL)" -msgstr "" +msgstr "Špansko (CL) / Español (CL)" #. module: base #: view:res.config.users:0 @@ -1562,6 +1641,10 @@ msgid "" "access to selected functionalities within the system. Click on 'Done' if you " "do not wish to add more users at this stage, you can always do this later." msgstr "" +"Ustvarjajte dodatne uporabnike in jih dodelite skupinam, ki jim bodo " +"omogočila dostop do izbranih funkcij v sistemu. Kliknite na \"Končano\", če " +"ne želite dodati več uporabnikov na tej stopnji, lahko pa to naredite tudi " +"kasneje." #. module: base #: model:res.country,name:base.bz @@ -1584,17 +1667,19 @@ msgid "" "Comma-separated list of allowed view modes, such as 'form', 'tree', " "'calendar', etc. (Default: tree,form)" msgstr "" +"Z vejico ločen seznam dovoljenih načinov pogleda, kot so \"oblika\", " +"\"drevo\", \"koledar\", itd (Default: drevo, oblika)" #. module: base #: code:addons/orm.py:3147 #, python-format msgid "A document was modified since you last viewed it (%s:%d)" -msgstr "" +msgstr "Dokument je bil spremenjem po vašem zadnjem ogledu (%s:%d)" #. module: base #: view:workflow:0 msgid "Workflow Editor" -msgstr "" +msgstr "Urejevalnik delovnik procesov" #. module: base #: selection:ir.module.module,state:0 @@ -1614,6 +1699,9 @@ msgid "" "order in Object, and you can have loop on the sales order line. Expression = " "`object.order_line`." msgstr "" +"Vpišite polje / izraz, ki bo vrnil na seznam. Npr. izberite prodajo vrstni " +"red predmetov, in lahko imate zanko na vrstici prodajnega naročila. Izraz = " +"`object.order_line`." #. module: base #: field:ir.property,fields_id:0 @@ -1625,7 +1713,7 @@ msgstr "Polje" #. module: base #: view:ir.rule:0 msgid "Groups (no group = global)" -msgstr "" +msgstr "Skupine (ni skupine = globalno)" #. module: base #: model:res.country,name:base.fo @@ -1637,7 +1725,7 @@ msgstr "Ferski otoki" #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Simplified" -msgstr "" +msgstr "Poenostavljen" #. module: base #: model:res.country,name:base.st @@ -1652,7 +1740,7 @@ msgstr "Račun" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese (BR) / Português (BR)" -msgstr "" +msgstr "Portugalsko (BR) / Português (BR)" #. module: base #: model:res.country,name:base.bb @@ -1670,7 +1758,7 @@ msgstr "Madagaskar" msgid "" "The Object name must start with x_ and not contain any special character !" msgstr "" -"Naziv objekta se mora začeti z 'x_' in ne sme vsebovati posebnih znakov." +"Naziv predmeta se mora začet z x_ in ne sme vsebovati posebnih znakov!" #. module: base #: field:ir.actions.configuration.wizard,note:0 @@ -1682,27 +1770,27 @@ msgstr "Naslednji čarovnik" #: view:ir.ui.menu:0 #: field:ir.ui.menu,name:0 msgid "Menu" -msgstr "Menu" +msgstr "Meni" #. module: base #: field:res.currency,rate:0 msgid "Current Rate" -msgstr "" +msgstr "Trenutno razmerje" #. module: base #: field:ir.ui.view.custom,ref_id:0 msgid "Original View" -msgstr "" +msgstr "Originalni pogled" #. module: base #: view:ir.values:0 msgid "Action To Launch" -msgstr "" +msgstr "Dejanje za zagon" #. module: base #: field:ir.actions.url,target:0 msgid "Action Target" -msgstr "" +msgstr "Cilj dejanja" #. module: base #: model:res.country,name:base.ai @@ -1725,6 +1813,8 @@ msgid "" "Provide the field name that the record id refers to for the write operation. " "If it is empty it will refer to the active id of the object." msgstr "" +"Navedite ime polja, ki se nanaša na zapis id za operacijo pisanja. Če je " +"prazna, se bo nanašalo na aktivni id predmeta." #. module: base #: model:res.country,name:base.zw @@ -1735,11 +1825,12 @@ msgstr "Zimbabve" #: view:base.module.update:0 msgid "Please be patient, as this operation may take a few seconds..." msgstr "" +"Prosimo, bodite potrpežljivi, saj lahko ta operacija traja nekaj sekund ..." #. module: base #: help:ir.values,action_id:0 msgid "This field is not used, it only helps you to select the right action." -msgstr "" +msgstr "Polje ni v uporabi, pomagam vas samo izbrati pravo dejanje." #. module: base #: field:ir.actions.server,email:0 @@ -1749,7 +1840,7 @@ msgstr "E-poštni naslov" #. module: base #: selection:base.language.install,lang:0 msgid "French (BE) / Français (BE)" -msgstr "" +msgstr "Francosko (BE) / Français (BE)" #. module: base #: view:ir.actions.server:0 @@ -1780,7 +1871,7 @@ msgstr "Preslikave polj" #. module: base #: view:base.language.export:0 msgid "Export Translations" -msgstr "" +msgstr "Izvoz prevodov" #. module: base #: model:ir.ui.menu,name:base.menu_custom @@ -1812,7 +1903,7 @@ msgstr "Litva" #: model:ir.model,name:base.model_partner_clear_ids #: view:partner.clear.ids:0 msgid "Clear IDs" -msgstr "" +msgstr "Počiši ID-je" #. module: base #: help:ir.cron,model:0 @@ -1820,17 +1911,19 @@ msgid "" "Name of object whose function will be called when this scheduler will run. " "e.g. 'res.partener'" msgstr "" +"Ime predmeta, katerih funkcija se bo klicalal, ko bo to tekel " +"razporejevalnik. npr. \"res.partener\"" #. module: base #: code:addons/orm.py:1040 #, python-format msgid "The perm_read method is not implemented on this object !" -msgstr "Metoda 'perm_read' ni implementirana za ta objekt." +msgstr "Metoda 'perm_read' ni implementirana za ta predmet!" #. module: base #: view:res.lang:0 msgid "%y - Year without century [00,99]." -msgstr "" +msgstr "%y - Leto brez stoletja [00,99]." #. module: base #: model:res.country,name:base.si @@ -1846,12 +1939,12 @@ msgstr "Pakistan" #: code:addons/orm.py:1350 #, python-format msgid "Invalid Object Architecture!" -msgstr "" +msgstr "Neveljavna arhitektura predmeta!" #. module: base #: model:ir.ui.menu,name:base.menu_email_gateway_form msgid "Messages" -msgstr "" +msgstr "Sporočila" #. module: base #: code:addons/base/ir/ir_model.py:303 @@ -1868,17 +1961,17 @@ msgstr "Napaka!" #. module: base #: view:res.lang:0 msgid "%p - Equivalent of either AM or PM." -msgstr "" +msgstr "%p - ekvivalenten bodisi AM ali PM." #. module: base #: view:ir.actions.server:0 msgid "Iteration Actions" -msgstr "" +msgstr "Ponovitvena dejanja" #. module: base #: help:multi_company.default,company_id:0 msgid "Company where the user is connected" -msgstr "" +msgstr "Podjetje kamor je uporabnik povezan" #. module: base #: field:publisher_warranty.contract,date_stop:0 @@ -1897,6 +1990,8 @@ msgid "" "One of the records you are trying to modify has already been deleted " "(Document type: %s)." msgstr "" +"Eden izmed zapisov, ki jih poskušate spremeniti, so že izbrisana (Vrsta " +"dokumenta: %s)." #. module: base #: model:ir.actions.act_window,help:base.action_country @@ -1905,6 +2000,9 @@ msgid "" "partner records. You can create or delete countries to make sure the ones " "you are working on will be maintained." msgstr "" +"Prikaz in upravljanje seznam vseh držav, ki jih je mogoče dodeliti vašemu " +"zapisu partnerja. Lahko ustvarite ali izbrišete države, da se prepričate, da " +"tisti s katerimi delate, da so vzdrževani." #. module: base #: model:res.partner.category,name:base.res_partner_category_7 @@ -1919,18 +2017,18 @@ msgstr "Otok Norfolk" #. module: base #: selection:base.language.install,lang:0 msgid "Korean (KR) / 한국어 (KR)" -msgstr "" +msgstr "Korejsko (KR) / 한국어 (KR)" #. module: base #: help:ir.model.fields,model:0 msgid "The technical name of the model this field belongs to" -msgstr "" +msgstr "Tehnično ime modela h kateremu to polje pripada" #. module: base #: field:ir.actions.server,action_id:0 #: selection:ir.actions.server,state:0 msgid "Client Action" -msgstr "Odjemalčeva akcija" +msgstr "Klientovo dejanje" #. module: base #: model:res.country,name:base.bd @@ -1940,7 +2038,7 @@ msgstr "Bangladeš" #. module: base #: constraint:res.company:0 msgid "Error! You can not create recursive companies." -msgstr "Napaka. Ne morete ustvariti rekurzivnih družb." +msgstr "Napaka! Ne morete ustvariti rekurzivnih podjetij." #. module: base #: selection:publisher_warranty.contract,state:0 @@ -1971,7 +2069,7 @@ msgstr "res.partner.event" #. module: base #: model:res.widget,title:base.facebook_widget msgid "Facebook" -msgstr "" +msgstr "Facebook" #. module: base #: model:res.country,name:base.am @@ -1982,12 +2080,12 @@ msgstr "Armenija" #: model:ir.actions.act_window,name:base.ir_property_form #: model:ir.ui.menu,name:base.menu_ir_property_form_all msgid "Configuration Parameters" -msgstr "" +msgstr "Parametri konfiguracije" #. module: base #: constraint:ir.cron:0 msgid "Invalid arguments" -msgstr "" +msgstr "Neveljavni argumenti" #. module: base #: model:res.country,name:base.se @@ -2027,17 +2125,17 @@ msgstr "Vrsta bančnega računa" #: field:res.config.users,config_logo:0 #: field:res.config.view,config_logo:0 msgid "Image" -msgstr "" +msgstr "Slika" #. module: base #: view:ir.actions.server:0 msgid "Iteration Action Configuration" -msgstr "" +msgstr "Konfiguracija ponovitvenega dejanja" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Canceled" -msgstr "" +msgstr "Preklicano" #. module: base #: model:res.country,name:base.at @@ -2062,7 +2160,7 @@ msgstr "Koledar" #. module: base #: field:res.partner.address,partner_id:0 msgid "Partner Name" -msgstr "" +msgstr "Ime partnerja" #. module: base #: field:workflow.activity,signal_send:0 @@ -2072,7 +2170,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_17 msgid "HR sector" -msgstr "" +msgstr "Sektor HR" #. module: base #: code:addons/orm.py:3817 @@ -2082,6 +2180,9 @@ msgid "" "separated list of valid field names (optionally followed by asc/desc for the " "direction)" msgstr "" +"Navedeno neveljavno \"naročilo\" Veljavna specifikacija \"naročila\" je z " +"vejico ločen seznam veljavnih imen polj (opcijsko za smetri sledi " +"naraščajoče/padajoče)" #. module: base #: model:ir.model,name:base.model_ir_module_module_dependency @@ -2098,7 +2199,7 @@ msgstr "Osnutek" #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Extended" -msgstr "" +msgstr "Razširjeno" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_contact @@ -2107,6 +2208,9 @@ msgid "" "way you want to print them in letters and other documents. Some example: " "Mr., Mrs. " msgstr "" +"Upravljanje kontaktnih naslovov, ki jih želite imeti na voljo v vašem " +"sistemu in tako, kot želite, da jih natisnete na pisma in druge dokumente " +"Nekateri primere: gospod, gospa. " #. module: base #: field:res.company,rml_footer1:0 @@ -2134,12 +2238,12 @@ msgstr "Odvisnosti" #. module: base #: field:multi_company.default,company_id:0 msgid "Main Company" -msgstr "Glavna družba" +msgstr "Glavno podjetje" #. module: base #: field:ir.ui.menu,web_icon_hover:0 msgid "Web Icon File (hover)" -msgstr "" +msgstr "Datoteka spletne ikone (hover)" #. module: base #: view:ir.actions.server:0 @@ -2147,6 +2251,8 @@ msgid "" "If you use a formula type, use a python expression using the variable " "'object'." msgstr "" +"Če uporabite tip formule, uporabite python izraz z uporabo spremenljivke " +"'object'." #. module: base #: field:res.partner.address,birthdate:0 @@ -2157,7 +2263,7 @@ msgstr "Datum rojstva" #: model:ir.actions.act_window,name:base.action_partner_title_contact #: model:ir.ui.menu,name:base.menu_partner_title_contact msgid "Contact Titles" -msgstr "" +msgstr "Naziv kontakta" #. module: base #: view:base.language.import:0 @@ -2165,11 +2271,13 @@ msgid "" "Please double-check that the file encoding is set to UTF-8 (sometimes called " "Unicode) when the translator exports it." msgstr "" +"Prosimo, še enkrat preverite, da je nastavljeno za datoteko kodiranje UTF-8 " +"(včasih se imenuje Unicode), ko je prevajalec izvozi." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (DO) / Español (DO)" -msgstr "" +msgstr "Špansko (DO) / Español (DO)" #. module: base #: model:ir.model,name:base.model_workflow_activity @@ -2182,11 +2290,13 @@ msgid "" "Reference of the target resource, whose model/table depends on the 'Resource " "Name' field." msgstr "" +"Sklic ciljnega vira, katerega model / tabela je odvisno od polja \"Ime " +"vira\"." #. module: base #: field:ir.model.fields,select_level:0 msgid "Searchable" -msgstr "" +msgstr "Možno iskati" #. module: base #: model:res.country,name:base.uy @@ -2196,12 +2306,12 @@ msgstr "Urugvaj" #. module: base #: selection:base.language.install,lang:0 msgid "Finnish / Suomi" -msgstr "" +msgstr "Finsko / Suomi" #. module: base #: field:ir.rule,perm_write:0 msgid "Apply For Write" -msgstr "" +msgstr "Uporabi za pisanje" #. module: base #: field:ir.sequence,prefix:0 @@ -2211,12 +2321,12 @@ msgstr "Predpona" #. module: base #: selection:base.language.install,lang:0 msgid "German / Deutsch" -msgstr "" +msgstr "Nemško / Deutsch" #. module: base #: help:ir.actions.server,trigger_name:0 msgid "Select the Signal name that is to be used as the trigger." -msgstr "" +msgstr "Izberite ime signala, ki bo uporabljeno za sprožilec." #. module: base #: view:ir.actions.server:0 @@ -2226,7 +2336,7 @@ msgstr "Preslikava polj" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese / Português" -msgstr "" +msgstr "Portugalsko/ Português" #. module: base #: model:res.partner.title,name:base.res_partner_title_sir @@ -2237,7 +2347,7 @@ msgstr "Gospod" #: code:addons/orm.py:1622 #, python-format msgid "There is no view of type '%s' defined for the structure!" -msgstr "" +msgstr "Ni navedeno vrste pogleda '%s' za strukturo!" #. module: base #: field:ir.default,ref_id:0 @@ -2248,7 +2358,7 @@ msgstr "Sklic ID" #: model:ir.actions.server,name:base.action_start_configurator #: model:ir.ui.menu,name:base.menu_view_base_module_configuration msgid "Start Configuration" -msgstr "" +msgstr "Začni s konfiguracijo" #. module: base #: model:res.country,name:base.mt @@ -2258,7 +2368,7 @@ msgstr "Malta" #. module: base #: field:ir.actions.server,fields_lines:0 msgid "Field Mappings." -msgstr "" +msgstr "Preslikave polj" #. module: base #: model:ir.model,name:base.model_ir_module_module @@ -2286,7 +2396,7 @@ msgstr "Opis" #: model:ir.actions.act_window,name:base.action_workflow_instance_form #: model:ir.ui.menu,name:base.menu_workflow_instance msgid "Instances" -msgstr "Pojavitve" +msgstr "Primeri" #. module: base #: model:res.country,name:base.aq @@ -2296,12 +2406,12 @@ msgstr "Antarktika" #. module: base #: field:ir.actions.report.xml,auto:0 msgid "Custom python parser" -msgstr "" +msgstr "Python parser po meri" #. module: base #: view:base.language.import:0 msgid "_Import" -msgstr "" +msgstr "_Uvozi" #. module: base #: view:res.partner.canal:0 @@ -2311,17 +2421,17 @@ msgstr "Kanal" #. module: base #: field:res.lang,grouping:0 msgid "Separator Format" -msgstr "" +msgstr "Oblika ločila" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Unvalidated" -msgstr "" +msgstr "Ni potrjeno" #. module: base #: model:ir.ui.menu,name:base.next_id_9 msgid "Database Structure" -msgstr "Struktura skladišča podatkov" +msgstr "Struktura podatkovne baze" #. module: base #: model:ir.actions.act_window,name:base.action_partner_mass_mail @@ -2339,7 +2449,7 @@ msgstr "Mayotte" #: code:addons/base/ir/ir_actions.py:597 #, python-format msgid "Please specify an action to launch !" -msgstr "" +msgstr "Prosim, navedite dejanje za zagon!" #. module: base #: view:res.payterm:0 @@ -2349,7 +2459,7 @@ msgstr "Plačilni pogoj" #. module: base #: selection:res.lang,direction:0 msgid "Right-to-Left" -msgstr "" +msgstr "Z desne na levo" #. module: base #: view:ir.actions.act_window:0 @@ -2358,7 +2468,7 @@ msgstr "" #: model:ir.model,name:base.model_ir_filters #: model:ir.ui.menu,name:base.menu_ir_filters msgid "Filters" -msgstr "" +msgstr "Filtri" #. module: base #: code:addons/orm.py:758 @@ -2371,31 +2481,31 @@ msgstr "Preverite, če imajo vse vaše vrstice %d stolpcev." #: view:ir.cron:0 #: model:ir.ui.menu,name:base.menu_ir_cron_act msgid "Scheduled Actions" -msgstr "Planirane akcije" +msgstr "Planirana dejanja" #. module: base #: field:res.partner.address,title:0 #: field:res.partner.title,name:0 #: field:res.widget,title:0 msgid "Title" -msgstr "Titula" +msgstr "Naziv" #. module: base #: help:ir.property,res_id:0 msgid "If not set, acts as a default value for new resources" -msgstr "" +msgstr "Če ni nastavljeno, se obnaša kot privzera vrednost za nove vire" #. module: base #: code:addons/orm.py:3448 #, python-format msgid "Recursivity Detected." -msgstr "" +msgstr "Zaznana rekurzivnost." #. module: base #: code:addons/base/module/module.py:262 #, python-format msgid "Recursion error in modules dependencies !" -msgstr "Napaka rekurzije v odvisnostih modulov." +msgstr "Napaka rekurzije v odvisnostih modulih!" #. module: base #: view:base.language.install:0 @@ -2404,11 +2514,14 @@ msgid "" "loading a new language it becomes available as default interface language " "for users and partners." msgstr "" +"Ta čarovnik vam pomaga pri dodajanju novega jezika v vaš OpenERP sistem. Po " +"nalaganju novega jezika, postane dostopen kot privzeti jezik vmesnika vašim " +"uporabnikom in partnerjem." #. module: base #: view:ir.model:0 msgid "Create a Menu" -msgstr "Ustvari menu" +msgstr "Ustvari meni" #. module: base #: help:res.partner,vat:0 @@ -2416,11 +2529,13 @@ msgid "" "Value Added Tax number. Check the box if the partner is subjected to the " "VAT. Used by the VAT legal statement." msgstr "" +"Številka davka na dodano vrednost. Preverite polje, če je partner predmet " +"DDV. Uporabljeno za DDV pravno izjavo." #. module: base #: model:ir.model,name:base.model_maintenance_contract msgid "maintenance.contract" -msgstr "" +msgstr "maintenance.contract" #. module: base #: model:res.country,name:base.ru @@ -2435,7 +2550,7 @@ msgstr "" #. module: base #: field:res.company,name:0 msgid "Company Name" -msgstr "Naziv družbe" +msgstr "Ime podjetja" #. module: base #: model:ir.actions.act_window,name:base.action_country @@ -2446,7 +2561,7 @@ msgstr "Države" #. module: base #: selection:ir.translation,type:0 msgid "RML (deprecated - use Report)" -msgstr "" +msgstr "RML (opuščeno - uporabite Poročilo)" #. module: base #: view:ir.rule:0 @@ -2456,43 +2571,43 @@ msgstr "Posnemi pravila" #. module: base #: view:ir.property:0 msgid "Field Information" -msgstr "" +msgstr "Podatki polja" #. module: base #: view:ir.actions.todo:0 msgid "Search Actions" -msgstr "" +msgstr "Dejanje iskanja" #. module: base #: model:ir.actions.act_window,name:base.action_view_partner_wizard_ean_check #: view:partner.wizard.ean.check:0 msgid "Ean check" -msgstr "" +msgstr "Preveri ean" #. module: base #: field:res.partner,vat:0 msgid "VAT" -msgstr "DDV ID" +msgstr "DDV" #. module: base #: view:res.lang:0 msgid "12. %w ==> 5 ( Friday is the 6th day)" -msgstr "" +msgstr "12. %w ==> (Petek je šesti dan)" #. module: base #: constraint:res.partner.category:0 msgid "Error ! You can not create recursive categories." -msgstr "Napaka! Ne morete ustvariti rekurzivne kategorije." +msgstr "Napaka! Rekurzivnih kategorij ne morete ustvariti." #. module: base #: view:res.lang:0 msgid "%x - Appropriate date representation." -msgstr "" +msgstr "%x - Ustrezen datum zastopanja." #. module: base #: view:res.lang:0 msgid "%d - Day of the month [01,31]." -msgstr "" +msgstr "%d - Dan v mesecu [01,31]." #. module: base #: model:res.country,name:base.tj @@ -2502,12 +2617,12 @@ msgstr "Tadžikistan" #. module: base #: selection:ir.module.module,license:0 msgid "GPL-2 or later version" -msgstr "" +msgstr "GPL-2 ali naslednja verzija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir msgid "M." -msgstr "" +msgstr "G." #. module: base #: code:addons/base/module/module.py:429 @@ -2526,17 +2641,19 @@ msgid "" "Operation prohibited by access rules, or performed on an already deleted " "document (Operation: read, Document type: %s)." msgstr "" +"Operacijo prepovedujejo dostopna pravila, ali se izvajajo na že izbrisanem " +"dokumentnu (Operacija: branje, vrsta dokumenta: %s)." #. module: base #: model:res.country,name:base.nr msgid "Nauru" -msgstr "" +msgstr "Nauru" #. module: base #: code:addons/base/module/module.py:200 #, python-format msgid "The certificate ID of the module must be unique !" -msgstr "" +msgstr "ID potrdila modula mora biti edinstven!" #. module: base #: model:ir.model,name:base.model_ir_property @@ -2560,7 +2677,7 @@ msgstr "Črna gora" #. module: base #: view:ir.cron:0 msgid "Technical Data" -msgstr "" +msgstr "Tehnični podatki" #. module: base #: view:res.partner:0 @@ -2575,13 +2692,15 @@ msgid "" "import a language pack from here. Other OpenERP languages than the official " "ones can be found on launchpad." msgstr "" +"Če potrebujete drug jezik, ki je uradno dostopen, ga lahko tukaj uvozite. " +"Ostali OpenERP jeziki, ki niso uradni, so dostopni na launchpad." #. module: base #: view:ir.module.module:0 #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "To be upgraded" -msgstr "Za nadgraditi" +msgstr "Bo nadgrajeno" #. module: base #: model:res.country,name:base.ly @@ -2596,7 +2715,7 @@ msgstr "Centralnoafriška republika" #. module: base #: model:res.country,name:base.li msgid "Liechtenstein" -msgstr "" +msgstr "Liechtenstein" #. module: base #: model:ir.model,name:base.model_partner_sms_send @@ -2613,7 +2732,7 @@ msgstr "Črtna koda (EAN13)" #: code:addons/orm.py:1622 #, python-format msgid "Invalid Architecture!" -msgstr "" +msgstr "Neveljavna arhitektura" #. module: base #: model:res.country,name:base.pt @@ -2624,12 +2743,12 @@ msgstr "Portugalska" #: sql_constraint:ir.model.data:0 msgid "" "You cannot have multiple records with the same id for the same module !" -msgstr "" +msgstr "Ne morete imeti več zapisov z istim id za isti modul!" #. module: base #: field:ir.module.module,certificate:0 msgid "Quality Certificate" -msgstr "" +msgstr "Potrdilo kakovosti" #. module: base #: view:res.lang:0 @@ -2640,17 +2759,17 @@ msgstr "6. %d, %m ==> 05, 12" #: field:res.config.users,date:0 #: field:res.users,date:0 msgid "Last Connection" -msgstr "" +msgstr "Zadnja povezava" #. module: base #: field:ir.actions.act_window,help:0 msgid "Action description" -msgstr "" +msgstr "Opis dejanja" #. module: base #: help:res.partner,customer:0 msgid "Check this box if the partner is a customer." -msgstr "" +msgstr "Označite to polje, če je partner stranka." #. module: base #: model:ir.actions.act_window,name:base.res_lang_act_window @@ -2664,7 +2783,7 @@ msgstr "Jeziki" #: selection:workflow.activity,join_mode:0 #: selection:workflow.activity,split_mode:0 msgid "Xor" -msgstr "Izključujoči ALI" +msgstr "Xor" #. module: base #: model:res.country,name:base.ec @@ -2689,7 +2808,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_partner_form #: view:res.partner:0 msgid "Customers" -msgstr "" +msgstr "Stranke" #. module: base #: model:res.country,name:base.au @@ -2718,12 +2837,12 @@ msgstr "Osnovno polje" #. module: base #: view:publisher_warranty.contract:0 msgid "Validate" -msgstr "" +msgstr "Preveri" #. module: base #: field:ir.actions.todo,restart:0 msgid "Restart" -msgstr "" +msgstr "Ponoven zagon" #. module: base #: field:ir.actions.report.xml,report_sxw_content:0 @@ -2740,13 +2859,15 @@ msgstr "Čarovnik" #. module: base #: view:ir.cron:0 msgid "Action to Trigger" -msgstr "" +msgstr "Dejanje za zagon" #. module: base #: code:addons/base/res/res_user.py:136 #, python-format msgid "\"email_from\" needs to be set to send welcome mails to users" msgstr "" +"\"email_form\" mora biti nastavljen za pošiljanje e-pošte dobrodošlice " +"uporabnikom" #. module: base #: selection:ir.translation,type:0 @@ -2764,12 +2885,12 @@ msgstr "Privzeto" #: field:ir.model.fields,required:0 #: field:res.partner.bank.type.field,required:0 msgid "Required" -msgstr "Obvezno" +msgstr "Zahtevano" #. module: base #: view:res.users:0 msgid "Default Filters" -msgstr "" +msgstr "Privzeti filtri" #. module: base #: field:res.request.history,name:0 @@ -2779,7 +2900,7 @@ msgstr "Povzetek" #. module: base #: field:multi_company.default,expression:0 msgid "Expression" -msgstr "" +msgstr "Izraz" #. module: base #: help:ir.actions.server,subject:0 @@ -2787,6 +2908,8 @@ msgid "" "Specify the subject. You can use fields from the object, e.g. `Hello [[ " "object.partner_id.name ]]`" msgstr "" +"Navedite predmet. Uporabite lahko polja iz predmeta, npr. 'Pozdravljeni " +"[[object.partner_id.name]]'" #. module: base #: view:res.company:0 @@ -2799,6 +2922,8 @@ msgid "" "Optional help text for the users with a description of the target view, such " "as its usage and purpose." msgstr "" +"Opcijski teksti pomoči za uporabnike z opisi ciljnega pogleda, kot je " +"uporaba in namen." #. module: base #: model:res.country,name:base.va @@ -2813,28 +2938,28 @@ msgstr ".ZIP datoteka modula" #. module: base #: field:ir.ui.view,xml_id:0 msgid "XML ID" -msgstr "" +msgstr "ID XML" #. module: base #: model:res.partner.category,name:base.res_partner_category_16 msgid "Telecom sector" -msgstr "" +msgstr "Sektor telekom" #. module: base #: field:workflow.transition,trigger_model:0 msgid "Trigger Object" -msgstr "" +msgstr "Predmet sprožilca" #. module: base #: view:res.users:0 msgid "Current Activity" -msgstr "" +msgstr "Trenutna aktivnost" #. module: base #: view:workflow.activity:0 #: field:workflow.activity,in_transitions:0 msgid "Incoming Transitions" -msgstr "" +msgstr "Prihajajočite transakcije" #. module: base #: model:res.country,name:base.sr @@ -2844,7 +2969,7 @@ msgstr "Surinam" #. module: base #: model:ir.ui.menu,name:base.marketing_menu msgid "Marketing" -msgstr "" +msgstr "Marketing" #. module: base #: view:res.partner.bank:0 @@ -2855,7 +2980,7 @@ msgstr "Bančni račun" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (HN) / Español (HN)" -msgstr "" +msgstr "Špansko (HN) / Español (HN)" #. module: base #: view:ir.sequence.type:0 @@ -2865,7 +2990,7 @@ msgstr "Vrsta zaporedja" #. module: base #: view:ir.ui.view.custom:0 msgid "Customized Architecture" -msgstr "" +msgstr "Prilagojena arhitektura" #. module: base #: field:ir.module.module,license:0 @@ -2875,17 +3000,17 @@ msgstr "Licenca" #. module: base #: field:ir.attachment,url:0 msgid "Url" -msgstr "" +msgstr "Url" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Always" -msgstr "" +msgstr "Vedno" #. module: base #: selection:ir.translation,type:0 msgid "SQL Constraint" -msgstr "" +msgstr "SQL omejitve" #. module: base #: field:ir.actions.server,srcmodel_id:0 @@ -2899,11 +3024,13 @@ msgid "" "The selected language has been successfully installed. You must change the " "preferences of the user and open a new menu to view the changes." msgstr "" +"Izbrani jezik je bil uspešno nameščen. Spremeniti morate lasnosti uporabnika " +"in odpreti nov meni za ogled sprememb." #. module: base #: sql_constraint:ir.config_parameter:0 msgid "Key must be unique." -msgstr "" +msgstr "Ključ mora biti edinstven." #. module: base #: view:ir.actions.act_window:0 @@ -2919,7 +3046,7 @@ msgstr "Ekvatorialna Gvineja" #: view:base.module.import:0 #: model:ir.actions.act_window,name:base.action_view_base_module_import msgid "Module Import" -msgstr "" +msgstr "Uvoz modula" #. module: base #: field:res.bank,zip:0 @@ -2937,12 +3064,12 @@ msgstr "Avtor" #. module: base #: model:res.country,name:base.mk msgid "FYROM" -msgstr "" +msgstr "FYROM" #. module: base #: view:res.lang:0 msgid "%c - Appropriate date and time representation." -msgstr "" +msgstr "%c - Ustrezni datum in čas zastopanja." #. module: base #: code:addons/base/res/res_config.py:422 @@ -2952,11 +3079,14 @@ msgid "" "\n" "Click 'Continue' and enjoy your OpenERP experience..." msgstr "" +"Vaša podatkovna baza je v celoti konfigurirana.\n" +"\n" +"Kliknite 'Nadaljuj' in uživajte v izkušnji OpenERP..." #. module: base #: selection:base.language.install,lang:0 msgid "Hebrew / עִבְרִי" -msgstr "" +msgstr "Židovsko / עִבְרִי" #. module: base #: model:res.country,name:base.bo @@ -2999,12 +3129,12 @@ msgstr "Poskušate odstraniti modul, ki je nameščen ali bo nameščen" #. module: base #: view:base.module.upgrade:0 msgid "The selected modules have been updated / installed !" -msgstr "" +msgstr "Izbrani moduli so bili posodobljeni / nameščeni!" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PR) / Español (PR)" -msgstr "" +msgstr "Špansko (PR) / Español (PR)" #. module: base #: model:res.country,name:base.gt @@ -3017,17 +3147,17 @@ msgstr "Gvatemala" #: model:ir.ui.menu,name:base.menu_workflow #: model:ir.ui.menu,name:base.menu_workflow_root msgid "Workflows" -msgstr "Poteki dela" +msgstr "Delovni procesi" #. module: base #: field:ir.translation,xml_id:0 msgid "XML Id" -msgstr "" +msgstr "Id XML" #. module: base #: model:ir.actions.act_window,name:base.action_config_user_form msgid "Create Users" -msgstr "" +msgstr "Ustvari uporabnike" #. module: base #: model:ir.model,name:base.model_res_partner_title @@ -3037,12 +3167,12 @@ msgstr "res.partner.title" #. module: base #: view:ir.values:0 msgid "tree_but_action, client_print_multi" -msgstr "" +msgstr "Copy text \t tree_but_action, client_print_multi" #. module: base #: model:res.partner.category,name:base.res_partner_category_retailers0 msgid "Retailers" -msgstr "" +msgstr "Trgovci na drobno" #. module: base #: help:ir.cron,priority:0 @@ -3068,7 +3198,7 @@ msgstr "Lesoto" #: code:addons/base/ir/ir_model.py:114 #, python-format msgid "You can not remove the model '%s' !" -msgstr "Ne morete odstraniti modela '%s'." +msgstr "Ne morete odstraniti modela '%s'!" #. module: base #: model:res.country,name:base.ke @@ -3078,12 +3208,12 @@ msgstr "Kenija" #. module: base #: view:res.partner.event:0 msgid "Event" -msgstr "" +msgstr "Dogodek" #. module: base #: model:ir.ui.menu,name:base.menu_custom_reports msgid "Custom Reports" -msgstr "" +msgstr "Poročila po meri" #. module: base #: selection:base.language.install,lang:0 @@ -3093,18 +3223,18 @@ msgstr "" #. module: base #: view:base.module.configuration:0 msgid "System Configuration Done" -msgstr "" +msgstr "Konfiguracija sistema končana" #. module: base #: code:addons/orm.py:929 #, python-format msgid "Error occurred while validating the field(s) %s: %s" -msgstr "" +msgstr "Napaka se je pojavila med preverjanjem polj %s: %s" #. module: base #: view:ir.property:0 msgid "Generic" -msgstr "" +msgstr "Splošno" #. module: base #: model:res.country,name:base.sm @@ -3135,17 +3265,17 @@ msgstr "Benin" #: code:addons/base/publisher_warranty/publisher_warranty.py:281 #, python-format msgid "That contract is already registered in the system." -msgstr "" +msgstr "Ta pogodba je že registrirana v sistemu." #. module: base #: help:ir.sequence,suffix:0 msgid "Suffix value of the record for the sequence" -msgstr "" +msgstr "Pripona vrednosti zapisa za zaporedje" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PY) / Español (PY)" -msgstr "" +msgstr "Špansko (PY) / Español (PY)" #. module: base #: field:ir.config_parameter,key:0 @@ -3169,17 +3299,19 @@ msgid "" "You can not create this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"Ne morete ustvariti tega dokumenta (%s)! Bodite prepričani, da vaš " +"uporabnik pripada tem skupinam: %s." #. module: base #: model:res.country,name:base.mu msgid "Mauritius" -msgstr "" +msgstr "Mauricius" #. module: base #: view:ir.model.access:0 #: view:ir.rule:0 msgid "Full Access" -msgstr "" +msgstr "Polni dostop" #. module: base #: view:ir.actions.act_window:0 @@ -3193,7 +3325,7 @@ msgstr "Varnost" #. module: base #: model:res.widget,title:base.openerp_favorites_twitter_widget msgid "OpenERP Favorites" -msgstr "" +msgstr "OpenERP priljubljene" #. module: base #: model:res.country,name:base.za @@ -3210,13 +3342,13 @@ msgstr "Namščen" #. module: base #: selection:base.language.install,lang:0 msgid "Ukrainian / українська" -msgstr "" +msgstr "Ukrajinsko / українська" #. module: base #: model:ir.actions.act_window,name:base.action_translation #: model:ir.ui.menu,name:base.menu_action_translation msgid "Translation Terms" -msgstr "" +msgstr "Pogoji prevodov" #. module: base #: model:res.country,name:base.sn @@ -3241,12 +3373,12 @@ msgstr "Brazilija" #. module: base #: view:res.lang:0 msgid "%M - Minute [00,59]." -msgstr "" +msgstr "%M - Minute [00,59]." #. module: base #: selection:ir.module.module,license:0 msgid "Affero GPL-3" -msgstr "" +msgstr "Affero GPL-3" #. module: base #: field:ir.sequence,number_next:0 @@ -3256,12 +3388,12 @@ msgstr "Naslednja številka" #. module: base #: help:workflow.transition,condition:0 msgid "Expression to be satisfied if we want the transition done." -msgstr "" +msgstr "Izraz, ki ja treba izpolniti, če želimo izpolniti transakcijo." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PA) / Español (PA)" -msgstr "" +msgstr "Špansko (PA) / Español (PA)" #. module: base #: view:res.currency:0 @@ -3286,11 +3418,14 @@ msgid "" "invoice, then `object.invoice_address_id.mobile` is the field which gives " "the correct mobile number" msgstr "" +"Zagotavlja polja, ki se uporablja za pridobivanje mobilne številke, npr, " +"izberete račun, nato pa polje `object.invoice_address_id.mobile`, ki daje " +"pravo mobilno številko" #. module: base #: view:base.module.upgrade:0 msgid "System update completed" -msgstr "" +msgstr "Posodobitev sistema je končano" #. module: base #: selection:res.request,state:0 @@ -3321,28 +3456,28 @@ msgstr "Podatki" #: field:ir.ui.menu,parent_id:0 #: field:wizard.ir.model.menu.create,menu_id:0 msgid "Parent Menu" -msgstr "Nadmenu" +msgstr "Nameni" #. module: base #: field:ir.rule,perm_unlink:0 msgid "Apply For Delete" -msgstr "" +msgstr "Uporabi za izbris" #. module: base #: code:addons/base/ir/ir_model.py:319 #, python-format msgid "Cannot rename column to %s, because that column already exists!" -msgstr "" +msgstr "Ne morem preimenovati stolpca v %s, ker ta stolpec že obstaja." #. module: base #: view:ir.attachment:0 msgid "Attached To" -msgstr "" +msgstr "Pripeto k" #. module: base #: field:res.lang,decimal_point:0 msgid "Decimal Separator" -msgstr "" +msgstr "Decimalni ločevalnik" #. module: base #: model:ir.actions.act_window,help:base.action_res_groups @@ -3354,6 +3489,12 @@ msgid "" "to see. Whether they can have a read, write, create and delete access right " "can be managed from here." msgstr "" +"Skupina je nabor funkcionalnih območij, ki bodo dodeljene uporabniku, da se " +"jim omogoči dostop in pravice do specifičnih aplikacij in nalog v sistemu. " +"Lahko ustvarite skupine po meri ali uredite tiste, ki veljajo privzeto, da " +"si prilagodite pogled menija, ki ga bodo uporabniki lahko videli. Ali lahko " +"imajo pravice za dosotp do branje, pisanje, ustvarjanje in brisanje, lahko " +"upravljate od tukaj." #. module: base #: view:res.partner:0 @@ -3377,6 +3518,12 @@ msgid "" "Would your payment have been carried out after this mail was sent, please " "consider the present one as void." msgstr "" +"Prosimo, upoštevajte, da so naslednja plačila sedaj na vrsti. Če je bilo " +"poslano vaše plačilo, prosimo, posredujte vaše podatke plačila. Če bo " +"plačilo dodatno zamudilo, se prosim obrnite na nas glede tega. " +" \n" +"Če je bilo vaše plačilo izvedeno po tem, ko je bil poslano to sporočilo, " +"prosimo, obravnavajte prejšnjega kot neveljavnega." #. module: base #: model:res.country,name:base.mx @@ -3386,12 +3533,12 @@ msgstr "Mehika" #. module: base #: model:ir.ui.menu,name:base.menu_base_config_plugins msgid "Plugins" -msgstr "" +msgstr "Vtičniki" #. module: base #: field:res.company,child_ids:0 msgid "Child Companies" -msgstr "Hčerinske družbe" +msgstr "Hčerinska podjetja" #. module: base #: model:ir.model,name:base.model_res_users @@ -3407,7 +3554,7 @@ msgstr "Nikaragva" #: code:addons/orm.py:1046 #, python-format msgid "The write method is not implemented on this object !" -msgstr "Metoda 'write' ni implementirana za ta objekt." +msgstr "Metoda 'write' ni implementirana za ta predmet!" #. module: base #: view:res.partner.event:0 @@ -3418,7 +3565,7 @@ msgstr "Splošni opis" #: model:ir.actions.act_window,name:base.action_config_simple_view_form #: view:res.config.view:0 msgid "Configure Your Interface" -msgstr "" +msgstr "Nastavite vaš vmesnik" #. module: base #: field:ir.values,meta:0 @@ -3428,7 +3575,7 @@ msgstr "Meta podatki" #. module: base #: sql_constraint:ir.ui.view_sc:0 msgid "Shortcut for this menu already exists!" -msgstr "" +msgstr "Bližnjica za ta meni že obstaja!" #. module: base #: model:res.country,name:base.ve @@ -3456,7 +3603,7 @@ msgstr "" #. module: base #: field:res.partner,parent_id:0 msgid "Parent Partner" -msgstr "" +msgstr "Matični partner" #. module: base #: view:ir.module.module:0 @@ -3476,7 +3623,7 @@ msgstr "Kazahstan" #. module: base #: view:res.lang:0 msgid "%w - Weekday number [0(Sunday),6]." -msgstr "" +msgstr "%w - Številka dneva v tednu [0(nedelja),6]" #. module: base #: model:ir.actions.act_window,help:base.action_partner_form @@ -3489,6 +3636,13 @@ msgid "" "plugin, don't forget to register emails to each contact so that the gateway " "will automatically attach incoming emails to the right partner." msgstr "" +"Stranka je bistvo s katerim poslujete, kot podjetje ali organizacija. " +"Stranka ima lahko več kontaktov ali naslovov, ki so ljudje, kateri delajo za " +"t o podjetje. Lahko uporabite zavihek zgodovina, za spremljanje vseh " +"transakcij stranke, prodajna naročila, e-pošta, priložnosti, pritožbe, itd. " +"Če uporabljate e-poštni prehod, vtičnik Outlook ali Thunderbird, ne pozabite " +"registrirati e-pošte vsakemu kontaktu, tako da bo prehod avtomatsko pripel e-" +"pošte k pravemu partnerju." #. module: base #: field:ir.actions.report.xml,name:0 @@ -3516,7 +3670,7 @@ msgstr "" #: field:workflow,name:0 #: field:workflow.activity,name:0 msgid "Name" -msgstr "Naziv" +msgstr "Ime" #. module: base #: help:ir.actions.act_window,multi:0 @@ -3524,6 +3678,8 @@ msgid "" "If set to true, the action will not be displayed on the right toolbar of a " "form view" msgstr "" +"Če je nastavljeno na true, dejanje ne bo prikazano v desni orodni vrstici " +"pogleda obrazca." #. module: base #: model:res.country,name:base.ms @@ -3537,6 +3693,8 @@ msgid "" "The Selection Options expression is not a valid Pythonic expression.Please " "provide an expression in the [('key','Label'), ...] format." msgstr "" +"Izraz možnosti izražanja ni veljaven Pythonic izraza. Prosim navedite izraz " +"v [(\"ključ\", \"oznaka\"), ...] obliki." #. module: base #: model:ir.ui.menu,name:base.menu_translation_app @@ -3550,6 +3708,8 @@ msgid "" "The user's timezone, used to perform timezone conversions between the server " "and the client." msgstr "" +"Uporabniški časovni pas, uporabljen za pretvorbo časovnega pasa med " +"strežnikom in klientom." #. module: base #: field:ir.module.module,demo:0 @@ -3559,12 +3719,12 @@ msgstr "Predstavitveni podatki" #. module: base #: selection:base.language.install,lang:0 msgid "English (UK)" -msgstr "" +msgstr "Angleščina (Združeno kraljestvo)" #. module: base #: selection:base.language.install,lang:0 msgid "Japanese / 日本語" -msgstr "" +msgstr "Japonsko / 日本語" #. module: base #: help:workflow.transition,act_from:0 @@ -3572,11 +3732,13 @@ msgid "" "Source activity. When this activity is over, the condition is tested to " "determine if we can start the ACT_TO activity." msgstr "" +"Vir dejavnost. Ko je ta dejavnost končana je pogoj preizkušen, da se " +"ugotovi, ali bomo lahko začeli dejavnost ACT_TO." #. module: base #: model:res.partner.category,name:base.res_partner_category_3 msgid "Starter Partner" -msgstr "" +msgstr "Začetni partner" #. module: base #: help:ir.model.fields,relation_field:0 @@ -3584,6 +3746,8 @@ msgid "" "For one2many fields, the field on the target model that implement the " "opposite many2one relationship" msgstr "" +"Za one2many polja, v polje na ciljni model, ki izvajajo nasprotno odnos " +"many2one" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window_view @@ -3598,12 +3762,12 @@ msgstr "Splet" #. module: base #: selection:base.language.install,lang:0 msgid "English (CA)" -msgstr "" +msgstr "Angleško (CA)" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract msgid "publisher_warranty.contract" -msgstr "" +msgstr "publisher_warranty.contract" #. module: base #: model:res.country,name:base.et @@ -3613,12 +3777,12 @@ msgstr "Etiopija" #. module: base #: help:res.country.state,code:0 msgid "The state code in three chars.\n" -msgstr "" +msgstr "Koda zvezne države v treh znakih.\n" #. module: base #: model:res.country,name:base.sj msgid "Svalbard and Jan Mayen Islands" -msgstr "" +msgstr "Svalbardovi in Jan Mayenovi otoki" #. module: base #: model:ir.model,name:base.model_ir_actions_wizard @@ -3639,17 +3803,17 @@ msgstr "Združi po" #: view:res.config:0 #: view:res.config.installer:0 msgid "title" -msgstr "" +msgstr "naslov" #. module: base #: model:ir.model,name:base.model_base_language_install msgid "Install Language" -msgstr "" +msgstr "Namesti jezik" #. module: base #: view:ir.translation:0 msgid "Translation" -msgstr "" +msgstr "Prevod" #. module: base #: selection:res.request,state:0 @@ -3669,34 +3833,34 @@ msgstr "Lastnost 'on_delete' za za 'many2one' polja" #. module: base #: field:ir.actions.server,write_id:0 msgid "Write Id" -msgstr "" +msgstr "Id zapisa" #. module: base #: model:ir.ui.menu,name:base.menu_product msgid "Products" -msgstr "" +msgstr "Izdelki" #. module: base #: field:ir.actions.act_window,domain:0 #: field:ir.filters,domain:0 msgid "Domain Value" -msgstr "" +msgstr "Vrednost domene" #. module: base #: view:ir.actions.server:0 msgid "SMS Configuration" -msgstr "" +msgstr "SMS konfiguracija" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (BO) / Español (BO)" -msgstr "" +msgstr "Špansko (BO) / Español (BO)" #. module: base #: model:ir.actions.act_window,name:base.ir_access_act #: model:ir.ui.menu,name:base.menu_ir_access_act msgid "Access Controls List" -msgstr "" +msgstr "Seznam kontrole dostopa" #. module: base #: model:res.country,name:base.um @@ -3707,7 +3871,7 @@ msgstr "" #: field:res.partner.bank,state:0 #: field:res.partner.bank.type.field,bank_type_id:0 msgid "Bank Type" -msgstr "" +msgstr "Vrsta banke" #. module: base #: code:addons/base/res/res_user.py:58 @@ -3738,11 +3902,13 @@ msgstr "" msgid "" "Unable to process module \"%s\" because an external dependency is not met: %s" msgstr "" +"Ni mogoče procesirati modula \"%s\", ker zunanja odvisnost ni izpolnjena: %s" #. module: base #: view:publisher_warranty.contract.wizard:0 msgid "Please enter the serial key provided in your contract document:" msgstr "" +"Prosim vnestite serijski ključ, ki je naveden na vašem dokumentu pogodbe" #. module: base #: view:workflow.activity:0 @@ -3754,23 +3920,23 @@ msgstr "Začetek poteka dela" #: code:addons/__init__.py:834 #, python-format msgid "module base cannot be loaded! (hint: verify addons-path)" -msgstr "" +msgstr "osnova modula ne more biti naložena (namig: preverite pod dodatkov)" #. module: base #: view:res.partner.bank:0 msgid "Bank Account Owner" -msgstr "" +msgstr "Lastnik bančnega računa" #. module: base #: model:ir.actions.act_window,name:base.act_values_form msgid "Client Actions Connections" -msgstr "" +msgstr "Povezave dejanj klienta" #. module: base #: field:ir.attachment,res_name:0 #: field:ir.ui.view_sc,resource:0 msgid "Resource Name" -msgstr "Naziv resursa" +msgstr "Ime vira" #. module: base #: selection:ir.cron,interval_type:0 @@ -3797,11 +3963,14 @@ msgid "" "form, signal tests the name of the pressed button. If signal is NULL, no " "button is necessary to validate this transition." msgstr "" +"Ko operacija transakcije pride iz pritisnjenega gumba v obrazcu klienta, " +"signal testira ime pritisnjenega gumba. Če je signal NULL, ni potreben gumb " +"za preverjanje transakcije." #. module: base #: help:multi_company.default,object_id:0 msgid "Object affected by this rule" -msgstr "" +msgstr "To pravilo vpliva na predmet" #. module: base #: report:ir.module.reference.graph:0 @@ -3811,17 +3980,17 @@ msgstr "Imenik" #. module: base #: field:wizard.ir.model.menu.create,name:0 msgid "Menu Name" -msgstr "Naziv menuja" +msgstr "Ime Menija" #. module: base #: view:ir.module.module:0 msgid "Author Website" -msgstr "" +msgstr "Avtorjeva spletna stran" #. module: base #: view:ir.attachment:0 msgid "Month" -msgstr "" +msgstr "Mesec" #. module: base #: model:res.country,name:base.my @@ -3832,7 +4001,7 @@ msgstr "Malezija" #: view:base.language.install:0 #: model:ir.actions.act_window,name:base.action_view_base_language_install msgid "Load Official Translation" -msgstr "" +msgstr "Naloži uraden prevod" #. module: base #: model:ir.model,name:base.model_res_request_history @@ -3842,7 +4011,7 @@ msgstr "res.request.history" #. module: base #: view:ir.actions.server:0 msgid "Client Action Configuration" -msgstr "" +msgstr "Nastavitve klientovih dejanj" #. module: base #: model:ir.model,name:base.model_res_partner_address @@ -3856,11 +4025,13 @@ msgid "" "Whether values for this field can be translated (enables the translation " "mechanism for that field)" msgstr "" +"Ali so lahko te vrednosti za to polje prevedene (omogoči prevajalni " +"mehanizem za to polje)" #. module: base #: view:res.lang:0 msgid "%S - Seconds [00,61]." -msgstr "" +msgstr "%S - Sekund [00,61]" #. module: base #: model:res.country,name:base.cv @@ -3870,7 +4041,7 @@ msgstr "Zelenortski otoki" #. module: base #: view:base.module.import:0 msgid "Select module package to import (.zip file):" -msgstr "" +msgstr "Izberite paket modula za uvoz (.zip datoteka)" #. module: base #: model:ir.actions.act_window,name:base.act_res_partner_event @@ -3889,13 +4060,14 @@ msgstr "ir.actions.url" #. module: base #: model:res.widget,title:base.currency_converter_widget msgid "Currency Converter" -msgstr "" +msgstr "Pretvornik valik" #. module: base #: code:addons/orm.py:156 #, python-format msgid "Wrong ID for the browse record, got %r, expected an integer." msgstr "" +"Napačen ID za brskanje zapisa, dobljen %r, pričakovano celo številko." #. module: base #: model:ir.actions.act_window,name:base.action_partner_addess_tree @@ -3911,7 +4083,7 @@ msgstr "Število dodanih modulov" #. module: base #: view:res.currency:0 msgid "Price Accuracy" -msgstr "" +msgstr "Natančnost cene" #. module: base #: selection:base.language.install,lang:0 @@ -3922,7 +4094,7 @@ msgstr "" #: view:res.config:0 #: view:res.config.installer:0 msgid "vsep" -msgstr "" +msgstr "vsep" #. module: base #: selection:base.language.install,lang:0 @@ -3933,17 +4105,17 @@ msgstr "" #: code:addons/orm.py:1049 #, python-format msgid "The create method is not implemented on this object !" -msgstr "Metoda 'create' ni implementirana za ta objekt." +msgstr "Metoda 'create' ni implementirana za ta predmet!" #. module: base #: field:workflow.triggers,workitem_id:0 msgid "Workitem" -msgstr "" +msgstr "Postavka dela" #. module: base #: view:ir.actions.todo:0 msgid "Set as Todo" -msgstr "" +msgstr "Nastavi na Je treba opraviti" #. module: base #: field:ir.actions.act_window.view,act_window_id:0 @@ -3954,7 +4126,7 @@ msgstr "" #: selection:ir.values,key:0 #: view:res.users:0 msgid "Action" -msgstr "Akcija" +msgstr "Dejanje" #. module: base #: view:ir.actions.server:0 @@ -3969,22 +4141,22 @@ msgstr "ir.cron" #. module: base #: view:ir.rule:0 msgid "Combination of rules" -msgstr "" +msgstr "Kombinacija pravil" #. module: base #: view:ir.sequence:0 msgid "Current Year without Century: %(y)s" -msgstr "" +msgstr "Trenutno leto brez stoletja: %(y)s" #. module: base #: field:ir.actions.server,trigger_obj_id:0 msgid "Trigger On" -msgstr "" +msgstr "Sprožilec vključen" #. module: base #: sql_constraint:ir.rule:0 msgid "Rule must have at least one checked access right !" -msgstr "" +msgstr "Pravilo mora imet vsaj eno označeno pravilo dostopa!" #. module: base #: model:res.country,name:base.fj @@ -4016,7 +4188,7 @@ msgstr "Zgodovina zahteve" #: field:ir.module.module,menus_by_module:0 #: view:res.groups:0 msgid "Menus" -msgstr "Menuji" +msgstr "Meniji" #. module: base #: selection:base.language.install,lang:0 @@ -4038,17 +4210,17 @@ msgstr "Ustvari dejanje" #: model:ir.model,name:base.model_ir_model #: model:ir.ui.menu,name:base.ir_model_model_menu msgid "Objects" -msgstr "Objekti" +msgstr "Predmeti" #. module: base #: field:res.lang,time_format:0 msgid "Time Format" -msgstr "Oblika zapisa časa" +msgstr "Oblika časa" #. module: base #: view:ir.module.module:0 msgid "Defined Reports" -msgstr "" +msgstr "Opredeljena poročila" #. module: base #: view:ir.actions.report.xml:0 @@ -4076,7 +4248,7 @@ msgstr "Delni potek" #. module: base #: model:ir.model,name:base.model_res_config msgid "res.config" -msgstr "" +msgstr "res.config" #. module: base #: field:workflow.transition,signal:0 @@ -4099,17 +4271,17 @@ msgstr "" #. module: base #: field:ir.cron,doall:0 msgid "Repeat Missed" -msgstr "" +msgstr "Zgrešene ponovitve" #. module: base #: help:ir.actions.server,state:0 msgid "Type of the Action that is to be executed" -msgstr "" +msgstr "Vrsta dejanja, ki bo izvršeno" #. module: base #: field:ir.server.object.lines,server_id:0 msgid "Object Mapping" -msgstr "Preslikava objekta" +msgstr "Preslikava predmeta" #. module: base #: help:res.currency,rate:0 @@ -4127,29 +4299,30 @@ msgstr "Združeno kraljestvo" #: view:res.config.users:0 #: view:res.config.view:0 msgid "res_config_contents" -msgstr "" +msgstr "res_config_contents" #. module: base #: help:res.partner.category,active:0 msgid "The active field allows you to hide the category without removing it." msgstr "" +"Polje dejanja vam dovoljuje skrivanje kategorije brez, da bi jo odstranili." #. module: base #: report:ir.module.reference.graph:0 msgid "Object:" -msgstr "Objekt:" +msgstr "Predmet:" #. module: base #: model:res.country,name:base.bw msgid "Botswana" -msgstr "" +msgstr "Botsvana" #. module: base #: model:ir.actions.act_window,name:base.action_partner_title_partner #: model:ir.ui.menu,name:base.menu_partner_title_partner #: view:res.partner.title:0 msgid "Partner Titles" -msgstr "" +msgstr "Nazivi partnerja" #. module: base #: help:ir.actions.act_window,auto_refresh:0 @@ -4159,7 +4332,7 @@ msgstr "Dodaj samoosvežitev k pogledu" #. module: base #: help:res.partner,employee:0 msgid "Check this box if the partner is an Employee." -msgstr "" +msgstr "Označi to polje, če je partner zaposlen" #. module: base #: field:ir.actions.report.xml,report_rml_content:0 @@ -4171,7 +4344,7 @@ msgstr "RML vsebina" #: model:ir.actions.act_window,name:base.action_workflow_workitem_form #: model:ir.ui.menu,name:base.menu_workflow_workitem msgid "Workitems" -msgstr "" +msgstr "Predmeti dela" #. module: base #: field:base.language.export,advice:0 @@ -4190,11 +4363,13 @@ msgid "" "You cannot perform this operation. New Record Creation is not allowed for " "this object as this object is for reporting purpose." msgstr "" +"Ne morete izvesti te operacije. Ustvaritev novega zapisa ni dovoljeno za ta " +"predemet, ker je ta predmet namenjen samo za poročanje." #. module: base #: view:base.language.import:0 msgid "- module,type,name,res_id,src,value" -msgstr "" +msgstr "- module,type,name,res_id,src,value" #. module: base #: selection:base.language.install,lang:0 @@ -4207,11 +4382,13 @@ msgid "" "Provide the field name where the record id is stored after the create " "operations. If it is empty, you can not track the new record." msgstr "" +"Navedite ime polja kjer je id zapisa shranjen po operaciji kreacije. Če je " +"prazen, ne morete slediti novega zapisa." #. module: base #: help:ir.model.fields,relation:0 msgid "For relationship fields, the technical name of the target model" -msgstr "" +msgstr "Za sorodna polja, tehnično ime ciljnega modela" #. module: base #: selection:base.language.install,lang:0 @@ -4226,43 +4403,43 @@ msgstr "Podedovan pogled" #. module: base #: view:ir.translation:0 msgid "Source Term" -msgstr "" +msgstr "Izraz izvora" #. module: base #: model:ir.ui.menu,name:base.menu_main_pm msgid "Project" -msgstr "" +msgstr "Projekt" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 msgid "Web Icon Image (hover)" -msgstr "" +msgstr "Slika spletne ikone (hover)" #. module: base #: view:base.module.import:0 msgid "Module file successfully imported!" -msgstr "" +msgstr "Datoteka modula je bila uspešno uvožena!" #. module: base #: selection:ir.actions.todo,state:0 msgid "Cancelled" -msgstr "" +msgstr "Preklicano" #. module: base #: view:res.config.users:0 msgid "Create User" -msgstr "" +msgstr "Ustvari uporabnika" #. module: base #: view:partner.clear.ids:0 msgid "Want to Clear Ids ? " -msgstr "" +msgstr "Želite počistiti Id-je? " #. module: base #: field:publisher_warranty.contract,name:0 #: field:publisher_warranty.contract.wizard,name:0 msgid "Serial Key" -msgstr "" +msgstr "Serijski ključ" #. module: base #: selection:res.request,priority:0 @@ -4272,12 +4449,12 @@ msgstr "Nizka" #. module: base #: model:ir.ui.menu,name:base.menu_audit msgid "Audit" -msgstr "" +msgstr "Pregled računov" #. module: base #: model:res.country,name:base.lc msgid "Saint Lucia" -msgstr "" +msgstr "Sveta Lucija" #. module: base #: view:publisher_warranty.contract:0 @@ -4287,12 +4464,12 @@ msgstr "Vzdrežvalna pogodba" #. module: base #: help:ir.actions.server,trigger_obj_id:0 msgid "Select the object from the model on which the workflow will executed." -msgstr "" +msgstr "Izberite predmet iz modela na katerem bo delovni proces izvršen." #. module: base #: field:res.partner,employee:0 msgid "Employee" -msgstr "" +msgstr "Zaposleni" #. module: base #: field:ir.model.access,perm_create:0 @@ -4302,34 +4479,34 @@ msgstr "Ustvari dostop" #. module: base #: field:res.partner.address,state_id:0 msgid "Fed. State" -msgstr "" +msgstr "Zvezna država" #. module: base #: field:ir.actions.server,copy_object:0 msgid "Copy Of" -msgstr "" +msgstr "Kopija" #. module: base #: field:ir.model,osv_memory:0 msgid "In-memory model" -msgstr "" +msgstr "Model v spominu" #. module: base #: view:partner.clear.ids:0 msgid "Clear Ids" -msgstr "" +msgstr "Počisti Id-je" #. module: base #: model:res.country,name:base.io msgid "British Indian Ocean Territory" -msgstr "Britanska ozemlja v Indijskem oceanu" +msgstr "Britansko ozemlje v indijskem oceanu" #. module: base #: field:res.config.users,view:0 #: field:res.config.view,view:0 #: field:res.users,view:0 msgid "Interface" -msgstr "" +msgstr "Vmesnik" #. module: base #: view:ir.actions.server:0 @@ -4339,7 +4516,7 @@ msgstr "Preslikava polj" #. module: base #: view:publisher_warranty.contract:0 msgid "Refresh Validation Dates" -msgstr "" +msgstr "Osveži datume preverjanja" #. module: base #: view:ir.model:0 @@ -4395,7 +4572,7 @@ msgstr "Ni implementirano" #. module: base #: model:ir.model,name:base.model_res_widget_user msgid "res.widget.user" -msgstr "" +msgstr "res.widget.user" #. module: base #: field:res.partner.category,complete_name:0 @@ -4405,18 +4582,18 @@ msgstr "Polno ime" #. module: base #: view:base.module.configuration:0 msgid "_Ok" -msgstr "" +msgstr "_V redu" #. module: base #: help:ir.filters,user_id:0 msgid "False means for every user" -msgstr "" +msgstr "False pomeni za vsakega uporabnika" #. module: base #: code:addons/base/module/module.py:198 #, python-format msgid "The name of the module must be unique !" -msgstr "" +msgstr "Ime modula mora biti edinstven!" #. module: base #: model:res.country,name:base.mz @@ -4426,7 +4603,7 @@ msgstr "Mozambik" #. module: base #: model:ir.ui.menu,name:base.menu_project_long_term msgid "Long Term Planning" -msgstr "" +msgstr "Dolgoročno načrtovanje" #. module: base #: field:ir.actions.server,message:0 @@ -4439,13 +4616,13 @@ msgstr "Sporočilo" #. module: base #: field:ir.actions.act_window.view,multi:0 msgid "On Multiple Doc." -msgstr "" +msgstr "Na večih dokumentih" #. module: base #: view:res.partner:0 #: field:res.partner,user_id:0 msgid "Salesman" -msgstr "" +msgstr "Prodajalec" #. module: base #: field:res.partner,address:0 @@ -4459,11 +4636,12 @@ msgstr "Stiki" msgid "" "Unable to delete this document because it is used as a default property" msgstr "" +"Ne morem izbrisati tega dokumenta, ker se uporablja kot privzeta lastnost" #. module: base #: view:res.widget.wizard:0 msgid "Add" -msgstr "" +msgstr "Dodaj" #. module: base #: view:base.module.upgrade:0 @@ -4475,7 +4653,7 @@ msgstr "Izvedi planirane nadgradnje" #. module: base #: view:res.widget:0 msgid "Widgets" -msgstr "" +msgstr "Gradniki" #. module: base #: model:res.country,name:base.cz @@ -4485,7 +4663,7 @@ msgstr "Češka republika" #. module: base #: view:res.widget.wizard:0 msgid "Widget Wizard" -msgstr "" +msgstr "Čarovnik gradnikov" #. module: base #: model:ir.actions.act_window,help:base.act_ir_actions_todo_form @@ -4494,6 +4672,9 @@ msgid "" "OpenERP. They are launched during the installation of new modules, but you " "can choose to restart some wizards manually from this menu." msgstr "" +"Konfiguracijski čarovniki se uporabljajo za konfiguracijo novega primerka " +"OpenERP. Ti se zaženejo med namestitvijo novih modulov, vendar pa se lahko " +"odločite, da ponovno zaženete nekaj čarovnikov ročno iz tega menija." #. module: base #: code:addons/base/res/res_user.py:206 @@ -4502,17 +4683,19 @@ msgid "" "Please use the change password wizard (in User Preferences or User menu) to " "change your own password." msgstr "" +"Prosim, uporabite ta čarovnik za spreminjanje glesa (v Uporabniških " +"nastavitvah ali meniju Uporabnik), za spremembo vašega gesla." #. module: base #: code:addons/orm.py:1350 #, python-format msgid "Insufficient fields for Calendar View!" -msgstr "" +msgstr "Premalo pol za pogled koledarja!" #. module: base #: selection:ir.property,type:0 msgid "Integer" -msgstr "" +msgstr "Celo število" #. module: base #: help:ir.actions.report.xml,report_rml:0 @@ -4520,12 +4703,14 @@ msgid "" "The path to the main report file (depending on Report Type) or NULL if the " "content is in another data field" msgstr "" +"Pot do datoteke glavnega poročila (odvisno od vrste poročila) ali NULL, če " +"je vsebina v drugem polju podatkov" #. module: base #: help:res.config.users,company_id:0 #: help:res.users,company_id:0 msgid "The company this user is currently working for." -msgstr "" +msgstr "Podjetje, za katerega trenutno dela ta uporabnik." #. module: base #: model:ir.model,name:base.model_wizard_ir_model_menu_create @@ -4540,7 +4725,7 @@ msgstr "Prehod" #. module: base #: field:res.groups,menu_access:0 msgid "Access Menu" -msgstr "" +msgstr "Meni dostopa" #. module: base #: model:res.country,name:base.na @@ -4555,12 +4740,12 @@ msgstr "Mongolija" #. module: base #: view:ir.module.module:0 msgid "Created Menus" -msgstr "" +msgstr "Ustvarjeni meniji" #. module: base #: selection:ir.ui.view,type:0 msgid "mdx" -msgstr "" +msgstr "mdx" #. module: base #: model:res.country,name:base.bi @@ -4581,12 +4766,12 @@ msgstr "Zapri" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (MX) / Español (MX)" -msgstr "" +msgstr "Špansko (MX) / Español (MX)" #. module: base #: view:res.log:0 msgid "My Logs" -msgstr "" +msgstr "Moji dnevniki" #. module: base #: model:res.country,name:base.bt @@ -4596,7 +4781,7 @@ msgstr "Butan" #. module: base #: help:ir.sequence,number_next:0 msgid "Next number of this sequence" -msgstr "" +msgstr "Naslednja številka tega zaporedja" #. module: base #: model:res.partner.category,name:base.res_partner_category_11 @@ -4611,12 +4796,12 @@ msgstr "To okno" #. module: base #: view:publisher_warranty.contract:0 msgid "Publisher Warranty Contracts" -msgstr "" +msgstr "Pogodbe založniške garancije" #. module: base #: help:res.log,name:0 msgid "The logging message." -msgstr "" +msgstr "Prijavno sporočilo." #. module: base #: field:base.language.export,format:0 @@ -4626,7 +4811,7 @@ msgstr "Oblika datoteke" #. module: base #: field:res.lang,iso_code:0 msgid "ISO code" -msgstr "" +msgstr "ISO koda" #. module: base #: model:ir.model,name:base.model_res_config_view @@ -4637,12 +4822,12 @@ msgstr "res.config.view" #: view:res.log:0 #: field:res.log,read:0 msgid "Read" -msgstr "" +msgstr "Branje" #. module: base #: sql_constraint:res.country:0 msgid "The name of the country must be unique !" -msgstr "" +msgstr "Ime države mora biti edinstveno!" #. module: base #: model:ir.actions.act_window,help:base.action_country_state @@ -4651,11 +4836,13 @@ msgid "" "federal states you are working on from here. Each state is attached to one " "country." msgstr "" +"Če delate na ameriškem trgu, lahko tukaj upravljate različne zvezne dežele " +"na katerih delatej. Vsako stanje je vezano na eno državo." #. module: base #: view:workflow.workitem:0 msgid "Workflow Workitems" -msgstr "Elementi poteka dela" +msgstr "Elementi delovnih procesov" #. module: base #: model:res.country,name:base.vc @@ -4682,13 +4869,13 @@ msgstr "Polja" #. module: base #: model:ir.actions.act_window,name:base.action_partner_employee_form msgid "Employees" -msgstr "" +msgstr "Zaposleni" #. module: base #: help:res.log,read:0 msgid "" "If this log item has been read, get() should not send it to the client" -msgstr "" +msgstr "Če je bil ta predmet dnevnika prebran, get() ne sme poslati klientu" #. module: base #: field:res.company,rml_header2:0 @@ -4713,6 +4900,10 @@ msgid "" "channels that will be maintained at the creation of a document in the " "system. Some examples of channels can be: Website, Phone Call, Reseller, etc." msgstr "" +"Sledite od kje prihajajo vaše poti in priložnosti z ustvarjanjem " +"specifičnega kanala, ki se bo vzdrževal z ustvarjanjem dokumenta v sistemu. " +"Nekateri primeri kanalov so lahko: Spletna stran, Telefonski klic, " +"Preprodajalec, itd." #. module: base #: model:res.partner.bank.type.field,name:base.bank_normal_field @@ -4791,7 +4982,7 @@ msgstr "Burkina Faso" #. module: base #: selection:ir.actions.todo,state:0 msgid "Skipped" -msgstr "Preskočeno" +msgstr "Izpuščeno" #. module: base #: selection:ir.model.fields,state:0 @@ -4801,7 +4992,7 @@ msgstr "Polje po meri" #. module: base #: field:ir.module.module,web:0 msgid "Has a web component" -msgstr "" +msgstr "Ima spletno komponento" #. module: base #: model:res.country,name:base.cc @@ -4813,17 +5004,17 @@ msgstr "Kokosovi (Keelingovi) otoki" #: selection:base.module.import,state:0 #: selection:base.module.update,state:0 msgid "init" -msgstr "" +msgstr "init" #. module: base #: view:res.lang:0 msgid "11. %U or %W ==> 48 (49th week)" -msgstr "" +msgstr "11. %U ali %w ==> 48 (49 teden)" #. module: base #: model:ir.model,name:base.model_res_partner_bank_type_field msgid "Bank type fields" -msgstr "" +msgstr "Polja vrste banke" #. module: base #: selection:base.language.install,lang:0 @@ -4838,11 +5029,14 @@ msgid "" "\n" "This addon is already installed on your system" msgstr "" +"\n" +"\n" +"Ta dodatek je že nameščen na vaš sistem" #. module: base #: help:ir.cron,interval_number:0 msgid "Repeat every x." -msgstr "" +msgstr "Ponovi vsakih x." #. module: base #: wizard_view:server.action.create,step_1:0 @@ -4858,7 +5052,7 @@ msgstr "1cm 28cm 20cm 28cm" #. module: base #: field:ir.module.module,maintainer:0 msgid "Maintainer" -msgstr "" +msgstr "Vzdrževalec" #. module: base #: field:ir.sequence,suffix:0 @@ -4883,17 +5077,17 @@ msgstr "E-pošta pošiljatelja" #. module: base #: field:ir.default,field_name:0 msgid "Object Field" -msgstr "" +msgstr "Polje predmeta" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PE) / Español (PE)" -msgstr "" +msgstr "Špansko (PE) / Español (PE)" #. module: base #: selection:base.language.install,lang:0 msgid "French (CH) / Français (CH)" -msgstr "" +msgstr "Francosko (CH) / Français (CH)" #. module: base #: help:res.config.users,action_id:0 @@ -4902,17 +5096,19 @@ msgid "" "If specified, this action will be opened at logon for this user, in addition " "to the standard menu." msgstr "" +"Če je navedeno, bo to dejanje odprto ob prijavi tega uporabnika, poleg " +"standardnega menija." #. module: base #: view:ir.values:0 msgid "Client Actions" -msgstr "" +msgstr "Klientova dejanja" #. module: base #: code:addons/orm.py:1806 #, python-format msgid "The exists method is not implemented on this object !" -msgstr "" +msgstr "Obstoječa metoda ni implementirana v ta predmet!" #. module: base #: code:addons/base/module/module.py:336 @@ -4921,21 +5117,23 @@ msgid "" "You try to upgrade a module that depends on the module: %s.\n" "But this module is not available in your system." msgstr "" +"Poizkušate nadgraditi modul, ki je odvisen od tega modula: %s.\n" +"Ampak ta modul ni dostopen na vašem sistemu." #. module: base #: field:workflow.transition,act_to:0 msgid "Destination Activity" -msgstr "" +msgstr "Dejanja destinacije" #. module: base #: view:ir.values:0 msgid "Connect Events to Actions" -msgstr "" +msgstr "Poveži dogodke dejanjem" #. module: base #: model:ir.model,name:base.model_base_update_translations msgid "base.update.translations" -msgstr "" +msgstr "base.update.translations" #. module: base #: field:ir.module.category,parent_id:0 @@ -4975,12 +5173,12 @@ msgstr "Prekliči odstranitev" #: view:res.partner:0 #: view:res.partner.address:0 msgid "Communication" -msgstr "" +msgstr "Komunikacija" #. module: base #: view:ir.actions.report.xml:0 msgid "RML Report" -msgstr "" +msgstr "RML poročilo" #. module: base #: model:ir.model,name:base.model_ir_server_object_lines @@ -4991,7 +5189,7 @@ msgstr "ir.server.object.lines" #: code:addons/base/module/module.py:531 #, python-format msgid "Module %s: Invalid Quality Certificate" -msgstr "" +msgstr "Modul %s: Neveljavno potrdilo kakovosti" #. module: base #: model:res.country,name:base.kw @@ -5001,7 +5199,7 @@ msgstr "Kuvajt" #. module: base #: field:workflow.workitem,inst_id:0 msgid "Instance" -msgstr "Primerek" +msgstr "Primer" #. module: base #: help:ir.actions.report.xml,attachment:0 @@ -5010,11 +5208,14 @@ msgid "" "Keep empty to not save the printed reports. You can use a python expression " "with the object and time variables." msgstr "" +"To je ime datoteke priloge, ki se uporablja za shranjevanje tiskanja " +"rezultatov. Naj bo prazno, če ne želite shraniti tiskanih poročil. Lahko " +"uporabite python izraz s predmetom in spremenljivk časa." #. module: base #: selection:ir.property,type:0 msgid "Many2One" -msgstr "" +msgstr "Many2One" #. module: base #: model:res.country,name:base.ng @@ -6657,7 +6858,7 @@ msgstr "Naslednji konfiguracijski korak" #. module: base #: field:res.groups,comment:0 msgid "Comment" -msgstr "Pripomba" +msgstr "Opomba" #. module: base #: model:res.country,name:base.ro diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index dc07b55a78e..51d796a3a1e 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -245,9 +245,7 @@ class res_company(osv.osv): return False def _get_logo(self, cr, uid, ids): - return open(os.path.join( - tools.config['root_path'], '..', 'pixmaps', 'your_logo.png'), - 'rb') .read().encode('base64') + return open(os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64') _header = """
diff --git a/pixmaps/your_logo.png b/openerp/addons/base/res/res_company_logo.png similarity index 100% rename from pixmaps/your_logo.png rename to openerp/addons/base/res/res_company_logo.png diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 51be4adc747..bb1e8ec26bb 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -700,7 +700,7 @@ class users_view(osv.osv): self._process_values_groups(cr, uid, values, context) return super(users_view, self).write(cr, uid, ids, values, context) - def read(self, cr, uid, ids, fields, context=None, load='_classic_read'): + def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): if not fields: group_fields, fields = [], self.fields_get(cr, uid, context).keys() else: diff --git a/openerp/conf/__init__.py b/openerp/conf/__init__.py index 7de8070f9e2..0a975c5d4e2 100644 --- a/openerp/conf/__init__.py +++ b/openerp/conf/__init__.py @@ -28,8 +28,21 @@ parsing, configuration file loading and saving, ...) in this module and provide real Python variables, e.g. addons_paths is really a list of paths. +To initialize properly this module, openerp.tools.config.parse_config() +must be used. + """ import deprecation +# Paths to search for OpenERP addons. +addons_paths = [] + +# List of server-wide modules to load. Those modules are supposed to provide +# features not necessarily tied to a particular database. This is in contrast +# to modules that are always bound to a specific database when they are +# installed (i.e. the majority of OpenERP addons). This is set with the --load +# command-line option. +server_wide_modules = [] + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/modules/graph.py b/openerp/modules/graph.py index 078d23c235b..539dda25b50 100644 --- a/openerp/modules/graph.py +++ b/openerp/modules/graph.py @@ -58,16 +58,16 @@ class Graph(dict): """ - def add_node(self, name, deps): + def add_node(self, name, info): max_depth, father = 0, None - for n in [Node(x, self) for x in deps]: + for n in [Node(x, self, None) for x in info['depends']]: if n.depth >= max_depth: father = n max_depth = n.depth if father: - return father.add_child(name) + return father.add_child(name, info) else: - return Node(name, self) + return Node(name, self, info) def update_from_db(self, cr): if not len(self): @@ -120,7 +120,7 @@ class Graph(dict): continue later.clear() current.remove(package) - node = self.add_node(package, deps) + node = self.add_node(package, info) node.data = info for kind in ('init', 'demo', 'update'): if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force: @@ -154,12 +154,13 @@ class Graph(dict): class Singleton(object): - def __new__(cls, name, graph): + def __new__(cls, name, graph, info): if name in graph: inst = graph[name] else: inst = object.__new__(cls) inst.name = name + inst.info = info graph[name] = inst return inst @@ -167,19 +168,21 @@ class Singleton(object): class Node(Singleton): """ One module in the modules dependency graph. - Node acts as a per-module singleton. + Node acts as a per-module singleton. A node is constructed via + Graph.add_module() or Graph.add_modules(). Some of its fields are from + ir_module_module (setted by Graph.update_from_db()). """ - def __init__(self, name, graph): + def __init__(self, name, graph, info): self.graph = graph if not hasattr(self, 'children'): self.children = [] if not hasattr(self, 'depth'): self.depth = 0 - def add_child(self, name): - node = Node(name, self.graph) + def add_child(self, name, info): + node = Node(name, self.graph, info) node.depth = self.depth + 1 if node not in self.children: self.children.append(node) diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 9f6c517dca7..b06368ba1b2 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -158,7 +158,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= logger.info('module %s: loading objects', package.name) migrations.migrate_module(package, 'pre') register_module_classes(package.name) - models = pool.instanciate(package.name, cr) + models = pool.load(cr, package) loaded_modules.append(package.name) if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'): init_module_models(cr, package.name, models) @@ -273,8 +273,6 @@ def load_modules(db, force_demo=False, status=None, update_module=False): # This is a brand new pool, just created in pooler.get_db_and_pool() pool = pooler.get_pool(cr.dbname) - processed_modules = [] # for cleanup step after install - loaded_modules = [] # to avoid double loading report = tools.assertion_report() if 'base' in tools.config['update'] or 'all' in tools.config['update']: cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed')) @@ -285,8 +283,10 @@ def load_modules(db, force_demo=False, status=None, update_module=False): if not graph: logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)') raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)')) - loaded, processed = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report) - processed_modules.extend(processed) + + # processed_modules: for cleanup step after install + # loaded_modules: to avoid double loading + loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report) if tools.config['load_language']: for lang in tools.config['load_language'].split(','): @@ -347,7 +347,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""") for (model, name) in cr.fetchall(): model_obj = pool.get(model) - if model_obj.is_transient(): + if model_obj and model_obj.is_transient(): logger.notifyChannel('init', netsvc.LOG_WARNING, 'The transient model %s (%s) should not have explicit access rules!' % (model, name)) cr.execute("SELECT model from ir_model") diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 2bf86318fa4..b40e186e9a1 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -31,7 +31,6 @@ import openerp.osv as osv import openerp.tools as tools import openerp.tools.osutil as osutil from openerp.tools.safe_eval import safe_eval as eval -import openerp.pooler as pooler from openerp.tools.translate import _ import openerp.netsvc as netsvc @@ -58,6 +57,11 @@ loaded = [] logger = netsvc.Logger() def initialize_sys_path(): + """ Add all addons paths in sys.path. + + This ensures something like ``import crm`` works even if the addons are + not in the PYTHONPATH. + """ global ad_paths if ad_paths: @@ -250,6 +254,8 @@ def load_information_from_description_file(module): info['license'] = info.get('license') or 'AGPL-3' info.setdefault('installable', True) info.setdefault('active', False) + # If the following is provided, it is called after the module is --loaded. + info.setdefault('post_load', None) for kind in ['data', 'demo', 'test', 'init_xml', 'update_xml', 'demo_xml']: info.setdefault(kind, []) @@ -289,23 +295,22 @@ def init_module_models(cr, module_name, obj_list): t[1](cr, *t[2]) cr.commit() +# Import hook to write a addon m in both sys.modules['m'] and +# sys.modules['openerp.addons.m']. Otherwise it could be loaded twice +# if imported twice using different names. +#class MyImportHook(object): +# def find_module(self, module_name, package_path): +# print ">>>", module_name, package_path +# def load_module(self, module_name): +# raise ImportError("Restricted") -def load_module(module_name): - """ Load a Python module found on the addons paths.""" - fm = imp.find_module(module_name, ad_paths) - try: - imp.load_module(module_name, *fm) - finally: - if fm[0]: - fm[0].close() - +#sys.meta_path.append(MyImportHook()) def register_module_classes(m): """ Register module named m, if not already registered. - This will load the module and register all of its models. (Actually, the - explicit constructor call of each of the models inside the module will - register them.) + This loads the module and register all of its models, thanks to either + the MetaModel metaclass, or the explicit instantiation of the model. """ @@ -325,7 +330,7 @@ def register_module_classes(m): try: zip_mod_path = mod_path + '.zip' if not os.path.isfile(zip_mod_path): - load_module(m) + __import__(m) else: zimp = zipimport.zipimporter(zip_mod_path) zimp.load_module(m) diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 3dcebf90361..ea6d863e442 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -77,14 +77,21 @@ class Registry(object): """ Return a model for a given name or raise KeyError if it doesn't exist.""" return self.models[model_name] - def instanciate(self, module, cr): - """ Instanciate all the classes of a given module for a particular db.""" + def load(self, cr, module): + """ Load a given module in the registry. + + At the Python level, the modules are already loaded, but not yet on a + per-registry level. This method populates a registry with the given + modules, i.e. it instanciates all the classes of a the given module + and registers them in the registry. + + """ res = [] # Instantiate registered classes (via the MetaModel automatic discovery # or via explicit constructor call), and add them to the pool. - for cls in openerp.osv.orm.MetaModel.module_to_models.get(module, []): + for cls in openerp.osv.orm.MetaModel.module_to_models.get(module.name, []): res.append(cls.create_instance(self, cr)) return res diff --git a/openerp/netsvc.py b/openerp/netsvc.py index 359813e7d41..8d11891640e 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -60,20 +60,21 @@ def close_socket(sock): #.apidoc title: Common Services: netsvc #.apidoc module-mods: member-order: bysource +def abort_response(error, description, origin, details): + if not tools.config['debug_mode']: + raise Exception("%s -- %s\n\n%s"%(origin, description, details)) + else: + raise + class Service(object): """ Base class for *Local* services Functionality here is trusted, no authentication. """ _services = {} - def __init__(self, name, audience=''): + def __init__(self, name): Service._services[name] = self self.__name = name - self._methods = {} - - def joinGroup(self, name): - raise Exception("No group for local services") - #GROUPS.setdefault(name, {})[self.__name] = self @classmethod def exists(cls, name): @@ -84,35 +85,13 @@ class Service(object): if cls.exists(name): cls._services.pop(name) - def exportMethod(self, method): - if callable(method): - self._methods[method.__name__] = method +def LocalService(name): + # Special case for addons support, will be removed in a few days when addons + # are updated to directly use openerp.osv.osv.service. + if name == 'object_proxy': + return openerp.osv.osv.service - def abortResponse(self, error, description, origin, details): - if not tools.config['debug_mode']: - raise Exception("%s -- %s\n\n%s"%(origin, description, details)) - else: - raise - -class LocalService(object): - """ Proxy for local services. - - Any instance of this class will behave like the single instance - of Service(name) - """ - __logger = logging.getLogger('service') - def __init__(self, name): - self.__name = name - try: - self._service = Service._services[name] - for method_name, method_definition in self._service._methods.items(): - setattr(self, method_name, method_definition) - except KeyError, keyError: - self.__logger.error('This service does not exist: %s' % (str(keyError),) ) - raise - - def __call__(self, method, *params): - return getattr(self, method)(*params) + return Service._services[name] class ExportService(object): """ Proxy for exported services. @@ -126,33 +105,22 @@ class ExportService(object): """ _services = {} - _groups = {} _logger = logging.getLogger('web-services') - - def __init__(self, name, audience=''): + + def __init__(self, name): ExportService._services[name] = self self.__name = name self._logger.debug("Registered an exported service: %s" % name) - def joinGroup(self, name): - ExportService._groups.setdefault(name, {})[self.__name] = self - @classmethod def getService(cls,name): return cls._services[name] + # Dispatch a RPC call w.r.t. the method name. The dispatching + # w.r.t. the service (this class) is done by OpenERPDispatcher. def dispatch(self, method, auth, params): raise Exception("stub dispatch at %s" % self.__name) - def new_dispatch(self,method,auth,params): - raise Exception("stub dispatch at %s" % self.__name) - - def abortResponse(self, error, description, origin, details): - if not tools.config['debug_mode']: - raise Exception("%s -- %s\n\n%s"%(origin, description, details)) - else: - raise - BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10) #The background is set with 40 plus the number of the color, and the foreground with 30 #These are the sequences need to get colored ouput @@ -425,33 +393,36 @@ def log(title, msg, channel=logging.DEBUG_RPC, depth=None, fn=""): logger.log(channel, indent+line) indent=indent_after -class OpenERPDispatcher: - def log(self, title, msg, channel=logging.DEBUG_RPC, depth=None, fn=""): +def dispatch_rpc(service_name, method, params, auth): + """ Handle a RPC call. + + This is pure Python code, the actual marshalling (from/to XML-RPC or + NET-RPC) is done in a upper layer. + """ + def _log(title, msg, channel=logging.DEBUG_RPC, depth=None, fn=""): log(title, msg, channel=channel, depth=depth, fn=fn) - def dispatch(self, service_name, method, params): - try: - auth = getattr(self, 'auth_provider', None) - logger = logging.getLogger('result') - start_time = end_time = 0 - if logger.isEnabledFor(logging.DEBUG_RPC_ANSWER): - self.log('service', tuple(replace_request_password(params)), depth=None, fn='%s.%s'%(service_name,method)) - if logger.isEnabledFor(logging.DEBUG_RPC): - start_time = time.time() - result = ExportService.getService(service_name).dispatch(method, auth, params) - if logger.isEnabledFor(logging.DEBUG_RPC): - end_time = time.time() - if not logger.isEnabledFor(logging.DEBUG_RPC_ANSWER): - self.log('service (%.3fs)' % (end_time - start_time), tuple(replace_request_password(params)), depth=1, fn='%s.%s'%(service_name,method)) - self.log('execution time', '%.3fs' % (end_time - start_time), channel=logging.DEBUG_RPC_ANSWER) - self.log('result', result, channel=logging.DEBUG_RPC_ANSWER) - return result - except Exception, e: - self.log('exception', tools.exception_to_unicode(e)) - tb = getattr(e, 'traceback', sys.exc_info()) - tb_s = "".join(traceback.format_exception(*tb)) - if tools.config['debug_mode'] and isinstance(tb[2], types.TracebackType): - import pdb - pdb.post_mortem(tb[2]) - raise OpenERPDispatcherException(e, tb_s) + try: + logger = logging.getLogger('result') + start_time = end_time = 0 + if logger.isEnabledFor(logging.DEBUG_RPC_ANSWER): + _log('service', tuple(replace_request_password(params)), depth=None, fn='%s.%s'%(service_name,method)) + if logger.isEnabledFor(logging.DEBUG_RPC): + start_time = time.time() + result = ExportService.getService(service_name).dispatch(method, auth, params) + if logger.isEnabledFor(logging.DEBUG_RPC): + end_time = time.time() + if not logger.isEnabledFor(logging.DEBUG_RPC_ANSWER): + _log('service (%.3fs)' % (end_time - start_time), tuple(replace_request_password(params)), depth=1, fn='%s.%s'%(service_name,method)) + _log('execution time', '%.3fs' % (end_time - start_time), channel=logging.DEBUG_RPC_ANSWER) + _log('result', result, channel=logging.DEBUG_RPC_ANSWER) + return result + except Exception, e: + _log('exception', tools.exception_to_unicode(e)) + tb = getattr(e, 'traceback', sys.exc_info()) + tb_s = "".join(traceback.format_exception(*tb)) + if tools.config['debug_mode'] and isinstance(tb[2], types.TracebackType): + import pdb + pdb.post_mortem(tb[2]) + raise OpenERPDispatcherException(e, tb_s) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 4a56c83b352..37ba721c8cf 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1126,17 +1126,6 @@ class BaseModel(object): """ Import given data in given module - :param cr: database cursor - :param uid: current user id - :param fields: list of fields - :param data: data to import - :param mode: 'init' or 'update' for record creation - :param current_module: module name - :param noupdate: flag for record creation - :param context: context arguments, like lang, time zone, - :param filename: optional file to store partial import state for recovery - :rtype: tuple - This method is used when importing data via client menu. Example of fields to import for a sale.order:: @@ -1149,6 +1138,22 @@ class BaseModel(object): order_line/price_unit, order_line/product_uom_qty, order_line/product_uom/id (=xml_id) + + This method returns a 4-tuple with the following structure: + + * The first item is a return code, it returns either ``-1`` in case o + + :param cr: database cursor + :param uid: current user id + :param fields: list of fields + :param data: data to import + :param mode: 'init' or 'update' for record creation + :param current_module: module name + :param noupdate: flag for record creation + :param context: context arguments, like lang, time zone, + :param filename: optional file to store partial import state for recovery + :returns: 4-tuple of a return code, an errored resource, an error message and ??? + :rtype: (int, dict|0, str|0, ''|0) """ if not context: context = {} diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index f827ff680fb..00672dd94bd 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -40,13 +40,13 @@ class except_osv(Exception): self.value = value self.args = (exc_type, name) +service = None -class object_proxy(netsvc.Service): +class object_proxy(): def __init__(self): self.logger = logging.getLogger('web-services') - netsvc.Service.__init__(self, 'object_proxy', audience='') - self.exportMethod(self.exec_workflow) - self.exportMethod(self.execute) + global service + service = self def check(f): @wraps(f) @@ -120,14 +120,14 @@ class object_proxy(netsvc.Service): except orm.except_orm, inst: if inst.name == 'AccessError': self.logger.debug("AccessError", exc_info=True) - self.abortResponse(1, inst.name, 'warning', inst.value) + netsvc.abort_response(1, inst.name, 'warning', inst.value) except except_osv, inst: - self.abortResponse(1, inst.name, inst.exc_type, inst.value) + netsvc.abort_response(1, inst.name, inst.exc_type, inst.value) except IntegrityError, inst: osv_pool = pooler.get_pool(dbname) for key in osv_pool._sql_error.keys(): if key in inst[0]: - self.abortResponse(1, _('Constraint Error'), 'warning', + netsvc.abort_response(1, _('Constraint Error'), 'warning', tr(osv_pool._sql_error[key], 'sql_constraint') or inst[0]) if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION): msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set') @@ -148,9 +148,9 @@ class object_proxy(netsvc.Service): msg += _('\n\n[object with reference: %s - %s]') % (model_name, model) except Exception: pass - self.abortResponse(1, _('Integrity Error'), 'warning', msg) + netsvc.abort_response(1, _('Integrity Error'), 'warning', msg) else: - self.abortResponse(1, _('Integrity Error'), 'warning', inst[0]) + netsvc.abort_response(1, _('Integrity Error'), 'warning', inst[0]) except Exception: self.logger.exception("Uncaught exception") raise diff --git a/openerp/report/custom.py b/openerp/report/custom.py index f3d6cfbc074..051d1f29862 100644 --- a/openerp/report/custom.py +++ b/openerp/report/custom.py @@ -136,16 +136,15 @@ class report_custom(report_int): ids = self.pool.get(report.model_id.model).search(cr, uid, []) datas['ids'] = ids - service = netsvc.LocalService("object_proxy") report_id = datas['report_id'] - report = service.execute(cr.dbname, uid, 'ir.report.custom', 'read', [report_id], context=context)[0] - fields = service.execute(cr.dbname, uid, 'ir.report.custom.fields', 'read', report['fields_child0'], context=context) + report = self.pool.get('ir.report.custom').read(cr, uid, [report_id], context=context)[0] + fields = self.pool.get('ir.report.custom.fields').read(cr, uid, report['fields_child0'], context=context) fields.sort(lambda x,y : x['sequence'] - y['sequence']) if report['field_parent']: - parent_field = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [report['field_parent'][0]],['model']) - model_name = service.execute(cr.dbname, uid, 'ir.model', 'read', [report['model_id'][0]], ['model'],context=context)[0]['model'] + parent_field = self.pool.get('ir.model.fields').read(cr, uid, [report['field_parent'][0]], ['model']) + model_name = self.pool.get('ir.model').read(cr, uid, [report['model_id'][0]], ['model'], context=context)[0]['model'] fct = {} fct['id'] = lambda x : x @@ -160,9 +159,7 @@ class report_custom(report_int): field_child = f['field_child'+str(i)] if field_child: row.append( - service.execute(cr.dbname, uid, - 'ir.model.fields', 'read', [field_child[0]], - ['name'], context=context)[0]['name'] + self.pool.get('ir.model.fields').read(cr, uid, [field_child[0]], ['name'], context=context)[0]['name'] ) if f['fc'+str(i)+'_operande']: fct_name = 'id' @@ -346,7 +343,7 @@ class report_custom(report_int): def _create_lines(self, cr, uid, ids, report, fields, results, context): - service = netsvc.LocalService("object_proxy") + pool = pooler.get_pool(cr.dbname) pdf_string = cStringIO.StringIO() can = canvas.init(fname=pdf_string, format='pdf') @@ -376,7 +373,7 @@ class report_custom(report_int): for f in fields: field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0]) if field_id: - type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype']) + type = pool.get('ir.model.fields').read(cr, uid, [field_id],['ttype']) if type[0]['ttype'] == 'date': date_idx = idx fct[idx] = process_date[report['frequency']] @@ -449,7 +446,7 @@ class report_custom(report_int): def _create_bars(self, cr, uid, ids, report, fields, results, context): - service = netsvc.LocalService("object_proxy") + pool = pooler.get_pool(cr.dbname) pdf_string = cStringIO.StringIO() can = canvas.init(fname=pdf_string, format='pdf') @@ -475,7 +472,7 @@ class report_custom(report_int): for f in fields: field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0]) if field_id: - type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype']) + type = pool.get('ir.model.fields').read(cr, uid, [field_id],['ttype']) if type[0]['ttype'] == 'date': date_idx = idx fct[idx] = process_date[report['frequency']] diff --git a/openerp/report/interface.py b/openerp/report/interface.py index edd70a911f0..9a97c445671 100644 --- a/openerp/report/interface.py +++ b/openerp/report/interface.py @@ -41,9 +41,9 @@ def toxml(value): return unicode_value.replace('&', '&').replace('<','<').replace('>','>') class report_int(netsvc.Service): - def __init__(self, name, audience='*'): + def __init__(self, name): assert not self.exists(name), 'The report "%s" already exists!' % name - super(report_int, self).__init__(name, audience) + super(report_int, self).__init__(name) if name[0:7]<>'report.': raise Exception, 'ConceptionError, bad report name, should start with "report."' self.name = name @@ -51,8 +51,6 @@ class report_int(netsvc.Service): self.name2 = '.'.join(name.split('.')[1:]) # TODO the reports have methods with a 'title' kwarg that is redundant with this attribute self.title = None - #self.joinGroup('report') - self.exportMethod(self.create) def create(self, cr, uid, ids, datas, context=None): return False diff --git a/openerp/report/print_xml.py b/openerp/report/print_xml.py index ad2b0528d99..b7074a2d0c3 100644 --- a/openerp/report/print_xml.py +++ b/openerp/report/print_xml.py @@ -137,9 +137,8 @@ class document(object): value = self.get_value(browser, attrs['name']) - service = netsvc.LocalService("object_proxy") - ids = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'search', [('res_model','=',model),('res_id','=',int(value))]) - datas = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'read', ids) + ids = self.pool.get('ir.attachment').search(self.cr, self.uid, [('res_model','=',model),('res_id','=',int(value))]) + datas = self.pool.get('ir.attachment').read(self.cr, self.uid, ids) if len(datas): # if there are several, pick first diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index b9ee98fcab0..62e1585dade 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -19,9 +19,19 @@ # ############################################################################## +import logging +import threading +import time + import http_server import netrpc_server import web_services +import websrv_lib + +import openerp.netsvc +import openerp.osv +import openerp.tools +import openerp.wsgi #.apidoc title: RPC Services @@ -34,5 +44,56 @@ import web_services low-level behavior of the wire. """ +def start_services(): + """ Start all services. + + Services include the different servers and cron threads. + + """ + # Instantiate local services (this is a legacy design). + openerp.osv.osv.start_object_proxy() + # Export (for RPC) services. + web_services.start_web_services() + + # Initialize the HTTP stack. + #http_server.init_servers() + #http_server.init_xmlrpc() + #http_server.init_static_http() + netrpc_server.init_servers() + + # Start the main cron thread. + openerp.netsvc.start_agent() + + # Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC). + openerp.netsvc.Server.startAll() + + + # Start the WSGI server. + openerp.wsgi.start_server() + + +def stop_services(): + """ Stop all services. """ + openerp.netsvc.Agent.quit() + openerp.netsvc.Server.quitAll() + openerp.wsgi.stop_server() + config = openerp.tools.config + logger = logging.getLogger('server') + logger.info("Initiating shutdown") + logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") + logging.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). + for thread in threading.enumerate(): + if thread != threading.currentThread() and not thread.isDaemon(): + while thread.isAlive(): + # Need a busyloop here as thread.join() masks signals + # and would prevent the forced shutdown. + thread.join(0.05) + time.sleep(0.05) + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py index 61713e9f2dd..9bfb9397d19 100644 --- a/openerp/service/http_server.py +++ b/openerp/service/http_server.py @@ -154,7 +154,6 @@ class BaseHttpDaemon(threading.Thread, netsvc.Server): try: self.server = ThreadedHTTPServer((interface, port), handler, proto=self._RealProto) - self.server.vdirs = [] self.server.logRequests = True self.server.timeout = self._busywait_timeout logging.getLogger("web-services").info( @@ -191,29 +190,8 @@ class BaseHttpDaemon(threading.Thread, netsvc.Server): res += ", %d threads" % (self.server.numThreads,) return res - def append_svc(self, service): - if not isinstance(service, HTTPDir): - raise Exception("Wrong class for http service") - - pos = len(self.server.vdirs) - lastpos = pos - while pos > 0: - pos -= 1 - if self.server.vdirs[pos].matches(service.path): - lastpos = pos - # we won't break here, but search all way to the top, to - # ensure there is no lesser entry that will shadow the one - # we are inserting. - self.server.vdirs.insert(lastpos, service) - - def list_services(self): - ret = [] - for svc in self.server.vdirs: - ret.append( ( svc.path, str(svc.handler)) ) - - return ret - - +# No need for these two classes: init_server() below can initialize correctly +# directly the BaseHttpDaemon class. class HttpDaemon(BaseHttpDaemon): _RealProto = 'HTTP' def __init__(self, interface, port): @@ -244,33 +222,8 @@ def init_servers(): httpsd = HttpSDaemon(tools.config.get('xmlrpcs_interface', ''), int(tools.config.get('xmlrpcs_port', 8071))) -def reg_http_service(hts, secure_only = False): - """ Register some handler to httpd. - hts must be an HTTPDir - """ - global httpd, httpsd - - if httpd and not secure_only: - httpd.append_svc(hts) - - if httpsd: - httpsd.append_svc(hts) - - if (not httpd) and (not httpsd): - logging.getLogger('httpd').warning("No httpd available to register service %s" % hts.path) - return - -def list_http_services(protocol=None): - global httpd, httpsd - if httpd and (protocol == 'http' or protocol == None): - return httpd.list_services() - elif httpsd and (protocol == 'https' or protocol == None): - return httpsd.list_services() - else: - raise Exception("Incorrect protocol or no http services") - import SimpleXMLRPCServer -class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,HttpLogHandler,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): +class XMLRPCRequestHandler(FixSendError,HttpLogHandler,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): rpc_paths = [] protocol_version = 'HTTP/1.1' _logger = logging.getLogger('xmlrpc') @@ -278,7 +231,8 @@ class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,HttpLogHandler, def _dispatch(self, method, params): try: service_name = self.path.split("/")[-1] - return self.dispatch(service_name, method, params) + auth = getattr(self, 'auth_provider', None) + return netsvc.dispatch_rpc(service_name, method, params, auth) except netsvc.OpenERPDispatcherException, e: raise xmlrpclib.Fault(tools.exception_to_unicode(e.exception), e.traceback) @@ -296,14 +250,14 @@ class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,HttpLogHandler, def init_xmlrpc(): if tools.config.get('xmlrpc', False): # Example of http file serving: - # reg_http_service(HTTPDir('/test/',HTTPHandler)) - reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler)) + # reg_http_service('/test/', HTTPHandler) + reg_http_service('/xmlrpc/', XMLRPCRequestHandler) logging.getLogger("web-services").info("Registered XML-RPC over HTTP") if tools.config.get('xmlrpcs', False) \ and not tools.config.get('xmlrpc', False): # only register at the secure server - reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler), True) + reg_http_service('/xmlrpc/', XMLRPCRequestHandler, secure_only=True) logging.getLogger("web-services").info("Registered XML-RPC over HTTPS only") class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler): @@ -345,65 +299,21 @@ def init_static_http(): base_path = tools.config.get('static_http_url_prefix', '/') - reg_http_service(HTTPDir(base_path,StaticHTTPHandler)) + reg_http_service(base_path, StaticHTTPHandler) logging.getLogger("web-services").info("Registered HTTP dir %s for %s" % \ (document_root, base_path)) -class OerpAuthProxy(AuthProxy): - """ Require basic authentication.. +import security - This is a copy of the BasicAuthProxy, which however checks/caches the db - as well. - """ - def __init__(self,provider): - AuthProxy.__init__(self,provider) +class OpenERPAuthProvider(AuthProvider): + """ Require basic authentication.""" + def __init__(self,realm='OpenERP User'): + self.realm = realm self.auth_creds = {} self.auth_tries = 0 self.last_auth = None - def checkRequest(self,handler,path, db=False): - auth_str = handler.headers.get('Authorization',False) - try: - if not db: - db = handler.get_db_from_path(path) - except Exception: - if path.startswith('/'): - path = path[1:] - psp= path.split('/') - if len(psp)>1: - db = psp[0] - else: - #FIXME! - self.provider.log("Wrong path: %s, failing auth" %path) - raise AuthRejectedExc("Authorization failed. Wrong sub-path.") - if self.auth_creds.get(db): - return True - if auth_str and auth_str.startswith('Basic '): - auth_str=auth_str[len('Basic '):] - (user,passwd) = base64.decodestring(auth_str).split(':') - self.provider.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db)) - acd = self.provider.authenticate(db,user,passwd,handler.client_address) - if acd != False: - self.auth_creds[db] = acd - self.last_auth = db - return True - if self.auth_tries > 5: - self.provider.log("Failing authorization after 5 requests w/o password") - raise AuthRejectedExc("Authorization failed.") - self.auth_tries += 1 - raise AuthRequiredExc(atype='Basic', realm=self.provider.realm) - -import security -class OpenERPAuthProvider(AuthProvider): - def __init__(self,realm='OpenERP User'): - self.realm = realm - - def setupAuth(self, multi, handler): - if not multi.sec_realms.has_key(self.realm): - multi.sec_realms[self.realm] = OerpAuthProxy(self) - handler.auth_proxy = multi.sec_realms[self.realm] - def authenticate(self, db, user, passwd, client_address): try: uid = security.login(db,user,passwd) @@ -417,4 +327,36 @@ class OpenERPAuthProvider(AuthProvider): def log(self, msg, lvl=logging.INFO): logging.getLogger("auth").log(lvl,msg) + def checkRequest(self,handler,path, db=False): + auth_str = handler.headers.get('Authorization',False) + try: + if not db: + db = handler.get_db_from_path(path) + except Exception: + if path.startswith('/'): + path = path[1:] + psp= path.split('/') + if len(psp)>1: + db = psp[0] + else: + #FIXME! + self.log("Wrong path: %s, failing auth" %path) + raise AuthRejectedExc("Authorization failed. Wrong sub-path.") + if self.auth_creds.get(db): + return True + if auth_str and auth_str.startswith('Basic '): + auth_str=auth_str[len('Basic '):] + (user,passwd) = base64.decodestring(auth_str).split(':') + self.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db)) + acd = self.authenticate(db,user,passwd,handler.client_address) + if acd != False: + self.auth_creds[db] = acd + self.last_auth = db + return True + if self.auth_tries > 5: + self.log("Failing authorization after 5 requests w/o password") + raise AuthRejectedExc("Authorization failed.") + self.auth_tries += 1 + raise AuthRequiredExc(atype='Basic', realm=self.realm) + #eof diff --git a/openerp/service/netrpc_server.py b/openerp/service/netrpc_server.py index 70855a018e5..3667b38c0b8 100644 --- a/openerp/service/netrpc_server.py +++ b/openerp/service/netrpc_server.py @@ -36,7 +36,7 @@ import openerp.netsvc as netsvc import openerp.tiny_socket as tiny_socket import openerp.tools as tools -class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher): +class TinySocketClientThread(threading.Thread): def __init__(self, sock, threads): spn = sock and sock.getpeername() spn = 'netrpc-client-%s:%s' % spn[0:2] @@ -59,7 +59,8 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher): while self.running: try: msg = ts.myreceive() - result = self.dispatch(msg[0], msg[1], msg[2:]) + auth = getattr(self, 'auth_provider', None) + result = netsvc.dispatch_rpc(msg[0], msg[1], msg[2:], auth) ts.mysend(result) except socket.timeout: #terminate this channel because other endpoint is gone @@ -107,7 +108,7 @@ class TinySocketServerThread(threading.Thread,netsvc.Server): self.socket.listen(5) self.threads = [] netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO, - "starting NET-RPC service at %s port %d" % (interface or '0.0.0.0', port,)) + "starting NET-RPC service on %s:%s" % (interface or '0.0.0.0', port,)) def run(self): try: diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index c768a3cb877..c941d3a809f 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -87,7 +87,6 @@ def _initialize_db(serv, id, db_name, demo, lang, user_password): class db(netsvc.ExportService): def __init__(self, name="db"): netsvc.ExportService.__init__(self, name) - self.joinGroup("web-services") self.actions = {} self.id = 0 self.id_protect = threading.Semaphore() @@ -97,7 +96,8 @@ class db(netsvc.ExportService): def dispatch(self, method, auth, params): if method in [ 'create', 'get_progress', 'drop', 'dump', 'restore', 'rename', - 'change_admin_password', 'migrate_databases' ]: + 'change_admin_password', 'migrate_databases', + 'create_database' ]: passwd = params[0] params = params[1:] security.check_super(passwd) @@ -110,8 +110,6 @@ class db(netsvc.ExportService): fn = getattr(self, 'exp_'+method) return fn(*params) - def new_dispatch(self,method,auth,params): - pass def _create_empty_database(self, name): db = sql_db.db_connect('template1') cr = db.cursor() @@ -138,6 +136,20 @@ class db(netsvc.ExportService): self.actions[id]['thread'] = create_thread return id + def exp_create_database(self, db_name, demo, lang, user_password='admin'): + """ Similar to exp_create but blocking.""" + self.id_protect.acquire() + self.id += 1 + id = self.id + self.id_protect.release() + + self.actions[id] = {'clean': False} + + logging.getLogger('db.create').info('CREATE DATABASE %s', db_name.lower()) + self._create_empty_database(db_name) + _initialize_db(self, id, db_name, demo, lang, user_password) + return True + def exp_get_progress(self, id): if self.actions[id]['thread'].isAlive(): # return openerp.modules.init_progress[db_name] @@ -342,9 +354,9 @@ class db(netsvc.ExportService): tools.config['update']['base'] = True pooler.restart_pool(db, force_demo=False, update_module=True) except except_orm, inst: - self.abortResponse(1, inst.name, 'warning', inst.value) + netsvc.abort_response(1, inst.name, 'warning', inst.value) except except_osv, inst: - self.abortResponse(1, inst.name, inst.exc_type, inst.value) + netsvc.abort_response(1, inst.name, inst.exc_type, inst.value) except Exception: import traceback tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback)) @@ -352,24 +364,9 @@ class db(netsvc.ExportService): raise return True -class _ObjectService(netsvc.ExportService): - "A common base class for those who have fn(db, uid, password,...) " - - def common_dispatch(self, method, auth, params): - (db, uid, passwd ) = params[0:3] - params = params[3:] - security.check(db,uid,passwd) - cr = pooler.get_db(db).cursor() - fn = getattr(self, 'exp_'+method) - res = fn(cr, uid, *params) - cr.commit() - cr.close() - return res - -class common(_ObjectService): +class common(netsvc.ExportService): def __init__(self,name="common"): - _ObjectService.__init__(self,name) - self.joinGroup("web-services") + netsvc.ExportService.__init__(self,name) def dispatch(self, method, auth, params): logger = netsvc.Logger() @@ -382,7 +379,7 @@ class common(_ObjectService): return res or False elif method == 'logout': if auth: - auth.logout(params[1]) + auth.logout(params[1]) # TODO I didn't see any AuthProxy implementing this method. logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db)) return True elif method in ['about', 'timezone_get', 'get_server_environment', @@ -399,10 +396,6 @@ class common(_ObjectService): fn = getattr(self, 'exp_'+method) return fn(*params) - - def new_dispatch(self,method,auth,params): - pass - def exp_about(self, extended=False): """Return information about the OpenERP Server. @@ -436,7 +429,7 @@ GNU Public Licence. return rc.get_available_updates(rc.id, openerp.modules.get_modules_with_version()) except tm.RemoteContractException, e: - self.abortResponse(1, 'Migration Error', 'warning', str(e)) + netsvc.abort_response(1, 'Migration Error', 'warning', str(e)) def exp_get_migration_scripts(self, contract_id, contract_password): @@ -504,7 +497,7 @@ GNU Public Licence. return True except tm.RemoteContractException, e: - self.abortResponse(1, 'Migration Error', 'warning', str(e)) + netsvc.abort_response(1, 'Migration Error', 'warning', str(e)) except Exception, e: import traceback tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback)) @@ -568,7 +561,6 @@ GNU Public Licence. class objects_proxy(netsvc.ExportService): def __init__(self, name="object"): netsvc.ExportService.__init__(self,name) - self.joinGroup('web-services') def dispatch(self, method, auth, params): (db, uid, passwd ) = params[0:3] @@ -578,16 +570,12 @@ class objects_proxy(netsvc.ExportService): if method not in ['execute','exec_workflow']: raise NameError("Method not available %s" % method) security.check(db,uid,passwd) - ls = netsvc.LocalService('object_proxy') - fn = getattr(ls, method) + assert openerp.osv.osv.service, "The object_proxy class must be started with start_object_proxy." + fn = getattr(openerp.osv.osv.service, method) res = fn(db, uid, *params) return res - def new_dispatch(self,method,auth,params): - pass - - # # Wizard ID: 1 # - None = end of wizard @@ -602,7 +590,6 @@ class objects_proxy(netsvc.ExportService): class wizard(netsvc.ExportService): def __init__(self, name='wizard'): netsvc.ExportService.__init__(self,name) - self.joinGroup('web-services') self.id = 0 self.wiz_datas = {} self.wiz_name = {} @@ -618,9 +605,6 @@ class wizard(netsvc.ExportService): res = fn(db, uid, *params) return res - def new_dispatch(self,method,auth,params): - pass - def _execute(self, db, uid, wiz_id, datas, action, context): self.wiz_datas[wiz_id].update(datas) wiz = netsvc.LocalService('wizard.'+self.wiz_name[wiz_id]) @@ -664,7 +648,6 @@ class ExceptionWithTraceback(Exception): class report_spool(netsvc.ExportService): def __init__(self, name='report'): netsvc.ExportService.__init__(self, name) - self.joinGroup('web-services') self._reports = {} self.id = 0 self.id_protect = threading.Semaphore() @@ -672,16 +655,54 @@ class report_spool(netsvc.ExportService): def dispatch(self, method, auth, params): (db, uid, passwd ) = params[0:3] params = params[3:] - if method not in ['report','report_get']: + if method not in ['report', 'report_get', 'render_report']: raise KeyError("Method not supported %s" % method) security.check(db,uid,passwd) fn = getattr(self, 'exp_' + method) res = fn(db, uid, *params) return res + def exp_render_report(self, db, uid, object, ids, datas=None, context=None): + if not datas: + datas={} + if not context: + context={} - def new_dispatch(self,method,auth,params): - pass + self.id_protect.acquire() + self.id += 1 + id = self.id + self.id_protect.release() + + self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} + + cr = pooler.get_db(db).cursor() + import traceback + import sys + try: + obj = netsvc.LocalService('report.'+object) + (result, format) = obj.create(cr, uid, ids, datas, context) + if not result: + tb = sys.exc_info() + self._reports[id]['exception'] = ExceptionWithTraceback('RML is not available at specified location or not enough data to print!', tb) + self._reports[id]['result'] = result + self._reports[id]['format'] = format + self._reports[id]['state'] = True + except Exception, exception: + + tb = sys.exc_info() + tb_s = "".join(traceback.format_exception(*tb)) + logger = netsvc.Logger() + logger.notifyChannel('web-services', netsvc.LOG_ERROR, + 'Exception: %s\n%s' % (str(exception), tb_s)) + if hasattr(exception, 'name') and hasattr(exception, 'value'): + self._reports[id]['exception'] = ExceptionWithTraceback(tools.ustr(exception.name), tools.ustr(exception.value)) + else: + self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb) + self._reports[id]['state'] = True + cr.commit() + cr.close() + + return self._check_report(id) def exp_report(self, db, uid, object, ids, datas=None, context=None): if not datas: @@ -732,7 +753,7 @@ class report_spool(netsvc.ExportService): result = self._reports[report_id] exc = result['exception'] if exc: - self.abortResponse(exc, exc.message, 'warning', exc.traceback) + netsvc.abort_response(exc, exc.message, 'warning', exc.traceback) res = {'state': result['state']} if res['state']: if tools.config['reportgz']: diff --git a/openerp/service/websrv_lib.py b/openerp/service/websrv_lib.py index 2e098169bae..1efab672eb3 100644 --- a/openerp/service/websrv_lib.py +++ b/openerp/service/websrv_lib.py @@ -52,61 +52,17 @@ class AuthProvider: def __init__(self,realm): self.realm = realm - def setupAuth(self, multi,handler): - """ Attach an AuthProxy object to handler - """ - pass - def authenticate(self, user, passwd, client_address): return False def log(self, msg): print msg -class BasicAuthProvider(AuthProvider): - def setupAuth(self, multi, handler): - if not multi.sec_realms.has_key(self.realm): - multi.sec_realms[self.realm] = BasicAuthProxy(self) - - -class AuthProxy: - """ This class will hold authentication information for a handler, - i.e. a connection - """ - def __init__(self, provider): - self.provider = provider - def checkRequest(self,handler,path = '/'): """ Check if we are allowed to process that request """ pass -class BasicAuthProxy(AuthProxy): - """ Require basic authentication.. - """ - def __init__(self,provider): - AuthProxy.__init__(self,provider) - self.auth_creds = None - self.auth_tries = 0 - - def checkRequest(self,handler,path = '/'): - if self.auth_creds: - return True - auth_str = handler.headers.get('Authorization',False) - if auth_str and auth_str.startswith('Basic '): - auth_str=auth_str[len('Basic '):] - (user,passwd) = base64.decodestring(auth_str).split(':') - self.provider.log("Found user=\"%s\", passwd=\"%s\"" %(user,passwd)) - self.auth_creds = self.provider.authenticate(user,passwd,handler.client_address) - if self.auth_creds: - return True - if self.auth_tries > 5: - self.provider.log("Failing authorization after 5 requests w/o password") - raise AuthRejectedExc("Authorization failed.") - self.auth_tries += 1 - raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm) - - class HTTPHandler(SimpleHTTPRequestHandler): def __init__(self,request, client_address, server): SimpleHTTPRequestHandler.__init__(self,request,client_address,server) @@ -125,13 +81,17 @@ class HTTPHandler(SimpleHTTPRequestHandler): def setup(self): pass +# A list of HTTPDir. +handlers = [] + class HTTPDir: """ A dispatcher class, like a virtual folder in httpd """ - def __init__(self,path,handler, auth_provider = None): + def __init__(self, path, handler, auth_provider=None, secure_only=False): self.path = path self.handler = handler self.auth_provider = auth_provider + self.secure_only = secure_only def matches(self, request): """ Test if some request matches us. If so, return @@ -140,6 +100,48 @@ class HTTPDir: return self.path return False + def instanciate_handler(self, request, client_address, server): + handler = self.handler(noconnection(request), client_address, server) + if self.auth_provider: + handler.auth_provider = self.auth_provider() + return handler + +def reg_http_service(path, handler, auth_provider=None, secure_only=False): + """ Register a HTTP handler at a given path. + + The auth_provider will be instanciated and set on the handler instances. + """ + global handlers + service = HTTPDir(path, handler, auth_provider, secure_only) + pos = len(handlers) + lastpos = pos + while pos > 0: + pos -= 1 + if handlers[pos].matches(service.path): + lastpos = pos + # we won't break here, but search all way to the top, to + # ensure there is no lesser entry that will shadow the one + # we are inserting. + handlers.insert(lastpos, service) + +def list_http_services(protocol=None): + global handlers + ret = [] + for svc in handlers: + if protocol is None or protocol == 'http' or svc.secure_only: + ret.append((svc.path, str(svc.handler))) + + return ret + +def find_http_service(path, secure=False): + global handlers + for vdir in handlers: + p = vdir.matches(path) + if p == False or (vdir.secure_only and not secure): + continue + return vdir + return None + class noconnection(object): """ a class to use instead of the real connection """ @@ -246,11 +248,10 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.in_handlers = {} - self.sec_realms = {} SocketServer.StreamRequestHandler.__init__(self,request,client_address,server) self.log_message("MultiHttpHandler init for %s" %(str(client_address))) - def _handle_one_foreign(self,fore, path, auth_provider): + def _handle_one_foreign(self, fore, path): """ This method overrides the handle_one_request for *children* handlers. It is required, since the first line should not be read again.. @@ -266,9 +267,9 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): return self.request_version = fore.request_version - if auth_provider and auth_provider.realm: + if hasattr(fore, 'auth_provider'): try: - self.sec_realms[auth_provider.realm].checkRequest(fore,path) + fore.auth_provider.checkRequest(fore,path) except AuthRequiredExc,ae: # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the # authorisation features of HTTP/1.1 @@ -408,35 +409,29 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): return self.do_OPTIONS() return - - for vdir in self.server.vdirs: - p = vdir.matches(self.path) - if p == False: - continue + vdir = find_http_service(self.path, self.server.proto == 'HTTPS') + if vdir: + p = vdir.path npath = self.path[len(p):] if not npath.startswith('/'): npath = '/' + npath if not self.in_handlers.has_key(p): - self.in_handlers[p] = vdir.handler(noconnection(self.request),self.client_address,self.server) - if vdir.auth_provider: - vdir.auth_provider.setupAuth(self, self.in_handlers[p]) + self.in_handlers[p] = vdir.instanciate_handler(noconnection(self.request),self.client_address,self.server) hnd = self.in_handlers[p] hnd.rfile = self.rfile hnd.wfile = self.wfile self.rlpath = self.raw_requestline try: - self._handle_one_foreign(hnd,npath, vdir.auth_provider) + self._handle_one_foreign(hnd, npath) except IOError, e: if e.errno == errno.EPIPE: self.log_message("Could not complete request %s," \ "client closed connection", self.rlpath.rstrip()) else: raise - return - # if no match: - self.send_error(404, "Path not found: %s" % self.path) - return + else: # no match: + self.send_error(404, "Path not found: %s" % self.path) def _get_ignore_body(self,fore): if not fore.headers.has_key("content-length"): diff --git a/openerp/tools/config.py b/openerp/tools/config.py index f7335bcf0c5..3304a4f4a99 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -24,6 +24,7 @@ import optparse import os import sys import openerp +import openerp.conf import openerp.loglevels as loglevels import logging import openerp.release as release @@ -101,8 +102,10 @@ class configmanager(object): group.add_option("-P", "--import-partial", dest="import_partial", my_default='', help="Use this for big data importation, if it crashes you will be able to continue at the current state. Provide a filename to store intermediate importation states.") group.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored") + group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules") parser.add_option_group(group) + # XML-RPC / HTTP group = optparse.OptionGroup(parser, "XML-RPC Configuration") group.add_option("--xmlrpc-interface", dest="xmlrpc_interface", my_default='', help="Specify the TCP IP address for the XML-RPC protocol. The empty string binds to all interfaces.") @@ -112,6 +115,7 @@ class configmanager(object): help="disable the XML-RPC protocol") parser.add_option_group(group) + # XML-RPC / HTTPS title = "XML-RPC Secure Configuration" if not self.has_ssl: title += " (disabled as ssl is unavailable)" @@ -139,6 +143,13 @@ class configmanager(object): help="disable the NETRPC protocol") parser.add_option_group(group) + # WEB + # TODO move to web addons after MetaOption merge + group = optparse.OptionGroup(parser, "Web interface Configuration") + group.add_option("--db-filter", dest="dbfilter", default='.*', + help="Filter listed database", metavar="REGEXP") + parser.add_option_group(group) + # Static HTTP group = optparse.OptionGroup(parser, "Static HTTP service") group.add_option("--static-http-enable", dest="static_http_enable", action="store_true", my_default=False, help="enable static HTTP service for serving plain HTML files") @@ -260,9 +271,26 @@ class configmanager(object): self.options[option.dest] = option.my_default self.casts[option.dest] = option - self.parse_config() + self.parse_config(None, False) - def parse_config(self, args=None): + def parse_config(self, args=None, complete=True): + """ Parse the configuration file (if any) and the command-line + arguments. + + This method initializes openerp.tools.config and openerp.conf (the + former should be removed in the furture) with library-wide + configuration values. + + This method must be called before proper usage of this library can be + made. + + Typical usage of this method: + + openerp.tools.config.parse_config(sys.argv[1:]) + + :param complete: this is a hack used in __init__(), leave it to True. + + """ if args is None: args = [] opt, args = self.parser.parse_args(args) @@ -319,8 +347,8 @@ class configmanager(object): 'netrpc_interface', 'netrpc_port', 'db_maxconn', 'import_partial', 'addons_path', 'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone', 'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs', - 'secure_cert_file', 'secure_pkey_file', - 'static_http_enable', 'static_http_document_root', 'static_http_url_prefix' + 'static_http_enable', 'static_http_document_root', 'static_http_url_prefix', + 'secure_cert_file', 'secure_pkey_file', 'dbfilter' ] for arg in keys: @@ -419,6 +447,17 @@ class configmanager(object): if opt.save: self.save() + openerp.conf.addons_paths = self.options['addons_path'].split(',') + openerp.conf.server_wide_modules = \ + map(lambda m: m.strip(), opt.server_wide_modules.split(',')) if \ + opt.server_wide_modules else [] + if complete: + openerp.modules.module.initialize_sys_path() + openerp.modules.loading.open_openerp_namespace() + # openerp.addons.__path__.extend(openerp.conf.addons_paths) # This + # is not compatible with initialize_sys_path(): import crm and + # import openerp.addons.crm load twice the module. + def _generate_pgpassfile(self): """ Generate the pgpass file with the parameters from the command line (db_host, db_user, diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index b45a941bfc2..bb4ce9db87d 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -1,10 +1,12 @@ # -*- encoding: utf-8 -*- +import threading import types import time # used to eval time.strftime expressions from datetime import datetime, timedelta import logging import openerp.pooler as pooler +import openerp.sql_db as sql_db import misc from config import config import yaml_tag @@ -331,6 +333,7 @@ class YamlInterpreter(object): def _create_record(self, model, fields): record_dict = {} + fields = fields or {} for field_name, expression in fields.items(): field_value = self._eval_field(model, field_name, expression) record_dict[field_name] = field_value @@ -800,4 +803,19 @@ def yaml_import(cr, module, yamlfile, idref=None, mode='init', noupdate=False): # keeps convention of convert.py convert_yaml_import = yaml_import +def threaded_yaml_import(db_name, module_name, file_name, delay=0): + def f(): + time.sleep(delay) + cr = None + fp = None + try: + cr = sql_db.db_connect(db_name).cursor() + fp = misc.file_open(file_name) + convert_yaml_import(cr, module_name, fp, {}, 'update', True) + finally: + if cr: cr.close() + if fp: fp.close() + threading.Thread(target=f).start() + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/wizard/__init__.py b/openerp/wizard/__init__.py index df0b942d0df..2ed01921afa 100644 --- a/openerp/wizard/__init__.py +++ b/openerp/wizard/__init__.py @@ -44,7 +44,6 @@ class interface(netsvc.Service): def __init__(self, name): assert not self.exists('wizard.'+name), 'The wizard "%s" already exists!' % (name,) super(interface, self).__init__('wizard.'+name) - self.exportMethod(self.execute) self.wiz_name = name def translate_view(self, cr, node, state, lang): @@ -156,7 +155,7 @@ class interface(netsvc.Service): if isinstance(e, except_wizard) \ or isinstance(e, except_osv) \ or isinstance(e, except_orm): - self.abortResponse(2, e.name, 'warning', e.value) + netsvc.abort_response(2, e.name, 'warning', e.value) else: import traceback tb_s = reduce(lambda x, y: x+y, traceback.format_exception( diff --git a/openerp/workflow/wkf_service.py b/openerp/workflow/wkf_service.py index 12fb5eec287..a8d829aa546 100644 --- a/openerp/workflow/wkf_service.py +++ b/openerp/workflow/wkf_service.py @@ -36,15 +36,9 @@ class workflow_service(netsvc.Service): >>> wf_service = netsvc.LocalService("workflow") """ - def __init__(self, name='workflow', audience='*'): - netsvc.Service.__init__(self, name, audience) - self.exportMethod(self.trg_write) - self.exportMethod(self.trg_delete) - self.exportMethod(self.trg_create) - self.exportMethod(self.trg_validate) - self.exportMethod(self.trg_redirect) - self.exportMethod(self.trg_trigger) - self.exportMethod(self.clear_cache) + + def __init__(self, name='workflow'): + netsvc.Service.__init__(self, name) self.wkf_on_create_cache={} def clear_cache(self, cr, uid): diff --git a/openerp/wsgi.py b/openerp/wsgi.py new file mode 100644 index 00000000000..5a8f19f8d83 --- /dev/null +++ b/openerp/wsgi.py @@ -0,0 +1,375 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 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 . +# +############################################################################## + +""" WSGI stuffs (proof of concept for now) + +This module offers a WSGI interface to OpenERP. + +""" + +import httplib +import urllib +import xmlrpclib +import StringIO + +import logging +import os +import signal +import sys +import threading +import time + +import openerp +import openerp.tools.config as config +import service.websrv_lib as websrv_lib + +def xmlrpc_return(start_response, service, method, params): + """ Helper to call a service's method with some params, using a + wsgi-supplied ``start_response`` callback.""" + # This mimics SimpleXMLRPCDispatcher._marshaled_dispatch() for exception + # handling. + try: + result = openerp.netsvc.dispatch_rpc(service, method, params, None) # TODO auth + response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None) + except openerp.netsvc.OpenERPDispatcherException, e: + fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e.exception), e.traceback) + response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) + except: + exc_type, exc_value, exc_tb = sys.exc_info() + fault = xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)) + 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): + """ The main OpenERP WSGI handler.""" + if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/openerp/xmlrpc'): + length = int(environ['CONTENT_LENGTH']) + data = environ['wsgi.input'].read(length) + + params, method = xmlrpclib.loads(data) + + path = environ['PATH_INFO'][len('/openerp/xmlrpc'):] + if path.startswith('/'): path = path[1:] + if path.endswith('/'): p = path[:-1] + path = path.split('/') + + # All routes are hard-coded. Need a way to register addons-supplied handlers. + + # No need for a db segment. + if len(path) == 1: + service = path[0] + + if service == 'common': + if method in ('create_database', 'list', 'server_version'): + return xmlrpc_return(start_response, 'db', method, params) + else: + return xmlrpc_return(start_response, 'common', method, params) + # A db segment must be given. + elif len(path) == 2: + service, db_name = path + params = (db_name,) + params + + if service == 'model': + return xmlrpc_return(start_response, 'object', method, params) + elif service == 'report': + return xmlrpc_return(start_response, 'report', method, params) + + # TODO the body has been read, need to raise an exception (not return None). + +def legacy_wsgi_xmlrpc(environ, start_response): + 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, ... + + params, method = xmlrpclib.loads(data) + return xmlrpc_return(start_response, path, method, params) + +def wsgi_jsonrpc(environ, start_response): + pass + +def wsgi_webdav(environ, start_response): + if environ['REQUEST_METHOD'] == 'OPTIONS' and environ['PATH_INFO'] == '*': + return return_options(environ, start_response) + + http_dir = websrv_lib.find_http_service(environ['PATH_INFO']) + if http_dir: + path = environ['PATH_INFO'][len(http_dir.path):] + if path.startswith('/'): + environ['PATH_INFO'] = path + else: + environ['PATH_INFO'] = '/' + path + return http_to_wsgi(http_dir)(environ, start_response) + +def return_options(environ, start_response): + # Microsoft specific header, see + # http://www.ibm.com/developerworks/rational/library/2089.html + if 'Microsoft' in environ.get('User-Agent', ''): + option = [('MS-Author-Via', 'DAV')] + else: + option = [] + options += [('DAV', '1 2'), ('Allow', 'GET HEAD PROPFIND OPTIONS REPORT')] + start_response("200 OK", [('Content-Length', str(0))] + options) + return [] + +def http_to_wsgi(http_dir): + """ + Turn a BaseHTTPRequestHandler into a WSGI entry point. + + Actually the argument is not a bare BaseHTTPRequestHandler but is wrapped + (as a class, so it needs to be instanciated) in a HTTPDir. + + This code is adapted from wbsrv_lib.MultiHTTPHandler._handle_one_foreign(). + It is a temporary solution: the HTTP sub-handlers (in particular the + document_webdav addon) have to be WSGIfied. + """ + def wsgi_handler(environ, start_response): + + # Extract from the WSGI environment the necessary data. + scheme = environ['wsgi.url_scheme'] + + headers = {} + for key, value in environ.items(): + if key.startswith('HTTP_'): + key = key[5:].replace('_', '-').title() + headers[key] = value + if key == 'CONTENT_LENGTH': + key = key.replace('_', '-').title() + headers[key] = value + if environ.get('Content-Type'): + headers['Content-Type'] = environ['Content-Type'] + + path = urllib.quote(environ.get('PATH_INFO', '')) + if environ.get('QUERY_STRING'): + path += '?' + environ['QUERY_STRING'] + + request_version = 'HTTP/1.1' # TODO + request_line = "%s %s %s\n" % (environ['REQUEST_METHOD'], path, request_version) + + class Dummy(object): + pass + + # Let's pretend we have a server to hand to the handler. + server = Dummy() + server.server_name = environ['SERVER_NAME'] + server.server_port = int(environ['SERVER_PORT']) + + # Initialize the underlying handler and associated auth. provider. + con = openerp.service.websrv_lib.noconnection(environ['wsgi.input']) + handler = http_dir.instanciate_handler(con, environ['REMOTE_ADDR'], server) + + # Populate the handler as if it is called by a regular HTTP server + # and the request is already parsed. + handler.wfile = StringIO.StringIO() + handler.rfile = environ['wsgi.input'] + handler.headers = headers + handler.command = environ['REQUEST_METHOD'] + handler.path = path + handler.request_version = request_version + handler.close_connection = 1 + handler.raw_requestline = request_line + handler.requestline = request_line + + # Handle authentication if there is an auth. provider associated to + # the handler. + if hasattr(handler, 'auth_provider'): + try: + handler.auth_provider.checkRequest(handler, path) + except websrv_lib.AuthRequiredExc, ae: + # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the + # authorisation features of HTTP/1.1 + if request_version != 'HTTP/1.1' and ('Darwin/9.' not in handler.headers.get('User-Agent', '')): + start_response("403 Forbidden", []) + return [] + start_response("401 Authorization required", [ + ('WWW-Authenticate', '%s realm="%s"' % (ae.atype,ae.realm)), + # ('Connection', 'keep-alive'), + ('Content-Type', 'text/html'), + ('Content-Length', 4), # len(self.auth_required_msg) + ]) + return ['Blah'] # self.auth_required_msg + except websrv_lib.AuthRejectedExc,e: + start_response("403 %s" % (e.args[0],), []) + return [] + + method_name = 'do_' + handler.command + + # Support the OPTIONS method even when not provided directly by the + # handler. TODO I would prefer to remove it and fix the handler if + # needed. + if not hasattr(handler, method_name): + if handler.command == 'OPTIONS': + return return_options(environ, start_response) + start_response("501 Unsupported method (%r)" % handler.command, []) + return [] + + # Finally, call the handler's method. + try: + method = getattr(handler, method_name) + method() + # The DAV handler buffers its output and provides a _flush() + # method. + getattr(handler, '_flush', lambda: None)() + response = parse_http_response(handler.wfile.getvalue()) + response_headers = response.getheaders() + body = response.read() + start_response(str(response.status) + ' ' + response.reason, response_headers) + return [body] + except (websrv_lib.AuthRejectedExc, websrv_lib.AuthRequiredExc): + raise + except Exception, e: + start_response("500 Internal error", []) + return [] + + return wsgi_handler + +def parse_http_response(s): + """ Turn a HTTP response string into a httplib.HTTPResponse object.""" + class DummySocket(StringIO.StringIO): + """ + This is used to provide a StringIO to httplib.HTTPResponse + which, instead of taking a file object, expects a socket and + uses its makefile() method. + """ + def makefile(self, *args, **kw): + return self + response = httplib.HTTPResponse(DummySocket(s)) + response.begin() + return response + +# WSGI handlers registered through the register_wsgi_handler() function below. +module_handlers = [] + +def register_wsgi_handler(handler): + """ Register a WSGI handler. + + Handlers are tried in the order they are added. We might provide a way to + register a handler for specific routes later. + """ + module_handlers.append(handler) + +def application(environ, start_response): + """ WSGI entry point.""" + + # Try all handlers until one returns some result (i.e. not None). + wsgi_handlers = [ + wsgi_xmlrpc, + wsgi_jsonrpc, + legacy_wsgi_xmlrpc, + wsgi_webdav + ] + module_handlers + for handler in wsgi_handlers: + result = handler(environ, start_response) + if result is None: + continue + return result + + # We never returned from the loop. + response = 'No handler found.\n' + start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))]) + return [response] + +# The WSGI server, started by start_server(), stopped by stop_server(). +httpd = None + +def serve(): + """ Serve HTTP requests via werkzeug development server. + + If werkzeug can not be imported, we fall back to wsgiref's simple_server. + + Calling this function is blocking, you might want to call it in its own + thread. + """ + + global httpd + + # TODO Change the xmlrpc_* options to http_* + interface = config['xmlrpc_interface'] or '0.0.0.0' + port = config['xmlrpc_port'] + try: + import werkzeug.serving + httpd = werkzeug.serving.make_server(interface, port, application, threaded=True) + logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s', interface, port) + except ImportError, e: + import wsgiref.simple_server + logging.getLogger('wsgi').warn('Werkzeug module unavailable, falling back to wsgiref.') + httpd = wsgiref.simple_server.make_server(interface, port, application) + logging.getLogger('wsgi').info('HTTP service (wsgiref) running on %s:%s', interface, port) + + httpd.serve_forever() + +def start_server(): + """ Call serve() in its own thread. + + The WSGI server can be shutdown with stop_server() below. + """ + threading.Thread(target=openerp.wsgi.serve).start() + +def stop_server(): + """ Initiate the shutdown of the WSGI server. + + The server is supposed to have been started by start_server() above. + """ + if httpd: + httpd.shutdown() + +# Master process id, can be used for signaling. +arbiter_pid = None + +# Application setup before we can spawn any worker process. +# This is suitable for e.g. gunicorn's on_starting hook. +def on_starting(server): + global arbiter_pid + arbiter_pid = os.getpid() # TODO check if this is true even after replacing the executable + config = openerp.tools.config + #openerp.tools.cache = kill_workers_cache + openerp.netsvc.init_logger() + openerp.osv.osv.start_object_proxy() + openerp.service.web_services.start_web_services() + +# Install our own signal handler on the master process. +def when_ready(server): + # Hijack gunicorn's SIGWINCH handling; we can choose another one. + signal.signal(signal.SIGWINCH, make_winch_handler(server)) + +# Our signal handler will signal a SGIQUIT to all workers. +def make_winch_handler(server): + def handle_winch(sig, fram): + server.kill_workers(signal.SIGQUIT) # This is gunicorn specific. + return handle_winch + +# Kill gracefuly the workers (e.g. because we want to clear their cache). +# This is done by signaling a SIGWINCH to the master process, so it can be +# called by the workers themselves. +def kill_workers(): + try: + os.kill(arbiter_pid, signal.SIGWINCH) + except OSError, e: + if e.errno == errno.ESRCH: # no such pid + return + raise + +class kill_workers_cache(openerp.tools.ormcache): + def clear(self, dbname, *args, **kwargs): + kill_workers() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/pixmaps/openerp-intro.bmp b/pixmaps/openerp-intro.bmp deleted file mode 100644 index 8d3c9340c9b..00000000000 Binary files a/pixmaps/openerp-intro.bmp and /dev/null differ diff --git a/pixmaps/openerp-slogan.bmp b/pixmaps/openerp-slogan.bmp deleted file mode 100644 index a3cffd104f2..00000000000 Binary files a/pixmaps/openerp-slogan.bmp and /dev/null differ diff --git a/python25-compat/BaseHTTPServer.py b/python25-compat/BaseHTTPServer.py deleted file mode 100644 index 5f2d558b689..00000000000 --- a/python25-compat/BaseHTTPServer.py +++ /dev/null @@ -1,587 +0,0 @@ -"""HTTP server base class. - -Note: the class in this module doesn't implement any HTTP request; see -SimpleHTTPServer for simple implementations of GET, HEAD and POST -(including CGI scripts). It does, however, optionally implement HTTP/1.1 -persistent connections, as of version 0.3. - -Contents: - -- BaseHTTPRequestHandler: HTTP request handler base class -- test: test function - -XXX To do: - -- log requests even later (to capture byte count) -- log user-agent header and other interesting goodies -- send error log to separate file -""" - - -# See also: -# -# HTTP Working Group T. Berners-Lee -# INTERNET-DRAFT R. T. Fielding -# H. Frystyk Nielsen -# Expires September 8, 1995 March 8, 1995 -# -# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt -# -# and -# -# Network Working Group R. Fielding -# Request for Comments: 2616 et al -# Obsoletes: 2068 June 1999 -# Category: Standards Track -# -# URL: http://www.faqs.org/rfcs/rfc2616.html - -# Log files -# --------- -# -# Here's a quote from the NCSA httpd docs about log file format. -# -# | The logfile format is as follows. Each line consists of: -# | -# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb -# | -# | host: Either the DNS name or the IP number of the remote client -# | rfc931: Any information returned by identd for this person, -# | - otherwise. -# | authuser: If user sent a userid for authentication, the user name, -# | - otherwise. -# | DD: Day -# | Mon: Month (calendar name) -# | YYYY: Year -# | hh: hour (24-hour format, the machine's timezone) -# | mm: minutes -# | ss: seconds -# | request: The first line of the HTTP request as sent by the client. -# | ddd: the status code returned by the server, - if not available. -# | bbbb: the total number of bytes sent, -# | *not including the HTTP/1.0 header*, - if not available -# | -# | You can determine the name of the file accessed through request. -# -# (Actually, the latter is only true if you know the server configuration -# at the time the request was made!) - -__version__ = "0.3" - -__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] - -import sys -import time -import socket # For gethostbyaddr() -import mimetools -import SocketServer - -# Default error message template -DEFAULT_ERROR_MESSAGE = """\ - -Error response - - -

Error response

-

Error code %(code)d. -

Message: %(message)s. -

Error code explanation: %(code)s = %(explain)s. - -""" - -DEFAULT_ERROR_CONTENT_TYPE = "text/html" - -def _quote_html(html): - return html.replace("&", "&").replace("<", "<").replace(">", ">") - -class HTTPServer(SocketServer.TCPServer): - - allow_reuse_address = 1 # Seems to make sense in testing environment - - def server_bind(self): - """Override server_bind to store the server name.""" - SocketServer.TCPServer.server_bind(self) - host, port = self.socket.getsockname()[:2] - self.server_name = socket.getfqdn(host) - self.server_port = port - - -class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): - - """HTTP request handler base class. - - The following explanation of HTTP serves to guide you through the - code as well as to expose any misunderstandings I may have about - HTTP (so you don't need to read the code to figure out I'm wrong - :-). - - HTTP (HyperText Transfer Protocol) is an extensible protocol on - top of a reliable stream transport (e.g. TCP/IP). The protocol - recognizes three parts to a request: - - 1. One line identifying the request type and path - 2. An optional set of RFC-822-style headers - 3. An optional data part - - The headers and data are separated by a blank line. - - The first line of the request has the form - - - - where is a (case-sensitive) keyword such as GET or POST, - is a string containing path information for the request, - and should be the string "HTTP/1.0" or "HTTP/1.1". - is encoded using the URL encoding scheme (using %xx to signify - the ASCII character with hex code xx). - - The specification specifies that lines are separated by CRLF but - for compatibility with the widest range of clients recommends - servers also handle LF. Similarly, whitespace in the request line - is treated sensibly (allowing multiple spaces between components - and allowing trailing whitespace). - - Similarly, for output, lines ought to be separated by CRLF pairs - but most clients grok LF characters just fine. - - If the first line of the request has the form - - - - (i.e. is left out) then this is assumed to be an HTTP - 0.9 request; this form has no optional headers and data part and - the reply consists of just the data. - - The reply form of the HTTP 1.x protocol again has three parts: - - 1. One line giving the response code - 2. An optional set of RFC-822-style headers - 3. The data - - Again, the headers and data are separated by a blank line. - - The response code line has the form - - - - where is the protocol version ("HTTP/1.0" or "HTTP/1.1"), - is a 3-digit response code indicating success or - failure of the request, and is an optional - human-readable string explaining what the response code means. - - This server parses the request and the headers, and then calls a - function specific to the request type (). Specifically, - a request SPAM will be handled by a method do_SPAM(). If no - such method exists the server sends an error response to the - client. If it exists, it is called with no arguments: - - do_SPAM() - - Note that the request name is case sensitive (i.e. SPAM and spam - are different requests). - - The various request details are stored in instance variables: - - - client_address is the client IP address in the form (host, - port); - - - command, path and version are the broken-down request line; - - - headers is an instance of mimetools.Message (or a derived - class) containing the header information; - - - rfile is a file object open for reading positioned at the - start of the optional input data part; - - - wfile is a file object open for writing. - - IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING! - - The first thing to be written must be the response line. Then - follow 0 or more header lines, then a blank line, and then the - actual data (if any). The meaning of the header lines depends on - the command executed by the server; in most cases, when data is - returned, there should be at least one header line of the form - - Content-type: / - - where and should be registered MIME types, - e.g. "text/html" or "text/plain". - - """ - - # The Python system version, truncated to its first component. - sys_version = "Python/" + sys.version.split()[0] - - # The server software version. You may want to override this. - # The format is multiple whitespace-separated strings, - # where each string is of the form name[/version]. - server_version = "BaseHTTP/" + __version__ - - # The default request version. This only affects responses up until - # the point where the request line is parsed, so it mainly decides what - # the client gets back when sending a malformed request line. - # Most web servers default to HTTP 0.9, i.e. don't send a status line. - default_request_version = "HTTP/0.9" - - def parse_request(self): - """Parse a request (internal). - - The request should be stored in self.raw_requestline; the results - are in self.command, self.path, self.request_version and - self.headers. - - Return True for success, False for failure; on failure, an - error is sent back. - - """ - self.command = None # set in case of error on the first line - self.request_version = version = self.default_request_version - self.close_connection = 1 - requestline = self.raw_requestline - if requestline[-2:] == '\r\n': - requestline = requestline[:-2] - elif requestline[-1:] == '\n': - requestline = requestline[:-1] - self.requestline = requestline - words = requestline.split() - if len(words) == 3: - [command, path, version] = words - if version[:5] != 'HTTP/': - self.send_error(400, "Bad request version (%r)" % version) - return False - try: - base_version_number = version.split('/', 1)[1] - version_number = base_version_number.split(".") - # RFC 2145 section 3.1 says there can be only one "." and - # - major and minor numbers MUST be treated as - # separate integers; - # - HTTP/2.4 is a lower version than HTTP/2.13, which in - # turn is lower than HTTP/12.3; - # - Leading zeros MUST be ignored by recipients. - if len(version_number) != 2: - raise ValueError - version_number = int(version_number[0]), int(version_number[1]) - except (ValueError, IndexError): - self.send_error(400, "Bad request version (%r)" % version) - return False - if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": - self.close_connection = 0 - if version_number >= (2, 0): - self.send_error(505, - "Invalid HTTP Version (%s)" % base_version_number) - return False - elif len(words) == 2: - [command, path] = words - self.close_connection = 1 - if command != 'GET': - self.send_error(400, - "Bad HTTP/0.9 request type (%r)" % command) - return False - elif not words: - return False - else: - self.send_error(400, "Bad request syntax (%r)" % requestline) - return False - self.command, self.path, self.request_version = command, path, version - - # Examine the headers and look for a Connection directive - self.headers = self.MessageClass(self.rfile, 0) - - conntype = self.headers.get('Connection', "") - if conntype.lower() == 'close': - self.close_connection = 1 - elif (conntype.lower() == 'keep-alive' and - self.protocol_version >= "HTTP/1.1"): - self.close_connection = 0 - return True - - def handle_one_request(self): - """Handle a single HTTP request. - - You normally don't need to override this method; see the class - __doc__ string for information on how to handle specific HTTP - commands such as GET and POST. - - """ - self.raw_requestline = self.rfile.readline() - if not self.raw_requestline: - self.close_connection = 1 - return - if not self.parse_request(): # An error code has been sent, just exit - return - mname = 'do_' + self.command - if not hasattr(self, mname): - self.send_error(501, "Unsupported method (%r)" % self.command) - return - method = getattr(self, mname) - method() - - def handle(self): - """Handle multiple requests if necessary.""" - self.close_connection = 1 - - self.handle_one_request() - while not self.close_connection: - self.handle_one_request() - - def send_error(self, code, message=None): - """Send and log an error reply. - - Arguments are the error code, and a detailed message. - The detailed message defaults to the short entry matching the - response code. - - This sends an error response (so it must be called before any - output has been generated), logs the error, and finally sends - a piece of HTML explaining the error to the user. - - """ - - try: - short, long = self.responses[code] - except KeyError: - short, long = '???', '???' - if message is None: - message = short - explain = long - self.log_error("code %d, message %s", code, message) - # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201) - content = (self.error_message_format % - {'code': code, 'message': _quote_html(message), 'explain': explain}) - self.send_response(code, message) - self.send_header("Content-Type", self.error_content_type) - self.send_header('Connection', 'close') - self.end_headers() - if self.command != 'HEAD' and code >= 200 and code not in (204, 304): - self.wfile.write(content) - - error_message_format = DEFAULT_ERROR_MESSAGE - error_content_type = DEFAULT_ERROR_CONTENT_TYPE - - def send_response(self, code, message=None): - """Send the response header and log the response code. - - Also send two standard headers with the server software - version and the current date. - - """ - self.log_request(code) - if message is None: - if code in self.responses: - message = self.responses[code][0] - else: - message = '' - if self.request_version != 'HTTP/0.9': - self.wfile.write("%s %d %s\r\n" % - (self.protocol_version, code, message)) - # print (self.protocol_version, code, message) - self.send_header('Server', self.version_string()) - self.send_header('Date', self.date_time_string()) - - def send_header(self, keyword, value): - """Send a MIME header.""" - if self.request_version != 'HTTP/0.9': - self.wfile.write("%s: %s\r\n" % (keyword, value)) - - if keyword.lower() == 'connection': - if value.lower() == 'close': - self.close_connection = 1 - elif value.lower() == 'keep-alive': - self.close_connection = 0 - - def end_headers(self): - """Send the blank line ending the MIME headers.""" - if self.request_version != 'HTTP/0.9': - self.wfile.write("\r\n") - - def log_request(self, code='-', size='-'): - """Log an accepted request. - - This is called by send_response(). - - """ - - self.log_message('"%s" %s %s', - self.requestline, str(code), str(size)) - - def log_error(self, format, *args): - """Log an error. - - This is called when a request cannot be fulfilled. By - default it passes the message on to log_message(). - - Arguments are the same as for log_message(). - - XXX This should go to the separate error log. - - """ - - self.log_message(format, *args) - - def log_message(self, format, *args): - """Log an arbitrary message. - - This is used by all other logging functions. Override - it if you have specific logging wishes. - - The first argument, FORMAT, is a format string for the - message to be logged. If the format string contains - any % escapes requiring parameters, they should be - specified as subsequent arguments (it's just like - printf!). - - The client host and current date/time are prefixed to - every message. - - """ - - sys.stderr.write("%s - - [%s] %s\n" % - (self.address_string(), - self.log_date_time_string(), - format%args)) - - def version_string(self): - """Return the server software version string.""" - return self.server_version + ' ' + self.sys_version - - def date_time_string(self, timestamp=None): - """Return the current date and time formatted for a message header.""" - if timestamp is None: - timestamp = time.time() - year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp) - s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( - self.weekdayname[wd], - day, self.monthname[month], year, - hh, mm, ss) - return s - - def log_date_time_string(self): - """Return the current time formatted for logging.""" - now = time.time() - year, month, day, hh, mm, ss, x, y, z = time.localtime(now) - s = "%02d/%3s/%04d %02d:%02d:%02d" % ( - day, self.monthname[month], year, hh, mm, ss) - return s - - weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] - - monthname = [None, - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - - def address_string(self): - """Return the client address formatted for logging. - - This version looks up the full hostname using gethostbyaddr(), - and tries to find a name that contains at least one dot. - - """ - - host, port = self.client_address[:2] - return socket.getfqdn(host) - - # Essentially static class variables - - # The version of the HTTP protocol we support. - # Set this to HTTP/1.1 to enable automatic keepalive - protocol_version = "HTTP/1.0" - - # The Message-like class used to parse headers - MessageClass = mimetools.Message - - # Table mapping response codes to messages; entries have the - # form {code: (shortmessage, longmessage)}. - # See RFC 2616. - responses = { - 100: ('Continue', 'Request received, please continue'), - 101: ('Switching Protocols', - 'Switching to new protocol; obey Upgrade header'), - - 200: ('OK', 'Request fulfilled, document follows'), - 201: ('Created', 'Document created, URL follows'), - 202: ('Accepted', - 'Request accepted, processing continues off-line'), - 203: ('Non-Authoritative Information', 'Request fulfilled from cache'), - 204: ('No Content', 'Request fulfilled, nothing follows'), - 205: ('Reset Content', 'Clear input form for further input.'), - 206: ('Partial Content', 'Partial content follows.'), - - 300: ('Multiple Choices', - 'Object has several resources -- see URI list'), - 301: ('Moved Permanently', 'Object moved permanently -- see URI list'), - 302: ('Found', 'Object moved temporarily -- see URI list'), - 303: ('See Other', 'Object moved -- see Method and URL list'), - 304: ('Not Modified', - 'Document has not changed since given time'), - 305: ('Use Proxy', - 'You must use proxy specified in Location to access this ' - 'resource.'), - 307: ('Temporary Redirect', - 'Object moved temporarily -- see URI list'), - - 400: ('Bad Request', - 'Bad request syntax or unsupported method'), - 401: ('Unauthorized', - 'No permission -- see authorization schemes'), - 402: ('Payment Required', - 'No payment -- see charging schemes'), - 403: ('Forbidden', - 'Request forbidden -- authorization will not help'), - 404: ('Not Found', 'Nothing matches the given URI'), - 405: ('Method Not Allowed', - 'Specified method is invalid for this server.'), - 406: ('Not Acceptable', 'URI not available in preferred format.'), - 407: ('Proxy Authentication Required', 'You must authenticate with ' - 'this proxy before proceeding.'), - 408: ('Request Timeout', 'Request timed out; try again later.'), - 409: ('Conflict', 'Request conflict.'), - 410: ('Gone', - 'URI no longer exists and has been permanently removed.'), - 411: ('Length Required', 'Client must specify Content-Length.'), - 412: ('Precondition Failed', 'Precondition in headers is false.'), - 413: ('Request Entity Too Large', 'Entity is too large.'), - 414: ('Request-URI Too Long', 'URI is too long.'), - 415: ('Unsupported Media Type', 'Entity body in unsupported format.'), - 416: ('Requested Range Not Satisfiable', - 'Cannot satisfy request range.'), - 417: ('Expectation Failed', - 'Expect condition could not be satisfied.'), - - 500: ('Internal Server Error', 'Server got itself in trouble'), - 501: ('Not Implemented', - 'Server does not support this operation'), - 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'), - 503: ('Service Unavailable', - 'The server cannot process the request due to a high load'), - 504: ('Gateway Timeout', - 'The gateway server did not receive a timely response'), - 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'), - } - - -def test(HandlerClass = BaseHTTPRequestHandler, - ServerClass = HTTPServer, protocol="HTTP/1.0"): - """Test the HTTP request handler class. - - This runs an HTTP server on port 8000 (or the first command line - argument). - - """ - - if sys.argv[1:]: - port = int(sys.argv[1]) - else: - port = 8000 - server_address = ('', port) - - HandlerClass.protocol_version = protocol - httpd = ServerClass(server_address, HandlerClass) - - sa = httpd.socket.getsockname() - print "Serving HTTP on", sa[0], "port", sa[1], "..." - httpd.serve_forever() - - -if __name__ == '__main__': - test() diff --git a/python25-compat/SimpleXMLRPCServer.py b/python25-compat/SimpleXMLRPCServer.py deleted file mode 100644 index 43757a03dda..00000000000 --- a/python25-compat/SimpleXMLRPCServer.py +++ /dev/null @@ -1,611 +0,0 @@ -"""Simple XML-RPC Server. - -This module can be used to create simple XML-RPC servers -by creating a server and either installing functions, a -class instance, or by extending the SimpleXMLRPCServer -class. - -It can also be used to handle XML-RPC requests in a CGI -environment using CGIXMLRPCRequestHandler. - -A list of possible usage patterns follows: - -1. Install functions: - -server = SimpleXMLRPCServer(("localhost", 8000)) -server.register_function(pow) -server.register_function(lambda x,y: x+y, 'add') -server.serve_forever() - -2. Install an instance: - -class MyFuncs: - def __init__(self): - # make all of the string functions available through - # string.func_name - import string - self.string = string - def _listMethods(self): - # implement this method so that system.listMethods - # knows to advertise the strings methods - return list_public_methods(self) + \ - ['string.' + method for method in list_public_methods(self.string)] - def pow(self, x, y): return pow(x, y) - def add(self, x, y) : return x + y - -server = SimpleXMLRPCServer(("localhost", 8000)) -server.register_introspection_functions() -server.register_instance(MyFuncs()) -server.serve_forever() - -3. Install an instance with custom dispatch method: - -class Math: - def _listMethods(self): - # this method must be present for system.listMethods - # to work - return ['add', 'pow'] - def _methodHelp(self, method): - # this method must be present for system.methodHelp - # to work - if method == 'add': - return "add(2,3) => 5" - elif method == 'pow': - return "pow(x, y[, z]) => number" - else: - # By convention, return empty - # string if no help is available - return "" - def _dispatch(self, method, params): - if method == 'pow': - return pow(*params) - elif method == 'add': - return params[0] + params[1] - else: - raise 'bad method' - -server = SimpleXMLRPCServer(("localhost", 8000)) -server.register_introspection_functions() -server.register_instance(Math()) -server.serve_forever() - -4. Subclass SimpleXMLRPCServer: - -class MathServer(SimpleXMLRPCServer): - def _dispatch(self, method, params): - try: - # We are forcing the 'export_' prefix on methods that are - # callable through XML-RPC to prevent potential security - # problems - func = getattr(self, 'export_' + method) - except AttributeError: - raise Exception('method "%s" is not supported' % method) - else: - return func(*params) - - def export_add(self, x, y): - return x + y - -server = MathServer(("localhost", 8000)) -server.serve_forever() - -5. CGI script: - -server = CGIXMLRPCRequestHandler() -server.register_function(pow) -server.handle_request() -""" - -# Written by Brian Quinlan (brian@sweetapp.com). -# Based on code written by Fredrik Lundh. - -import xmlrpclib -from xmlrpclib import Fault -import SocketServer -import BaseHTTPServer -import sys -import os -import traceback -try: - import fcntl -except ImportError: - fcntl = None - -def resolve_dotted_attribute(obj, attr, allow_dotted_names=True): - """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d - - Resolves a dotted attribute name to an object. Raises - an AttributeError if any attribute in the chain starts with a '_'. - - If the optional allow_dotted_names argument is false, dots are not - supported and this function operates similar to getattr(obj, attr). - """ - - if allow_dotted_names: - attrs = attr.split('.') - else: - attrs = [attr] - - for i in attrs: - if i.startswith('_'): - raise AttributeError( - 'attempt to access private attribute "%s"' % i - ) - else: - obj = getattr(obj,i) - return obj - -def list_public_methods(obj): - """Returns a list of attribute strings, found in the specified - object, which represent callable attributes""" - - return [member for member in dir(obj) - if not member.startswith('_') and - hasattr(getattr(obj, member), '__call__')] - -def remove_duplicates(lst): - """remove_duplicates([2,2,2,1,3,3]) => [3,1,2] - - Returns a copy of a list without duplicates. Every list - item must be hashable and the order of the items in the - resulting list is not defined. - """ - u = {} - for x in lst: - u[x] = 1 - - return u.keys() - -class SimpleXMLRPCDispatcher: - """Mix-in class that dispatches XML-RPC requests. - - This class is used to register XML-RPC method handlers - and then to dispatch them. There should never be any - reason to instantiate this class directly. - """ - - def __init__(self, allow_none, encoding): - self.funcs = {} - self.instance = None - self.allow_none = allow_none - self.encoding = encoding - - def register_instance(self, instance, allow_dotted_names=False): - """Registers an instance to respond to XML-RPC requests. - - Only one instance can be installed at a time. - - If the registered instance has a _dispatch method then that - method will be called with the name of the XML-RPC method and - its parameters as a tuple - e.g. instance._dispatch('add',(2,3)) - - If the registered instance does not have a _dispatch method - then the instance will be searched to find a matching method - and, if found, will be called. Methods beginning with an '_' - are considered private and will not be called by - SimpleXMLRPCServer. - - If a registered function matches a XML-RPC request, then it - will be called instead of the registered instance. - - If the optional allow_dotted_names argument is true and the - instance does not have a _dispatch method, method names - containing dots are supported and resolved, as long as none of - the name segments start with an '_'. - - *** SECURITY WARNING: *** - - Enabling the allow_dotted_names options allows intruders - to access your module's global variables and may allow - intruders to execute arbitrary code on your machine. Only - use this option on a secure, closed network. - - """ - - self.instance = instance - self.allow_dotted_names = allow_dotted_names - - def register_function(self, function, name = None): - """Registers a function to respond to XML-RPC requests. - - The optional name argument can be used to set a Unicode name - for the function. - """ - - if name is None: - name = function.__name__ - self.funcs[name] = function - - def register_introspection_functions(self): - """Registers the XML-RPC introspection methods in the system - namespace. - - see http://xmlrpc.usefulinc.com/doc/reserved.html - """ - - self.funcs.update({'system.listMethods' : self.system_listMethods, - 'system.methodSignature' : self.system_methodSignature, - 'system.methodHelp' : self.system_methodHelp}) - - def register_multicall_functions(self): - """Registers the XML-RPC multicall method in the system - namespace. - - see http://www.xmlrpc.com/discuss/msgReader$1208""" - - self.funcs.update({'system.multicall' : self.system_multicall}) - - def _marshaled_dispatch(self, data, dispatch_method = None): - """Dispatches an XML-RPC method from marshalled (XML) data. - - XML-RPC methods are dispatched from the marshalled (XML) data - using the _dispatch method and the result is returned as - marshalled data. For backwards compatibility, a dispatch - function can be provided as an argument (see comment in - SimpleXMLRPCRequestHandler.do_POST) but overriding the - existing method through subclassing is the prefered means - of changing method dispatch behavior. - """ - - try: - params, method = xmlrpclib.loads(data) - - # generate response - if dispatch_method is not None: - response = dispatch_method(method, params) - else: - response = self._dispatch(method, params) - # wrap response in a singleton tuple - response = (response,) - response = xmlrpclib.dumps(response, methodresponse=1, - allow_none=self.allow_none, encoding=self.encoding) - except Fault, fault: - response = xmlrpclib.dumps(fault, allow_none=self.allow_none, - encoding=self.encoding) - except: - # report exception back to server - exc_type, exc_value, exc_tb = sys.exc_info() - response = xmlrpclib.dumps( - xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)), - encoding=self.encoding, allow_none=self.allow_none, - ) - - return response - - def system_listMethods(self): - """system.listMethods() => ['add', 'subtract', 'multiple'] - - Returns a list of the methods supported by the server.""" - - methods = self.funcs.keys() - if self.instance is not None: - # Instance can implement _listMethod to return a list of - # methods - if hasattr(self.instance, '_listMethods'): - methods = remove_duplicates( - methods + self.instance._listMethods() - ) - # if the instance has a _dispatch method then we - # don't have enough information to provide a list - # of methods - elif not hasattr(self.instance, '_dispatch'): - methods = remove_duplicates( - methods + list_public_methods(self.instance) - ) - methods.sort() - return methods - - def system_methodSignature(self, method_name): - """system.methodSignature('add') => [double, int, int] - - Returns a list describing the signature of the method. In the - above example, the add method takes two integers as arguments - and returns a double result. - - This server does NOT support system.methodSignature.""" - - # See http://xmlrpc.usefulinc.com/doc/sysmethodsig.html - - return 'signatures not supported' - - def system_methodHelp(self, method_name): - """system.methodHelp('add') => "Adds two integers together" - - Returns a string containing documentation for the specified method.""" - - method = None - if method_name in self.funcs: - method = self.funcs[method_name] - elif self.instance is not None: - # Instance can implement _methodHelp to return help for a method - if hasattr(self.instance, '_methodHelp'): - return self.instance._methodHelp(method_name) - # if the instance has a _dispatch method then we - # don't have enough information to provide help - elif not hasattr(self.instance, '_dispatch'): - try: - method = resolve_dotted_attribute( - self.instance, - method_name, - self.allow_dotted_names - ) - except AttributeError: - pass - - # Note that we aren't checking that the method actually - # be a callable object of some kind - if method is None: - return "" - else: - import pydoc - return pydoc.getdoc(method) - - def system_multicall(self, call_list): - """system.multicall([{'methodName': 'add', 'params': [2, 2]}, ...]) => \ -[[4], ...] - - Allows the caller to package multiple XML-RPC calls into a single - request. - - See http://www.xmlrpc.com/discuss/msgReader$1208 - """ - - results = [] - for call in call_list: - method_name = call['methodName'] - params = call['params'] - - try: - # XXX A marshalling error in any response will fail the entire - # multicall. If someone cares they should fix this. - results.append([self._dispatch(method_name, params)]) - except Fault, fault: - results.append( - {'faultCode' : fault.faultCode, - 'faultString' : fault.faultString} - ) - except: - exc_type, exc_value, exc_tb = sys.exc_info() - results.append( - {'faultCode' : 1, - 'faultString' : "%s:%s" % (exc_type, exc_value)} - ) - return results - - def _dispatch(self, method, params): - """Dispatches the XML-RPC method. - - XML-RPC calls are forwarded to a registered function that - matches the called XML-RPC method name. If no such function - exists then the call is forwarded to the registered instance, - if available. - - If the registered instance has a _dispatch method then that - method will be called with the name of the XML-RPC method and - its parameters as a tuple - e.g. instance._dispatch('add',(2,3)) - - If the registered instance does not have a _dispatch method - then the instance will be searched to find a matching method - and, if found, will be called. - - Methods beginning with an '_' are considered private and will - not be called. - """ - - func = None - try: - # check to see if a matching function has been registered - func = self.funcs[method] - except KeyError: - if self.instance is not None: - # check for a _dispatch method - if hasattr(self.instance, '_dispatch'): - return self.instance._dispatch(method, params) - else: - # call instance method directly - try: - func = resolve_dotted_attribute( - self.instance, - method, - self.allow_dotted_names - ) - except AttributeError: - pass - - if func is not None: - return func(*params) - else: - raise Exception('method "%s" is not supported' % method) - -class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """Simple XML-RPC request handler class. - - Handles all HTTP POST requests and attempts to decode them as - XML-RPC requests. - """ - - # Class attribute listing the accessible path components; - # paths not on this list will result in a 404 error. - rpc_paths = ('/', '/RPC2') - - def is_rpc_path_valid(self): - if self.rpc_paths: - return self.path in self.rpc_paths - else: - # If .rpc_paths is empty, just assume all paths are legal - return True - - def do_POST(self): - """Handles the HTTP POST request. - - Attempts to interpret all HTTP POST requests as XML-RPC calls, - which are forwarded to the server's _dispatch method for handling. - """ - - # Check that the path is legal - if not self.is_rpc_path_valid(): - self.report_404() - return - - try: - # Get arguments by reading body of request. - # We read this in chunks to avoid straining - # socket.read(); around the 10 or 15Mb mark, some platforms - # begin to have problems (bug #792570). - max_chunk_size = 10*1024*1024 - size_remaining = int(self.headers["content-length"]) - L = [] - while size_remaining: - chunk_size = min(size_remaining, max_chunk_size) - L.append(self.rfile.read(chunk_size)) - size_remaining -= len(L[-1]) - data = ''.join(L) - - # In previous versions of SimpleXMLRPCServer, _dispatch - # could be overridden in this class, instead of in - # SimpleXMLRPCDispatcher. To maintain backwards compatibility, - # check to see if a subclass implements _dispatch and dispatch - # using that method if present. - response = self.server._marshaled_dispatch( - data, getattr(self, '_dispatch', None) - ) - except Exception, e: # This should only happen if the module is buggy - # internal error, report as HTTP server error - self.send_response(500) - - # Send information about the exception if requested - if hasattr(self.server, '_send_traceback_header') and \ - self.server._send_traceback_header: - self.send_header("X-exception", str(e)) - self.send_header("X-traceback", traceback.format_exc()) - - self.end_headers() - else: - # got a valid XML RPC response - self.send_response(200) - self.send_header("Content-type", "text/xml") - self.send_header("Content-length", str(len(response))) - self.end_headers() - self.wfile.write(response) - - # shut down the connection - self.wfile.flush() - self.connection.shutdown(1) - - def report_404 (self): - # Report a 404 error - self.send_response(404) - response = 'No such page' - self.send_header("Content-type", "text/plain") - self.send_header("Content-length", str(len(response))) - self.end_headers() - self.wfile.write(response) - # shut down the connection - self.wfile.flush() - self.connection.shutdown(1) - - def log_request(self, code='-', size='-'): - """Selectively log an accepted request.""" - - if self.server.logRequests: - BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size) - -class SimpleXMLRPCServer(SocketServer.TCPServer, - SimpleXMLRPCDispatcher): - """Simple XML-RPC server. - - Simple XML-RPC server that allows functions and a single instance - to be installed to handle requests. The default implementation - attempts to dispatch XML-RPC calls to the functions or instance - installed in the server. Override the _dispatch method inhereted - from SimpleXMLRPCDispatcher to change this behavior. - """ - - allow_reuse_address = True - - # Warning: this is for debugging purposes only! Never set this to True in - # production code, as will be sending out sensitive information (exception - # and stack trace details) when exceptions are raised inside - # SimpleXMLRPCRequestHandler.do_POST - _send_traceback_header = False - - def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler, - logRequests=True, allow_none=False, encoding=None, bind_and_activate=True): - self.logRequests = logRequests - - SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) - SocketServer.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) - - # [Bug #1222790] If possible, set close-on-exec flag; if a - # method spawns a subprocess, the subprocess shouldn't have - # the listening socket open. - if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'): - flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) - flags |= fcntl.FD_CLOEXEC - fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags) - -class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher): - """Simple handler for XML-RPC data passed through CGI.""" - - def __init__(self, allow_none=False, encoding=None): - SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) - - def handle_xmlrpc(self, request_text): - """Handle a single XML-RPC request""" - - response = self._marshaled_dispatch(request_text) - - print 'Content-Type: text/xml' - print 'Content-Length: %d' % len(response) - print - sys.stdout.write(response) - - def handle_get(self): - """Handle a single HTTP GET request. - - Default implementation indicates an error because - XML-RPC uses the POST method. - """ - - code = 400 - message, explain = \ - BaseHTTPServer.BaseHTTPRequestHandler.responses[code] - - response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % \ - { - 'code' : code, - 'message' : message, - 'explain' : explain - } - print 'Status: %d %s' % (code, message) - print 'Content-Type: text/html' - print 'Content-Length: %d' % len(response) - print - sys.stdout.write(response) - - def handle_request(self, request_text = None): - """Handle a single XML-RPC request passed through a CGI post method. - - If no XML data is given then it is read from stdin. The resulting - XML-RPC response is printed to stdout along with the correct HTTP - headers. - """ - - if request_text is None and \ - os.environ.get('REQUEST_METHOD', None) == 'GET': - self.handle_get() - else: - # POST data is normally available through stdin - if request_text is None: - request_text = sys.stdin.read() - - self.handle_xmlrpc(request_text) - -if __name__ == '__main__': - print 'Running XML-RPC server on port 8000' - server = SimpleXMLRPCServer(("localhost", 8000)) - server.register_function(pow) - server.register_function(lambda x,y: x+y, 'add') - server.serve_forever() diff --git a/python25-compat/SocketServer.py b/python25-compat/SocketServer.py deleted file mode 100644 index 2c41fbb6dc0..00000000000 --- a/python25-compat/SocketServer.py +++ /dev/null @@ -1,681 +0,0 @@ -"""Generic socket server classes. - -This module tries to capture the various aspects of defining a server: - -For socket-based servers: - -- address family: - - AF_INET{,6}: IP (Internet Protocol) sockets (default) - - AF_UNIX: Unix domain sockets - - others, e.g. AF_DECNET are conceivable (see -- socket type: - - SOCK_STREAM (reliable stream, e.g. TCP) - - SOCK_DGRAM (datagrams, e.g. UDP) - -For request-based servers (including socket-based): - -- client address verification before further looking at the request - (This is actually a hook for any processing that needs to look - at the request before anything else, e.g. logging) -- how to handle multiple requests: - - synchronous (one request is handled at a time) - - forking (each request is handled by a new process) - - threading (each request is handled by a new thread) - -The classes in this module favor the server type that is simplest to -write: a synchronous TCP/IP server. This is bad class design, but -save some typing. (There's also the issue that a deep class hierarchy -slows down method lookups.) - -There are five classes in an inheritance diagram, four of which represent -synchronous servers of four types: - - +------------+ - | BaseServer | - +------------+ - | - v - +-----------+ +------------------+ - | TCPServer |------->| UnixStreamServer | - +-----------+ +------------------+ - | - v - +-----------+ +--------------------+ - | UDPServer |------->| UnixDatagramServer | - +-----------+ +--------------------+ - -Note that UnixDatagramServer derives from UDPServer, not from -UnixStreamServer -- the only difference between an IP and a Unix -stream server is the address family, which is simply repeated in both -unix server classes. - -Forking and threading versions of each type of server can be created -using the ForkingMixIn and ThreadingMixIn mix-in classes. For -instance, a threading UDP server class is created as follows: - - class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass - -The Mix-in class must come first, since it overrides a method defined -in UDPServer! Setting the various member variables also changes -the behavior of the underlying server mechanism. - -To implement a service, you must derive a class from -BaseRequestHandler and redefine its handle() method. You can then run -various versions of the service by combining one of the server classes -with your request handler class. - -The request handler class must be different for datagram or stream -services. This can be hidden by using the request handler -subclasses StreamRequestHandler or DatagramRequestHandler. - -Of course, you still have to use your head! - -For instance, it makes no sense to use a forking server if the service -contains state in memory that can be modified by requests (since the -modifications in the child process would never reach the initial state -kept in the parent process and passed to each child). In this case, -you can use a threading server, but you will probably have to use -locks to avoid two requests that come in nearly simultaneous to apply -conflicting changes to the server state. - -On the other hand, if you are building e.g. an HTTP server, where all -data is stored externally (e.g. in the file system), a synchronous -class will essentially render the service "deaf" while one request is -being handled -- which may be for a very long time if a client is slow -to reqd all the data it has requested. Here a threading or forking -server is appropriate. - -In some cases, it may be appropriate to process part of a request -synchronously, but to finish processing in a forked child depending on -the request data. This can be implemented by using a synchronous -server and doing an explicit fork in the request handler class -handle() method. - -Another approach to handling multiple simultaneous requests in an -environment that supports neither threads nor fork (or where these are -too expensive or inappropriate for the service) is to maintain an -explicit table of partially finished requests and to use select() to -decide which request to work on next (or whether to handle a new -incoming request). This is particularly important for stream services -where each client can potentially be connected for a long time (if -threads or subprocesses cannot be used). - -Future work: -- Standard classes for Sun RPC (which uses either UDP or TCP) -- Standard mix-in classes to implement various authentication - and encryption schemes -- Standard framework for select-based multiplexing - -XXX Open problems: -- What to do with out-of-band data? - -BaseServer: -- split generic "request" functionality out into BaseServer class. - Copyright (C) 2000 Luke Kenneth Casson Leighton - - example: read entries from a SQL database (requires overriding - get_request() to return a table entry from the database). - entry is processed by a RequestHandlerClass. - -""" - -# Author of the BaseServer patch: Luke Kenneth Casson Leighton - -# XXX Warning! -# There is a test suite for this module, but it cannot be run by the -# standard regression test. -# To run it manually, run Lib/test/test_socketserver.py. - -__version__ = "0.4" - - -import socket -import select -import sys -import os -try: - import threading -except ImportError: - import dummy_threading as threading - -__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", - "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", - "StreamRequestHandler","DatagramRequestHandler", - "ThreadingMixIn", "ForkingMixIn"] -if hasattr(socket, "AF_UNIX"): - __all__.extend(["UnixStreamServer","UnixDatagramServer", - "ThreadingUnixStreamServer", - "ThreadingUnixDatagramServer"]) - -class BaseServer: - - """Base class for server classes. - - Methods for the caller: - - - __init__(server_address, RequestHandlerClass) - - serve_forever(poll_interval=0.5) - - shutdown() - - handle_request() # if you do not use serve_forever() - - fileno() -> int # for select() - - Methods that may be overridden: - - - server_bind() - - server_activate() - - get_request() -> request, client_address - - handle_timeout() - - verify_request(request, client_address) - - server_close() - - process_request(request, client_address) - - close_request(request) - - handle_error() - - Methods for derived classes: - - - finish_request(request, client_address) - - Class variables that may be overridden by derived classes or - instances: - - - timeout - - address_family - - socket_type - - allow_reuse_address - - Instance variables: - - - RequestHandlerClass - - socket - - """ - - timeout = None - - def __init__(self, server_address, RequestHandlerClass): - """Constructor. May be extended, do not override.""" - self.server_address = server_address - self.RequestHandlerClass = RequestHandlerClass - self.__is_shut_down = threading.Event() - self.__serving = False - - def server_activate(self): - """Called by constructor to activate the server. - - May be overridden. - - """ - pass - - def serve_forever(self, poll_interval=0.5): - """Handle one request at a time until shutdown. - - Polls for shutdown every poll_interval seconds. Ignores - self.timeout. If you need to do periodic tasks, do them in - another thread. - """ - self.__serving = True - self.__is_shut_down.clear() - while self.__serving: - # XXX: Consider using another file descriptor or - # connecting to the socket to wake this up instead of - # polling. Polling reduces our responsiveness to a - # shutdown request and wastes cpu at all other times. - r, w, e = select.select([self], [], [], poll_interval) - if r: - self._handle_request_noblock() - self.__is_shut_down.set() - - def shutdown(self): - """Stops the serve_forever loop. - - Blocks until the loop has finished. This must be called while - serve_forever() is running in another thread, or it will - deadlock. - """ - self.__serving = False - self.__is_shut_down.wait() - - # The distinction between handling, getting, processing and - # finishing a request is fairly arbitrary. Remember: - # - # - handle_request() is the top-level call. It calls - # select, get_request(), verify_request() and process_request() - # - get_request() is different for stream or datagram sockets - # - process_request() is the place that may fork a new process - # or create a new thread to finish the request - # - finish_request() instantiates the request handler class; - # this constructor will handle the request all by itself - - def handle_request(self): - """Handle one request, possibly blocking. - - Respects self.timeout. - """ - # Support people who used socket.settimeout() to escape - # handle_request before self.timeout was available. - timeout = self.socket.gettimeout() - if timeout is None: - timeout = self.timeout - elif self.timeout is not None: - timeout = min(timeout, self.timeout) - fd_sets = select.select([self], [], [], timeout) - if not fd_sets[0]: - self.handle_timeout() - return - self._handle_request_noblock() - - def _handle_request_noblock(self): - """Handle one request, without blocking. - - I assume that select.select has returned that the socket is - readable before this function was called, so there should be - no risk of blocking in get_request(). - """ - try: - request, client_address = self.get_request() - except socket.error: - return - if self.verify_request(request, client_address): - try: - self.process_request(request, client_address) - except: - self.handle_error(request, client_address) - self.close_request(request) - - def handle_timeout(self): - """Called if no new request arrives within self.timeout. - - Overridden by ForkingMixIn. - """ - pass - - def verify_request(self, request, client_address): - """Verify the request. May be overridden. - - Return True if we should proceed with this request. - - """ - return True - - def process_request(self, request, client_address): - """Call finish_request. - - Overridden by ForkingMixIn and ThreadingMixIn. - - """ - self.finish_request(request, client_address) - self.close_request(request) - - def server_close(self): - """Called to clean-up the server. - - May be overridden. - - """ - pass - - def finish_request(self, request, client_address): - """Finish one request by instantiating RequestHandlerClass.""" - self.RequestHandlerClass(request, client_address, self) - - def close_request(self, request): - """Called to clean up an individual request.""" - pass - - def handle_error(self, request, client_address): - """Handle an error gracefully. May be overridden. - - The default is to print a traceback and continue. - - """ - print '-'*40 - print 'Exception happened during processing of request from', - print client_address - import traceback - traceback.print_exc() # XXX But this goes to stderr! - print '-'*40 - - -class TCPServer(BaseServer): - - """Base class for various socket-based server classes. - - Defaults to synchronous IP stream (i.e., TCP). - - Methods for the caller: - - - __init__(server_address, RequestHandlerClass, bind_and_activate=True) - - serve_forever(poll_interval=0.5) - - shutdown() - - handle_request() # if you don't use serve_forever() - - fileno() -> int # for select() - - Methods that may be overridden: - - - server_bind() - - server_activate() - - get_request() -> request, client_address - - handle_timeout() - - verify_request(request, client_address) - - process_request(request, client_address) - - close_request(request) - - handle_error() - - Methods for derived classes: - - - finish_request(request, client_address) - - Class variables that may be overridden by derived classes or - instances: - - - timeout - - address_family - - socket_type - - request_queue_size (only for stream sockets) - - allow_reuse_address - - Instance variables: - - - server_address - - RequestHandlerClass - - socket - - """ - - address_family = socket.AF_INET - - socket_type = socket.SOCK_STREAM - - request_queue_size = 5 - - allow_reuse_address = False - - def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): - """Constructor. May be extended, do not override.""" - BaseServer.__init__(self, server_address, RequestHandlerClass) - self.socket = socket.socket(self.address_family, - self.socket_type) - if bind_and_activate: - self.server_bind() - self.server_activate() - - def server_bind(self): - """Called by constructor to bind the socket. - - May be overridden. - - """ - if self.allow_reuse_address: - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.bind(self.server_address) - self.server_address = self.socket.getsockname() - - def server_activate(self): - """Called by constructor to activate the server. - - May be overridden. - - """ - self.socket.listen(self.request_queue_size) - - def server_close(self): - """Called to clean-up the server. - - May be overridden. - - """ - self.socket.close() - - def fileno(self): - """Return socket file number. - - Interface required by select(). - - """ - return self.socket.fileno() - - def get_request(self): - """Get the request and client address from the socket. - - May be overridden. - - """ - return self.socket.accept() - - def close_request(self, request): - """Called to clean up an individual request.""" - request.close() - - -class UDPServer(TCPServer): - - """UDP server class.""" - - allow_reuse_address = False - - socket_type = socket.SOCK_DGRAM - - max_packet_size = 8192 - - def get_request(self): - data, client_addr = self.socket.recvfrom(self.max_packet_size) - return (data, self.socket), client_addr - - def server_activate(self): - # No need to call listen() for UDP. - pass - - def close_request(self, request): - # No need to close anything. - pass - -class ForkingMixIn: - - """Mix-in class to handle each request in a new process.""" - - timeout = 300 - active_children = None - max_children = 40 - - def collect_children(self): - """Internal routine to wait for children that have exited.""" - if self.active_children is None: return - while len(self.active_children) >= self.max_children: - # XXX: This will wait for any child process, not just ones - # spawned by this library. This could confuse other - # libraries that expect to be able to wait for their own - # children. - try: - pid, status = os.waitpid(0, options=0) - except os.error: - pid = None - if pid not in self.active_children: continue - self.active_children.remove(pid) - - # XXX: This loop runs more system calls than it ought - # to. There should be a way to put the active_children into a - # process group and then use os.waitpid(-pgid) to wait for any - # of that set, but I couldn't find a way to allocate pgids - # that couldn't collide. - for child in self.active_children: - try: - pid, status = os.waitpid(child, os.WNOHANG) - except os.error: - pid = None - if not pid: continue - try: - self.active_children.remove(pid) - except ValueError, e: - raise ValueError('%s. x=%d and list=%r' % (e.message, pid, - self.active_children)) - - def handle_timeout(self): - """Wait for zombies after self.timeout seconds of inactivity. - - May be extended, do not override. - """ - self.collect_children() - - def process_request(self, request, client_address): - """Fork a new subprocess to process the request.""" - self.collect_children() - pid = os.fork() - if pid: - # Parent process - if self.active_children is None: - self.active_children = [] - self.active_children.append(pid) - self.close_request(request) - return - else: - # Child process. - # This must never return, hence os._exit()! - try: - self.finish_request(request, client_address) - os._exit(0) - except: - try: - self.handle_error(request, client_address) - finally: - os._exit(1) - - -class ThreadingMixIn: - """Mix-in class to handle each request in a new thread.""" - - # Decides how threads will act upon termination of the - # main process - daemon_threads = False - - def process_request_thread(self, request, client_address): - """Same as in BaseServer but as a thread. - - In addition, exception handling is done here. - - """ - try: - self.finish_request(request, client_address) - self.close_request(request) - except: - self.handle_error(request, client_address) - self.close_request(request) - - def process_request(self, request, client_address): - """Start a new thread to process the request.""" - t = threading.Thread(target = self.process_request_thread, - args = (request, client_address)) - if self.daemon_threads: - t.setDaemon (1) - t.start() - - -class ForkingUDPServer(ForkingMixIn, UDPServer): pass -class ForkingTCPServer(ForkingMixIn, TCPServer): pass - -class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass -class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass - -if hasattr(socket, 'AF_UNIX'): - - class UnixStreamServer(TCPServer): - address_family = socket.AF_UNIX - - class UnixDatagramServer(UDPServer): - address_family = socket.AF_UNIX - - class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass - - class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass - -class BaseRequestHandler: - - """Base class for request handler classes. - - This class is instantiated for each request to be handled. The - constructor sets the instance variables request, client_address - and server, and then calls the handle() method. To implement a - specific service, all you need to do is to derive a class which - defines a handle() method. - - The handle() method can find the request as self.request, the - client address as self.client_address, and the server (in case it - needs access to per-server information) as self.server. Since a - separate instance is created for each request, the handle() method - can define arbitrary other instance variariables. - - """ - - def __init__(self, request, client_address, server): - self.request = request - self.client_address = client_address - self.server = server - try: - self.setup() - self.handle() - self.finish() - finally: - sys.exc_traceback = None # Help garbage collection - - def setup(self): - pass - - def handle(self): - pass - - def finish(self): - pass - - -# The following two classes make it possible to use the same service -# class for stream or datagram servers. -# Each class sets up these instance variables: -# - rfile: a file object from which receives the request is read -# - wfile: a file object to which the reply is written -# When the handle() method returns, wfile is flushed properly - - -class StreamRequestHandler(BaseRequestHandler): - - """Define self.rfile and self.wfile for stream sockets.""" - - # Default buffer sizes for rfile, wfile. - # We default rfile to buffered because otherwise it could be - # really slow for large data (a getc() call per byte); we make - # wfile unbuffered because (a) often after a write() we want to - # read and we need to flush the line; (b) big writes to unbuffered - # files are typically optimized by stdio even when big reads - # aren't. - rbufsize = -1 - wbufsize = 0 - - def setup(self): - self.connection = self.request - self.rfile = self.connection.makefile('rb', self.rbufsize) - self.wfile = self.connection.makefile('wb', self.wbufsize) - - def finish(self): - if not self.wfile.closed: - self.wfile.flush() - self.wfile.close() - self.rfile.close() - - -class DatagramRequestHandler(BaseRequestHandler): - - # XXX Regrettably, I cannot get this working on Linux; - # s.recvfrom() doesn't return a meaningful client address. - - """Define self.rfile and self.wfile for datagram sockets.""" - - def setup(self): - try: - from cStringIO import StringIO - except ImportError: - from StringIO import StringIO - self.packet, self.socket = self.request - self.rfile = StringIO(self.packet) - self.wfile = StringIO() - - def finish(self): - self.socket.sendto(self.wfile.getvalue(), self.client_address) diff --git a/setup.README b/setup.README deleted file mode 100644 index 5ee564ecfb4..00000000000 --- a/setup.README +++ /dev/null @@ -1,27 +0,0 @@ -Some instructions to use setup.py for a user-install. -This file should/will be moved on a proper documentation place later. - -- Possibly clean any left-over of the previous build. - > rm -rf dist openerp_server.egg-info - -- Possibly copy the addons in the server if we want them to be packaged - together: - > rsync -av --delete \ - --exclude .bzr/ \ - --exclude .bzrignore \ - --exclude /__init__.py \ - --exclude /base \ - --exclude /base_quality_interrogation.py \ - openerp/addons - -- Create the user-local directory where we want the package to be installed: - > mkdir -p /home/openerp/openerp-tmp/lib/python2.6/site-packages/ - -- Use --prefix to specify where the package is installed and include that - place in PYTHONPATH: - > PYTHONPATH=/home/openerp/openerp-tmp/lib/python2.6/site-packages/ \ - python setup.py install --prefix=/home/openerp/openerp-tmp - -- Run the main script, again specifying the PYTHONPATH: - > PYTHONPATH=/home/openerp/openerp-tmp/lib/python2.6/site-packages/ \ - /home/openerp/openerp-tmp/bin/openerp-server diff --git a/setup.cfg b/setup.cfg index 483eb2f22e1..2f64223e455 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,4 +17,4 @@ requires=python >= 2.5 # Need to overwrite the install-part of the RPM to patch # the filenames of the man pages. -install_script=rpminstall_sh.txt +install_script=setup_rpm.sh diff --git a/setup.py b/setup.py index 58424dbad12..9595c1a9257 100755 --- a/setup.py +++ b/setup.py @@ -20,57 +20,12 @@ # ############################################################################## -# setup from TinERP -# taken from straw http://www.nongnu.org/straw/index.html -# taken from gnomolicious http://www.nongnu.org/gnomolicious/ -# adapted by Nicolas Évrard -# -# doc/migrate is not included since about 6.1-dev -# doc/tests is not included -# python25-compat/*py should be in the openerp (and imported appropriately) - -import sys -import os +import glob, os, re, setuptools, sys from os.path import join, isfile -import glob -from setuptools import setup, find_packages - -# Backports os.walk with followlinks from python 2.6. -# Needed to add all addons files to data_files for Windows packaging. -def walk_followlinks(top, topdown=True, onerror=None, followlinks=False): - from os.path import join, isdir, islink - from os import listdir, error - - try: - names = listdir(top) - except error, err: - if onerror is not None: - onerror(err) - return - - dirs, nondirs = [], [] - for name in names: - if isdir(join(top, name)): - dirs.append(name) - else: - nondirs.append(name) - - if topdown: - yield top, dirs, nondirs - for name in dirs: - path = join(top, name) - if followlinks or not islink(path): - for x in walk_followlinks(path, topdown, onerror, followlinks): - yield x - if not topdown: - yield top, dirs, nondirs - -if sys.version_info < (2, 6): - os.walk = walk_followlinks +execfile(join('openerp', 'release.py')) py2exe_keywords = {} -py2exe_data_files = [] if os.name == 'nt': import py2exe py2exe_keywords['console'] = [ @@ -94,37 +49,30 @@ if os.name == 'nt': "excludes" : ["Tkconstants","Tkinter","tcl"], } } - # TODO is it still necessary now that we don't use the library.zip file? - def data_files(): - '''For Windows, we consider all the addons as data files. - It seems also that package_data below isn't honored by py2exe.''' - files = [] - os.chdir('openerp') - for (dp, dn, names) in os.walk('addons'): - files.append((join('openerp',dp), map(lambda x: join('openerp', dp, x), names))) - os.chdir('..') - files.append(('openerp', [join('openerp', 'import_xml.rng'),])) - # copy pytz/timzeone - # TODO check if we have to also copy dateutil's timezone data. - import pytz - # Make sure the layout of pytz hasn't changed - assert (pytz.__file__.endswith('__init__.pyc') or - pytz.__file__.endswith('__init__.py')), pytz.__file__ - pytz_dir = os.path.dirname(pytz.__file__) +# List all data files +def data(): + files = [] + for root, dirnames, filenames in os.walk('openerp'): + for filename in filenames: + if not re.match(r'.*(\.pyc|\.pyo|\~)$',filename): + files.append(os.path.join(root, filename)) + d = {} + for v in files: + k=os.path.dirname(v) + if k in d: + d[k].append(v) + else: + d[k]=[v] + r = d.items() + return r - saved_dir = os.getcwd() - os.chdir(pytz_dir) - for dp, dn, names in os.walk('zoneinfo'): - files.append((join('pytz',dp), map(lambda x: join(pytz_dir, dp, x), names))) - os.chdir(saved_dir) +def gen_manifest(): + file_list="\n".join(data()) + open('MANIFEST','w').write(file_list) - return files - py2exe_data_files = data_files() - -execfile(join('openerp', 'release.py')) - -setup(name = name, +setuptools.setup( + name = name, version = version, description = description, long_description = long_desc, @@ -133,18 +81,10 @@ setup(name = name, author_email = author_email, classifiers = filter(None, classifiers.split("\n")), license = license, - data_files = [ - (join('man', 'man1'), ['man/openerp-server.1']), - (join('man', 'man5'), ['man/openerp_serverrc.5']), - ('doc', filter(isfile, glob.glob('doc/*'))), - ] + py2exe_data_files, scripts = ['openerp-server'], - packages = find_packages(), - include_package_data = True, - package_data = { - '': ['*.yml', '*.xml', '*.po', '*.pot', '*.csv'], - }, - dependency_links = ['http://download.gna.org/pychart/'], + data_files = data(), + packages = setuptools.find_packages(), + #include_package_data = True, install_requires = [ # We require the same version as caldav for lxml. 'lxml==2.1.5', @@ -156,6 +96,7 @@ setup(name = name, # It is probably safe to move to PyChart 1.39 (the latest one). # (Let setup.py choose the latest one, and we should check we can remove pychart from # our tree.) + # http://download.gna.org/pychart/ 'pychart', 'pydot', 'pytz', diff --git a/rpminstall_sh.txt b/setup_rpm.sh similarity index 100% rename from rpminstall_sh.txt rename to setup_rpm.sh diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000000..396284efaf7 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import test_xmlrpc diff --git a/tests/test_xmlrpc.py b/tests/test_xmlrpc.py new file mode 100644 index 00000000000..30af863f12d --- /dev/null +++ b/tests/test_xmlrpc.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# Run with one of these commands: +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_xmlrpc.py +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy nosetests tests/test_xmlrpc.py +# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_xmlrpc +import os +import time +import unittest2 +import xmlrpclib + +import openerp + +ADDONS_PATH = os.environ['OPENERP_ADDONS_PATH'] +PORT = int(os.environ['OPENERP_PORT']) +DB = os.environ['OPENERP_DATABASE'] + +HOST = '127.0.0.1' + +ADMIN_USER = 'admin' +ADMIN_USER_ID = 1 +ADMIN_PASSWORD = 'admin' + +common_proxy_60 = None +db_proxy_60 = None +object_proxy_60 = None + +def setUpModule(): + """ + Start the OpenERP server similary to the openerp-server script and + setup some xmlrpclib proxies. + """ + openerp.tools.config['addons_path'] = ADDONS_PATH + openerp.tools.config['xmlrpc_port'] = PORT + openerp.service.start_services() + + global common_proxy_60 + global db_proxy_60 + global object_proxy_60 + + # Use the old (pre 6.1) API. + url = 'http://%s:%d/xmlrpc/' % (HOST, PORT) + common_proxy_60 = xmlrpclib.ServerProxy(url + 'common') + db_proxy_60 = xmlrpclib.ServerProxy(url + 'db') + object_proxy_60 = xmlrpclib.ServerProxy(url + 'object') + +def tearDownModule(): + """ Shutdown the OpenERP server similarly to a single ctrl-c. """ + openerp.service.stop_services() + +class test_xmlrpc(unittest2.TestCase): + + def test_xmlrpc_create_database_polling(self): + """ + Simulate a OpenERP client requesting the creation of a database and + polling the server until the creation is complete. + """ + progress_id = db_proxy_60.create(ADMIN_PASSWORD, DB, True, False, + ADMIN_PASSWORD) + while True: + time.sleep(1) + progress, users = db_proxy_60.get_progress(ADMIN_PASSWORD, + progress_id) + if progress == 1.0: + break + + def test_xmlrpc_login(self): + """ Try to login on the common service. """ + uid = common_proxy_60.login(DB, ADMIN_USER, ADMIN_PASSWORD) + assert uid == ADMIN_USER_ID + + def test_xmlrpc_ir_model_search(self): + """ Try a search on the object service. """ + ids = object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, + 'ir.model', 'search', []) + assert ids + ids = object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, + 'ir.model', 'search', [], {}) + assert ids + +if __name__ == '__main__': + unittest2.main() +