diff --git a/bin/openerp-server.py b/bin/openerp-server.py deleted file mode 100755 index c61a22858c0..00000000000 --- a/bin/openerp-server.py +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/bin/env python -# -*- coding: UTF-8 -*- - -import os -import sys - -if __name__ == "__main__": - print '-' * 70 - print "DEPRECATED: you are starting the OpenERP server with its old path," - print "please use the new executable (available in the parent directory)." - print '-' * 70 - - # Change to the parent directory ... - os.chdir(os.path.normpath(os.path.dirname(__file__))) - os.chdir('..') - # ... and execute the new executable. - os.execv('openerp-server', sys.argv) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/debian/control b/debian/control index 7a1bfb62bb8..acd4a72c44b 100644 --- a/debian/control +++ b/debian/control @@ -23,6 +23,7 @@ Depends: python-libxslt1, python-lxml, python-mako, + python-mock, python-openid, python-psutil, python-psycopg2, @@ -33,6 +34,7 @@ Depends: python-reportlab, python-simplejson, python-tz, + python-unittest2, python-vatnumber, python-vobject, python-webdav, diff --git a/openerp/__init__.py b/openerp/__init__.py index c874a22c0e2..c9db7076e71 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -40,7 +40,6 @@ import service import sql_db import test import tools -import wizard import workflow # backward compatilbility # TODO: This is for the web addons, can be removed later. diff --git a/openerp/addons/base/i18n/es.po b/openerp/addons/base/i18n/es.po index 4f7618db5c8..19b3e20976f 100644 --- a/openerp/addons/base/i18n/es.po +++ b/openerp/addons/base/i18n/es.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-12-05 20:42+0000\n" -"Last-Translator: Santi (Pexego) \n" +"PO-Revision-Date: 2012-12-09 23:26+0000\n" +"Last-Translator: lambdasoftware \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: 2012-12-06 04:39+0000\n" +"X-Launchpad-Export-Date: 2012-12-10 04:36+0000\n" "X-Generator: Launchpad (build 16341)\n" #. module: base @@ -541,7 +541,7 @@ msgstr "Nombre de relación" #. module: base #: view:ir.rule:0 msgid "Create Access Right" -msgstr "" +msgstr "Otorge derecho de acceso" #. module: base #: model:res.country,name:base.tv @@ -581,7 +581,7 @@ msgstr "" #. module: base #: view:workflow.transition:0 msgid "Workflow Transition" -msgstr "" +msgstr "Transición del flujo de trabajo" #. module: base #: model:res.country,name:base.gf @@ -704,7 +704,7 @@ msgstr "Colombia" #. module: base #: model:res.partner.title,name:base.res_partner_title_mister msgid "Mister" -msgstr "" +msgstr "Señor" #. module: base #: help:res.country,code:0 @@ -733,7 +733,7 @@ msgstr "Sin traducir" #. module: base #: view:ir.mail_server:0 msgid "Outgoing Mail Server" -msgstr "" +msgstr "Servidor de correo saliente" #. module: base #: help:ir.actions.act_window,context:0 @@ -927,7 +927,7 @@ msgstr "Sueco / svenska" #: field:base.language.export,name:0 #: field:ir.attachment,datas_fname:0 msgid "File Name" -msgstr "" +msgstr "Nombre del archivo" #. module: base #: model:res.country,name:base.rs @@ -1024,7 +1024,7 @@ msgstr "Preferencias de email" #: code:addons/base/ir/ir_fields.py:196 #, python-format msgid "'%s' does not seem to be a valid date for field '%%(field)s'" -msgstr "" +msgstr "'%s' no parece ser una fecha valida para el campo '%%(field)s'" #. module: base #: view:res.partner:0 @@ -1156,7 +1156,7 @@ msgstr "Usuarios google" #. module: base #: model:ir.module.module,shortdesc:base.module_fleet msgid "Fleet Management" -msgstr "" +msgstr "Gestión de flotas" #. module: base #: help:ir.server.object.lines,value:0 @@ -2721,7 +2721,7 @@ msgstr "Nombre de acceso rápido" #. module: base #: field:res.partner,contact_address:0 msgid "Complete Address" -msgstr "" +msgstr "Dirección completa" #. module: base #: help:ir.actions.act_window,limit:0 @@ -2793,7 +2793,7 @@ msgstr "ID de registro" #. module: base #: view:ir.filters:0 msgid "My Filters" -msgstr "" +msgstr "Mis filtros" #. module: base #: field:ir.actions.server,email:0 @@ -2879,7 +2879,7 @@ msgstr "Responsable" #: code:addons/base/ir/ir_model.py:718 #, python-format msgid "Sorry, you are not allowed to access this document." -msgstr "" +msgstr "Lo siento, no está autorizado para acceder a este documento." #. module: base #: model:res.country,name:base.py @@ -2894,7 +2894,7 @@ msgstr "Fiji" #. module: base #: view:ir.actions.report.xml:0 msgid "Report Xml" -msgstr "" +msgstr "Informe Xml" #. module: base #: model:ir.module.module,description:base.module_purchase @@ -2965,7 +2965,7 @@ msgstr "Hededado" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "yes" -msgstr "" +msgstr "Sí" #. module: base #: field:ir.model.fields,serialization_field_id:0 @@ -3056,7 +3056,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_web_linkedin msgid "LinkedIn Integration" -msgstr "" +msgstr "Integración con LinkedIn" #. module: base #: code:addons/orm.py:2021 @@ -3370,7 +3370,7 @@ msgstr "Calendario" #. module: base #: model:ir.module.category,name:base.module_category_knowledge_management msgid "Knowledge" -msgstr "" +msgstr "Conocimiento" #. module: base #: field:workflow.activity,signal_send:0 @@ -3535,7 +3535,7 @@ msgstr "workflow.actividad" #. module: base #: view:base.language.export:0 msgid "Export Complete" -msgstr "" +msgstr "Exportación completada" #. module: base #: help:ir.ui.view_sc,res_id:0 @@ -3564,7 +3564,7 @@ msgstr "Finlandés / Suomi" #. module: base #: view:ir.config_parameter:0 msgid "System Properties" -msgstr "" +msgstr "Propiedades de sistema" #. module: base #: field:ir.sequence,prefix:0 @@ -3621,7 +3621,7 @@ msgstr "" #. module: base #: field:base.language.export,modules:0 msgid "Modules To Export" -msgstr "" +msgstr "Módulos a exportar" #. module: base #: model:res.country,name:base.mt @@ -3724,7 +3724,7 @@ msgstr "Antártida" #. module: base #: view:res.partner:0 msgid "Persons" -msgstr "" +msgstr "Personas" #. module: base #: view:base.language.import:0 @@ -3903,7 +3903,7 @@ msgstr "Tayiko / اردو" #: code:addons/orm.py:3870 #, python-format msgid "Access Denied" -msgstr "" +msgstr "Acceso denegado" #. module: base #: field:res.company,name:0 @@ -3996,7 +3996,7 @@ msgstr "%x - Representación apropiada de fecha." #. module: base #: view:res.partner:0 msgid "Tag" -msgstr "" +msgstr "Etiqueta" #. module: base #: view:res.lang:0 @@ -4048,7 +4048,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sk msgid "Slovakia" -msgstr "" +msgstr "Eslovaquia" #. module: base #: model:res.country,name:base.nr @@ -4599,7 +4599,7 @@ msgstr "" #. module: base #: field:ir.module.module,latest_version:0 msgid "Installed Version" -msgstr "" +msgstr "Versión instalada" #. module: base #: field:ir.module.module,license:0 @@ -4895,7 +4895,7 @@ msgstr "Flujos" #. module: base #: model:ir.ui.menu,name:base.next_id_73 msgid "Purchase" -msgstr "" +msgstr "Compra" #. module: base #: selection:base.language.install,lang:0 @@ -5054,7 +5054,7 @@ msgstr "Establecer a NULL" #. module: base #: view:res.users:0 msgid "Save" -msgstr "" +msgstr "Guardar" #. module: base #: field:ir.actions.report.xml,report_xml:0 @@ -5248,7 +5248,7 @@ msgstr "Tasas" #. module: base #: model:ir.module.module,shortdesc:base.module_email_template msgid "Email Templates" -msgstr "" +msgstr "Plantillas de correo electrónico" #. module: base #: model:res.country,name:base.sy @@ -5397,7 +5397,7 @@ msgstr "" #. module: base #: view:ir.rule:0 msgid "Write Access Right" -msgstr "" +msgstr "Permiso de escritura" #. module: base #: model:ir.actions.act_window,help:base.action_res_groups @@ -5432,7 +5432,7 @@ msgstr "Historial" #. module: base #: model:res.country,name:base.im msgid "Isle of Man" -msgstr "" +msgstr "Isla de Man" #. module: base #: help:ir.actions.client,res_model:0 @@ -6109,7 +6109,7 @@ msgstr "Nombre del recurso" #. module: base #: field:res.partner,is_company:0 msgid "Is a Company" -msgstr "" +msgstr "¿Es una empresa?" #. module: base #: selection:ir.cron,interval_type:0 @@ -6189,7 +6189,7 @@ msgstr "" #. module: base #: sql_constraint:ir.filters:0 msgid "Filter names must be unique" -msgstr "" +msgstr "Los nombres de filtro deben ser únicos" #. module: base #: help:multi_company.default,object_id:0 @@ -6204,7 +6204,7 @@ msgstr "" #. module: base #: field:ir.filters,is_default:0 msgid "Default filter" -msgstr "" +msgstr "Filtro por defecto" #. module: base #: report:ir.module.reference:0 @@ -6932,7 +6932,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_auth_anonymous msgid "Anonymous" -msgstr "" +msgstr "Anónimo" #. module: base #: model:ir.module.module,description:base.module_base_import @@ -7439,7 +7439,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_14 msgid "Manufacturer" -msgstr "" +msgstr "Fabricante" #. module: base #: help:res.users,company_id:0 @@ -8055,7 +8055,7 @@ msgstr "Francés (CH) / Français (CH)" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 msgid "Distributor" -msgstr "" +msgstr "Distribuidor" #. module: base #: help:ir.actions.server,subject:0 @@ -15511,7 +15511,7 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Internal Notes" -msgstr "" +msgstr "Notas internas" #. module: base #: selection:res.partner.address,type:0 @@ -15553,7 +15553,7 @@ msgstr "Empresas: " #. module: base #: view:res.partner:0 msgid "Is a Company?" -msgstr "" +msgstr "¿Es una empresa?" #. module: base #: code:addons/base/res/res_company.py:159 @@ -15575,7 +15575,7 @@ msgstr "Crear objeto" #. module: base #: model:res.country,name:base.ss msgid "South Sudan" -msgstr "" +msgstr "Sudán del Sur" #. module: base #: field:ir.filters,context:0 diff --git a/openerp/addons/base/i18n/es_DO.po b/openerp/addons/base/i18n/es_DO.po index 73c03ec05ae..8855ee6a517 100644 --- a/openerp/addons/base/i18n/es_DO.po +++ b/openerp/addons/base/i18n/es_DO.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-12-06 20:42+0000\n" +"PO-Revision-Date: 2012-12-07 15:49+0000\n" "Last-Translator: Carlos Matos Villar \n" "Language-Team: Spanish (Dominican Republic) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-12-07 04:34+0000\n" +"X-Launchpad-Export-Date: 2012-12-08 04:58+0000\n" "X-Generator: Launchpad (build 16341)\n" #. module: base @@ -9141,7 +9141,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "2. %a ,%A ==> Fri, Friday" -msgstr "" +msgstr "2. %a ,%A ==> Vie, Viernes" #. module: base #: code:addons/base/ir/ir_translation.py:341 @@ -9150,6 +9150,8 @@ msgid "" "Translation features are unavailable until you install an extra OpenERP " "translation." msgstr "" +"Las Características de Traducción no están disponibles hasta que usted " +"instala una traducción extra en OpenERP." #. module: base #: model:ir.module.module,description:base.module_l10n_nl @@ -9193,16 +9195,56 @@ msgid "" "\n" " " msgstr "" +"\n" +"Este es el modulo para gestionar el plan de cuenta para Neerlandés en " +"OpenERP.\n" +"=============================================================================" +"=======\n" +"\n" +"Lea los cambios en el archivo __openerp__.py para la versión de " +"información.\n" +"Read changelog in file __openerp__.py for version information.\n" +"Dit is een basismodule om een uitgebreid grootboek- en BTW schema voor\n" +"Nederlandse bedrijven te installeren in OpenERP versie 7.0.\n" +"\n" +"De BTW rekeningen zijn waar nodig gekoppeld om de juiste rapportage te " +"genereren,\n" +"denk b.v. aan intracommunautaire verwervingen waarbij u 21% BTW moet " +"opvoeren,\n" +"maar tegelijkertijd ook 21% als voorheffing weer mag aftrekken.\n" +"\n" +"Na installatie van deze module word de configuratie wizard voor 'Accounting' " +"aangeroepen.\n" +"* U krijgt een lijst met grootboektemplates aangeboden waarin zich ook het\n" +"Nederlandse grootboekschema bevind.\n" +"\n" +"* Als de configuratie wizard start, wordt u gevraagd om de naam van uw " +"bedrijf\n" +"in te voeren, welke grootboekschema te installeren, uit hoeveel cijfers een\n" +"grootboekrekening mag bestaan, het rekeningnummer van uw bank en de " +"currency\n" +"om Journalen te creeren.\n" +"\n" +"Let op!! -> De template van het Nederlandse rekeningschema is opgebouwd uit " +"4\n" +"cijfers. Dit is het minimale aantal welk u moet invullen, u mag het aantal " +"verhogen.\n" +"De extra cijfers worden dan achter het rekeningnummer aangevult met " +"'nullen'.\n" +"\n" +" " #. module: base #: help:ir.rule,global:0 msgid "If no group is specified the rule is global and applied to everyone" msgstr "" +"Si no se especifica ningún grupo, la regla es global y se aplica a todo el " +"mundo." #. module: base #: model:res.country,name:base.td msgid "Chad" -msgstr "" +msgstr "Chad" #. module: base #: help:ir.cron,priority:0 @@ -9210,31 +9252,33 @@ msgid "" "The priority of the job, as an integer: 0 means higher priority, 10 means " "lower priority." msgstr "" +"Prioridad del trabajo, expresada con un entero: 0 significa la máxima " +"prioridad, 10 significa la prioridad más baja." #. module: base #: model:ir.model,name:base.model_workflow_transition msgid "workflow.transition" -msgstr "" +msgstr "workflow.transition" #. module: base #: view:res.lang:0 msgid "%a - Abbreviated weekday name." -msgstr "" +msgstr "%a - Nombre abreviado del día de la semana." #. module: base #: view:ir.ui.menu:0 msgid "Submenus" -msgstr "" +msgstr "Submenús" #. module: base #: report:ir.module.reference:0 msgid "Introspection report on objects" -msgstr "" +msgstr "Introspección informe sobre los objetos" #. module: base #: model:ir.module.module,shortdesc:base.module_web_analytics msgid "Google Analytics" -msgstr "" +msgstr "Google Analytics" #. module: base #: model:ir.module.module,description:base.module_note @@ -9257,83 +9301,84 @@ msgstr "" #. module: base #: model:res.country,name:base.dm msgid "Dominica" -msgstr "" +msgstr "Dominica" #. module: base #: field:ir.translation,name:0 msgid "Translated field" -msgstr "" +msgstr "Campos Traducidos" #. module: base #: model:ir.module.module,shortdesc:base.module_stock_location msgid "Advanced Routes" -msgstr "" +msgstr "Rutas avanzadas" #. module: base #: model:ir.module.module,shortdesc:base.module_pad msgid "Collaborative Pads" -msgstr "" +msgstr "Pads colaborativos" #. module: base #: model:res.country,name:base.np msgid "Nepal" -msgstr "" +msgstr "Nepal" #. module: base #: model:ir.module.module,shortdesc:base.module_document_page msgid "Document Page" -msgstr "" +msgstr "Página de Documentos" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_ar msgid "Argentina Localization Chart Account" -msgstr "" +msgstr "Plan de Cuenta Localización Argentina" #. module: base #: field:ir.module.module,description_html:0 msgid "Description HTML" -msgstr "" +msgstr "HTML de Descripción" #. module: base #: help:res.groups,implied_ids:0 msgid "Users of this group automatically inherit those groups" msgstr "" +"Los usuarios de este grupo automaticamente heredan de aquellos grupos" #. module: base #: model:ir.module.module,summary:base.module_note msgid "Sticky notes, Collaborative, Memos" -msgstr "" +msgstr "Notas adesivas, Colaborativas, Memos" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_attendance #: model:res.groups,name:base.group_hr_attendance msgid "Attendances" -msgstr "" +msgstr "Asistencias" #. module: base #: model:ir.module.module,shortdesc:base.module_warning msgid "Warning Messages and Alerts" -msgstr "" +msgstr "Mensajes de aviso y alertas" #. module: base #: model:ir.actions.act_window,name:base.action_ui_view_custom #: model:ir.ui.menu,name:base.menu_action_ui_view_custom #: view:ir.ui.view.custom:0 msgid "Customized Views" -msgstr "" +msgstr "Vistas personalizadas" #. module: base #: view:base.module.import:0 #: model:ir.actions.act_window,name:base.action_view_base_module_import msgid "Module Import" -msgstr "" +msgstr "Importación de módulo" #. module: base #: model:ir.actions.act_window,name:base.act_values_form_action #: model:ir.ui.menu,name:base.menu_values_form_action #: view:ir.values:0 msgid "Action Bindings" -msgstr "" +msgstr "Enlaces de acciones" #. module: base #: help:res.partner,lang:0 @@ -9341,6 +9386,9 @@ msgid "" "If the selected language is loaded in the system, all documents related to " "this contact will be printed in this language. If not, it will be English." msgstr "" +"Si el lenguaje seleccionado esta cargado en el sistema, todos los documentos " +"relacionados a este contacto serán impresos en este lenguaje. Si no, este " +"será Ingles." #. module: base #: model:ir.module.module,description:base.module_hr_evaluation @@ -9378,7 +9426,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_view_base_module_update msgid "Update Modules List" -msgstr "" +msgstr "Actualizar lista de módulos" #. module: base #: code:addons/base/module/module.py:338 @@ -9386,11 +9434,13 @@ msgstr "" msgid "" "Unable to upgrade module \"%s\" because an external dependency is not met: %s" msgstr "" +"Imposible actualizar el módulo \"%s\" porqué hay una dependencia externa no " +"resuelta: %s" #. module: base #: model:ir.module.module,shortdesc:base.module_account msgid "eInvoicing" -msgstr "" +msgstr "Facturación electrónica" #. module: base #: code:addons/base/res/res_users.py:175 @@ -9401,37 +9451,41 @@ msgid "" "sure to save and close all forms before switching to a different company. " "(You can click on Cancel in the User Preferences now)" msgstr "" +"Tenga en cuenta que los documentos que se muestran actualmente pueden no ser " +"relevantes después de cambiar a otra compañía. Asegúrese de guardar y cerrar " +"todas los formularios modificados antes de cambiar a una compañía diferente " +"(ahora puede hacer clic en Cancelar en las preferencias del usuario)" #. module: base #: code:addons/orm.py:2821 #, python-format msgid "The value \"%s\" for the field \"%s.%s\" is not in the selection" -msgstr "" +msgstr "El valor \"%s\" para el campo \"%s.%s\" no está en la selección" #. module: base #: view:ir.actions.configuration.wizard:0 msgid "Continue" -msgstr "" +msgstr "Siguiente" #. module: base #: selection:base.language.install,lang:0 msgid "Thai / ภาษาไทย" -msgstr "" +msgstr "Tailandés / ภาษาไทย" #. module: base #: view:res.lang:0 msgid "%j - Day of the year [001,366]." -msgstr "" +msgstr "%j - Día del año [001,366]." #. module: base #: selection:base.language.install,lang:0 msgid "Slovenian / slovenščina" -msgstr "" +msgstr "Esloveno / slovenščina" #. module: base #: field:res.currency,position:0 msgid "Symbol Position" -msgstr "" +msgstr "Posición de Simbolo" #. module: base #: model:ir.module.module,description:base.module_l10n_de @@ -9445,16 +9499,20 @@ msgid "" "German accounting chart and localization.\n" " " msgstr "" +"\n" +"Plan de cuentas y localización alemana.\n" +"===============================\n" +" " #. module: base #: field:ir.actions.report.xml,attachment_use:0 msgid "Reload from Attachment" -msgstr "" +msgstr "Recargar desde adjunto" #. module: base #: model:res.country,name:base.mx msgid "Mexico" -msgstr "" +msgstr "México" #. module: base #: code:addons/orm.py:3871 @@ -9465,11 +9523,15 @@ msgid "" "\n" "(Document type: %s)" msgstr "" +"Para este tipo de documentos, usted solo puede acceder a archivos que usted " +"mismo creó.\n" +"\n" +"(Tipo de Documento: %s)" #. module: base #: view:base.language.export:0 msgid "documentation" -msgstr "" +msgstr "documentación" #. module: base #: help:ir.model,osv_memory:0 @@ -9477,62 +9539,64 @@ msgid "" "This field specifies whether the model is transient or not (i.e. if records " "are automatically deleted from the database or not)" msgstr "" +"Este campo especifica si el modelo es trascendente o no (Ejemplo: Si los " +"archivos son automáticamente eliminados desde la base de datos o no)" #. module: base #: code:addons/base/ir/ir_mail_server.py:441 #, python-format msgid "Missing SMTP Server" -msgstr "" +msgstr "Servidor SMTP ausente" #. module: base #: field:ir.attachment,name:0 msgid "Attachment Name" -msgstr "" +msgstr "Nombre del adjunto" #. module: base #: field:base.language.export,data:0 #: field:base.language.import,data:0 msgid "File" -msgstr "" +msgstr "Archivo" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_install msgid "Module Upgrade Install" -msgstr "" +msgstr "Instalar actualizar módulo" #. module: base #: model:ir.model,name:base.model_ir_actions_configuration_wizard msgid "ir.actions.configuration.wizard" -msgstr "" +msgstr "ir.actions.configuration.wizard" #. module: base #: view:res.lang:0 msgid "%b - Abbreviated month name." -msgstr "" +msgstr "%b - Nombre abreviado del mes." #. module: base #: code:addons/base/ir/ir_model.py:721 #, python-format msgid "Sorry, you are not allowed to delete this document." -msgstr "" +msgstr "Lo sentimos, usted no tiene permitod eliminar este documento." #. module: base #: constraint:ir.rule:0 msgid "Rules can not be applied on the Record Rules model." -msgstr "" +msgstr "Las reglas no pueden ser aplicadas en el archivo modelo de reglas." #. module: base #: field:res.partner,supplier:0 #: field:res.partner.address,is_supplier_add:0 #: model:res.partner.category,name:base.res_partner_category_1 msgid "Supplier" -msgstr "" +msgstr "Proveedor" #. module: base #: view:ir.actions.server:0 #: selection:ir.actions.server,state:0 msgid "Multi Actions" -msgstr "" +msgstr "Multi acciones" #. module: base #: model:ir.module.module,summary:base.module_mail @@ -9559,91 +9623,109 @@ msgid "" "* Show all costs associated to a vehicle or to a type of service\n" "* Analysis graph for costs\n" msgstr "" +"\n" +"Vehículo, Alquiler, seguros, costos\n" +"================================\n" +"Con este modulo, OpenERP les ayuda a administrar todos sus vehículos, \n" +"los contratos asociados a esos vehículos así como el servicio, log de\n" +"entradas de combustible, costos y algunas otras características necesarias " +"para la gestión \n" +"de sus fletes de vehículo(s)\n" +"\n" +"Características Principales\n" +"------------------\n" +"*Agrega vehículos a sus fletes\n" +"*Gestiona contratos para vehículos\n" +"*Recordatorios cuando un contrato alcanza su fecha de expiración\n" +"*Agregar servicios, entradas de log de combustible, valores de cuenta " +"kilómetros para todos los vehículos\n" +"*Muestra todo el costo asociado a un vehículo o a un tipo de servicio\n" +"*Análisis gráficos para costos\n" #. module: base #: field:multi_company.default,company_dest_id:0 msgid "Default Company" -msgstr "" +msgstr "Compañía por defecto" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (EC) / Español (EC)" -msgstr "" +msgstr "Español (EC) / Español (EC)" #. module: base #: help:ir.ui.view,xml_id:0 msgid "ID of the view defined in xml file" -msgstr "" +msgstr "El ID de la vista definido en el archivo xml." #. module: base #: model:ir.model,name:base.model_base_module_import msgid "Import Module" -msgstr "" +msgstr "Importar módulo" #. module: base #: model:res.country,name:base.as msgid "American Samoa" -msgstr "" +msgstr "Samoa Americana" #. module: base #: view:ir.attachment:0 msgid "My Document(s)" -msgstr "" +msgstr "Mis Documentos" #. module: base #: help:ir.actions.act_window,res_model:0 msgid "Model name of the object to open in the view window" -msgstr "" +msgstr "Nombre del modelo del objeto a abrir en la ventana de la vista." #. module: base #: field:ir.model.fields,selectable:0 msgid "Selectable" -msgstr "" +msgstr "Seleccionable" #. module: base #: code:addons/base/ir/ir_mail_server.py:220 #, python-format msgid "Everything seems properly set up!" -msgstr "" +msgstr "¡Todo parece correctamente configurado!" #. module: base #: view:res.request.link:0 msgid "Request Link" -msgstr "" +msgstr "Solicitar enlace" #. module: base #: view:ir.attachment:0 #: selection:ir.attachment,type:0 #: field:ir.module.module,url:0 msgid "URL" -msgstr "" +msgstr "URL" #. module: base #: help:res.country,name:0 msgid "The full name of the country." -msgstr "" +msgstr "El nombre completo del país." #. module: base #: selection:ir.actions.server,state:0 msgid "Iteration" -msgstr "" +msgstr "Iteración" #. module: base #: code:addons/orm.py:4213 #: code:addons/orm.py:4314 #, python-format msgid "UserError" -msgstr "" +msgstr "Error de usuario" #. module: base #: model:ir.module.module,summary:base.module_project_issue msgid "Support, Bug Tracker, Helpdesk" -msgstr "" +msgstr "Soporte, Rastreador de Bug, Ayudante de Escritorio" #. module: base #: model:res.country,name:base.ae msgid "United Arab Emirates" -msgstr "" +msgstr "Emiratos Árabes Unidos" #. module: base #: help:ir.ui.menu,needaction_enabled:0 @@ -9659,21 +9741,23 @@ msgstr "" msgid "" "Unable to delete this document because it is used as a default property" msgstr "" +"No se ha podido eliminar este documento ya que se utiliza como una propiedad " +"por defecto" #. module: base #: model:res.partner.category,name:base.res_partner_category_5 msgid "Silver" -msgstr "" +msgstr "Plateado" #. module: base #: field:res.partner.title,shortcut:0 msgid "Abbreviation" -msgstr "" +msgstr "Abreviación" #. module: base #: model:ir.ui.menu,name:base.menu_crm_case_job_req_main msgid "Recruitment" -msgstr "" +msgstr "Proceso de selección" #. module: base #: model:ir.module.module,description:base.module_l10n_gr @@ -9685,11 +9769,17 @@ msgid "" "Greek accounting chart and localization.\n" " " msgstr "" +"\n" +"Módulo para administrar el plan de cuentas para Grecia.\n" +"============================================\n" +"\n" +"Plan de cuentas y localización griego.\n" +" " #. module: base #: view:ir.values:0 msgid "Action Reference" -msgstr "" +msgstr "Referencia de la acción" #. module: base #: model:ir.module.module,description:base.module_auth_ldap diff --git a/openerp/addons/base/i18n/hr.po b/openerp/addons/base/i18n/hr.po index 908dc21eed1..ef10cfa1019 100644 --- a/openerp/addons/base/i18n/hr.po +++ b/openerp/addons/base/i18n/hr.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: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-11-24 21:10+0000\n" +"PO-Revision-Date: 2012-12-09 19:36+0000\n" "Last-Translator: Goran Kliska \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-12-04 04:59+0000\n" -"X-Generator: Launchpad (build 16335)\n" +"X-Launchpad-Export-Date: 2012-12-10 04:36+0000\n" +"X-Generator: Launchpad (build 16341)\n" "Language: hr\n" #. module: base @@ -532,7 +532,7 @@ msgstr "Naziv relacije" #. module: base #: view:ir.rule:0 msgid "Create Access Right" -msgstr "" +msgstr "Kreiraj pravo pristupa" #. module: base #: model:res.country,name:base.tv @@ -582,7 +582,7 @@ msgstr "Francuska Guyana" #. module: base #: model:ir.module.module,summary:base.module_hr msgid "Jobs, Departments, Employees Details" -msgstr "" +msgstr "Radna mjesta, odjeli, podaci o radnicima" #. module: base #: model:ir.module.module,description:base.module_analytic @@ -695,7 +695,7 @@ msgstr "Kolumbija" #. module: base #: model:res.partner.title,name:base.res_partner_title_mister msgid "Mister" -msgstr "" +msgstr "Gospodin" #. module: base #: help:res.country,code:0 @@ -828,6 +828,11 @@ msgid "" "This module provides the Integration of the LinkedIn with OpenERP.\n" " " msgstr "" +"\n" +"OpenERP Web LinkedIn modul.\n" +"============================\n" +"Integracija LinkedIn-a sa OpenERP-om.\n" +" " #. module: base #: help:ir.actions.act_window,src_model:0 @@ -1132,7 +1137,7 @@ msgstr "Google korisnici" #. module: base #: model:ir.module.module,shortdesc:base.module_fleet msgid "Fleet Management" -msgstr "" +msgstr "Upravljanje flotom (automobili)" #. module: base #: help:ir.server.object.lines,value:0 @@ -1234,7 +1239,7 @@ msgstr "Zadnja verzija" #. module: base #: view:ir.rule:0 msgid "Delete Access Right" -msgstr "" +msgstr "Prava brisanja" #. module: base #: code:addons/base/ir/ir_mail_server.py:213 @@ -1304,7 +1309,7 @@ msgstr "Vidljivo" #. module: base #: model:ir.actions.client,name:base.action_client_base_menu msgid "Open Settings Menu" -msgstr "" +msgstr "Otvori izbornik postavki" #. module: base #: selection:base.language.install,lang:0 @@ -1427,7 +1432,7 @@ msgstr "Haiti" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_fr_hr_payroll msgid "French Payroll" -msgstr "" +msgstr "Francuska plaća" #. module: base #: view:ir.ui.view:0 @@ -2571,7 +2576,7 @@ msgstr "Grčka / Ελληνικά" #. module: base #: field:res.company,custom_footer:0 msgid "Custom Footer" -msgstr "" +msgstr "Prilagođeno podnožje" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_crm @@ -2879,7 +2884,7 @@ msgstr "Naslijeđeno" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "yes" -msgstr "" +msgstr "da" #. module: base #: field:ir.model.fields,serialization_field_id:0 @@ -14826,7 +14831,7 @@ msgstr "" #. module: base #: field:ir.sequence,implementation:0 msgid "Implementation" -msgstr "" +msgstr "Implementacija" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_ve @@ -14931,7 +14936,7 @@ msgstr "Ažuriranje sustava" #: field:ir.actions.report.xml,report_sxw_content:0 #: field:ir.actions.report.xml,report_sxw_content_data:0 msgid "SXW Content" -msgstr "" +msgstr "SXW Sadržaj" #. module: base #: help:ir.sequence,prefix:0 @@ -14946,7 +14951,7 @@ msgstr "Sejšeli" #. module: base #: model:res.partner.category,name:base.res_partner_category_4 msgid "Gold" -msgstr "" +msgstr "Zlatni" #. module: base #: code:addons/base/res/res_company.py:159 @@ -14973,7 +14978,7 @@ msgstr "Opći podaci" #. module: base #: field:ir.model.data,complete_name:0 msgid "Complete ID" -msgstr "" +msgstr "Puni ID" #. module: base #: model:res.country,name:base.tc @@ -14985,7 +14990,7 @@ msgstr "Turks and Caicos Islands" msgid "" "Tax Identification Number. Check the box if this contact is subjected to " "taxes. Used by the some of the legal statements." -msgstr "" +msgstr "Porezni broj (OIB) ." #. module: base #: field:res.partner.bank,partner_id:0 @@ -15070,7 +15075,7 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Internal Notes" -msgstr "" +msgstr "Interne bilješke" #. module: base #: selection:res.partner.address,type:0 @@ -15086,7 +15091,7 @@ msgstr "Corp." #. module: base #: model:ir.module.module,shortdesc:base.module_purchase_requisition msgid "Purchase Requisitions" -msgstr "" +msgstr "Natječaji u nabavi" #. module: base #: selection:ir.actions.act_window,target:0 @@ -15112,7 +15117,7 @@ msgstr "Partneri: " #. module: base #: view:res.partner:0 msgid "Is a Company?" -msgstr "" +msgstr "Je tvrtka=" #. module: base #: code:addons/base/res/res_company.py:159 @@ -15134,7 +15139,7 @@ msgstr "Kreiraj objekt" #. module: base #: model:res.country,name:base.ss msgid "South Sudan" -msgstr "" +msgstr "Južni Sudan" #. module: base #: field:ir.filters,context:0 diff --git a/openerp/addons/base/i18n/it.po b/openerp/addons/base/i18n/it.po index 2ff4d0bb006..b7b9d50b453 100644 --- a/openerp/addons/base/i18n/it.po +++ b/openerp/addons/base/i18n/it.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: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-12-01 13:29+0000\n" -"Last-Translator: Sergio Corato \n" +"PO-Revision-Date: 2012-12-09 12:05+0000\n" +"Last-Translator: Davide Corio - agilebg.com \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: 2012-12-04 04:57+0000\n" -"X-Generator: Launchpad (build 16335)\n" +"X-Launchpad-Export-Date: 2012-12-10 04:36+0000\n" +"X-Generator: Launchpad (build 16341)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -92,7 +92,7 @@ msgstr "" #. module: base #: model:ir.module.module,summary:base.module_point_of_sale msgid "Touchscreen Interface for Shops" -msgstr "Interfaccia Touchscreen per Negozzi" +msgstr "Interfaccia Touchscreen per Negozi" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll @@ -140,6 +140,9 @@ msgid "" "The module adds google user in res user.\n" "========================================\n" msgstr "" +"\n" +"Aggiunge lo username Google a res.user.\n" +"========================================\n" #. module: base #: help:res.partner,employee:0 @@ -322,7 +325,7 @@ msgstr "Gestione Vendite" msgid "" "The internal user that is in charge of communicating with this contact if " "any." -msgstr "" +msgstr "L'utente responsabile delle comunicazioni con questo contatto." #. module: base #: view:res.partner:0 diff --git a/openerp/addons/base/i18n/pt.po b/openerp/addons/base/i18n/pt.po index cc2a07de61f..1ee4820f500 100644 --- a/openerp/addons/base/i18n/pt.po +++ b/openerp/addons/base/i18n/pt.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-12-04 13:10+0000\n" +"PO-Revision-Date: 2012-12-07 10:59+0000\n" "Last-Translator: Rui Franco (multibase.pt) \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: 2012-12-05 05:18+0000\n" -"X-Generator: Launchpad (build 16335)\n" +"X-Launchpad-Export-Date: 2012-12-08 04:58+0000\n" +"X-Generator: Launchpad (build 16341)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -268,7 +268,7 @@ msgstr "Criado" #. module: base #: field:ir.actions.report.xml,report_xsl:0 msgid "XSL Path" -msgstr "" +msgstr "Caminho do XSL" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_tr @@ -570,7 +570,7 @@ msgstr "" #. module: base #: view:workflow.transition:0 msgid "Workflow Transition" -msgstr "" +msgstr "Transição do fluxo de trabalho" #. module: base #: model:res.country,name:base.gf @@ -580,7 +580,7 @@ msgstr "Guiana Francesa" #. module: base #: model:ir.module.module,summary:base.module_hr msgid "Jobs, Departments, Employees Details" -msgstr "" +msgstr "Funções, departamentos, informações sobre os empregados" #. module: base #: model:ir.module.module,description:base.module_analytic @@ -872,7 +872,7 @@ msgstr "Roménia - Contabilidade" #. module: base #: model:ir.model,name:base.model_res_config_settings msgid "res.config.settings" -msgstr "" +msgstr "res.config.settings" #. module: base #: help:res.partner,image_small:0 @@ -1271,7 +1271,7 @@ msgstr "Ilhas Caimão" #. module: base #: view:ir.rule:0 msgid "Record Rule" -msgstr "" +msgstr "Regra de gravação" #. module: base #: model:res.country,name:base.kr @@ -1314,7 +1314,7 @@ msgstr "Visível" #. module: base #: model:ir.actions.client,name:base.action_client_base_menu msgid "Open Settings Menu" -msgstr "" +msgstr "Abrir o menu de configuração" #. module: base #: selection:base.language.install,lang:0 @@ -1616,7 +1616,7 @@ msgstr "%Y - ." #. module: base #: view:res.company:0 msgid "Report Footer Configuration" -msgstr "" +msgstr "Configuração do rodapé de relatório" #. module: base #: field:ir.translation,comments:0 @@ -1775,7 +1775,7 @@ msgstr "" #. module: base #: field:res.partner,image_small:0 msgid "Small-sized image" -msgstr "" +msgstr "Imagem pequena" #. module: base #: model:ir.module.module,shortdesc:base.module_stock @@ -1897,7 +1897,7 @@ msgstr "" #. module: base #: selection:ir.translation,state:0 msgid "Translation in Progress" -msgstr "" +msgstr "Tradução em progresso" #. module: base #: model:ir.model,name:base.model_ir_rule @@ -1912,7 +1912,7 @@ msgstr "Dias" #. module: base #: model:ir.module.module,summary:base.module_fleet msgid "Vehicle, leasing, insurances, costs" -msgstr "" +msgstr "Veículo, 'leasing', seguros, custos" #. module: base #: view:ir.model.access:0 @@ -1999,7 +1999,7 @@ msgstr "Criar tarefas no SO" #: code:addons/base/ir/ir_model.py:316 #, python-format msgid "This column contains module data and cannot be removed!" -msgstr "" +msgstr "Esta coluna contém dados do módulo e não pode ser removida!" #. module: base #: field:ir.attachment,res_model:0 @@ -2744,7 +2744,7 @@ msgstr "ID do Registo" #. module: base #: view:ir.filters:0 msgid "My Filters" -msgstr "" +msgstr "Os meus filtros" #. module: base #: field:ir.actions.server,email:0 @@ -2797,7 +2797,7 @@ msgstr "Argumentos enviados ao cliente junto com a tag vista" #. module: base #: model:ir.module.module,summary:base.module_contacts msgid "Contacts, People and Companies" -msgstr "" +msgstr "Contactos, pessoas e empresas" #. module: base #: model:res.country,name:base.tt @@ -2830,7 +2830,7 @@ msgstr "Gestor" #: code:addons/base/ir/ir_model.py:718 #, python-format msgid "Sorry, you are not allowed to access this document." -msgstr "" +msgstr "Infelizmente, não está autorizado a aceder a este documento." #. module: base #: model:res.country,name:base.py @@ -2845,7 +2845,7 @@ msgstr "Fiji" #. module: base #: view:ir.actions.report.xml:0 msgid "Report Xml" -msgstr "" +msgstr "XML de Relatório" #. module: base #: model:ir.module.module,description:base.module_purchase @@ -2916,7 +2916,7 @@ msgstr "Herdado" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "yes" -msgstr "" +msgstr "sim" #. module: base #: field:ir.model.fields,serialization_field_id:0 @@ -3007,7 +3007,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_web_linkedin msgid "LinkedIn Integration" -msgstr "" +msgstr "Integração com o LinkedIn" #. module: base #: code:addons/orm.py:2021 @@ -3252,7 +3252,7 @@ msgstr "Suécia" #. module: base #: field:ir.actions.report.xml,report_file:0 msgid "Report File" -msgstr "" +msgstr "Ficheiro de relatório" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 @@ -3285,7 +3285,7 @@ msgstr "" #: code:addons/orm.py:3839 #, python-format msgid "Missing document(s)" -msgstr "" +msgstr "Documento(s) em falta" #. module: base #: model:ir.model,name:base.model_res_partner_bank_type @@ -3300,6 +3300,8 @@ msgid "" "For more details about translating OpenERP in your language, please refer to " "the" msgstr "" +"Para mais informações acerca da tradução do OpenERP para o seu idioma, por " +"favor, veja em" #. module: base #: field:res.partner,image:0 @@ -3486,7 +3488,7 @@ msgstr "workflow.activity" #. module: base #: view:base.language.export:0 msgid "Export Complete" -msgstr "" +msgstr "Exportação concluída" #. module: base #: help:ir.ui.view_sc,res_id:0 @@ -3577,6 +3579,8 @@ msgstr "Malta" msgid "" "Only users with the following access level are currently allowed to do that" msgstr "" +"Apenas utilizadores com o nível de acesso indicado de seguida estão " +"autorizados a fazer isso" #. module: base #: field:ir.actions.server,fields_lines:0 @@ -3667,7 +3671,7 @@ msgstr "Antártida" #. module: base #: view:res.partner:0 msgid "Persons" -msgstr "" +msgstr "Pessoas" #. module: base #: view:base.language.import:0 @@ -4144,7 +4148,7 @@ msgstr "Partilhar qualquer documento" #. module: base #: model:ir.module.module,summary:base.module_crm msgid "Leads, Opportunities, Phone Calls" -msgstr "" +msgstr "Dicas, oportunidades, telefonemas" #. module: base #: view:res.lang:0 @@ -4269,7 +4273,7 @@ msgstr "Campo base" #. module: base #: model:ir.module.category,name:base.module_category_managing_vehicles_and_contracts msgid "Managing vehicles and contracts" -msgstr "" +msgstr "Gestão de veículos e contratos" #. module: base #: model:ir.module.module,description:base.module_base_setup @@ -4519,7 +4523,7 @@ msgstr "Tipo de Sequência" #. module: base #: view:base.language.export:0 msgid "Unicode/UTF-8" -msgstr "" +msgstr "Unicode/UTF-8" #. module: base #: selection:base.language.install,lang:0 @@ -4531,12 +4535,12 @@ msgstr "Hindi / हिंदी" #: model:ir.actions.act_window,name:base.action_view_base_language_install #: model:ir.ui.menu,name:base.menu_view_base_language_install msgid "Load a Translation" -msgstr "" +msgstr "Carregar uma tradução" #. module: base #: field:ir.module.module,latest_version:0 msgid "Installed Version" -msgstr "" +msgstr "Versão instalada" #. module: base #: field:ir.module.module,license:0 @@ -4679,7 +4683,7 @@ msgstr "ir.actions.report.xml" #. module: base #: model:res.country,name:base.ps msgid "Palestinian Territory, Occupied" -msgstr "" +msgstr "Palestina" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_ch @@ -4836,12 +4840,12 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Portuguese (BR) / Português (BR)" -msgstr "" +msgstr "Português (BR)" #. module: base #: model:ir.model,name:base.model_ir_needaction_mixin msgid "ir.needaction_mixin" -msgstr "" +msgstr "ir.needaction_mixin" #. module: base #: view:base.language.export:0 @@ -4861,13 +4865,13 @@ msgstr "Aplicações para uma Indústria Específica" #. module: base #: model:ir.module.module,shortdesc:base.module_google_docs msgid "Google Docs integration" -msgstr "" +msgstr "Integração com o Google Docs" #. module: base #: code:addons/base/ir/ir_fields.py:328 #, python-format msgid "name" -msgstr "" +msgstr "nome" #. module: base #: model:ir.module.module,description:base.module_mrp_operations @@ -4923,7 +4927,7 @@ msgstr "Lesoto" #. module: base #: view:base.language.export:0 msgid ", or your preferred text editor" -msgstr "" +msgstr ", ou o seu editor de texto preferido" #. module: base #: model:ir.module.module,shortdesc:base.module_crm_partner_assign @@ -4990,12 +4994,12 @@ msgstr "Definir como Nulo" #. module: base #: view:res.users:0 msgid "Save" -msgstr "" +msgstr "Gravar" #. module: base #: field:ir.actions.report.xml,report_xml:0 msgid "XML Path" -msgstr "" +msgstr "Caminho do XML" #. module: base #: model:res.country,name:base.bj @@ -5077,7 +5081,7 @@ msgstr "Segurança" #. module: base #: selection:base.language.install,lang:0 msgid "Portuguese / Português" -msgstr "" +msgstr "Português" #. module: base #: code:addons/base/ir/ir_model.py:364 @@ -5168,7 +5172,7 @@ msgstr "Taxas" #. module: base #: model:ir.module.module,shortdesc:base.module_email_template msgid "Email Templates" -msgstr "" +msgstr "Modelos de mensagens" #. module: base #: model:res.country,name:base.sy @@ -5273,7 +5277,7 @@ msgstr "" #. module: base #: view:res.company:0 msgid "Preview Header/Footer" -msgstr "" +msgstr "Antevisão do Cabeçalho/Rodapé" #. module: base #: field:ir.ui.menu,parent_id:0 @@ -5311,7 +5315,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_res_partner_address msgid "res.partner.address" -msgstr "" +msgstr "res.partner.address" #. module: base #: view:ir.rule:0 @@ -5350,7 +5354,7 @@ msgstr "Histórico" #. module: base #: model:res.country,name:base.im msgid "Isle of Man" -msgstr "" +msgstr "Ilha de Man" #. module: base #: help:ir.actions.client,res_model:0 @@ -5513,7 +5517,7 @@ msgstr "" #. module: base #: model:res.groups,name:base.group_sale_salesman_all_leads msgid "See all Leads" -msgstr "" +msgstr "Ver todas as dicas" #. module: base #: model:res.country,name:base.ci @@ -5590,7 +5594,7 @@ msgstr "Configuração de precisão decimal" #: model:ir.model,name:base.model_ir_actions_act_url #: selection:ir.ui.menu,action:0 msgid "ir.actions.act_url" -msgstr "" +msgstr "ir.actions.act_ur" #. module: base #: model:ir.ui.menu,name:base.menu_translation_app @@ -5743,7 +5747,7 @@ msgstr "" #. module: base #: view:ir.translation:0 msgid "Comments" -msgstr "" +msgstr "Comentários" #. module: base #: model:res.country,name:base.et @@ -5753,7 +5757,7 @@ msgstr "Etiópia" #. module: base #: model:ir.module.category,name:base.module_category_authentication msgid "Authentication" -msgstr "" +msgstr "Autenticação" #. module: base #: model:res.country,name:base.sj @@ -5787,7 +5791,7 @@ msgstr "Título" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "true" -msgstr "" +msgstr "verdadeiro" #. module: base #: model:ir.model,name:base.model_base_language_install @@ -5797,7 +5801,7 @@ msgstr "Instalar Idioma" #. module: base #: model:res.partner.category,name:base.res_partner_category_11 msgid "Services" -msgstr "" +msgstr "Serviços" #. module: base #: view:ir.translation:0 @@ -5901,7 +5905,7 @@ msgstr "" #: code:addons/base/ir/workflow/workflow.py:99 #, python-format msgid "Operation forbidden" -msgstr "" +msgstr "Operação proibida" #. module: base #: view:ir.actions.server:0 @@ -5993,7 +5997,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_be_hr_payroll msgid "Belgium - Payroll" -msgstr "" +msgstr "Bélgica - folha de pagamentos" #. module: base #: view:workflow.activity:0 @@ -6025,7 +6029,7 @@ msgstr "Nome do Recurso" #. module: base #: field:res.partner,is_company:0 msgid "Is a Company" -msgstr "" +msgstr "É uma empresa" #. module: base #: selection:ir.cron,interval_type:0 @@ -6076,6 +6080,7 @@ msgstr "" msgid "" "Administrative divisions of a country. E.g. Fed. State, Departement, Canton" msgstr "" +"Divisões administrativas de um país. Exemplos: Distrito, Concelho, Freguesia" #. module: base #: view:res.partner.bank:0 @@ -6105,7 +6110,7 @@ msgstr "" #. module: base #: sql_constraint:ir.filters:0 msgid "Filter names must be unique" -msgstr "" +msgstr "Os nomes dos filtros devem ser únicos" #. module: base #: help:multi_company.default,object_id:0 @@ -6120,7 +6125,7 @@ msgstr "" #. module: base #: field:ir.filters,is_default:0 msgid "Default filter" -msgstr "" +msgstr "Filtro padrão" #. module: base #: report:ir.module.reference:0 @@ -6237,7 +6242,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_auth_reset_password msgid "Reset Password" -msgstr "" +msgstr "Repor a senha" #. module: base #: view:ir.attachment:0 @@ -6254,7 +6259,7 @@ msgstr "Malásia" #: code:addons/base/ir/ir_sequence.py:131 #, python-format msgid "Increment number must not be zero." -msgstr "" +msgstr "O valor de incremento não pode ser zero." #. module: base #: model:ir.module.module,shortdesc:base.module_account_cancel @@ -6454,7 +6459,7 @@ msgstr "ir.cron" #. module: base #: model:res.country,name:base.cw msgid "Curaçao" -msgstr "" +msgstr "Curaçao" #. module: base #: view:ir.sequence:0 @@ -6601,7 +6606,7 @@ msgstr "Israel" #: code:addons/base/res/res_config.py:444 #, python-format msgid "Cannot duplicate configuration!" -msgstr "" +msgstr "Não se pode duplicar a configuração!" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_syscohada @@ -6655,7 +6660,7 @@ msgstr "" #. module: base #: model:res.groups,name:base.group_partner_manager msgid "Contact Creation" -msgstr "" +msgstr "Criação de contacto" #. module: base #: view:ir.module.module:0 @@ -6711,7 +6716,7 @@ msgstr "" #. module: base #: view:ir.sequence:0 msgid "Week of the Year: %(woy)s" -msgstr "" +msgstr "Semana (do ano): %(woy)s" #. module: base #: field:res.users,id:0 @@ -6780,7 +6785,7 @@ msgstr "Títulos do Parceiro" #: code:addons/base/ir/ir_fields.py:228 #, python-format msgid "Use the format '%s'" -msgstr "" +msgstr "Use o formato '%s'" #. module: base #: help:ir.actions.act_window,auto_refresh:0 @@ -6812,12 +6817,12 @@ msgstr "WorkItems" #: code:addons/base/res/res_bank.py:195 #, python-format msgid "Invalid Bank Account Type Name format." -msgstr "" +msgstr "Formato inválido para o nome do tipo de conta bancária." #. module: base #: view:ir.filters:0 msgid "Filters visible only for one user" -msgstr "" +msgstr "Filtros visíveis só para o utilizador" #. module: base #: model:ir.model,name:base.model_ir_attachment @@ -6837,7 +6842,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_auth_anonymous msgid "Anonymous" -msgstr "" +msgstr "Anónimo" #. module: base #: model:ir.module.module,description:base.module_base_import @@ -6993,7 +6998,7 @@ msgstr "Somália" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_doctor msgid "Dr." -msgstr "" +msgstr "Dr." #. module: base #: model:res.groups,name:base.group_user @@ -7058,7 +7063,7 @@ msgstr "Copiar de" #. module: base #: field:ir.model.data,display_name:0 msgid "Record Name" -msgstr "" +msgstr "Nome do registo" #. module: base #: model:ir.model,name:base.model_ir_actions_client @@ -7074,7 +7079,7 @@ msgstr "Território Britânico do Oceano Índico" #. module: base #: model:ir.actions.server,name:base.action_server_module_immediate_install msgid "Module Immediate Install" -msgstr "" +msgstr "Instalação imediata do módulo" #. module: base #: view:ir.actions.server:0 @@ -7201,7 +7206,7 @@ msgstr "Em múltiplos docs" #: view:res.users:0 #: view:wizard.ir.model.menu.create:0 msgid "or" -msgstr "" +msgstr "ou" #. module: base #: model:ir.module.module,shortdesc:base.module_account_accountant @@ -7344,7 +7349,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_14 msgid "Manufacturer" -msgstr "" +msgstr "Fabricante" #. module: base #: help:res.users,company_id:0 @@ -7794,7 +7799,7 @@ msgstr "init" #: view:res.partner:0 #: field:res.partner,user_id:0 msgid "Salesperson" -msgstr "" +msgstr "Vendedor" #. module: base #: view:res.lang:0 @@ -7852,7 +7857,7 @@ msgstr "Password opcional para autenticação SMTP" #: code:addons/base/ir/ir_model.py:719 #, python-format msgid "Sorry, you are not allowed to modify this document." -msgstr "" +msgstr "Infelizmente, não pode alterar este documento." #. module: base #: code:addons/base/res/res_config.py:350 @@ -7942,7 +7947,7 @@ msgstr "Francês (CH) / Français (CH)" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 msgid "Distributor" -msgstr "" +msgstr "Distribuidor" #. module: base #: help:ir.actions.server,subject:0 @@ -8157,7 +8162,7 @@ msgstr "Contabilidade Analítica" #. module: base #: model:ir.model,name:base.model_ir_model_constraint msgid "ir.model.constraint" -msgstr "" +msgstr "ir.model.constraint" #. module: base #: model:ir.module.module,shortdesc:base.module_web_graph @@ -8190,7 +8195,7 @@ msgstr "Bélgica - Contabilidade" #. module: base #: view:ir.model.access:0 msgid "Access Control" -msgstr "" +msgstr "Controlo de acesso" #. module: base #: model:res.country,name:base.kw @@ -8294,7 +8299,7 @@ msgstr "Filipinas" #. module: base #: model:ir.module.module,summary:base.module_hr_timesheet_sheet msgid "Timesheets, Attendances, Activities" -msgstr "" +msgstr "Folhas de horas, assiduidade, atividades" #. module: base #: model:res.country,name:base.ma @@ -8407,7 +8412,7 @@ msgstr "Relatório de introspeção em objetos" #. module: base #: model:ir.module.module,shortdesc:base.module_web_analytics msgid "Google Analytics" -msgstr "" +msgstr "Google Analytics" #. module: base #: model:ir.module.module,description:base.module_note @@ -8435,7 +8440,7 @@ msgstr "Dominica" #. module: base #: field:ir.translation,name:0 msgid "Translated field" -msgstr "" +msgstr "Traduzir campo" #. module: base #: model:ir.module.module,shortdesc:base.module_stock_location @@ -8649,7 +8654,7 @@ msgstr "" #. module: base #: view:base.language.export:0 msgid "documentation" -msgstr "" +msgstr "documentação" #. module: base #: help:ir.model,osv_memory:0 @@ -8694,7 +8699,7 @@ msgstr "%b - Nome do mês abreviado." #: code:addons/base/ir/ir_model.py:721 #, python-format msgid "Sorry, you are not allowed to delete this document." -msgstr "" +msgstr "Infelizmente, não pode apagar este documento." #. module: base #: constraint:ir.rule:0 @@ -8768,7 +8773,7 @@ msgstr "Samoa Americana" #. module: base #: view:ir.attachment:0 msgid "My Document(s)" -msgstr "" +msgstr "Os meus documentos" #. module: base #: help:ir.actions.act_window,res_model:0 @@ -8850,7 +8855,7 @@ msgstr "" #. module: base #: field:res.partner.title,shortcut:0 msgid "Abbreviation" -msgstr "" +msgstr "Abreviatura" #. module: base #: model:ir.ui.menu,name:base.menu_crm_case_job_req_main @@ -9047,7 +9052,7 @@ msgstr "" #. module: base #: model:ir.module.category,name:base.module_category_warehouse_management msgid "Warehouse" -msgstr "" +msgstr "Armazém" #. module: base #: field:ir.exports,resource:0 @@ -9096,7 +9101,7 @@ msgstr "Relatório" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_prof msgid "Prof." -msgstr "" +msgstr "Prof." #. module: base #: code:addons/base/ir/ir_mail_server.py:239 @@ -9228,7 +9233,7 @@ msgstr "Ref. do Parceiro" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_expense msgid "Expense Management" -msgstr "" +msgstr "Gestão de despesas" #. module: base #: field:ir.attachment,create_date:0 @@ -9307,7 +9312,7 @@ msgstr "Modelos" #: code:addons/base/module/module.py:472 #, python-format msgid "The `base` module cannot be uninstalled" -msgstr "" +msgstr "O módulo \"base\" não pode ser desinstalado" #. module: base #: code:addons/base/ir/ir_cron.py:390 @@ -9334,7 +9339,7 @@ msgstr "osv_memory.autovacuum" #: code:addons/base/ir/ir_model.py:720 #, python-format msgid "Sorry, you are not allowed to create this kind of document." -msgstr "" +msgstr "Infelizmente, não pode criar este tipo de documento." #. module: base #: field:base.language.export,lang:0 @@ -9376,7 +9381,7 @@ msgstr "%H - Hora (24-horas) [00,23]." #. module: base #: field:ir.model.fields,on_delete:0 msgid "On Delete" -msgstr "" +msgstr "Ao apagar" #. module: base #: code:addons/base/ir/ir_model.py:340 @@ -9584,7 +9589,7 @@ msgstr "O código da moeda deve ser único por empresa!" #: code:addons/base/module/wizard/base_export_language.py:38 #, python-format msgid "New Language (Empty translation template)" -msgstr "" +msgstr "Novo idioma (modelo de tradução limpo)" #. module: base #: model:ir.module.module,description:base.module_auth_reset_password @@ -9654,7 +9659,7 @@ msgstr "Egipto" #. module: base #: view:ir.attachment:0 msgid "Creation" -msgstr "" +msgstr "Criação" #. module: base #: help:ir.actions.server,model_id:0 @@ -9726,7 +9731,7 @@ msgstr "" #. module: base #: field:res.partner,use_parent_address:0 msgid "Use Company Address" -msgstr "" +msgstr "Usar o endereço da empresa" #. module: base #: model:ir.module.module,summary:base.module_hr_holidays @@ -10107,7 +10112,7 @@ msgstr "Gravar Regras" #. module: base #: view:multi_company.default:0 msgid "Multi Company" -msgstr "" +msgstr "Multi-empresas" #. module: base #: model:ir.module.category,name:base.module_category_portal @@ -10118,13 +10123,13 @@ msgstr "Portal" #. module: base #: selection:ir.translation,state:0 msgid "To Translate" -msgstr "" +msgstr "Para traduzir" #. module: base #: code:addons/base/ir/ir_fields.py:295 #, python-format msgid "See all possible values" -msgstr "" +msgstr "Ver todos os valores possíveis" #. module: base #: model:ir.module.module,description:base.module_claim_from_delivery @@ -10291,7 +10296,7 @@ msgstr "Itália" #. module: base #: model:res.groups,name:base.group_sale_salesman msgid "See Own Leads" -msgstr "" +msgstr "Ver as próprias dicas" #. module: base #: view:ir.actions.todo:0 @@ -10523,7 +10528,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_stock msgid "Sales and Warehouse Management" -msgstr "" +msgstr "Gestão de vendas e de armazém" #. module: base #: field:ir.model.fields,model:0 @@ -10664,7 +10669,7 @@ msgstr "" #: code:addons/base/ir/ir_model.py:1023 #, python-format msgid "Permission Denied" -msgstr "" +msgstr "Permissão negada" #. module: base #: field:ir.ui.menu,child_id:0 @@ -10809,7 +10814,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bl msgid "Saint Barthélémy" -msgstr "" +msgstr "Saint Barthélémy" #. module: base #: selection:ir.module.module,license:0 @@ -10890,12 +10895,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_inventory_form #: model:ir.ui.menu,name:base.menu_action_inventory_form msgid "Default Company per Object" -msgstr "" +msgstr "Empresa padrão por objeto" #. module: base #: field:ir.ui.menu,needaction_counter:0 msgid "Number of actions the user has to perform" -msgstr "" +msgstr "Número de ações que o utilizador tem de realizar" #. module: base #: model:ir.module.module,shortdesc:base.module_web_hello @@ -11195,7 +11200,7 @@ msgstr "Operações de Produção" #. module: base #: view:base.language.export:0 msgid "Here is the exported translation file:" -msgstr "" +msgstr "Aqui está o ficheiro de tradução:" #. module: base #: field:ir.actions.report.xml,report_rml_content:0 @@ -11465,7 +11470,7 @@ msgstr "ir.fields.converter" #: code:addons/base/res/res_partner.py:436 #, python-format msgid "Couldn't create contact without email address !" -msgstr "" +msgstr "Não foi possível criar o contacto sem o endereço eletrónico!" #. module: base #: model:ir.module.category,name:base.module_category_manufacturing @@ -11717,7 +11722,7 @@ msgstr "UK - Contabilidade" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam msgid "Mrs." -msgstr "" +msgstr "Srª." #. module: base #: code:addons/base/ir/ir_model.py:424 @@ -11753,7 +11758,7 @@ msgstr "Repetição da Expressão" #. module: base #: model:res.partner.category,name:base.res_partner_category_16 msgid "Retailer" -msgstr "" +msgstr "Revendedor" #. module: base #: view:ir.model.fields:0 diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po index 2c18674f450..ad649948427 100644 --- a/openerp/addons/base/i18n/pt_BR.po +++ b/openerp/addons/base/i18n/pt_BR.po @@ -7,14 +7,15 @@ msgstr "" "Project-Id-Version: pt_BR\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-12-03 16:01+0000\n" -"PO-Revision-Date: 2012-12-03 09:37+0000\n" -"Last-Translator: Cristiano Korndörfer \n" +"PO-Revision-Date: 2012-12-07 22:22+0000\n" +"Last-Translator: Fábio Martinelli - http://zupy.com.br " +"\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: 2012-12-04 05:02+0000\n" -"X-Generator: Launchpad (build 16335)\n" +"X-Launchpad-Export-Date: 2012-12-08 04:58+0000\n" +"X-Generator: Launchpad (build 16341)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -3424,7 +3425,7 @@ msgstr "Armênia" #. module: base #: model:ir.module.module,summary:base.module_hr_evaluation msgid "Periodical Evaluations, Appraisals, Surveys" -msgstr "" +msgstr "Avaliações Periódicas, Pesquisas, Avaliações" #. module: base #: model:ir.actions.act_window,name:base.ir_property_form @@ -4184,7 +4185,7 @@ msgstr "%x - Representação apropriada para data." #. module: base #: view:res.partner:0 msgid "Tag" -msgstr "" +msgstr "Tag" #. module: base #: view:res.lang:0 @@ -4396,7 +4397,7 @@ msgstr "Compartilhar Qualquer Documento" #. module: base #: model:ir.module.module,summary:base.module_crm msgid "Leads, Opportunities, Phone Calls" -msgstr "" +msgstr "Prospectos, Oportunidades, Ligações Telefônicas" #. module: base #: view:res.lang:0 @@ -5119,7 +5120,7 @@ msgstr "Este arquivo foi gerado usando o universal" #. module: base #: model:res.partner.category,name:base.res_partner_category_7 msgid "IT Services" -msgstr "" +msgstr "Serviços de TI" #. module: base #: model:ir.module.category,name:base.module_category_specific_industry_applications @@ -5181,7 +5182,7 @@ msgstr "Saltar" #. module: base #: model:ir.module.module,shortdesc:base.module_event_sale msgid "Events Sales" -msgstr "" +msgstr "Venda de Eventos" #. module: base #: model:res.country,name:base.ls @@ -5191,7 +5192,7 @@ msgstr "Lesoto" #. module: base #: view:base.language.export:0 msgid ", or your preferred text editor" -msgstr "" +msgstr ", ou seu editor de texto preferido" #. module: base #: model:ir.module.module,shortdesc:base.module_crm_partner_assign @@ -5488,7 +5489,7 @@ msgstr "Data" #. module: base #: model:ir.module.module,shortdesc:base.module_event_moodle msgid "Event Moodle" -msgstr "" +msgstr "Evento Moodle" #. module: base #: model:ir.module.module,description:base.module_email_template @@ -5539,7 +5540,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_partner_category_form msgid "Partner Tags" -msgstr "" +msgstr "Tags de Parceiros" #. module: base #: view:res.company:0 @@ -5587,7 +5588,7 @@ msgstr "res.partner.address" #. module: base #: view:ir.rule:0 msgid "Write Access Right" -msgstr "" +msgstr "Permissão de Escrita" #. module: base #: model:ir.actions.act_window,help:base.action_res_groups @@ -5666,6 +5667,14 @@ msgid "" "wizard if the delivery is to be invoiced.\n" " " msgstr "" +"\n" +"Assistente de faturamento para entrega.\n" +"============================\n" +"\n" +"Quando você enviar ou entregar mercadorias, este módulo ativa " +"automaticamente o\n" +"assistente de faturamento se a entrega deve ser faturada.\n" +" " #. module: base #: selection:ir.translation,type:0 @@ -5703,6 +5712,10 @@ msgid "" "=======================\n" " " msgstr "" +"\n" +"Permitir que usuários se cadastrem.\n" +"=======================\n" +" " #. module: base #: model:res.country,name:base.zm @@ -5717,7 +5730,7 @@ msgstr "Iniciar o Assistente de Configuração" #. module: base #: model:ir.module.module,summary:base.module_mrp msgid "Manufacturing Orders, Bill of Materials, Routing" -msgstr "" +msgstr "Ordens de produção, lista de materiais, roteamento" #. module: base #: view:ir.module.module:0 @@ -6209,6 +6222,12 @@ msgid "" "Allows users to create custom dashboard.\n" " " msgstr "" +"\n" +"Permite que o usuário crie um painel personalizado.\n" +"========================================\n" +"\n" +"Permite aos usuários criar um painel personalizado.\n" +" " #. module: base #: model:ir.actions.act_window,name:base.ir_access_act @@ -6358,7 +6377,7 @@ msgstr "'%s' não parece ser um número para o campo '%% (field)s'" #: help:res.country.state,name:0 msgid "" "Administrative divisions of a country. E.g. Fed. State, Departement, Canton" -msgstr "" +msgstr "Divisões administrativas de um país. Ex: Estados, Cidades" #. module: base #: view:res.partner.bank:0 @@ -6537,7 +6556,7 @@ msgstr "Malásia" #: code:addons/base/ir/ir_sequence.py:131 #, python-format msgid "Increment number must not be zero." -msgstr "" +msgstr "Número de incremento não deve ser zero." #. module: base #: model:ir.module.module,shortdesc:base.module_account_cancel @@ -6782,6 +6801,13 @@ msgid "" "using the\n" "FTP client.\n" msgstr "" +"\n" +"Esta é uma interface FTP com sistema de gerenciamento de documentos.\n" +"================================================================\n" +"\n" +"Com este módulo você pode não apenas acessar documentos através do OpenERP\n" +"mas também conectar-se a eles através do sistema de arquivos usando um\n" +"cliente FTP.\n" #. module: base #: field:ir.model.fields,size:0 @@ -7093,7 +7119,7 @@ msgstr "Itens de trabalho" #: code:addons/base/res/res_bank.py:195 #, python-format msgid "Invalid Bank Account Type Name format." -msgstr "" +msgstr "Formato de Tipo de Conta Bancária inválido" #. module: base #: view:ir.filters:0 @@ -7841,7 +7867,7 @@ msgstr "Senha" #. module: base #: model:ir.module.module,shortdesc:base.module_portal_claim msgid "Portal Claim" -msgstr "" +msgstr "Portal de Solicitações" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_pe @@ -8356,7 +8382,7 @@ msgstr "Tipo de campos" #. module: base #: model:ir.module.module,summary:base.module_hr_recruitment msgid "Jobs, Recruitment, Applications, Job Interviews" -msgstr "" +msgstr "Empregos, Recrutamento, Candidaturas, Entrevistas de Emprego" #. module: base #: code:addons/base/module/module.py:513 @@ -8401,7 +8427,7 @@ msgstr "Aviso!" #. module: base #: view:ir.rule:0 msgid "Full Access Right" -msgstr "" +msgstr "Todos os direitos de acesso" #. module: base #: field:res.partner.category,parent_id:0 @@ -8506,7 +8532,7 @@ msgstr "Kuwait" #. module: base #: model:ir.module.module,shortdesc:base.module_account_followup msgid "Payment Follow-up Management" -msgstr "" +msgstr "Gestão de acompanhamento de pagamentos" #. module: base #: field:workflow.workitem,inst_id:0 @@ -8602,7 +8628,7 @@ msgstr "Filipinas" #. module: base #: model:ir.module.module,summary:base.module_hr_timesheet_sheet msgid "Timesheets, Attendances, Activities" -msgstr "" +msgstr "Planilhas, Atendimentos, Atividades" #. module: base #: model:res.country,name:base.ma @@ -9421,6 +9447,17 @@ msgid "" "\n" " " msgstr "" +"\n" +"Este módulo mostra os processos básicos envolvidos nos módulos selecionados " +"e na seqüência em que ocorrem.\n" +"=============================================================================" +"===================\n" +"\n" +" **Nota: ** Isso se aplica aos módulos contendo modulename_process.xml.\n" +"\n" +"**Ex: ** produto / processo / product_process.xml.\n" +"\n" +" " #. module: base #: view:res.lang:0 @@ -9482,7 +9519,7 @@ msgstr "Nenhum" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_holidays msgid "Leave Management" -msgstr "" +msgstr "Gerenciamento de Folgas" #. module: base #: model:res.company,overdue_msg:base.main_company @@ -9965,6 +10002,13 @@ msgid "" "Allow administrator to click a button to send a \"Reset Password\" request " "to a user.\n" msgstr "" +"\n" +"Trocar Senha\n" +"==============\n" +"\n" +"Permite aos usuários trocar sua senha a partir da pagina de login.\n" +"Permite ao administrador clicar no botão para requisitar ao usuário que " +"troque sua senha.\n" #. module: base #: help:ir.actions.server,email:0 @@ -10108,7 +10152,7 @@ msgstr "Usar o endereço da empresa" #. module: base #: model:ir.module.module,summary:base.module_hr_holidays msgid "Holidays, Allocation and Leave Requests" -msgstr "" +msgstr "Pedidos de Alocação de férias e licenças" #. module: base #: model:ir.module.module,description:base.module_web_hello @@ -10357,7 +10401,7 @@ msgstr "" #. module: base #: sql_constraint:ir.model.constraint:0 msgid "Constraints with the same name are unique per module." -msgstr "" +msgstr "Constraints com o mesmo nome são únicas por módulo." #. module: base #: model:ir.module.module,description:base.module_report_intrastat @@ -10402,7 +10446,7 @@ msgstr "res.request" #. module: base #: field:res.partner,image_medium:0 msgid "Medium-sized image" -msgstr "" +msgstr "Imagem de tamanho Médio" #. module: base #: view:ir.model:0 @@ -10429,7 +10473,7 @@ msgstr "Conteúdo do arquivo" #: view:ir.model.relation:0 #: model:ir.ui.menu,name:base.ir_model_relation_menu msgid "ManyToMany Relations" -msgstr "" +msgstr "Relação muitos para muitos" #. module: base #: model:res.country,name:base.pa @@ -10467,7 +10511,7 @@ msgstr "Ilhas Pitcairn" #. module: base #: field:res.partner,category_id:0 msgid "Tags" -msgstr "" +msgstr "Marcadores" #. module: base #: view:base.module.upgrade:0 @@ -10487,7 +10531,7 @@ msgstr "Registro de Regras" #. module: base #: view:multi_company.default:0 msgid "Multi Company" -msgstr "" +msgstr "Multi-Empresa" #. module: base #: model:ir.module.category,name:base.module_category_portal @@ -10498,13 +10542,13 @@ msgstr "Portal" #. module: base #: selection:ir.translation,state:0 msgid "To Translate" -msgstr "" +msgstr "Para traduzir" #. module: base #: code:addons/base/ir/ir_fields.py:295 #, python-format msgid "See all possible values" -msgstr "" +msgstr "Ver valores válidos" #. module: base #: model:ir.module.module,description:base.module_claim_from_delivery @@ -10539,7 +10583,7 @@ msgstr "" #. module: base #: help:ir.model.constraint,name:0 msgid "PostgreSQL constraint or foreign key name." -msgstr "" +msgstr "Nome da constraint PostgreSQL ou chave estrangeira(FK)" #. module: base #: view:res.lang:0 @@ -10559,12 +10603,12 @@ msgstr "Guiné Bissau" #. module: base #: field:ir.actions.report.xml,header:0 msgid "Add RML Header" -msgstr "" +msgstr "Adicionar cabeçalho RML" #. module: base #: help:res.company,rml_footer:0 msgid "Footer text displayed at the bottom of all reports." -msgstr "" +msgstr "Texto a ser mostrado no rodapé de todos os relatórios." #. module: base #: model:ir.module.module,shortdesc:base.module_note_pad @@ -10675,7 +10719,7 @@ msgstr "Itália" #. module: base #: model:res.groups,name:base.group_sale_salesman msgid "See Own Leads" -msgstr "" +msgstr "Ver seus Leads" #. module: base #: view:ir.actions.todo:0 @@ -10705,6 +10749,8 @@ msgid "" "Insufficient fields to generate a Calendar View for %s, missing a date_stop " "or a date_delay" msgstr "" +"Campos insuficiente para gerar uma visão de calendário (% s), faltando um " +"date_stop ou um date_delay" #. module: base #: field:workflow.activity,action:0 @@ -10771,6 +10817,7 @@ msgstr "ir.translation" msgid "" "Please contact your system administrator if you think this is an error." msgstr "" +"Contacte seu administrador do sistema se você acha que isto é um erro." #. module: base #: code:addons/base/module/module.py:519 @@ -10778,7 +10825,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #, python-format msgid "Apply Schedule Upgrade" -msgstr "" +msgstr "Aplicar atualizações agendas" #. module: base #: view:workflow.activity:0 @@ -10811,6 +10858,8 @@ msgid "" "One of the documents you are trying to access has been deleted, please try " "again after refreshing." msgstr "" +"Um dos documentos que você está tentando acessar foi excluído. Atualize sua " +"tela." #. module: base #: model:ir.model,name:base.model_ir_mail_server @@ -10823,6 +10872,8 @@ msgid "" "If the target model uses the need action mechanism, this field gives the " "number of actions the current user has to perform." msgstr "" +"Se o modelo de destino necessita do mecanismo de ação, este campo indica o " +"número de ações que o usuário atual tem para executar." #. module: base #: selection:base.language.install,lang:0 @@ -10919,7 +10970,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_stock msgid "Sales and Warehouse Management" -msgstr "" +msgstr "Gestão de vendas e armazens" #. module: base #: field:ir.model.fields,model:0 @@ -10965,7 +11016,7 @@ msgstr "" #. module: base #: help:res.partner,ean13:0 msgid "BarCode" -msgstr "" +msgstr "Código de barras" #. module: base #: help:ir.model.fields,model_id:0 @@ -10986,7 +11037,7 @@ msgstr "Martinica(França)" #. module: base #: help:res.partner,is_company:0 msgid "Check if the contact is a company, otherwise it is a person" -msgstr "" +msgstr "Marque se o contato é uma empresa." #. module: base #: view:ir.sequence.type:0 @@ -10997,7 +11048,7 @@ msgstr "Tipo de Sequências" #: code:addons/base/res/res_bank.py:195 #, python-format msgid "Formating Error" -msgstr "" +msgstr "Erro de Formatação" #. module: base #: model:res.country,name:base.ye @@ -11068,7 +11119,7 @@ msgstr "" #: code:addons/base/ir/ir_model.py:1023 #, python-format msgid "Permission Denied" -msgstr "" +msgstr "Permissão negada" #. module: base #: field:ir.ui.menu,child_id:0 @@ -11139,7 +11190,7 @@ msgstr "E-mail" #. module: base #: model:res.partner.category,name:base.res_partner_category_12 msgid "Office Supplies" -msgstr "" +msgstr "Materiais de escritório" #. module: base #: code:addons/custom.py:550 @@ -11227,7 +11278,7 @@ msgstr "Equador" #. module: base #: view:ir.rule:0 msgid "Read Access Right" -msgstr "" +msgstr "Direitos de leitura" #. module: base #: model:ir.module.module,shortdesc:base.module_analytic_user_function @@ -11287,18 +11338,18 @@ msgstr "Arabic / الْعَرَبيّة" #. module: base #: selection:ir.translation,state:0 msgid "Translated" -msgstr "" +msgstr "Traduzido" #. module: base #: model:ir.actions.act_window,name:base.action_inventory_form #: model:ir.ui.menu,name:base.menu_action_inventory_form msgid "Default Company per Object" -msgstr "" +msgstr "Empresa Padrão por Objeto" #. module: base #: field:ir.ui.menu,needaction_counter:0 msgid "Number of actions the user has to perform" -msgstr "" +msgstr "Número de ações que o usuário tem para realizar" #. module: base #: model:ir.module.module,shortdesc:base.module_web_hello @@ -11328,7 +11379,7 @@ msgstr "Domínio" #: code:addons/base/ir/ir_fields.py:167 #, python-format msgid "Use '1' for yes and '0' for no" -msgstr "" +msgstr "Use '1' para sim e '0' para não" #. module: base #: model:ir.module.module,shortdesc:base.module_marketing_campaign @@ -11349,7 +11400,7 @@ msgstr "" #: code:addons/base/ir/ir_fields.py:314 #, python-format msgid "Invalid database id '%s' for the field '%%(field)s'" -msgstr "" +msgstr "Base de dados invalida(%s) para o campo '%%(field)s'" #. module: base #: view:res.lang:0 @@ -11408,7 +11459,7 @@ msgstr "" #. module: base #: view:ir.filters:0 msgid "Shared" -msgstr "" +msgstr "Compartilhado" #. module: base #: code:addons/base/module/module.py:336 @@ -11486,6 +11537,9 @@ msgid "" "Allow users to sign up through OAuth2 Provider.\n" "===============================================\n" msgstr "" +"\n" +"Permite que os usuários se inscrevam através de um serviço OAuth2.\n" +"============================================================\n" #. module: base #: view:ir.cron:0 @@ -11507,12 +11561,12 @@ msgstr "Porto Rico" #. module: base #: model:ir.module.module,shortdesc:base.module_web_tests_demo msgid "Demonstration of web/javascript tests" -msgstr "" +msgstr "Demonstração de testes web/jsvascript" #. module: base #: field:workflow.transition,signal:0 msgid "Signal (Button Name)" -msgstr "" +msgstr "Sinal(Nome do botão)" #. module: base #: view:ir.actions.act_window:0 @@ -11542,7 +11596,7 @@ msgstr "Granada" #. module: base #: help:res.partner,customer:0 msgid "Check this box if this contact is a customer." -msgstr "" +msgstr "Marque se o contato é um cliente." #. module: base #: view:ir.actions.server:0 @@ -11570,7 +11624,7 @@ msgstr "" #. module: base #: field:res.users,partner_id:0 msgid "Related Partner" -msgstr "" +msgstr "Parceiro Relacionado" #. module: base #: code:addons/osv.py:151 @@ -11598,13 +11652,13 @@ msgstr "Operações de Produção" #. module: base #: view:base.language.export:0 msgid "Here is the exported translation file:" -msgstr "" +msgstr "Aqui está o arquivo de tradução exportado:" #. module: base #: field:ir.actions.report.xml,report_rml_content:0 #: field:ir.actions.report.xml,report_rml_content_data:0 msgid "RML Content" -msgstr "" +msgstr "Conteúdo RML" #. module: base #: view:res.lang:0 @@ -11762,6 +11816,13 @@ msgid "" "\n" "The decimal precision is configured per company.\n" msgstr "" +"\n" +"Configurar a precisão dos valores para diferentes tipos de uso: " +"contabilidade, vendas, compras.\n" +"=============================================================================" +"=========\n" +"\n" +"A precisão decimal é configurada por empresa.\n" #. module: base #: selection:res.company,paper_format:0 @@ -11771,7 +11832,7 @@ msgstr "A4" #. module: base #: view:res.config.installer:0 msgid "Configuration Installer" -msgstr "" +msgstr "Instalador de configuração" #. module: base #: field:res.partner,customer:0 @@ -11858,17 +11919,20 @@ msgid "" "(if you delete a native ACL, it will be re-created when you reload the " "module." msgstr "" +"Se você desmarcar o campo ativo, ele irá desativar a ACL sem excluí-lo.(Se " +"você excluir uma ACL nativa, ela será recriada quando você recarregar o " +"módulo)." #. module: base #: model:ir.model,name:base.model_ir_fields_converter msgid "ir.fields.converter" -msgstr "" +msgstr "ir.fields.converter" #. module: base #: code:addons/base/res/res_partner.py:436 #, python-format msgid "Couldn't create contact without email address !" -msgstr "" +msgstr "Não posso criar contatos sem endereço de email!" #. module: base #: model:ir.module.category,name:base.module_category_manufacturing @@ -11890,12 +11954,12 @@ msgstr "Cancelar Instalação" #. module: base #: model:ir.model,name:base.model_ir_model_relation msgid "ir.model.relation" -msgstr "" +msgstr "ir.model.relation" #. module: base #: model:ir.module.module,shortdesc:base.module_account_check_writing msgid "Check Writing" -msgstr "" +msgstr "Verifique a redação" #. module: base #: model:ir.module.module,description:base.module_plugin_outlook @@ -12120,7 +12184,7 @@ msgstr "UK - Contabilidade" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam msgid "Mrs." -msgstr "" +msgstr "Sra." #. module: base #: code:addons/base/ir/ir_model.py:424 @@ -12141,7 +12205,7 @@ msgstr "Ref. Usuário" #: code:addons/base/ir/ir_fields.py:227 #, python-format msgid "'%s' does not seem to be a valid datetime for field '%%(field)s'" -msgstr "" +msgstr "'%s' não parece ser um campo datetime válido '%%(field)s'" #. module: base #: model:res.partner.bank.type.field,name:base.bank_normal_field_bic @@ -12156,7 +12220,7 @@ msgstr "Expressão de repetição" #. module: base #: model:res.partner.category,name:base.res_partner_category_16 msgid "Retailer" -msgstr "" +msgstr "Varejista" #. module: base #: view:ir.model.fields:0 @@ -12207,6 +12271,8 @@ msgstr "" msgid "" "Please make sure no workitems refer to an activity before deleting it!" msgstr "" +"Certifique-se de que não há itens de trabalho para a atividade antes de " +"excluí-la!" #. module: base #: model:res.country,name:base.tr @@ -12295,7 +12361,7 @@ msgstr "Informações da Conexão" #. module: base #: model:res.partner.title,name:base.res_partner_title_prof msgid "Professor" -msgstr "" +msgstr "Professor" #. module: base #: model:res.country,name:base.hm @@ -12324,7 +12390,7 @@ msgstr "Ajuda você a lidar com suas cotações, pedidos e faturamento." #. module: base #: field:res.users,login_date:0 msgid "Latest connection" -msgstr "" +msgstr "Última conecção" #. module: base #: field:res.groups,implied_ids:0 @@ -12407,7 +12473,7 @@ msgstr "Binário" #. module: base #: model:res.partner.title,name:base.res_partner_title_doctor msgid "Doctor" -msgstr "" +msgstr "Doutor" #. module: base #: model:ir.module.module,description:base.module_mrp_repair @@ -12464,7 +12530,7 @@ msgstr "Outros Parceiros" #: view:workflow.workitem:0 #: field:workflow.workitem,state:0 msgid "Status" -msgstr "" +msgstr "Estado" #. module: base #: model:ir.actions.act_window,name:base.action_currency_form @@ -12476,7 +12542,7 @@ msgstr "Moedas" #. module: base #: model:res.partner.category,name:base.res_partner_category_8 msgid "Consultancy Services" -msgstr "" +msgstr "Serviços de consultoria" #. module: base #: help:ir.values,value:0 @@ -12496,7 +12562,7 @@ msgstr "O nome do grupo deve ser único!" #. module: base #: help:ir.translation,module:0 msgid "Module this term belongs to" -msgstr "" +msgstr "Este termo pertence ao módulo" #. module: base #: model:ir.module.module,description:base.module_web_view_editor @@ -12591,7 +12657,7 @@ msgstr "Aquisições" #. module: base #: model:res.partner.category,name:base.res_partner_category_6 msgid "Bronze" -msgstr "" +msgstr "Bronze" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_payroll_account @@ -12621,12 +12687,12 @@ msgstr "Mês de Criação" #. module: base #: field:ir.module.module,demo:0 msgid "Demo Data" -msgstr "" +msgstr "Dados de Demonstração" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_mister msgid "Mr." -msgstr "" +msgstr "Sr." #. module: base #: model:res.country,name:base.mv @@ -12636,7 +12702,7 @@ msgstr "Ilhas Maldivas" #. module: base #: model:ir.module.module,shortdesc:base.module_portal_crm msgid "Portal CRM" -msgstr "" +msgstr "Portal CRM" #. module: base #: model:ir.ui.menu,name:base.next_id_4 @@ -12781,7 +12847,7 @@ msgstr "" #. module: base #: field:ir.actions.report.xml,report_sxw:0 msgid "SXW Path" -msgstr "" +msgstr "Endereço do SXW" #. module: base #: model:ir.module.module,description:base.module_account_asset @@ -12814,7 +12880,7 @@ msgstr "Banco" #: model:ir.module.category,name:base.module_category_point_of_sale #: model:ir.module.module,shortdesc:base.module_point_of_sale msgid "Point of Sale" -msgstr "" +msgstr "Ponto de Venda" #. module: base #: model:ir.module.module,description:base.module_mail @@ -13011,7 +13077,7 @@ msgstr "Filtrar em meus documentos" #. module: base #: model:ir.module.module,summary:base.module_project_gtd msgid "Personal Tasks, Contexts, Timeboxes" -msgstr "" +msgstr "Tarefas pessoais, Contextos, Planilhas" #. module: base #: model:ir.module.module,description:base.module_l10n_cr @@ -13059,7 +13125,7 @@ msgstr "Gabão" #. module: base #: model:ir.module.module,summary:base.module_stock msgid "Inventory, Logistic, Storage" -msgstr "" +msgstr "Inventário, Logística, Armazenamento" #. module: base #: view:ir.actions.act_window:0 @@ -13123,7 +13189,7 @@ msgstr "Chipre" #. module: base #: field:res.users,new_password:0 msgid "Set Password" -msgstr "" +msgstr "Definir Senha" #. module: base #: field:ir.actions.server,subject:0 @@ -13171,7 +13237,7 @@ msgstr "Preferências" #. module: base #: model:res.partner.category,name:base.res_partner_category_9 msgid "Components Buyer" -msgstr "" +msgstr "Comprador de componentes" #. module: base #: view:ir.module.module:0 @@ -13179,6 +13245,8 @@ msgid "" "Do you confirm the uninstallation of this module? This will permanently " "erase all data currently stored by the module!" msgstr "" +"Confirma a desinstalação deste módulo? Isto apagará de forma permanente " +"todos os dados armazenados para este módulo!" #. module: base #: help:ir.cron,function:0 @@ -13245,7 +13313,7 @@ msgstr "Servidores de email de saída" #. module: base #: model:ir.ui.menu,name:base.menu_custom msgid "Technical" -msgstr "" +msgstr "Técnico" #. module: base #: model:res.country,name:base.cn @@ -13493,7 +13561,7 @@ msgstr "Ação a ser Executada" #: field:ir.model,modules:0 #: field:ir.model.fields,modules:0 msgid "In Modules" -msgstr "" +msgstr "Nos Módulos" #. module: base #: model:ir.module.module,shortdesc:base.module_contacts @@ -13592,7 +13660,7 @@ msgstr "Zaire" #. module: base #: model:ir.module.module,summary:base.module_project msgid "Projects, Tasks" -msgstr "" +msgstr "Projetos, Tarefas" #. module: base #: field:workflow.instance,res_id:0 @@ -13610,7 +13678,7 @@ msgstr "Informação" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "false" -msgstr "" +msgstr "falso" #. module: base #: model:ir.module.module,description:base.module_account_analytic_analysis @@ -13676,6 +13744,8 @@ msgid "" "The user this filter is private to. When left empty the filter is public and " "available to all users." msgstr "" +"O usuário de que este filtro é exclusivo, Quando em branco o filtro é " +"público e disponível para todos os usuários." #. module: base #: field:ir.actions.act_window,auto_refresh:0 @@ -13705,6 +13775,8 @@ msgid "" "Automatically set to let administators find new terms that might need to be " "translated" msgstr "" +"Automaticamente definida para permitir que administradores encontrem novos " +"termos que talvez precisem ser traduzidos" #. module: base #: code:addons/base/ir/ir_model.py:84 @@ -13835,6 +13907,8 @@ msgid "" "the user will have access to all records of everyone in the sales " "application." msgstr "" +"o usuário terá acesso a todos os registros de todos os usuários no módulo de " +"vendas." #. module: base #: model:ir.module.module,shortdesc:base.module_event @@ -13889,6 +13963,8 @@ msgid "" " the rightmost column (value) contains the " "translations" msgstr "" +"Formato CSV: você pode editá-lo diretamente com o seu software de planilha " +"favorito," #. module: base #: model:ir.module.module,description:base.module_account_chart @@ -13998,6 +14074,8 @@ msgid "" "Check this to define the report footer manually. Otherwise it will be " "filled in automatically." msgstr "" +"Marque esta opção para definir o rodapé do relatório manualmente. Caso " +"contrário, será preenchido automaticamente." #. module: base #: view:res.partner:0 @@ -14012,7 +14090,7 @@ msgstr "Instalar Módulos" #. module: base #: model:ir.ui.menu,name:base.menu_import_crm msgid "Import & Synchronize" -msgstr "" +msgstr "Importar & Sincronizar" #. module: base #: view:res.partner:0 @@ -14043,7 +14121,7 @@ msgstr "Origem" #: field:ir.model.constraint,date_init:0 #: field:ir.model.relation,date_init:0 msgid "Initialization Date" -msgstr "" +msgstr "Data de Inicialização" #. module: base #: model:res.country,name:base.vu @@ -14157,7 +14235,7 @@ msgstr "" #: code:addons/base/ir/ir_fields.py:147 #, python-format msgid "no" -msgstr "" +msgstr "não" #. module: base #: field:ir.actions.server,trigger_obj_id:0 @@ -14187,7 +14265,7 @@ msgstr "Configuração do Sistema pronta" #: view:ir.config_parameter:0 #: model:ir.ui.menu,name:base.ir_config_menu msgid "System Parameters" -msgstr "" +msgstr "Parâmetros do Sistema" #. module: base #: model:ir.module.module,description:base.module_l10n_ch @@ -14256,7 +14334,7 @@ msgstr "Ação em Multiplos Docs." #: model:ir.actions.act_window,name:base.action_partner_title_partner #: model:ir.ui.menu,name:base.menu_partner_title_partner msgid "Titles" -msgstr "" +msgstr "Títulos" #. module: base #: model:ir.module.module,description:base.module_anonymization @@ -14320,7 +14398,7 @@ msgstr "Luxemburgo" #. module: base #: model:ir.module.module,summary:base.module_base_calendar msgid "Personal & Shared Calendar" -msgstr "" +msgstr "Calendários Pessoais & Compartilhados" #. module: base #: selection:res.request,priority:0 @@ -14397,7 +14475,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_base_gengo msgid "Automated Translations through Gengo API" -msgstr "" +msgstr "Traduções automáticas através Gengo API" #. module: base #: model:ir.module.module,shortdesc:base.module_account_payment @@ -14432,7 +14510,7 @@ msgstr "Tailândia" #. module: base #: model:ir.module.module,summary:base.module_account_voucher msgid "Send Invoices and Track Payments" -msgstr "" +msgstr "Enviar Faturas e Rastrear Pagamentos" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_lead @@ -14557,12 +14635,12 @@ msgstr "Taxa de Câmbio" #: view:base.module.upgrade:0 #: field:base.module.upgrade,module_info:0 msgid "Modules to Update" -msgstr "" +msgstr "Módulos a serem Atualizados" #. module: base #: model:ir.ui.menu,name:base.menu_custom_multicompany msgid "Multi-Companies" -msgstr "" +msgstr "Multi-Empresas" #. module: base #: field:workflow,osv:0 @@ -14677,7 +14755,7 @@ msgstr "Uso de ação" #. module: base #: field:ir.module.module,name:0 msgid "Technical Name" -msgstr "" +msgstr "Nome Técnico" #. module: base #: model:ir.model,name:base.model_workflow_workitem @@ -14726,7 +14804,7 @@ msgstr "Contabilidade - Alemã" #. module: base #: view:ir.sequence:0 msgid "Day of the Year: %(doy)s" -msgstr "" +msgstr "Dia do Ano: %(doy)s" #. module: base #: field:ir.ui.menu,web_icon:0 @@ -14749,6 +14827,8 @@ msgid "" "If this field is empty, the view applies to all users. Otherwise, the view " "applies to the users of those groups only." msgstr "" +"Se este campo estiver vazio, a view se aplica a todos os usuários. Caso " +"contrário, a view se aplica aos usuários desses grupos apenas." #. module: base #: selection:base.language.install,lang:0 @@ -14786,7 +14866,7 @@ msgstr "" #. module: base #: view:base.language.export:0 msgid "Export Settings" -msgstr "" +msgstr "Configurações da Exportação" #. module: base #: field:ir.actions.act_window,src_model:0 @@ -14796,7 +14876,7 @@ msgstr "" #. module: base #: view:ir.sequence:0 msgid "Day of the Week (0:Monday): %(weekday)s" -msgstr "" +msgstr "Dia da Semana (0:Segunda): %(weekday)s" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:84 @@ -14810,7 +14890,7 @@ msgstr "Dependência não atendida!" #: code:addons/base/ir/ir_model.py:1023 #, python-format msgid "Administrator access is required to uninstall a module" -msgstr "" +msgstr "Somente Administradores podem desinstalar um módulo" #. module: base #: model:ir.model,name:base.model_base_module_configuration @@ -14826,6 +14906,10 @@ msgid "" "\n" "(Document type: %s, Operation: %s)" msgstr "" +"A operação solicitada não pode ser concluída devido a restrições de " +"segurança. Por favor, informe ao administrador do sistema.\n" +"\n" +"(Tipo de documento: %s, Operação: %s)" #. module: base #: model:ir.module.module,description:base.module_idea @@ -14996,7 +15080,7 @@ msgstr "Serviços Pós-Venda" #. module: base #: field:base.language.import,code:0 msgid "ISO Code" -msgstr "" +msgstr "Código ISO" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_fr @@ -15011,7 +15095,7 @@ msgstr "Executar" #. module: base #: selection:res.partner,type:0 msgid "Shipping" -msgstr "" +msgstr "Expedição" #. module: base #: model:ir.module.module,description:base.module_project_mrp @@ -15213,7 +15297,7 @@ msgstr "Janela Atual" #: model:ir.module.category,name:base.module_category_hidden #: view:res.users:0 msgid "Technical Settings" -msgstr "" +msgstr "Configurações Técnicas" #. module: base #: model:ir.module.category,description:base.module_category_accounting_and_finance @@ -15232,7 +15316,7 @@ msgstr "Plug-in Thunderbird" #. module: base #: model:ir.module.module,summary:base.module_event msgid "Trainings, Conferences, Meetings, Exhibitions, Registrations" -msgstr "" +msgstr "Treinamentos, Conferências, Reuniões, Exposições, Inscrições" #. module: base #: model:ir.model,name:base.model_res_country @@ -15250,7 +15334,7 @@ msgstr "País" #. module: base #: model:res.partner.category,name:base.res_partner_category_15 msgid "Wholesaler" -msgstr "" +msgstr "Atacadista" #. module: base #: model:ir.module.module,shortdesc:base.module_base_vat @@ -15315,7 +15399,7 @@ msgstr "Espanhol (SV) / Español (SV)" #. module: base #: model:ir.actions.act_window,name:base.open_module_tree msgid "Install a Module" -msgstr "" +msgstr "Instalar um Módulo" #. module: base #: field:ir.module.module,auto_install:0 @@ -15557,7 +15641,7 @@ msgstr "Seicheles" #. module: base #: model:res.partner.category,name:base.res_partner_category_4 msgid "Gold" -msgstr "" +msgstr "Ouro" #. module: base #: code:addons/base/res/res_company.py:159 @@ -15584,7 +15668,7 @@ msgstr "Informações Gerais" #. module: base #: field:ir.model.data,complete_name:0 msgid "Complete ID" -msgstr "" +msgstr "ID completo" #. module: base #: model:res.country,name:base.tc @@ -15685,7 +15769,7 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Internal Notes" -msgstr "" +msgstr "Notas Internas" #. module: base #: selection:res.partner.address,type:0 @@ -15706,7 +15790,7 @@ msgstr "Requisição de Compra" #. module: base #: selection:ir.actions.act_window,target:0 msgid "Inline Edit" -msgstr "" +msgstr "Edição em linha" #. module: base #: selection:ir.cron,interval_type:0 @@ -15727,7 +15811,7 @@ msgstr "Parceiros " #. module: base #: view:res.partner:0 msgid "Is a Company?" -msgstr "" +msgstr "É uma empresa?" #. module: base #: code:addons/base/res/res_company.py:159 @@ -15749,7 +15833,7 @@ msgstr "Criar Objeto" #. module: base #: model:res.country,name:base.ss msgid "South Sudan" -msgstr "" +msgstr "Sudão do Sul" #. module: base #: field:ir.filters,context:0 @@ -15835,7 +15919,7 @@ msgstr "Russo / русский язык" #. module: base #: model:ir.module.module,shortdesc:base.module_auth_signup msgid "Signup" -msgstr "" +msgstr "Inscrever-se" #~ msgid "SMS - Gateway: clickatell" #~ msgstr "SMS - Gateway: clickatell" diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index aacd6aa29c2..633977452a5 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -42,7 +42,7 @@ class actions(osv.osv): _order = 'name' _columns = { 'name': fields.char('Name', size=64, required=True), - 'type': fields.char('Action Type', required=True, size=32,readonly=True), + 'type': fields.char('Action Type', required=True, size=32), 'usage': fields.char('Action Usage', size=32), 'help': fields.text('Action description', help='Optional help text for the users with a description of the target view, such as its usage and purpose.', diff --git a/openerp/addons/base/ir/ir_cron.py b/openerp/addons/base/ir/ir_cron.py index 243f4c772ea..e2d791281d7 100644 --- a/openerp/addons/base/ir/ir_cron.py +++ b/openerp/addons/base/ir/ir_cron.py @@ -31,7 +31,6 @@ import netsvc import openerp import pooler import tools -from openerp.cron import WAKE_UP_NOW from osv import fields, osv from tools import DEFAULT_SERVER_DATETIME_FORMAT from tools.safe_eval import safe_eval as eval @@ -142,130 +141,6 @@ class ir_cron(osv.osv): except Exception, e: self._handle_callback_exception(cr, uid, model_name, method_name, args, job_id, e) - def _run_job(self, cr, job, now): - """ Run a given job taking care of the repetition. - - The cursor has a lock on the job (aquired by _run_jobs_multithread()) and this - method is run in a worker thread (spawned by _run_jobs_multithread())). - - :param job: job to be run (as a dictionary). - :param now: timestamp (result of datetime.now(), no need to call it multiple time). - - """ - try: - nextcall = datetime.strptime(job['nextcall'], DEFAULT_SERVER_DATETIME_FORMAT) - numbercall = job['numbercall'] - - ok = False - while nextcall < now and numbercall: - if numbercall > 0: - numbercall -= 1 - if not ok or job['doall']: - self._callback(cr, job['user_id'], job['model'], job['function'], job['args'], job['id']) - if numbercall: - nextcall += _intervalTypes[job['interval_type']](job['interval_number']) - ok = True - addsql = '' - if not numbercall: - addsql = ', active=False' - cr.execute("UPDATE ir_cron SET nextcall=%s, numbercall=%s"+addsql+" WHERE id=%s", - (nextcall.strftime(DEFAULT_SERVER_DATETIME_FORMAT), numbercall, job['id'])) - - if numbercall: - # Reschedule our own main cron thread if necessary. - # This is really needed if this job runs longer than its rescheduling period. - nextcall = calendar.timegm(nextcall.timetuple()) - openerp.cron.schedule_wakeup(nextcall, cr.dbname) - finally: - cr.commit() - cr.close() - openerp.cron.release_thread_slot() - - def _run_jobs_multithread(self): - # TODO remove 'check' argument from addons/base_action_rule/base_action_rule.py - """ Process the cron jobs by spawning worker threads. - - This selects in database all the jobs that should be processed. It then - tries to lock each of them and, if it succeeds, spawns a thread to run - the cron job (if it doesn't succeed, it means the job was already - locked to be taken care of by another thread). - - The cursor used to lock the job in database is given to the worker - thread (which has to close it itself). - - """ - db = self.pool.db - cr = db.cursor() - db_name = db.dbname - try: - jobs = {} # mapping job ids to jobs for all jobs being processed. - now = datetime.now() - # Careful to compare timestamps with 'UTC' - everything is UTC as of v6.1. - cr.execute("""SELECT * FROM ir_cron - WHERE numbercall != 0 - AND active AND nextcall <= (now() at time zone 'UTC') - ORDER BY priority""") - for job in cr.dictfetchall(): - if not openerp.cron.get_thread_slots(): - break - jobs[job['id']] = job - - task_cr = db.cursor() - try: - # Try to grab an exclusive lock on the job row from within the task transaction - acquired_lock = False - task_cr.execute("""SELECT * - FROM ir_cron - WHERE id=%s - FOR UPDATE NOWAIT""", - (job['id'],), log_exceptions=False) - acquired_lock = True - except psycopg2.OperationalError, e: - if e.pgcode == '55P03': - # Class 55: Object not in prerequisite state; 55P03: lock_not_available - _logger.debug('Another process/thread is already busy executing job `%s`, skipping it.', job['name']) - continue - else: - # Unexpected OperationalError - raise - finally: - if not acquired_lock: - # we're exiting due to an exception while acquiring the lot - task_cr.close() - - # Got the lock on the job row, now spawn a thread to execute it in the transaction with the lock - task_thread = threading.Thread(target=self._run_job, name=job['name'], args=(task_cr, job, now)) - # force non-daemon task threads (the runner thread must be daemon, and this property is inherited by default) - task_thread.setDaemon(False) - openerp.cron.take_thread_slot() - task_thread.start() - _logger.debug('Cron execution thread for job `%s` spawned', job['name']) - - # Find next earliest job ignoring currently processed jobs (by this and other cron threads) - find_next_time_query = """SELECT min(nextcall) AS min_next_call - FROM ir_cron WHERE numbercall != 0 AND active""" - if jobs: - cr.execute(find_next_time_query + " AND id NOT IN %s", (tuple(jobs.keys()),)) - else: - cr.execute(find_next_time_query) - next_call = cr.dictfetchone()['min_next_call'] - - if next_call: - next_call = calendar.timegm(time.strptime(next_call, DEFAULT_SERVER_DATETIME_FORMAT)) - else: - # no matching cron job found in database, re-schedule arbitrarily in 1 day, - # this delay will likely be modified when running jobs complete their tasks - next_call = time.time() + (24*3600) - - openerp.cron.schedule_wakeup(next_call, db_name) - - except Exception, ex: - _logger.warning('Exception in cron:', exc_info=True) - - finally: - cr.commit() - cr.close() - def _process_job(self, cr, job): """ Run a given job taking care of the repetition. @@ -365,19 +240,6 @@ class ir_cron(osv.osv): return False - def update_running_cron(self, cr): - """ Schedule as soon as possible a wake-up for this database. """ - # Verify whether the server is already started and thus whether we need to commit - # immediately our changes and restart the cron agent in order to apply the change - # immediately. The commit() is needed because as soon as the cron is (re)started it - # will query the database with its own cursor, possibly before the end of the - # current transaction. - # This commit() is not an issue in most cases, but we must absolutely avoid it - # when the server is only starting or loading modules (hence the test on pool._init). - if not self.pool._init: - cr.commit() - openerp.cron.schedule_wakeup(WAKE_UP_NOW, self.pool.db.dbname) - def _try_lock(self, cr, uid, ids, context=None): """Try to grab a dummy exclusive write-lock to the rows with the given ids, to make sure a following write() or unlink() will not block due @@ -393,20 +255,16 @@ class ir_cron(osv.osv): def create(self, cr, uid, vals, context=None): res = super(ir_cron, self).create(cr, uid, vals, context=context) - self.update_running_cron(cr) return res def write(self, cr, uid, ids, vals, context=None): self._try_lock(cr, uid, ids, context) res = super(ir_cron, self).write(cr, uid, ids, vals, context=context) - self.update_running_cron(cr) return res def unlink(self, cr, uid, ids, context=None): self._try_lock(cr, uid, ids, context) res = super(ir_cron, self).unlink(cr, uid, ids, context=context) - self.update_running_cron(cr) return res -ir_cron() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index a8475d33552..80e084502e5 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -43,7 +43,7 @@ class ir_ui_menu(osv.osv): def __init__(self, *args, **kwargs): self.cache_lock = threading.RLock() - self.clear_cache() + self._cache = {} r = super(ir_ui_menu, self).__init__(*args, **kwargs) self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache') return r @@ -51,6 +51,10 @@ class ir_ui_menu(osv.osv): def clear_cache(self): with self.cache_lock: # radical but this doesn't frequently happen + if self._cache: + # Normally this is done by openerp.tools.ormcache + # but since we do not use it, set it by ourself. + self.pool._any_cache_cleared = True self._cache = {} def _filter_visible_menus(self, cr, uid, ids, context=None): @@ -265,17 +269,33 @@ class ir_ui_menu(osv.osv): return res - def _get_needaction(self, cr, uid, ids, field_names, args, context=None): + def _get_needaction_enabled(self, cr, uid, ids, field_names, args, context=None): + """ needaction_enabled: tell whether the menu has a related action + that uses the needaction mechanism. """ + res = dict.fromkeys(ids, False) + for menu in self.browse(cr, uid, ids, context=context): + if menu.action and menu.action.type in ('ir.actions.act_window', 'ir.actions.client') and menu.action.res_model: + obj = self.pool.get(menu.action.res_model) + if obj and obj._needaction: + res[menu.id] = True + return res + + def get_needaction_data(self, cr, uid, ids, context=None): + """ Return for each menu entry of ids : + - if it uses the needaction mechanism (needaction_enabled) + - the needaction counter of the related action, taking into account + the action domain + """ res = {} for menu in self.browse(cr, uid, ids, context=context): res[menu.id] = { 'needaction_enabled': False, 'needaction_counter': False, } - if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model: + if menu.action and menu.action.type in ('ir.actions.act_window', 'ir.actions.client') and menu.action.res_model: obj = self.pool.get(menu.action.res_model) if obj and obj._needaction: - if menu.action.type=='ir.actions.act_window': + if menu.action.type == 'ir.actions.act_window': dom = menu.action.domain and eval(menu.action.domain, {'uid': uid}) or [] else: dom = eval(menu.action.params_store or '{}', {'uid': uid}).get('domain') @@ -286,7 +306,7 @@ class ir_ui_menu(osv.osv): _columns = { 'name': fields.char('Menu', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence'), - 'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child IDs'), + 'child_id': fields.one2many('ir.ui.menu', 'parent_id', 'Child IDs'), 'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True), 'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel', 'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\ @@ -296,11 +316,14 @@ class ir_ui_menu(osv.osv): 'icon': fields.selection(tools.icons, 'Icon', size=64), 'icon_pict': fields.function(_get_icon_pict, type='char', size=32), 'web_icon': fields.char('Web Icon File', size=128), - 'web_icon_hover':fields.char('Web Icon File (hover)', size=128), + 'web_icon_hover': fields.char('Web Icon File (hover)', size=128), 'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'), - 'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), - 'needaction_enabled': fields.function(_get_needaction, string='Target model uses the need action mechanism', type='boolean', help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'), - 'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'), + 'web_icon_hover_data': fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'), + 'needaction_enabled': fields.function(_get_needaction_enabled, + type='boolean', + store=True, + string='Target model uses the need action mechanism', + help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.'), 'action': fields.function(_action, fnct_inv=_action_inv, type='reference', string='Action', selection=[ @@ -317,12 +340,12 @@ class ir_ui_menu(osv.osv): return _('Error ! You can not create recursive Menu.') _constraints = [ - (osv.osv._check_recursion, _rec_message , ['parent_id']) + (osv.osv._check_recursion, _rec_message, ['parent_id']) ] _defaults = { - 'icon' : 'STOCK_OPEN', - 'icon_pict': ('stock', ('STOCK_OPEN','ICON_SIZE_MENU')), - 'sequence' : 10, + 'icon': 'STOCK_OPEN', + 'icon_pict': ('stock', ('STOCK_OPEN', 'ICON_SIZE_MENU')), + 'sequence': 10, } _order = "sequence,id" diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index fd00e72c4a2..73720f87740 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -406,6 +406,8 @@ class module(osv.osv): # Mark them to be installed. if to_install_ids: self.button_install(cr, uid, to_install_ids, context=context) + + openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return dict(ACTION_DICT, name=_('Install')) def button_immediate_install(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 16f4ee20334..1cbfd818d28 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -258,7 +258,7 @@ - + diff --git a/openerp/cli/__init__.py b/openerp/cli/__init__.py index a48d20e4483..7111112c026 100644 --- a/openerp/cli/__init__.py +++ b/openerp/cli/__init__.py @@ -2,6 +2,8 @@ import logging import sys import openerp +from openerp import tools +from openerp.modules import module _logger = logging.getLogger(__name__) @@ -32,8 +34,25 @@ import server def main(): args = sys.argv[1:] + + # The only shared option is '--addons-path=' needed to discover additional + # commands from modules + if len(args) > 1 and args[0].startswith('--addons-path=') and not args[1].startswith("-"): + tools.config.parse_config([args[0]]) + args = args[1:] + + # Default legacy command command = "server" + + # Subcommand discovery if len(args) and not args[0].startswith("-"): + for m in module.get_modules(): + m = 'openerp.addons.' + m + __import__(m) + #try: + #except Exception, e: + # raise + # print e command = args[0] args = args[1:] diff --git a/openerp/conf/__init__.py b/openerp/conf/__init__.py index c89ddf44734..0a975c5d4e2 100644 --- a/openerp/conf/__init__.py +++ b/openerp/conf/__init__.py @@ -35,10 +35,6 @@ must be used. import deprecation -# Maximum number of threads processing concurrently cron jobs. -max_cron_threads = 4 # Actually the default value here is meaningless, - # look at tools.config for the default value. - # Paths to search for OpenERP addons. addons_paths = [] diff --git a/openerp/cron.py b/openerp/cron.py deleted file mode 100644 index 7b67877f0fe..00000000000 --- a/openerp/cron.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2011 OpenERP SA () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -""" Cron jobs scheduling - -Cron jobs are defined in the ir_cron table/model. This module deals with all -cron jobs, for all databases of a single OpenERP server instance. - -It defines a single master thread that will spawn (a bounded number of) -threads to process individual cron jobs. - -The thread runs forever, checking every 60 seconds for new -'database wake-ups'. It maintains a heapq of database wake-ups. At each -wake-up, it will call ir_cron._run_jobs_multithread() for the given database. _run_jobs_multithread -will check the jobs defined in the ir_cron table and spawn accordingly threads -to process them. - -This module's behavior depends on the following configuration variable: -openerp.conf.max_cron_threads. - -""" - -import heapq -import logging -import threading -import time - -import openerp -import tools - -_logger = logging.getLogger(__name__) - -# Heapq of database wake-ups. Note that 'database wake-up' meaning is in -# the context of the cron management. This is not originally about loading -# a database, although having the database name in the queue will -# cause it to be loaded when the schedule time is reached, even if it was -# unloaded in the mean time. Normally a database's wake-up is cancelled by -# the RegistryManager when the database is unloaded - so this should not -# cause it to be reloaded. -# -# TODO: perhaps in the future we could consider a flag on ir.cron jobs -# that would cause database wake-up even if the database has not been -# loaded yet or was already unloaded (e.g. 'force_db_wakeup' or something) -# -# Each element is a triple (timestamp, database-name, boolean). The boolean -# specifies if the wake-up is canceled (so a wake-up can be canceled without -# relying on the heapq implementation detail; no need to remove the job from -# the heapq). -_wakeups = [] - -# Mapping of database names to the wake-up defined in the heapq, -# so that we can cancel the wake-up without messing with the heapq -# invariant: lookup the wake-up by database-name, then set -# its third element to True. -_wakeup_by_db = {} - -# Re-entrant lock to protect the above _wakeups and _wakeup_by_db variables. -# We could use a simple (non-reentrant) lock if the runner function below -# was more fine-grained, but we are fine with the loop owning the lock -# while spawning a few threads. -_wakeups_lock = threading.RLock() - -# Maximum number of threads allowed to process cron jobs concurrently. This -# variable is set by start_master_thread using openerp.conf.max_cron_threads. -_thread_slots = None - -# A (non re-entrant) lock to protect the above _thread_slots variable. -_thread_slots_lock = threading.Lock() - -# Sleep duration limits - must not loop too quickly, but can't sleep too long -# either, because a new job might be inserted in ir_cron with a much sooner -# execution date than current known ones. We won't see it until we wake! -MAX_SLEEP = 60 # 1 min -MIN_SLEEP = 1 # 1 sec - -# Dummy wake-up timestamp that can be used to force a database wake-up asap -WAKE_UP_NOW = 1 - -def get_thread_slots(): - """ Return the number of available thread slots """ - return _thread_slots - - -def release_thread_slot(): - """ Increment the number of available thread slots """ - global _thread_slots - with _thread_slots_lock: - _thread_slots += 1 - - -def take_thread_slot(): - """ Decrement the number of available thread slots """ - global _thread_slots - with _thread_slots_lock: - _thread_slots -= 1 - - -def cancel(db_name): - """ Cancel the next wake-up of a given database, if any. - - :param db_name: database name for which the wake-up is canceled. - - """ - _logger.debug("Cancel next wake-up for database '%s'.", db_name) - with _wakeups_lock: - if db_name in _wakeup_by_db: - _wakeup_by_db[db_name][2] = True - - -def cancel_all(): - """ Cancel all database wake-ups. """ - _logger.debug("Cancel all database wake-ups") - global _wakeups - global _wakeup_by_db - with _wakeups_lock: - _wakeups = [] - _wakeup_by_db = {} - - -def schedule_wakeup(timestamp, db_name): - """ Schedule a new wake-up for a database. - - If an earlier wake-up is already defined, the new wake-up is discarded. - If another wake-up is defined, that wake-up is discarded and the new one - is scheduled. - - :param db_name: database name for which a new wake-up is scheduled. - :param timestamp: when the wake-up is scheduled. - - """ - if not timestamp: - return - with _wakeups_lock: - if db_name in _wakeup_by_db: - task = _wakeup_by_db[db_name] - if not task[2] and timestamp > task[0]: - # existing wakeup is valid and occurs earlier than new one - return - task[2] = True # cancel existing task - task = [timestamp, db_name, False] - heapq.heappush(_wakeups, task) - _wakeup_by_db[db_name] = task - _logger.debug("Wake-up scheduled for database '%s' @ %s", db_name, - 'NOW' if timestamp == WAKE_UP_NOW else timestamp) - -def runner(): - """Neverending function (intended to be run in a dedicated thread) that - checks every 60 seconds the next database wake-up. TODO: make configurable - """ - while True: - runner_body() - -def runner_body(): - with _wakeups_lock: - while _wakeups and _wakeups[0][0] < time.time() and get_thread_slots(): - task = heapq.heappop(_wakeups) - timestamp, db_name, canceled = task - if canceled: - continue - del _wakeup_by_db[db_name] - registry = openerp.pooler.get_pool(db_name) - if not registry._init: - _logger.debug("Database '%s' wake-up! Firing multi-threaded cron job processing", db_name) - registry['ir.cron']._run_jobs_multithread() - amount = MAX_SLEEP - with _wakeups_lock: - # Sleep less than MAX_SLEEP if the next known wake-up will happen before that. - if _wakeups and get_thread_slots(): - amount = min(MAX_SLEEP, max(MIN_SLEEP, _wakeups[0][0] - time.time())) - _logger.debug("Going to sleep for %ss", amount) - time.sleep(amount) - -def start_master_thread(): - """ Start the above runner function in a daemon thread. - - The thread is a typical daemon thread: it will never quit and must be - terminated when the main process exits - with no consequence (the processing - threads it spawns are not marked daemon). - - """ - global _thread_slots - _thread_slots = openerp.conf.max_cron_threads - db_maxconn = tools.config['db_maxconn'] - if _thread_slots >= tools.config.get('db_maxconn', 64): - _logger.warning("Connection pool size (%s) is set lower than max number of cron threads (%s), " - "this may cause trouble if you reach that number of parallel cron tasks.", - db_maxconn, _thread_slots) - t = threading.Thread(target=runner, name="openerp.cron.master_thread") - t.setDaemon(True) - t.start() - _logger.debug("Master cron daemon started!") - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 6725151f19c..98955aff492 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -434,8 +434,9 @@ def get_modules(): return name def is_really_module(name): - name = opj(dir, name) - return os.path.isdir(name) or zipfile.is_zipfile(name) + manifest_name = opj(dir, name, '__openerp__.py') + zipfile_name = opj(dir, name) + return os.path.isfile(manifest_name) or zipfile.is_zipfile(zipfile_name) return map(clean, filter(is_really_module, os.listdir(dir))) plist = [] diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 5aa2eca26ef..d898cc7e8db 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -28,7 +28,6 @@ import threading import openerp.sql_db import openerp.osv.orm -import openerp.cron import openerp.tools import openerp.modules.db import openerp.tools.config @@ -58,6 +57,21 @@ class Registry(object): self.db_name = db_name self.db = openerp.sql_db.db_connect(db_name) + # In monoprocess cron jobs flag (pooljobs) + self.cron = False + + # Inter-process signaling (used only when openerp.multi_process is True): + # The `base_registry_signaling` sequence indicates the whole registry + # must be reloaded. + # The `base_cache_signaling sequence` indicates all caches must be + # invalidated (i.e. cleared). + self.base_registry_signaling_sequence = 1 + self.base_cache_signaling_sequence = 1 + + # Flag indicating if at least one model cache has been cleared. + # Useful only in a multi-process context. + self._any_cache_cleared = False + cr = self.db.cursor() has_unaccent = openerp.modules.db.has_unaccent(cr) if openerp.tools.config['unaccent'] and not has_unaccent: @@ -112,7 +126,7 @@ class Registry(object): monitor the ir.cron model for future jobs. See openerp.cron for details. """ - openerp.cron.schedule_wakeup(openerp.cron.WAKE_UP_NOW, self.db.dbname) + self.cron = True def clear_caches(self): """ Clear the caches @@ -121,6 +135,36 @@ class Registry(object): """ for model in self.models.itervalues(): model.clear_caches() + # Special case for ir_ui_menu which does not use openerp.tools.ormcache. + ir_ui_menu = self.models.get('ir.ui.menu') + if ir_ui_menu: + ir_ui_menu.clear_cache() + + + # Useful only in a multi-process context. + def reset_any_cache_cleared(self): + self._any_cache_cleared = False + + # Useful only in a multi-process context. + def any_cache_cleared(self): + return self._any_cache_cleared + + @classmethod + def setup_multi_process_signaling(cls, cr): + if not openerp.multi_process: + return + + # Inter-process signaling: + # The `base_registry_signaling` sequence indicates the whole registry + # must be reloaded. + # The `base_cache_signaling sequence` indicates all caches must be + # invalidated (i.e. cleared). + cr.execute("""SELECT sequence_name FROM information_schema.sequences WHERE sequence_name='base_registry_signaling'""") + if not cr.fetchall(): + cr.execute("""CREATE SEQUENCE base_registry_signaling INCREMENT BY 1 START WITH 1""") + cr.execute("""SELECT nextval('base_registry_signaling')""") + cr.execute("""CREATE SEQUENCE base_cache_signaling INCREMENT BY 1 START WITH 1""") + cr.execute("""SELECT nextval('base_cache_signaling')""") @contextmanager def cursor(self, auto_commit=True): @@ -182,6 +226,7 @@ class RegistryManager(object): cr = registry.db.cursor() try: + Registry.setup_multi_process_signaling(cr) registry.do_parent_store(cr) registry.get('ir.actions.report.xml').register_all(cr) cr.commit() @@ -195,20 +240,11 @@ class RegistryManager(object): @classmethod def delete(cls, db_name): - """Delete the registry linked to a given database. - - This also cleans the associated caches. For good measure this also - cancels the associated cron job. But please note that the cron job can - be running and take some time before ending, and that you should not - remove a registry if it can still be used by some thread. So it might - be necessary to call yourself openerp.cron.Agent.cancel(db_name) and - and join (i.e. wait for) the thread. - """ + """Delete the registry linked to a given database. """ with cls.registries_lock: if db_name in cls.registries: cls.registries[db_name].clear_caches() del cls.registries[db_name] - openerp.cron.cancel(db_name) @classmethod def delete_all(cls): @@ -232,5 +268,71 @@ class RegistryManager(object): if db_name in cls.registries: cls.registries[db_name].clear_caches() + @classmethod + def check_registry_signaling(cls, db_name): + if openerp.multi_process and db_name in cls.registries: + registry = cls.get(db_name, pooljobs=False) + cr = registry.db.cursor() + try: + cr.execute(""" + SELECT base_registry_signaling.last_value, + base_cache_signaling.last_value + FROM base_registry_signaling, base_cache_signaling""") + r, c = cr.fetchone() + # Check if the model registry must be reloaded (e.g. after the + # database has been updated by another process). + if registry.base_registry_signaling_sequence != r: + _logger.info("Reloading the model registry after database signaling.") + # Don't run the cron in the Gunicorn worker. + registry = cls.new(db_name, pooljobs=False) + registry.base_registry_signaling_sequence = r + # Check if the model caches must be invalidated (e.g. after a write + # occured on another process). Don't clear right after a registry + # has been reload. + elif registry.base_cache_signaling_sequence != c: + _logger.info("Invalidating all model caches after database signaling.") + registry.base_cache_signaling_sequence = c + registry.clear_caches() + registry.reset_any_cache_cleared() + # One possible reason caches have been invalidated is the + # use of decimal_precision.write(), in which case we need + # to refresh fields.float columns. + for model in registry.models.values(): + for column in model._columns.values(): + if hasattr(column, 'digits_change'): + column.digits_change(cr) + finally: + cr.close() + + @classmethod + def signal_caches_change(cls, db_name): + if openerp.multi_process and db_name in cls.registries: + # Check the registries if any cache has been cleared and signal it + # through the database to other processes. + registry = cls.get(db_name, pooljobs=False) + if registry.any_cache_cleared(): + _logger.info("At least one model cache has been cleared, signaling through the database.") + cr = registry.db.cursor() + r = 1 + try: + cr.execute("select nextval('base_cache_signaling')") + r = cr.fetchone()[0] + finally: + cr.close() + registry.base_cache_signaling_sequence = r + registry.reset_any_cache_cleared() + + @classmethod + def signal_registry_change(cls, db_name): + if openerp.multi_process and db_name in cls.registries: + registry = cls.get(db_name, pooljobs=False) + cr = registry.db.cursor() + r = 1 + try: + cr.execute("select nextval('base_registry_signaling')") + r = cr.fetchone()[0] + finally: + cr.close() + registry.base_registry_signaling_sequence = r # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/netsvc.py b/openerp/netsvc.py index e9b130979e7..37de4dd5b8b 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -20,6 +20,9 @@ # ############################################################################## +#.apidoc title: Common Services: netsvc +#.apidoc module-mods: member-order: bysource + import errno import logging import logging.handlers @@ -40,6 +43,7 @@ import openerp _logger = logging.getLogger(__name__) + def close_socket(sock): """ Closes a socket instance cleanly @@ -58,18 +62,14 @@ def close_socket(sock): raise sock.close() - -#.apidoc title: Common Services: netsvc -#.apidoc module-mods: member-order: bysource - def abort_response(dummy_1, description, dummy_2, details): # TODO Replace except_{osv,orm} with these directly. raise openerp.osv.osv.except_osv(description, details) class Service(object): - """ Base class for *Local* services - - Functionality here is trusted, no authentication. + """ Base class for Local services + Functionality here is trusted, no authentication. + Workflow engine and reports subclass this. """ _services = {} def __init__(self, name): @@ -145,7 +145,6 @@ class ColoredFormatter(DBFormatter): record.levelname = COLOR_PATTERN % (30 + fg_color, 40 + bg_color, record.levelname) return DBFormatter.format(self, record) - def init_logger(): from tools.translate import resetlocale resetlocale() @@ -246,85 +245,6 @@ def init_alternative_logger(): logger.addHandler(handler) logger.setLevel(logging.ERROR) -class Server: - """ Generic interface for all servers with an event loop etc. - Override this to impement http, net-rpc etc. servers. - - Servers here must have threaded behaviour. start() must not block, - there is no run(). - """ - __is_started = False - __servers = [] - __starter_threads = [] - - # we don't want blocking server calls (think select()) to - # wait forever and possibly prevent exiting the process, - # but instead we want a form of polling/busy_wait pattern, where - # _server_timeout should be used as the default timeout for - # all I/O blocking operations - _busywait_timeout = 0.5 - - def __init__(self): - Server.__servers.append(self) - if Server.__is_started: - # raise Exception('All instances of servers must be inited before the startAll()') - # Since the startAll() won't be called again, allow this server to - # init and then start it after 1sec (hopefully). Register that - # timer thread in a list, so that we can abort the start if quitAll - # is called in the meantime - t = threading.Timer(1.0, self._late_start) - t.name = 'Late start timer for %s' % str(self.__class__) - Server.__starter_threads.append(t) - t.start() - - def start(self): - _logger.debug("called stub Server.start") - - def _late_start(self): - self.start() - for thr in Server.__starter_threads: - if thr.finished.is_set(): - Server.__starter_threads.remove(thr) - - def stop(self): - _logger.debug("called stub Server.stop") - - def stats(self): - """ This function should return statistics about the server """ - return "%s: No statistics" % str(self.__class__) - - @classmethod - def startAll(cls): - if cls.__is_started: - return - _logger.info("Starting %d services" % len(cls.__servers)) - for srv in cls.__servers: - srv.start() - cls.__is_started = True - - @classmethod - def quitAll(cls): - if not cls.__is_started: - return - _logger.info("Stopping %d services" % len(cls.__servers)) - for thr in cls.__starter_threads: - if not thr.finished.is_set(): - thr.cancel() - cls.__starter_threads.remove(thr) - - for srv in cls.__servers: - srv.stop() - cls.__is_started = False - - @classmethod - def allStats(cls): - res = ["Servers %s" % ('stopped', 'started')[cls.__is_started]] - res.extend(srv.stats() for srv in cls.__servers) - return '\n'.join(res) - - def _close_socket(self): - close_socket(self.socket) - def replace_request_password(args): # password is always 3rd argument in a request, we replace it in RPC logs # so it's easier to forward logs for diagnostics/debugging purposes... diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 3e5c1198239..ea84cae978e 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -163,7 +163,7 @@ class boolean(_column): _logger.debug( "required=True is deprecated: making a boolean field" " `required` has no effect, as NULL values are " - "automatically turned into False.") + "automatically turned into False. args: %r",args) class integer(_column): _type = 'integer' diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index ef13253864b..e203ae79e0d 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2509,6 +2509,7 @@ class BaseModel(object): try: getattr(self, '_ormcache') self._ormcache = {} + self.pool._any_cache_cleared = True except AttributeError: pass @@ -3234,7 +3235,7 @@ class BaseModel(object): def _create_table(self, cr): - cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITHOUT OIDS' % (self._table,)) + cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id))' % (self._table,)) cr.execute(("COMMENT ON TABLE \"%s\" IS %%s" % self._table), (self._description,)) _schema.debug("Table '%s': created", self._table) @@ -3318,7 +3319,7 @@ class BaseModel(object): raise except_orm('Programming Error', ('Many2Many destination model does not exist: `%s`') % (f._obj,)) dest_model = self.pool.get(f._obj) ref = dest_model._table - cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL, "%s" INTEGER NOT NULL, UNIQUE("%s","%s")) WITH OIDS' % (m2m_tbl, col1, col2, col1, col2)) + cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL, "%s" INTEGER NOT NULL, UNIQUE("%s","%s"))' % (m2m_tbl, col1, col2, col1, col2)) # create foreign key references with ondelete=cascade, unless the targets are SQL views cr.execute("SELECT relkind FROM pg_class WHERE relkind IN ('v') AND relname=%s", (ref,)) if not cr.fetchall(): diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index 7703406ec96..018976ac663 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -23,6 +23,8 @@ from functools import wraps import logging +import threading + from psycopg2 import IntegrityError, errorcodes import orm @@ -168,6 +170,7 @@ class object_proxy(object): @check def execute(self, db, uid, obj, method, *args, **kw): + threading.currentThread().dbname = db cr = pooler.get_db(db).cursor() try: try: diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index c714c0178f0..307ee4a6526 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -28,16 +28,17 @@ import sys import threading import time +import cron import netrpc_server import web_services +import web_services +import wsgi_server -import openerp.cron import openerp.modules import openerp.netsvc import openerp.osv from openerp.release import nt_service_name import openerp.tools -import openerp.service.wsgi_server #.apidoc title: RPC Services @@ -73,37 +74,32 @@ def start_internal(): return openerp.netsvc.init_logger() openerp.modules.loading.open_openerp_namespace() + # Instantiate local services (this is a legacy design). openerp.osv.osv.start_object_proxy() # Export (for RPC) services. - web_services.start_web_services() + web_services.start_service() + load_server_wide_modules() start_internal_done = True def start_services(): """ Start all services including http, netrpc and cron """ start_internal() - - # Initialize the HTTP stack. - netrpc_server.init_servers() - - # Start the main cron thread. - if openerp.conf.max_cron_threads: - openerp.cron.start_master_thread() - - # Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC). - openerp.netsvc.Server.startAll() - + # Initialize the NETRPC server. + netrpc_server.start_service() # Start the WSGI server. - openerp.service.wsgi_server.start_server() + wsgi_server.start_service() + # Start the main cron thread. + cron.start_service() def stop_services(): """ Stop all services. """ - # stop scheduling new jobs; we will have to wait for the jobs to complete below - openerp.cron.cancel_all() + # stop services + cron.stop_service() + netrpc_server.stop_service() + wsgi_server.stop_service() - openerp.netsvc.Server.quitAll() - openerp.service.wsgi_server.stop_server() _logger.info("Initiating shutdown") _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") diff --git a/openerp/service/cron.py b/openerp/service/cron.py new file mode 100644 index 00000000000..337583b65e4 --- /dev/null +++ b/openerp/service/cron.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2011 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +""" Cron jobs scheduling + +Cron jobs are defined in the ir_cron table/model. This module deals with all +cron jobs, for all databases of a single OpenERP server instance. + +""" + +import logging +import threading +import time + +import openerp + +_logger = logging.getLogger(__name__) + +SLEEP_INTERVAL = 60 # 1 min + +def cron_runner(number): + while True: + time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style + registries = openerp.modules.registry.RegistryManager.registries + _logger.debug('cron%d polling for jobs', number) + for db_name, registry in registries.items(): + while True and registry.cron: + # acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) + # TODO why isnt openerp.addons.base defined ? + import sys + base = sys.modules['addons.base'] + acquired = base.ir.ir_cron.ir_cron._acquire_job(db_name) + if not acquired: + break + +def start_service(): + """ Start the above runner function in a daemon thread. + + The thread is a typical daemon thread: it will never quit and must be + terminated when the main process exits - with no consequence (the processing + threads it spawns are not marked daemon). + + """ + for i in range(openerp.tools.config['max_cron_threads']): + def target(): + cron_runner(i) + t = threading.Thread(target=target, name="openerp.service.cron.cron%d" % i) + t.setDaemon(True) + t.start() + _logger.debug("cron%d started!" % i) + +def stop_service(): + pass + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py index 20206cf147d..1496ea71646 100644 --- a/openerp/service/http_server.py +++ b/openerp/service/http_server.py @@ -176,6 +176,4 @@ class OpenERPAuthProvider(AuthProvider): self.auth_tries += 1 raise AuthRequiredExc(atype='Basic', realm=self.realm) -#eof - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/netrpc_server.py b/openerp/service/netrpc_server.py index cc78d0620cf..af89a734f28 100644 --- a/openerp/service/netrpc_server.py +++ b/openerp/service/netrpc_server.py @@ -22,8 +22,6 @@ #.apidoc title: NET-RPC Server """ This file contains instance of the net-rpc server - - """ import logging import select @@ -38,6 +36,85 @@ import openerp.tools as tools _logger = logging.getLogger(__name__) +class Server: + """ Generic interface for all servers with an event loop etc. + Override this to impement http, net-rpc etc. servers. + + Servers here must have threaded behaviour. start() must not block, + there is no run(). + """ + __is_started = False + __servers = [] + __starter_threads = [] + + # we don't want blocking server calls (think select()) to + # wait forever and possibly prevent exiting the process, + # but instead we want a form of polling/busy_wait pattern, where + # _server_timeout should be used as the default timeout for + # all I/O blocking operations + _busywait_timeout = 0.5 + + def __init__(self): + Server.__servers.append(self) + if Server.__is_started: + # raise Exception('All instances of servers must be inited before the startAll()') + # Since the startAll() won't be called again, allow this server to + # init and then start it after 1sec (hopefully). Register that + # timer thread in a list, so that we can abort the start if quitAll + # is called in the meantime + t = threading.Timer(1.0, self._late_start) + t.name = 'Late start timer for %s' % str(self.__class__) + Server.__starter_threads.append(t) + t.start() + + def start(self): + _logger.debug("called stub Server.start") + + def _late_start(self): + self.start() + for thr in Server.__starter_threads: + if thr.finished.is_set(): + Server.__starter_threads.remove(thr) + + def stop(self): + _logger.debug("called stub Server.stop") + + def stats(self): + """ This function should return statistics about the server """ + return "%s: No statistics" % str(self.__class__) + + @classmethod + def startAll(cls): + if cls.__is_started: + return + _logger.info("Starting %d services" % len(cls.__servers)) + for srv in cls.__servers: + srv.start() + cls.__is_started = True + + @classmethod + def quitAll(cls): + if not cls.__is_started: + return + _logger.info("Stopping %d services" % len(cls.__servers)) + for thr in cls.__starter_threads: + if not thr.finished.is_set(): + thr.cancel() + cls.__starter_threads.remove(thr) + + for srv in cls.__servers: + srv.stop() + cls.__is_started = False + + @classmethod + def allStats(cls): + res = ["Servers %s" % ('stopped', 'started')[cls.__is_started]] + res.extend(srv.stats() for srv in cls.__servers) + return '\n'.join(res) + + def _close_socket(self): + netsvc.close_socket(self.socket) + class TinySocketClientThread(threading.Thread): def __init__(self, sock, threads): spn = sock and sock.getpeername() @@ -99,10 +176,10 @@ def netrpc_handle_exception_legacy(e): return 'AccessDenied ' + str(e) return openerp.tools.exception_to_unicode(e) -class TinySocketServerThread(threading.Thread,netsvc.Server): +class TinySocketServerThread(threading.Thread,Server): def __init__(self, interface, port, secure=False): threading.Thread.__init__(self, name="NetRPCDaemon-%d"%port) - netsvc.Server.__init__(self) + Server.__init__(self) self.__port = port self.__interface = interface self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -157,11 +234,12 @@ class TinySocketServerThread(threading.Thread,netsvc.Server): netrpcd = None -def init_servers(): +def start_service(): global netrpcd if tools.config.get('netrpc', False): - netrpcd = TinySocketServerThread( - tools.config.get('netrpc_interface', ''), - int(tools.config.get('netrpc_port', 8070))) + netrpcd = TinySocketServerThread(tools.config.get('netrpc_interface', ''), int(tools.config.get('netrpc_port', 8070))) + +def stop_service(): + Server.quitAll() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 5b6d6f8be1c..c89841efa37 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -168,6 +168,7 @@ class db(netsvc.ExportService): def exp_duplicate_database(self, db_original_name, db_name): _logger.info('Duplicate database `%s` to `%s`.', db_original_name, db_name) + sql_db.close_db(db_original_name) db = sql_db.db_connect('postgres') cr = db.cursor() try: @@ -606,68 +607,13 @@ class objects_proxy(netsvc.ExportService): raise NameError("Method not available %s" % method) security.check(db,uid,passwd) assert openerp.osv.osv.service, "The object_proxy class must be started with start_object_proxy." + openerp.modules.registry.RegistryManager.check_registry_signaling(db) fn = getattr(openerp.osv.osv.service, method) res = fn(db, uid, *params) + openerp.modules.registry.RegistryManager.signal_caches_change(db) return res -# -# Wizard ID: 1 -# - None = end of wizard -# -# Wizard Type: 'form' -# - form -# - print -# -# Wizard datas: {} -# TODO: change local request to OSE request/reply pattern -# -class wizard(netsvc.ExportService): - def __init__(self, name='wizard'): - netsvc.ExportService.__init__(self,name) - self.id = 0 - self.wiz_datas = {} - self.wiz_name = {} - self.wiz_uid = {} - - def dispatch(self, method, params): - (db, uid, passwd ) = params[0:3] - threading.current_thread().uid = uid - params = params[3:] - if method not in ['execute','create']: - 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 _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]) - return wiz.execute(db, uid, self.wiz_datas[wiz_id], action, context) - - def exp_create(self, db, uid, wiz_name, datas=None): - if not datas: - datas={} -#FIXME: this is not thread-safe - self.id += 1 - self.wiz_datas[self.id] = {} - self.wiz_name[self.id] = wiz_name - self.wiz_uid[self.id] = uid - return self.id - - def exp_execute(self, db, uid, wiz_id, datas, action='init', context=None): - if not context: - context={} - - if wiz_id in self.wiz_uid: - if self.wiz_uid[wiz_id] == uid: - return self._execute(db, uid, wiz_id, datas, action, context) - else: - raise openerp.exceptions.AccessDenied() - else: - raise openerp.exceptions.Warning('Wizard not found.') - # # TODO: set a maximum report number per user to avoid DOS attacks # @@ -689,8 +635,10 @@ class report_spool(netsvc.ExportService): if method not in ['report', 'report_get', 'render_report']: raise KeyError("Method not supported %s" % method) security.check(db,uid,passwd) + openerp.modules.registry.RegistryManager.check_registry_signaling(db) fn = getattr(self, 'exp_' + method) res = fn(db, uid, *params) + openerp.modules.registry.RegistryManager.signal_caches_change(db) return res def exp_render_report(self, db, uid, object, ids, datas=None, context=None): @@ -802,13 +750,11 @@ class report_spool(netsvc.ExportService): raise Exception, 'ReportNotFound' -def start_web_services(): +def start_service(): db() common() objects_proxy() - wizard() report_spool() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/service/workers.py b/openerp/service/workers.py index 7bdf45c079f..c40904026f5 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -16,6 +16,10 @@ import sys import time import werkzeug.serving +try: + from setproctitle import setproctitle +except ImportError: + setproctitle = lambda x: None import openerp import openerp.tools.config as config @@ -134,7 +138,7 @@ class Multicorn(object): def process_spawn(self): while len(self.workers_http) < self.population: self.worker_spawn(WorkerHTTP, self.workers_http) - while len(self.workers_cron) < 1: # config option ? + while len(self.workers_cron) < config['max_cron_threads']: self.worker_spawn(WorkerCron, self.workers_cron) def sleep(self): @@ -189,8 +193,7 @@ class Multicorn(object): for pid in self.workers.keys(): self.worker_kill(pid, signal.SIGTERM) self.socket.close() - import __main__ - __main__.quit_signals_received = 1 + openerp.cli.server.quit_signals_received = 1 def run(self): self.start() @@ -252,7 +255,7 @@ class Worker(object): # Reset the worker if it consumes too much memory (e.g. caused by a memory leak). rss, vms = psutil.Process(os.getpid()).get_memory_info() if vms > config['limit_memory_soft']: - _logger.info('Virtual memory consumption too high, rebooting the worker.') + _logger.info('Worker (%d) virtual memory limit (%s) reached.', self.pid, vms) self.alive = False # Commit suicide after the request. # VMS and RLIMIT_AS are the same thing: virtual memory, a.k.a. address space @@ -263,7 +266,8 @@ class Worker(object): r = resource.getrusage(resource.RUSAGE_SELF) cpu_time = r.ru_utime + r.ru_stime def time_expired(n, stack): - _logger.info('CPU time limit exceeded.') + _logger.info('Worker (%d) CPU time limit (%s) reached.', config['limit_time_cpu']) + # We dont suicide in such case raise Exception('CPU time limit exceeded.') signal.signal(signal.SIGXCPU, time_expired) soft, hard = resource.getrlimit(resource.RLIMIT_CPU) @@ -274,6 +278,7 @@ class Worker(object): def start(self): self.pid = os.getpid() + setproctitle('openerp: %s %s' % (self.__class__.__name__, self.pid)) _logger.info("Worker %s (%s) alive", self.__class__.__name__, self.pid) # Reseed the random number generator random.seed() @@ -346,19 +351,27 @@ class WorkerBaseWSGIServer(werkzeug.serving.BaseWSGIServer): class WorkerCron(Worker): """ Cron workers """ def sleep(self): - time.sleep(60) + interval = 60 + self.pid % 10 # chorus effect + time.sleep(interval) def process_work(self): + _logger.debug("WorkerCron (%s) polling for jobs", self.pid) if config['db_name']: db_names = config['db_name'].split(',') else: db_names = openerp.netsvc.ExportService._services['db'].exp_list(True) for db_name in db_names: while True: - # TODO Each job should be considered as one request in multiprocessing - acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) + # acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) + # TODO why isnt openerp.addons.base defined ? + import base + acquired = base.ir.ir_cron.ir_cron._acquire_job(db_name) if not acquired: break + # dont keep cursors in multi database mode + if len(db_names) > 1: + openerp.sql_db.close_db(db_name) + # TODO Each job should be considered as one request instead of each db self.request_count += 1 def start(self): diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index bd78be27f77..67436a1c0bf 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -428,14 +428,14 @@ def serve(): _logger.info('HTTP service (werkzeug) running on %s:%s', interface, port) httpd.serve_forever() -def start_server(): +def start_service(): """ Call serve() in its own thread. The WSGI server can be shutdown with stop_server() below. """ threading.Thread(target=serve).start() -def stop_server(): +def stop_service(): """ Initiate the shutdown of the WSGI server. The server is supposed to have been started by start_server() above. diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py index 6e18007c340..4b4dcea9b8e 100644 --- a/openerp/tools/cache.py +++ b/openerp/tools/cache.py @@ -57,10 +57,12 @@ class ormcache(object): try: key = args[self.skiparg-2:] del d[key] + self2.pool._any_cache_cleared = True except KeyError: pass else: d.clear() + self2.pool._any_cache_cleared = True class ormcache_multi(ormcache): def __init__(self, skiparg=2, size=8192, multi=3): diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 0b5a95d05f6..1ad5f2b4baa 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -146,8 +146,9 @@ class configmanager(object): help="specify the TCP IP address for the NETRPC protocol") group.add_option("--netrpc-port", dest="netrpc_port", my_default=8070, help="specify the TCP port for the NETRPC protocol", type="int") - group.add_option("--no-netrpc", dest="netrpc", action="store_false", my_default=True, - help="disable the NETRPC protocol") + # Needed a few day for runbot and saas + group.add_option("--no-netrpc", dest="netrpc", action="store_false", my_default=False, help="disable the NETRPC protocol") + group.add_option("--netrpc", dest="netrpc", action="store_true", my_default=False, help="enable the NETRPC protocol") parser.add_option_group(group) # WEB @@ -269,8 +270,8 @@ class configmanager(object): "osv_memory tables. This is a decimal value expressed in hours, " "and the default is 1 hour.", type="float") - group.add_option("--max-cron-threads", dest="max_cron_threads", my_default=4, - help="Maximum number of threads processing concurrently cron jobs.", + group.add_option("--max-cron-threads", dest="max_cron_threads", my_default=2, + help="Maximum number of threads processing concurrently cron jobs (default 2).", type="int") group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true", help="Use the unaccent function provided by the database when available.") @@ -282,19 +283,19 @@ class configmanager(object): help="Specify the number of workers, 0 disable prefork mode.", type="int") group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default=640 * 1024 * 1024, - help="Maximum allowed virtual memory per worker, when reached the worker be reset after the current request.", + help="Maximum allowed virtual memory per worker, when reached the worker be reset after the current request (default 640M).", type="int") group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default=768 * 1024 * 1024, - help="Maximum allowed virtual memory per worker, when reached, any memory allocation will fail.", + help="Maximum allowed virtual memory per worker, when reached, any memory allocation will fail (default 768M).", type="int") group.add_option("--limit-time-cpu", dest="limit_time_cpu", my_default=60, - help="Maximum allowed CPU time per request.", + help="Maximum allowed CPU time per request (default 60).", type="int") - group.add_option("--limit-time-real", dest="limit_time_real", my_default=60, - help="Maximum allowed Real time per request. ", + group.add_option("--limit-time-real", dest="limit_time_real", my_default=120, + help="Maximum allowed Real time per request (default 120).", type="int") group.add_option("--limit-request", dest="limit_request", my_default=8192, - help="Maximum number of request to be processed per worker.", + help="Maximum number of request to be processed per worker (default 8192).", type="int") parser.add_option_group(group) @@ -479,8 +480,6 @@ class configmanager(object): if opt.save: self.save() - openerp.conf.max_cron_threads = self.options['max_cron_threads'] - openerp.conf.addons_paths = self.options['addons_path'].split(',') if opt.server_wide_modules: openerp.conf.server_wide_modules = map(lambda m: m.strip(), opt.server_wide_modules.split(',')) diff --git a/openerp/tools/image.py b/openerp/tools/image.py index eb3600a6652..f8f118e34e2 100644 --- a/openerp/tools/image.py +++ b/openerp/tools/image.py @@ -68,7 +68,7 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file return base64_source # create a thumbnail: will resize and keep ratios, then sharpen for better looking result image.thumbnail(size, Image.ANTIALIAS) - sharpener = ImageEnhance.Sharpness(image.convert('RGB')) + sharpener = ImageEnhance.Sharpness(image.convert('RGBA')) image = sharpener.enhance(2.0) # create a transparent image for background background = Image.new('RGBA', size, (255, 255, 255, 0)) diff --git a/openerp/tools/threadinglocal.py b/openerp/tools/threadinglocal.py deleted file mode 100644 index a68181c10e1..00000000000 --- a/openerp/tools/threadinglocal.py +++ /dev/null @@ -1,269 +0,0 @@ -# -*- coding: utf-8 -*- -#Copyright (c) 2004-2005, CherryPy Team (team@cherrypy.org) -#All rights reserved. -# -#Redistribution and use in source and binary forms, with or without -#modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of the CherryPy Team nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -#FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -#SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -#OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This is a backport of Python-2.4's threading.local() implementation - -"""Thread-local objects - -(Note that this module provides a Python version of thread - threading.local class. Depending on the version of Python you're - using, there may be a faster one available. You should always import - the local class from threading.) - -Thread-local objects support the management of thread-local data. -If you have data that you want to be local to a thread, simply create -a thread-local object and use its attributes: - - >>> mydata = local() - >>> mydata.number = 42 - >>> mydata.number - 42 - -You can also access the local-object's dictionary: - - >>> mydata.__dict__ - {'number': 42} - >>> mydata.__dict__.setdefault('widgets', []) - [] - >>> mydata.widgets - [] - -What's important about thread-local objects is that their data are -local to a thread. If we access the data in a different thread: - - >>> log = [] - >>> def f(): - ... items = mydata.__dict__.items() - ... items.sort() - ... log.append(items) - ... mydata.number = 11 - ... log.append(mydata.number) - - >>> import threading - >>> thread = threading.Thread(target=f) - >>> thread.start() - >>> thread.join() - >>> log - [[], 11] - -we get different data. Furthermore, changes made in the other thread -don't affect data seen in this thread: - - >>> mydata.number - 42 - -Of course, values you get from a local object, including a __dict__ -attribute, are for whatever thread was current at the time the -attribute was read. For that reason, you generally don't want to save -these values across threads, as they apply only to the thread they -came from. - -You can create custom local objects by subclassing the local class: - - >>> class MyLocal(local): - ... number = 2 - ... initialized = False - ... def __init__(self, **kw): - ... if self.initialized: - ... raise SystemError('__init__ called too many times') - ... self.initialized = True - ... self.__dict__.update(kw) - ... def squared(self): - ... return self.number ** 2 - -This can be useful to support default values, methods and -initialization. Note that if you define an __init__ method, it will be -called each time the local object is used in a separate thread. This -is necessary to initialize each thread's dictionary. - -Now if we create a local object: - - >>> mydata = MyLocal(color='red') - -Now we have a default number: - - >>> mydata.number - 2 - -an initial color: - - >>> mydata.color - 'red' - >>> del mydata.color - -And a method that operates on the data: - - >>> mydata.squared() - 4 - -As before, we can access the data in a separate thread: - - >>> log = [] - >>> thread = threading.Thread(target=f) - >>> thread.start() - >>> thread.join() - >>> log - [[('color', 'red'), ('initialized', True)], 11] - -without affecting this thread's data: - - >>> mydata.number - 2 - >>> mydata.color - Traceback (most recent call last): - ... - AttributeError: 'MyLocal' object has no attribute 'color' - -Note that subclasses can define slots, but they are not thread -local. They are shared across threads: - - >>> class MyLocal(local): - ... __slots__ = 'number' - - >>> mydata = MyLocal() - >>> mydata.number = 42 - >>> mydata.color = 'red' - -So, the separate thread: - - >>> thread = threading.Thread(target=f) - >>> thread.start() - >>> thread.join() - -affects what we see: - - >>> mydata.number - 11 - ->>> del mydata -""" - -# Threading import is at end - -class _localbase(object): - __slots__ = '_local__key', '_local__args', '_local__lock' - - def __new__(cls, *args, **kw): - self = object.__new__(cls) - key = '_local__key', 'thread.local.' + str(id(self)) - object.__setattr__(self, '_local__key', key) - object.__setattr__(self, '_local__args', (args, kw)) - object.__setattr__(self, '_local__lock', RLock()) - - if args or kw and (cls.__init__ is object.__init__): - raise TypeError("Initialization arguments are not supported") - - # We need to create the thread dict in anticipation of - # __init__ being called, to make sure we don't call it - # again ourselves. - dict = object.__getattribute__(self, '__dict__') - currentThread().__dict__[key] = dict - - return self - -def _patch(self): - key = object.__getattribute__(self, '_local__key') - d = currentThread().__dict__.get(key) - if d is None: - d = {} - currentThread().__dict__[key] = d - object.__setattr__(self, '__dict__', d) - - # we have a new instance dict, so call out __init__ if we have - # one - cls = type(self) - if cls.__init__ is not object.__init__: - args, kw = object.__getattribute__(self, '_local__args') - cls.__init__(self, *args, **kw) - else: - object.__setattr__(self, '__dict__', d) - -class local(_localbase): - - def __getattribute__(self, name): - lock = object.__getattribute__(self, '_local__lock') - lock.acquire() - try: - _patch(self) - return object.__getattribute__(self, name) - finally: - lock.release() - - def __setattr__(self, name, value): - lock = object.__getattribute__(self, '_local__lock') - lock.acquire() - try: - _patch(self) - return object.__setattr__(self, name, value) - finally: - lock.release() - - def __delattr__(self, name): - lock = object.__getattribute__(self, '_local__lock') - lock.acquire() - try: - _patch(self) - return object.__delattr__(self, name) - finally: - lock.release() - - - def __del__(): - threading_enumerate = enumerate - __getattribute__ = object.__getattribute__ - - def __del__(self): - key = __getattribute__(self, '_local__key') - - try: - threads = list(threading_enumerate()) - except: - # if enumerate fails, as it seems to do during - # shutdown, we'll skip cleanup under the assumption - # that there is nothing to clean up - return - - for thread in threads: - try: - __dict__ = thread.__dict__ - except AttributeError: - # Thread is dying, rest in peace - continue - - if key in __dict__: - try: - del __dict__[key] - except KeyError: - pass # didn't have anything in this thread - - return __del__ - __del__ = __del__() - -from threading import currentThread, enumerate, RLock - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/wizard/__init__.py b/openerp/wizard/__init__.py deleted file mode 100644 index debf0f1e74f..00000000000 --- a/openerp/wizard/__init__.py +++ /dev/null @@ -1,191 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -import copy -import logging - -import openerp.netsvc as netsvc -from openerp.tools.misc import UpdateableStr, UpdateableDict -from openerp.tools.translate import translate -from lxml import etree - -import openerp.pooler as pooler - -from openerp.osv.osv import except_osv -from openerp.osv.orm import except_orm - -_logger = logging.getLogger(__name__) - -class except_wizard(Exception): - def __init__(self, name, value): - self.name = name - self.value = value - self.args = (name, value) - -class interface(netsvc.Service): - """ - This is the base class used to implement Wizards. This class is deprecated - and `openerp.osv.TransientModel` must be used instead. - """ - states = {} - - def __init__(self, name): - assert not self.exists('wizard.'+name), 'The wizard "%s" already exists!' % (name,) - _logger.warning( - "The wizard %s uses the deprecated openerp.wizard.interface class.\n" - "It must use the openerp.osv.TransientModel class instead." % \ - name) - super(interface, self).__init__('wizard.'+name) - self.wiz_name = name - - def translate_view(self, cr, node, state, lang): - if node.get('string'): - trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.get('string').encode('utf8')) - if trans: - node.set('string', trans) - for n in node: - self.translate_view(cr, n, state, lang) - - def execute_cr(self, cr, uid, data, state='init', context=None): - if not context: - context={} - res = {} - try: - state_def = self.states[state] - - result_def = state_def.get('result', {}) - - actions_res = {} - # iterate through the list of actions defined for this state - for action in state_def.get('actions', []): - # execute them - action_res = action(self, cr, uid, data, context) - assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary' - actions_res.update(action_res) - - res = copy.copy(result_def) - res['datas'] = actions_res - - lang = context.get('lang', False) - if result_def['type'] == 'action': - res['action'] = result_def['action'](self, cr, uid, data, context) - elif result_def['type'] == 'form': - fields = copy.deepcopy(result_def['fields']) - arch = copy.copy(result_def['arch']) - button_list = copy.copy(result_def['state']) - - if isinstance(fields, UpdateableDict): - fields = fields.dict - if isinstance(arch, UpdateableStr): - arch = arch.string - - # fetch user-set defaut values for the field... shouldn't we pass it the uid? - ir_values_obj = pooler.get_pool(cr.dbname).get('ir.values') - defaults = ir_values_obj.get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)]) - default_values = dict([(x[1], x[2]) for x in defaults]) - for val in fields.keys(): - if 'default' in fields[val]: - # execute default method for this field - if callable(fields[val]['default']): - fields[val]['value'] = fields[val]['default'](uid, data, state) - else: - fields[val]['value'] = fields[val]['default'] - del fields[val]['default'] - else: - # if user has set a default value for the field, use it - if val in default_values: - fields[val]['value'] = default_values[val] - if 'selection' in fields[val]: - if not isinstance(fields[val]['selection'], (tuple, list)): - fields[val] = copy.copy(fields[val]) - fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context) - elif lang: - res_name = "%s,%s,%s" % (self.wiz_name, state, val) - trans = lambda x: translate(cr, res_name, 'selection', lang, x) or x - for idx, (key, val2) in enumerate(fields[val]['selection']): - fields[val]['selection'][idx] = (key, trans(val2)) - - if lang: - # translate fields - for field in fields: - res_name = "%s,%s,%s" % (self.wiz_name, state, field) - - trans = translate(cr, res_name, 'wizard_field', lang) - if trans: - fields[field]['string'] = trans - - if 'help' in fields[field]: - t = translate(cr, res_name, 'help', lang, fields[field]['help']) - if t: - fields[field]['help'] = t - - # translate arch - if not isinstance(arch, UpdateableStr): - doc = etree.XML(arch) - self.translate_view(cr, doc, state, lang) - arch = etree.tostring(doc) - - # translate buttons - button_list = list(button_list) - for i, aa in enumerate(button_list): - button_name = aa[0] - trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang) - if trans: - aa = list(aa) - aa[1] = trans - button_list[i] = aa - - res['fields'] = fields - res['arch'] = arch - res['state'] = button_list - - elif result_def['type'] == 'choice': - next_state = result_def['next_state'](self, cr, uid, data, context) - return self.execute_cr(cr, uid, data, next_state, context) - - except Exception, e: - if isinstance(e, except_wizard) \ - or isinstance(e, except_osv) \ - or isinstance(e, except_orm): - netsvc.abort_response(2, e.name, 'warning', e.value) - else: - _logger.exception('Exception in call:') - raise - - return res - - def execute(self, db, uid, data, state='init', context=None): - if not context: - context={} - cr = pooler.get_db(db).cursor() - try: - try: - res = self.execute_cr(cr, uid, data, state, context) - cr.commit() - except Exception: - cr.rollback() - raise - finally: - cr.close() - return res - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/setup.py b/setup.py index 7d41e4d5c3c..7811915ebcf 100755 --- a/setup.py +++ b/setup.py @@ -108,6 +108,7 @@ setuptools.setup( 'gdata', 'lxml < 3', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/ 'mako', + 'mock', 'PIL', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/ 'psutil', # windows binary code.google.com/p/psutil/downloads/list 'psycopg2', @@ -120,6 +121,7 @@ setuptools.setup( 'pyyaml', 'reportlab', # windows binary pypi.python.org/pypi/reportlab 'simplejson', + 'unittest2', 'vatnumber', 'vobject', 'werkzeug',