[MERGE] Sync with trunk.
authorThibault Delavallée <tde@openerp.com>
Fri, 21 Dec 2012 10:03:20 +0000 (11:03 +0100)
committerThibault Delavallée <tde@openerp.com>
Fri, 21 Dec 2012 10:03:20 +0000 (11:03 +0100)
bzr revid: tde@openerp.com-20121221100320-ntn6zsdcqlvz52xn

36 files changed:
.bzrignore
openerp/addons/base/__openerp__.py
openerp/addons/base/i18n/es.po
openerp/addons/base/i18n/es_EC.po
openerp/addons/base/i18n/et.po
openerp/addons/base/i18n/hu.po
openerp/addons/base/i18n/it.po
openerp/addons/base/i18n/ro.po
openerp/addons/base/module/module.py
openerp/addons/base/module/module_view.xml
openerp/addons/base/module/wizard/base_export_language_view.xml
openerp/addons/base/module/wizard/base_module_import_view.xml
openerp/addons/base/module/wizard/base_module_update_view.xml
openerp/addons/base/module/wizard/base_module_upgrade_view.xml
openerp/addons/base/res/__init__.py
openerp/addons/base/res/res_config.py
openerp/addons/base/res/res_partner.py
openerp/addons/base/res/res_users_view.xml
openerp/addons/base/res/wizard/__init__.py [new file with mode: 0644]
openerp/addons/base/res/wizard/change_password_wizard.py [new file with mode: 0644]
openerp/addons/base/res/wizard/change_password_wizard_view.xml [new file with mode: 0644]
openerp/addons/base/static/src/js/apps.js [new file with mode: 0644]
openerp/cli/server.py
openerp/modules/__init__.py
openerp/modules/module.py
openerp/release.py
openerp/service/__init__.py
openerp/service/web_services.py
openerp/service/wsgi_server.py
openerp/tests/test_mail.py
openerp/tools/mail.py
openerp/tools/osutil.py
win32/OpenERPServerService.py
win32/setup.py
win32/start.bat [deleted file]
win32/stop.bat [deleted file]

index 1e05648..e7618c7 100644 (file)
@@ -1,14 +1,21 @@
-.*
-*.egg-info
-*.orig
-*.vim
+.*.swp
+.bzrignore
+.idea
+.project
+.pydevproject
+.ropeproject
+.settings
+.DS_Store
+openerp/addons/*
+openerp/filestore*
+.Python
+*.pyc
+*.pyo
+bin/*
 build/
-RE:^bin/
-RE:^dist/
-RE:^include/
-
-RE:^share/
-RE:^man/
-RE:^lib/
-
-RE:^addons/\w+/doc/_build/
+include/
+lib/
+share/
+doc/_build/*
+win32/*.bat
+win32/meta.py
index d400b28..f2df885 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#    Copyright (C) 2010, 2012 OpenERP s.a. (<http://openerp.com>).
+#    Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -80,6 +80,7 @@ The kernel of OpenERP, needed for all installation.
         'res/res_bank_view.xml',
         'res/res_country_view.xml',
         'res/res_currency_view.xml',
+        'res/wizard/change_password_wizard_view.xml',
         'res/res_users_view.xml',
         'res/res_partner_data.xml',
         'res/ir_property_view.xml',
@@ -102,5 +103,8 @@ The kernel of OpenERP, needed for all installation.
     'installable': True,
     'auto_install': True,
     'css': ['static/src/css/modules.css'],
+    'js': [
+        'static/src/js/apps.js',
+    ],
 }
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index 9730848..2a50ce2 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-12-20 04:42+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:39+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
index 2d08fbd..ce83e82 100644 (file)
@@ -7,13 +7,13 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
 "Report-Msgid-Bugs-To: support@openerp.com\n"
 "POT-Creation-Date: 2012-12-03 16:01+0000\n"
-"PO-Revision-Date: 2012-12-20 02:14+0000\n"
+"PO-Revision-Date: 2012-12-20 19:00+0000\n"
 "Last-Translator: Cristian Salamea (Gnuthink) <ovnicraft@gmail.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-20 04:43+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:39+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
@@ -210,6 +210,15 @@ msgid ""
 "revenue\n"
 "reports."
 msgstr ""
+"\n"
+"Genere facturas desde los gastos y partes de horas.\n"
+"========================================================\n"
+"\n"
+"Módulo para generar facturas basadas en los costes (recursos humanos, "
+"gastos, ...).\n"
+"\n"
+"Puede definir tarifas en la contabilidad analítica, realizando algún informe "
+"teórico de beneficios."
 
 #. module: base
 #: model:ir.module.module,description:base.module_crm
@@ -378,6 +387,15 @@ msgid ""
 "    * Commitment Date\n"
 "    * Effective Date\n"
 msgstr ""
+"\n"
+"Añade información adicional al pedido de venta.\n"
+"===================================================\n"
+"\n"
+"Puede añadir las siguientes fechas adicionales a un pedido de venta:\n"
+"-----------------------------------------------------------\n"
+"    * Fecha solicitada\n"
+"    * Fecha de confirmación\n"
+"    * Fecha efectiva\n"
 
 #. module: base
 #: help:ir.actions.act_window,res_id:0
@@ -385,6 +403,8 @@ msgid ""
 "Database ID of record to open in form view, when ``view_mode`` is set to "
 "'form' only"
 msgstr ""
+"Id. de la base datos del registro para abrir en el formulario de vista, "
+"cuando se establece el modo de visto únicamente a 'formulario'"
 
 #. module: base
 #: field:res.partner.address,name:0
@@ -460,6 +480,8 @@ msgid ""
 "There is already a shared filter set as default for %(model)s, delete or "
 "change it before setting a new default"
 msgstr ""
+"Ya existe un filtro compartido por defecto para %(model)s, elimínelo o "
+"cámbielo antes de configurar uno nuevo"
 
 #. module: base
 #: code:addons/orm.py:2648
@@ -554,12 +576,12 @@ msgstr ""
 #. module: base
 #: field:ir.model.relation,name:0
 msgid "Relation Name"
-msgstr ""
+msgstr "Nombre de relación"
 
 #. module: base
 #: view:ir.rule:0
 msgid "Create Access Right"
-msgstr ""
+msgstr "Crear permisos de acceso"
 
 #. module: base
 #: model:res.country,name:base.tv
@@ -599,7 +621,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
@@ -722,7 +744,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
@@ -751,7 +773,7 @@ msgstr "Untranslated"
 #. 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
@@ -845,6 +867,14 @@ msgid ""
 "              </p>\n"
 "            "
 msgstr ""
+"<p class=\"oe_view_nocontent_create\">\n"
+"Pulse para añadir un contacto en la libreta de direcciones.\n"
+"</p><p>\n"
+"OpenERP le ayuda a gestionar todas las actividades relacionadas con los "
+"clientes: discusiones, historial de oportunidades de negocio, documentos, "
+"etc.\n"
+"</p>\n"
+"            "
 
 #. module: base
 #: model:ir.module.module,description:base.module_web_linkedin
@@ -901,7 +931,7 @@ msgstr "Rumanía - Contabilidad"
 #. module: base
 #: model:ir.model,name:base.model_res_config_settings
 msgid "res.config.settings"
-msgstr ""
+msgstr "Parámetros de configuración"
 
 #. module: base
 #: help:res.partner,image_small:0
@@ -910,6 +940,9 @@ msgid ""
 "image, with aspect ratio preserved. Use this field anywhere a small image is "
 "required."
 msgstr ""
+"Imagen de tamaño pequeño de este contacto. Se redimensiona automáticamente a "
+"64x64 px, con el ratio de aspecto preservado. Use este campo donde se "
+"requiera una imagen pequeña."
 
 #. module: base
 #: help:ir.actions.server,mobile:0
@@ -931,7 +964,7 @@ msgstr "Seguridad y autenticación"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_web_calendar
 msgid "Web Calendar"
-msgstr ""
+msgstr "Calendario web"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -942,7 +975,7 @@ msgstr "Swedish / svenska"
 #: field:base.language.export,name:0
 #: field:ir.attachment,datas_fname:0
 msgid "File Name"
-msgstr ""
+msgstr "Nombre de Archivo"
 
 #. module: base
 #: model:res.country,name:base.rs
@@ -1038,7 +1071,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
@@ -1055,6 +1088,7 @@ msgstr "Zimbabwe"
 msgid ""
 "Type of the constraint: `f` for a foreign key, `u` for other constraints."
 msgstr ""
+"Tipo de restricción: 'f' para un clave foránea, 'u' para otras restricciones."
 
 #. module: base
 #: view:ir.actions.report.xml:0
@@ -1136,7 +1170,7 @@ msgstr "Otra licencia OSI Aprobada"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_web_gantt
 msgid "Web Gantt"
-msgstr ""
+msgstr "Diagrama Gantt web"
 
 #. module: base
 #: model:ir.actions.act_window,name:base.act_menu_create
@@ -1163,7 +1197,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
@@ -1189,7 +1223,7 @@ msgstr "Principado de Andorra"
 #. module: base
 #: field:ir.rule,perm_read:0
 msgid "Apply for Read"
-msgstr ""
+msgstr "Aplicar para lectura"
 
 #. module: base
 #: model:res.country,name:base.mn
@@ -1219,7 +1253,7 @@ msgstr ""
 #: code:addons/base/ir/ir_model.py:727
 #, python-format
 msgid "Document model"
-msgstr ""
+msgstr "Modelo de documento"
 
 #. module: base
 #: view:res.lang:0
@@ -1269,12 +1303,12 @@ msgstr "El nombre del país debe ser único"
 #. module: base
 #: field:ir.module.module,installed_version:0
 msgid "Latest Version"
-msgstr ""
+msgstr "Última versión"
 
 #. module: base
 #: view:ir.rule:0
 msgid "Delete Access Right"
-msgstr ""
+msgstr "Eliminar permiso de acceso"
 
 #. module: base
 #: code:addons/base/ir/ir_mail_server.py:213
@@ -1301,7 +1335,7 @@ msgstr "Islas Caimán"
 #. module: base
 #: view:ir.rule:0
 msgid "Record Rule"
-msgstr ""
+msgstr "Regla de registro"
 
 #. module: base
 #: model:res.country,name:base.kr
@@ -1329,7 +1363,7 @@ msgstr "Contribuyentes"
 #. module: base
 #: field:ir.rule,perm_unlink:0
 msgid "Apply for Delete"
-msgstr ""
+msgstr "Aplicar para eliminación"
 
 #. module: base
 #: selection:ir.property,type:0
@@ -1344,7 +1378,7 @@ msgstr "Visible"
 #. module: base
 #: model:ir.actions.client,name:base.action_client_base_menu
 msgid "Open Settings Menu"
-msgstr ""
+msgstr "Abrir menú 'Configuración'"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -1430,7 +1464,7 @@ msgstr "Tests"
 #. module: base
 #: field:ir.actions.report.xml,attachment:0
 msgid "Save as Attachment Prefix"
-msgstr ""
+msgstr "Prefijo del adjunto al guardar como"
 
 #. module: base
 #: field:ir.ui.view_sc,res_id:0
@@ -1467,7 +1501,7 @@ msgstr "Haití"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_l10n_fr_hr_payroll
 msgid "French Payroll"
-msgstr ""
+msgstr "Nomina de Francia"
 
 #. module: base
 #: view:ir.ui.view:0
@@ -1587,6 +1621,12 @@ msgid ""
 "=============\n"
 "    "
 msgstr ""
+"\n"
+"Este módulo añade el menú y características de reclamaciones al portal si "
+"los módulos 'claim' y 'portal' están instalados.\n"
+"============================================================================="
+"====================\n"
+"    "
 
 #. module: base
 #: model:ir.actions.act_window,help:base.action_res_partner_bank_account_form
@@ -1618,7 +1658,7 @@ msgstr ""
 #. module: base
 #: model:res.country,name:base.mf
 msgid "Saint Martin (French part)"
-msgstr ""
+msgstr "San Martín (zona francesa)"
 
 #. module: base
 #: model:ir.model,name:base.model_ir_exports
@@ -1635,7 +1675,7 @@ msgstr "Ninguna lengua con el código \"%s\" existe"
 #: model:ir.module.category,name:base.module_category_social_network
 #: model:ir.module.module,shortdesc:base.module_mail
 msgid "Social Network"
-msgstr ""
+msgstr "Red Social"
 
 #. module: base
 #: view:res.lang:0
@@ -1645,12 +1685,12 @@ msgstr "%Y - Año con siglo."
 #. module: base
 #: view:res.company:0
 msgid "Report Footer Configuration"
-msgstr ""
+msgstr "Configuración de pie de informe"
 
 #. module: base
 #: field:ir.translation,comments:0
 msgid "Translation comments"
-msgstr ""
+msgstr "Comentarios de traducción"
 
 #. module: base
 #: model:ir.module.module,description:base.module_lunch
@@ -1715,7 +1755,7 @@ msgstr ""
 #. module: base
 #: help:res.partner,website:0
 msgid "Website of Partner or Company"
-msgstr ""
+msgstr "Sitio web de la empresa o compañía"
 
 #. module: base
 #: help:base.language.install,overwrite:0
@@ -1762,7 +1802,7 @@ msgstr ""
 #. module: base
 #: model:ir.module.module,summary:base.module_sale
 msgid "Quotations, Sale Orders, Invoicing"
-msgstr ""
+msgstr "Presupuestos, órdenes de venta, facturación"
 
 #. module: base
 #: field:res.users,login:0
index a722c4c..c6053f6 100644 (file)
@@ -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-19 19:49+0000\n"
+"PO-Revision-Date: 2012-12-20 18:03+0000\n"
 "Last-Translator: Ahti Hinnov <sipelgas@gmail.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-20 04:41+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:38+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
@@ -1355,7 +1355,7 @@ msgstr ""
 #: code:addons/base/module/wizard/base_language_install.py:53
 #, python-format
 msgid "Language Pack"
-msgstr ""
+msgstr "Keelepakett"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_web_tests
@@ -2005,7 +2005,7 @@ msgstr "Valem"
 #: code:addons/base/res/res_users.py:311
 #, python-format
 msgid "Can not remove root user!"
-msgstr "Ei saa eemaldada root kasutajat!"
+msgstr "Ei saa eemaldada juurkasutajat!"
 
 #. module: base
 #: model:res.country,name:base.mw
@@ -2750,7 +2750,7 @@ msgstr "Ekspordi tõlked"
 #: model:res.groups,name:base.group_sale_manager
 #: model:res.groups,name:base.group_tool_manager
 msgid "Manager"
-msgstr ""
+msgstr "Juht"
 
 #. module: base
 #: code:addons/base/ir/ir_model.py:718
@@ -3055,7 +3055,7 @@ msgstr "Viga! Sa ei saa luua rekursiivseid ettevõtteid."
 #: view:res.users:0
 #, python-format
 msgid "Application"
-msgstr ""
+msgstr "Rakendamine"
 
 #. module: base
 #: model:res.groups,comment:base.group_hr_manager
@@ -4467,6 +4467,8 @@ msgid ""
 "The selected language has been successfully installed. You must change the "
 "preferences of the user and open a new menu to view the changes."
 msgstr ""
+"Valitud keel on edukalt paigaldatud. Muudatuste nägemiseks pead sa muutma "
+"kasutaja eelistusi ja avama uue menüü."
 
 #. module: base
 #: field:ir.actions.act_window.view,view_id:0
@@ -5694,7 +5696,7 @@ msgstr "Omadus kustutamisel many2one väljadel"
 #. module: base
 #: model:ir.module.category,name:base.module_category_accounting_and_finance
 msgid "Accounting & Finance"
-msgstr ""
+msgstr "Raamatupidamine ja rahandus"
 
 #. module: base
 #: field:ir.actions.server,write_id:0
@@ -5717,7 +5719,7 @@ msgstr ""
 #: model:ir.module.category,name:base.module_category_usability
 #: view:res.users:0
 msgid "Usability"
-msgstr ""
+msgstr "Kasutatavus"
 
 #. module: base
 #: field:ir.actions.act_window,domain:0
@@ -5836,7 +5838,7 @@ msgstr "Grupi nimi ei tohi alata \"-\" märgiga"
 #. module: base
 #: view:ir.module.module:0
 msgid "Apps"
-msgstr ""
+msgstr "Rakendused"
 
 #. module: base
 #: view:ir.ui.view_sc:0
@@ -6508,7 +6510,7 @@ msgstr ""
 #. module: base
 #: model:res.groups,name:base.group_partner_manager
 msgid "Contact Creation"
-msgstr ""
+msgstr "Kontaktide loomine"
 
 #. module: base
 #: view:ir.module.module:0
@@ -9180,7 +9182,7 @@ msgstr "Gambia"
 #: view:res.partner:0
 #: field:res.users,company_ids:0
 msgid "Companies"
-msgstr "Firmad"
+msgstr "Ettevõtted"
 
 #. module: base
 #: help:res.currency,symbol:0
@@ -9249,7 +9251,7 @@ msgstr ""
 #: view:res.users:0
 #: view:wizard.ir.model.menu.create:0
 msgid "Cancel"
-msgstr "Tühista"
+msgstr "Loobu"
 
 #. module: base
 #: code:addons/orm.py:1509
@@ -9665,7 +9667,7 @@ msgstr "Kuvamine"
 #. module: base
 #: model:res.groups,name:base.group_multi_company
 msgid "Multi Companies"
-msgstr ""
+msgstr "Mitu ettevõtet"
 
 #. module: base
 #: help:res.users,menu_id:0
@@ -10034,7 +10036,7 @@ msgstr "Ettevõttega seotud pangakontod"
 #: model:ir.ui.menu,name:base.next_id_64
 #: view:res.users:0
 msgid "Sales"
-msgstr "Müügid"
+msgstr "Müük"
 
 #. module: base
 #: field:ir.actions.server,child_ids:0
@@ -10321,7 +10323,7 @@ msgstr ""
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_sale_stock
 msgid "Sales and Warehouse Management"
-msgstr ""
+msgstr "Müük ja laohaldus"
 
 #. module: base
 #: field:ir.model.fields,model:0
@@ -12095,7 +12097,7 @@ msgstr "ir.values"
 #. module: base
 #: model:res.groups,name:base.group_no_one
 msgid "Technical Features"
-msgstr ""
+msgstr "Tehnilised funktsioonid"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -14247,7 +14249,7 @@ msgstr "Faks"
 #: view:res.users:0
 #: field:res.users,company_id:0
 msgid "Company"
-msgstr "Firma"
+msgstr "Ettevõte"
 
 #. module: base
 #: model:ir.module.category,name:base.module_category_report_designer
index 514bc4d..3808cfd 100644 (file)
@@ -7,13 +7,13 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.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-19 16:59+0000\n"
+"PO-Revision-Date: 2012-12-20 15:01+0000\n"
 "Last-Translator: krnkris <Unknown>\n"
 "Language-Team: Hungarian <openerp-hungarian-team@lists.launchpad.net>\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-20 04:41+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:38+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
@@ -15914,6 +15914,10 @@ msgid ""
 "                                the rightmost column (value) contains the "
 "translations"
 msgstr ""
+"CSV formátum: szerkessze egyenesen a megszokott táblázatkezelő "
+"alkalmazásával,\n"
+"                                a leg jobboldalt lévő oszlop (érték) "
+"tartalmazza a fordításokat"
 
 #. module: base
 #: model:ir.module.module,description:base.module_account_chart
@@ -15924,11 +15928,16 @@ msgid ""
 "\n"
 "Deactivates minimal chart of accounts.\n"
 msgstr ""
+"\n"
+"a minimum számlatükör kikapcsolása.\n"
+"=============================\n"
+"\n"
+"Kikapcsolja a minimum számlatükröket.\n"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_base_crypt
 msgid "DB Password Encryption"
-msgstr ""
+msgstr "DB adatbázis jelszó titkosítás"
 
 #. module: base
 #: help:workflow.transition,act_to:0
@@ -15938,7 +15947,7 @@ msgstr "A cél tevékenység."
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_project_issue
 msgid "Issue Tracker"
-msgstr ""
+msgstr "Ügy nyomonkövetése"
 
 #. module: base
 #: view:base.module.update:0
@@ -15954,6 +15963,9 @@ msgid ""
 "The common interface for plug-in.\n"
 "=================================\n"
 msgstr ""
+"\n"
+"A plug-in általános intefész\n"
+"============================\n"
 
 #. module: base
 #: model:ir.module.module,description:base.module_sale_crm
@@ -15972,11 +15984,26 @@ msgid ""
 "modules.\n"
 "    "
 msgstr ""
+"\n"
+"Ez a modul útvonal rövidítéseket ad meg egy vagy több lehetséges eseményhez "
+"a CRM (ügyfélkapcsolat kezelőben).\n"
+"===========================================================================\n"
+"\n"
+"Ezek a rövidebb utak lehetővé teszik a kiválasztott esemény alapján generált "
+"megrendelések létrehozását.\n"
+"Különböző eseményekhez megnyílik (egy lista), ez generálja az események "
+"szerinti megrendeléseket.\n"
+"Az esemény ezután lezárásra kerül és hozzá lesz csatolva egy generált "
+"megrendeléshez.\n"
+"\n"
+"Ajánljuk ennek a modulnak a telepítését, ha az eladás és a crm modult is "
+"telepítette már.\n"
+"    "
 
 #. module: base
 #: model:res.country,name:base.bq
 msgid "Bonaire, Sint Eustatius and Saba"
-msgstr ""
+msgstr "Karib tengeri Bonaire, Sint Eustatius and Saba"
 
 #. module: base
 #: model:ir.actions.report.xml,name:base.ir_module_reference_print
@@ -16011,6 +16038,10 @@ msgid ""
 "your home page.\n"
 "You can track your suppliers, customers and other contacts.\n"
 msgstr ""
+"\n"
+"Ez a modul egy gyors áttekintést tesz lehetővé a címjegyzékén, ami elérhető "
+"a saját oldaláról.\n"
+"Nyomon követheti a beszállítóit, vásárlóit és egyéb ügyfeleit.\n"
 
 #. module: base
 #: help:res.company,custom_footer:0
@@ -16018,6 +16049,8 @@ msgid ""
 "Check this to define the report footer manually.  Otherwise it will be "
 "filled in automatically."
 msgstr ""
+"Jelölje be a kimutatás lábjegyzet kézi meghatározásához. Egyébként "
+"automatikusan ki lesz töltve."
 
 #. module: base
 #: view:res.partner:0
@@ -16032,7 +16065,7 @@ msgstr "Modulok telepítése"
 #. module: base
 #: model:ir.ui.menu,name:base.menu_import_crm
 msgid "Import & Synchronize"
-msgstr ""
+msgstr "Import & Szinkronizáció"
 
 #. module: base
 #: view:res.partner:0
@@ -16065,7 +16098,7 @@ msgstr "Forrás"
 #: field:ir.model.constraint,date_init:0
 #: field:ir.model.relation,date_init:0
 msgid "Initialization Date"
-msgstr ""
+msgstr "Alap adatok"
 
 #. module: base
 #: model:res.country,name:base.vu
@@ -16096,6 +16129,26 @@ msgid ""
 "    Unit price=225, Discount=0,00, Net price=225.\n"
 "    "
 msgstr ""
+"\n"
+"Ez a modul lehetővé teszi az árengedmények számítását a megrendelések és "
+"számlák sorain a partner árlistája alapján.\n"
+"============================================================================="
+"==================================\n"
+"\n"
+"Ehhez egy új jelölő négyzet lesz, melynek neve 'látható árengedmény', hozzá "
+"lesz adva az árlista formához.\n"
+"\n"
+"**Például:**\n"
+"    A PC1 termékhez és az \"ASUSTEK\" partnerhez: ha a listaár=450, és az ár "
+"az \n"
+"    Asustek árlista ár=255 árból lett kalkulálva. Ha be van jelölve a "
+"négyzet akkor\n"
+"    megrendelés sorához ez lesz jelölve: Egységár=450, Árengedmény=50,00, "
+"Nettó ár=225.\n"
+"    Ha nincs bejelölve a négyzet akkor a megrendelés és a számla sorain a "
+"következő lesz:\n"
+"    Egységár=225, Árengedmény=0,00, Nettó ár=225.\n"
+"    "
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_crm
@@ -16113,6 +16166,13 @@ msgid ""
 "OpenOffice. \n"
 "Once you have modified it you can upload the report using the same wizard.\n"
 msgstr ""
+"\n"
+"Ez a modul együtt lesz használva az OpenERP OpenOffice Pluginnal.\n"
+"=========================================================\n"
+"\n"
+"Ez a modul az Import/Export .sxw kimutatáshoz varázsló ad amit az OpenOffice-"
+"al tud módosítani.. \n"
+"módosítás után ezzel a varázslóval újra fel tudja tölteni a kimutatást.\n"
 
 #. module: base
 #: view:base.module.upgrade:0
@@ -16147,7 +16207,7 @@ msgstr ""
 #. module: base
 #: selection:ir.mail_server,smtp_encryption:0
 msgid "TLS (STARTTLS)"
-msgstr ""
+msgstr "TLS (STARTTLS)"
 
 #. module: base
 #: help:ir.actions.act_window,usage:0
@@ -16818,6 +16878,38 @@ msgid ""
 "* Moves Analysis\n"
 "    "
 msgstr ""
+"\n"
+"Több-raktárhely kezelése, multi- és struktúrált  raktár helyek\n"
+"==============================================================\n"
+"\n"
+"A raktár és leltár kezelés a hierarchikus elhelyezkedés struktúrán alapul, a "
+"raktárhelyből a raktárba kapcsolattal. \n"
+"A dupla bevitelű raktár rendszer lehetővé teszi a vevők és beszállítók "
+"kezelését beleértve a gyártási raktárkészletet is. \n"
+"\n"
+"OpenERP-ben megvan a lehetőség a köteg és gyáriszám kezelésre biztosítva a "
+"nyomon követhetőséget, ami a gyártást szavatolja.\n"
+"\n"
+"Fő jellemzők\n"
+"-------------\n"
+"* Mozgások előzményei és tervezése,\n"
+"* Raktár értékelése (alapár vagy átlagár, ...)\n"
+"* Erőteljesség a raktárkészlet különbségek tükrében\n"
+"* Automata újrarendelés szabályok\n"
+"* Bárkódok támogatása\n"
+"* Gyors hiba érzékelés a dupla beviteli rendszer  miatt\n"
+"* Nyomon követhetőség (ellentétes irányú / Folyamat irányú, Széria számok, "
+"...)\n"
+"\n"
+"Dashboard / Műszerfal kimutatások a Raktárhely kezeléshez ideérve:\n"
+"----------------------------------------------------------\n"
+"* Bejövő áruk (Grafikon)\n"
+"* Kimenő áruk (Grafikon)\n"
+"* Lehetséges beszerzés\n"
+"* Raktári tételek analízisei / elemzései\n"
+"* Záró tételek raktárhelyei\n"
+"* Mozgás analízis, elemzés\n"
+"    "
 
 #. module: base
 #: model:ir.module.module,description:base.module_document_page
@@ -16866,7 +16958,7 @@ msgstr "Gyermek elem mező"
 #. module: base
 #: view:ir.rule:0
 msgid "Detailed algorithm:"
-msgstr ""
+msgstr "Részletes algoritmus:"
 
 #. module: base
 #: field:ir.actions.act_url,usage:0
@@ -16883,7 +16975,7 @@ msgstr "Művelet használata"
 #. module: base
 #: field:ir.module.module,name:0
 msgid "Technical Name"
-msgstr ""
+msgstr "Technikai név"
 
 #. module: base
 #: model:ir.model,name:base.model_workflow_workitem
@@ -16922,7 +17014,7 @@ msgstr "Automatikus betöltés bézet"
 #. module: base
 #: view:res.users:0
 msgid "Allowed Companies"
-msgstr ""
+msgstr "Engedélyezett vállalatok"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_l10n_de
@@ -16932,7 +17024,7 @@ msgstr "Németország - Könyvelés"
 #. module: base
 #: view:ir.sequence:0
 msgid "Day of the Year: %(doy)s"
-msgstr ""
+msgstr "Az év napja: %(doy)s"
 
 #. module: base
 #: field:ir.ui.menu,web_icon:0
@@ -16955,6 +17047,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 ""
+"Ha ez a mező üres, akkor a nézet az összes felhasználóra érvényes. "
+"Egyébként, csak arra a kijelölt csoport felhasználóra vonatkozik a nézet."
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -16988,21 +17082,44 @@ msgid ""
 "customers' expenses if your work by project.\n"
 "    "
 msgstr ""
+"\n"
+"Munkavállalók szerinti kiadások kezelése\n"
+"============================\n"
+"\n"
+"Ez az alkalmazás lehetővé teszi a munkavállalók napi kiadásait. Hozzáférést "
+"biztosít a munkavállalói kiadási jegyzeteihez és azok kiegészítésének és "
+"érvényesítésének jogához vagy érvénytelenítheti is a jegyzeteket. Az "
+"érvényesítés után egy számlát készít a munkavállaló részére.\n"
+"A munkavállalók bevihetik a saját kiadásaikat amit az érvényesítési út "
+"automatikusan felad könyvelésre az osztályvezető érvényesítése után.\n"
+"\n"
+"\n"
+"A teljes folyamat a következő:\n"
+"----------------------------------\n"
+"* Kiadás terve\n"
+"* a munkavállaló visszaigazolása a listára\n"
+"* az osztályvezetője általi érvényesítés\n"
+"* a könyvelő érvényesítése és számla készítés\n"
+"\n"
+"Ez a modul használja az analitikai, elemző számlát és kompatibilis az "
+"időbeosztásos számlázás modullal így automatikus munkavállalói kiadás újra-"
+"számlázást készíthet ha projektenként dolgozik.\n"
+"    "
 
 #. module: base
 #: view:base.language.export:0
 msgid "Export Settings"
-msgstr ""
+msgstr "A beállítások exportálása"
 
 #. module: base
 #: field:ir.actions.act_window,src_model:0
 msgid "Source Model"
-msgstr ""
+msgstr "Modell forrás"
 
 #. module: base
 #: view:ir.sequence:0
 msgid "Day of the Week (0:Monday): %(weekday)s"
-msgstr ""
+msgstr "A hét napja (0:Hétfő): %(weekday)s"
 
 #. module: base
 #: code:addons/base/module/wizard/base_module_upgrade.py:84
@@ -17016,7 +17133,7 @@ msgstr "Függőség nem teljesült !"
 #: code:addons/base/ir/ir_model.py:1023
 #, python-format
 msgid "Administrator access is required to uninstall a module"
-msgstr ""
+msgstr "Adminisztrátori hozzáférés szükséges a modul törléséhez"
 
 #. module: base
 #: model:ir.model,name:base.model_base_module_configuration
@@ -17032,6 +17149,10 @@ msgid ""
 "\n"
 "(Document type: %s, Operation: %s)"
 msgstr ""
+"Az igényelt műveletet nem lehetett végrehajtani biztonsági korlátok miatt. "
+"Kérem vegye fel a kapcsolatot a rendszer adminisztrátorral.\n"
+"\n"
+"(Dokumentum típus: %s, Művelet: %s)"
 
 #. module: base
 #: model:ir.module.module,description:base.module_idea
@@ -17048,6 +17169,19 @@ msgid ""
 "The managers can obtain an easy view of best ideas from all the users.\n"
 "Once installed, check the menu 'Ideas' in the 'Tools' main menu."
 msgstr ""
+"\n"
+"Ez a modul lehetővé teszi a felhasználók könnyű és hatékony vállalati "
+"fejlesztéshez való csatlakozását.\n"
+"============================================================================="
+"==========\n"
+"\n"
+"Lehetővé teszi mindenki számára az ötleteinek közzétételét a különböző "
+"témákban.\n"
+"Ezután, a többi felhasználó megjegyzéseket fűzhet hozzá és szavazhat egy "
+"bizonyos ötletre.\n"
+"Minden ötletnek van egy pontértékelése a szavazatok alapján.\n"
+"A vezető rálát az összes felhasználóra és az ötleteikre.\n"
+"Ha telepítve lett, az 'eszközök' menü 'ötletek' címszó alatt találja az meg."
 
 #. module: base
 #: code:addons/orm.py:5248
@@ -17056,6 +17190,8 @@ msgid ""
 "%s This might be '%s' in the current model, or a field of the same name in "
 "an o2m."
 msgstr ""
+"%s Ez lehet, hogy '%s' a jelenlegi modellben, vagy egy mező ugyanazzal a "
+"névvel az o2m-ben."
 
 #. module: base
 #: model:ir.module.module,description:base.module_account_payment
@@ -17087,6 +17223,29 @@ msgid ""
 "have a new option to import payment orders as bank statement lines.\n"
 "    "
 msgstr ""
+"\n"
+"Modul a beszállítók számlái kifizetésének kezeléséhez.\n"
+"=======================================================\n"
+"\n"
+"Ez a modul lehetővé teszi a kifizetések létrehozását és kezelését, a "
+"következő szándékkal\n"
+"-----------------------------------------------------------------------------"
+"---- \n"
+"    * egy a könnyű plug-in alap variációkból az automatikus kifizetés "
+"működtetésre.\n"
+"    * lehetővé teszi a hatékonyabb számla kifizetés szervezést.\n"
+"\n"
+"Figyelem:\n"
+"~~~~~~~~\n"
+"A kifizetés megbízás visszaigazolása nem készít könyvelés bejegyzést, csak "
+"rögzíti a \n"
+"tényt ,hogy elkészítette a bankhoz a megbízást. A megbízás bevitelét\n"
+"el kell végezni a szokásos módon a banki kivonattal. Azonban, ezt csak\n"
+"akkor, ha megjött a banktól a kivonat, hogy azt a bank befogadta \n"
+"azt és ekkor beviheti azt a könyvelésébe is. Ennek a műveletnek a "
+"segítségéhez, lesz\n"
+"egy új lehetősége a fizetési megbízás importálása mint banki kivonat sorok.\n"
+"    "
 
 #. module: base
 #: field:ir.model,access_ids:0
@@ -17099,7 +17258,7 @@ msgstr "Hozzáférés"
 #: field:res.partner,vat:0
 #, python-format
 msgid "TIN"
-msgstr ""
+msgstr "TIN"
 
 #. module: base
 #: model:res.country,name:base.aw
@@ -17110,7 +17269,7 @@ msgstr "Aruba"
 #: code:addons/base/module/wizard/base_module_import.py:58
 #, python-format
 msgid "File is not a zip file!"
-msgstr ""
+msgstr "A fájl nem zip fájl!"
 
 #. module: base
 #: model:res.country,name:base.ar
@@ -17164,7 +17323,7 @@ msgstr "Haladó kimutatás"
 #. module: base
 #: model:ir.module.module,summary:base.module_purchase
 msgid "Purchase Orders, Receptions, Supplier Invoices"
-msgstr ""
+msgstr "Megrendelések, Átvétel igazolások, Beszállítói számlák"
 
 #. module: base
 #: model:ir.module.module,description:base.module_hr_payroll
@@ -17183,6 +17342,19 @@ msgid ""
 "    * Integrated with Holiday Management\n"
 "    "
 msgstr ""
+"\n"
+"Általános bérszámfejtői rendszer\n"
+"=======================\n"
+"\n"
+"    * Munkavállalók adatai\n"
+"    * Munkavállalók szerződései\n"
+"    * Útlevél alapú szerződés\n"
+"    * Engedmények/Levonások\n"
+"    * Lehetőség az alap/Bruttó/Nettó fizetés beállításához\n"
+"    * Munkavállalók fizetési papírjai\n"
+"    * Havi bérszámfejtési regiszter\n"
+"    * Integrálva a szabadság szervezővel\n"
+"    "
 
 #. module: base
 #: model:ir.model,name:base.model_ir_model_data
@@ -17202,7 +17374,7 @@ msgstr "Értékesítés utáni szolgáltatások"
 #. module: base
 #: field:base.language.import,code:0
 msgid "ISO Code"
-msgstr ""
+msgstr "ISO Kód"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_l10n_fr
@@ -17217,7 +17389,7 @@ msgstr "Indítás"
 #. module: base
 #: selection:res.partner,type:0
 msgid "Shipping"
-msgstr ""
+msgstr "Szállítás"
 
 #. module: base
 #: model:ir.module.module,description:base.module_project_mrp
@@ -17252,6 +17424,30 @@ msgid ""
 "the\n"
 "task is completed.\n"
 msgstr ""
+"\n"
+"Az beszerzéssoraiból automatikusan készít projekt/terv feladatot.\n"
+"===========================================================\n"
+"\n"
+"Ez a modul minden beszerzés igény sorból elkészít egy új feladatot\n"
+"(pl.: a megrendelés sorait), ha a szóban forgó termék kielégíti a következő\n"
+"jellemzőket:\n"
+"\n"
+"    * Termék típusa = Szolgáltatás\n"
+"    * Beszerzés módszere (Megrendelés végrehajtás) = MTO (Rendelés "
+"előkészítése)\n"
+"    * Ellátás/Beszerzés módszer = Gyártás\n"
+"\n"
+"Ezen felül, ha a tervet a termék leírásban meghatározták (a beszerzés "
+"fülön), \n"
+"akkor egy új munka lesz létrehozva ehhez a tervhez. Máskülönben, az új\n"
+"feladat nem függ egyik tervtől sem, és később hozzáadható egy másik tervhez "
+"kézzel.\n"
+"\n"
+"Ha a terv feladat el lett végezve vagy törölve lett, akkor a kapcsolódó "
+"beszerzés \n"
+"munkafolyamat frissítve lesz annak megfelelően. Például, ha ez a beszerzés \n"
+"egy megrendelés sorához tartozik, akkor a megrendelés sora leszállításként \n"
+"értendő, ha a feladatot elvégezték.\n"
 
 #. module: base
 #: field:ir.actions.act_window,limit:0
@@ -17261,13 +17457,13 @@ msgstr "Limit"
 #. module: base
 #: model:res.groups,name:base.group_hr_user
 msgid "Officer"
-msgstr ""
+msgstr "Hivatalnok"
 
 #. module: base
 #: code:addons/orm.py:789
 #, python-format
 msgid "Serialization field `%s` not found for sparse field `%s`!"
-msgstr ""
+msgstr "Soros művelet mező `%s` nem található az elszórt mezőkhöz `%s`!"
 
 #. module: base
 #: model:res.country,name:base.jm
@@ -17278,7 +17474,7 @@ msgstr "Jamaika"
 #: field:res.partner,color:0
 #: field:res.partner.address,color:0
 msgid "Color Index"
-msgstr ""
+msgstr "Szín mutató"
 
 #. module: base
 #: model:ir.actions.act_window,help:base.action_partner_category_form
@@ -17312,12 +17508,26 @@ msgid ""
 "user name and password for the invitation of the survey.\n"
 "    "
 msgstr ""
+"\n"
+"Ez a modul felmérésekhez használható.\n"
+"==================================\n"
+"\n"
+"Ez a különböző felhasználók egyes kérdéseinek a válaszán vagy vizsgálati "
+"szempontjain alapul.\n"
+"Egy felmérésnek több oldala lehet. Mindegyik oldal több kérdést tartalmazhat "
+"és mindegyik\n"
+"kérdésre több választ is tartalmazhat. Különböző felhasználó különböző "
+"választ adhat a \n"
+"különböző kérdésekre ha a felmérés elkészült. Partnerek is küldhetnek emailt "
+"a felhasználó\n"
+"nevével és jelszóval meghívásként a felmérésben való részvételhez.\n"
+"    "
 
 #. module: base
 #: code:addons/base/ir/ir_model.py:163
 #, python-format
 msgid "Model '%s' contains module data and cannot be removed!"
-msgstr ""
+msgstr "Modell '%s' modul adatokat tartalmaz és ezért nem lehet törölni!"
 
 #. module: base
 #: model:res.country,name:base.az
@@ -17334,12 +17544,12 @@ msgstr "Figyelem"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_edi
 msgid "Electronic Data Interchange (EDI)"
-msgstr ""
+msgstr "Elektormos adat kicserélés (EDI)"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_account_anglo_saxon
 msgid "Anglo-Saxon Accounting"
-msgstr ""
+msgstr "Angolszász könyvelés"
 
 #. module: base
 #: model:res.country,name:base.vg
@@ -17365,12 +17575,12 @@ msgstr "Cseh / Čeština"
 #. module: base
 #: model:ir.module.category,name:base.module_category_generic_modules
 msgid "Generic Modules"
-msgstr ""
+msgstr "Általános modulok"
 
 #. module: base
 #: model:res.country,name:base.mk
 msgid "Macedonia, the former Yugoslav Republic of"
-msgstr ""
+msgstr "Macedónia, korábban Jugoszláv Köztársaság"
 
 #. module: base
 #: model:res.country,name:base.rw
@@ -17384,11 +17594,14 @@ msgid ""
 "Allow users to login through OpenID.\n"
 "====================================\n"
 msgstr ""
+"\n"
+"Engedélyezi a felhasználók OpenID általi belépését.\n"
+"====================================\n"
 
 #. module: base
 #: help:ir.mail_server,smtp_port:0
 msgid "SMTP Port. Usually 465 for SSL, and 25 or 587 for other cases."
-msgstr ""
+msgstr "SMTP Port. Rendszerint 465 az SSL, és 25 vagy 587 egyéb esetben."
 
 #. module: base
 #: model:res.country,name:base.ck
@@ -17419,7 +17632,7 @@ msgstr "Jelenlegi ablak"
 #: model:ir.module.category,name:base.module_category_hidden
 #: view:res.users:0
 msgid "Technical Settings"
-msgstr ""
+msgstr "Műszaki beállítások"
 
 #. module: base
 #: model:ir.module.category,description:base.module_category_accounting_and_finance
@@ -17427,16 +17640,18 @@ msgid ""
 "Helps you handle your accounting needs, if you are not an accountant, we "
 "suggest you to install only the Invoicing."
 msgstr ""
+"Segít a könyvelés igényeinek kezelésében, ha Ön nem könyvelő, akkor azt "
+"ajánljuk, hogy csak a számlázást telepítse."
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_plugin_thunderbird
 msgid "Thunderbird Plug-In"
-msgstr ""
+msgstr "Thunderbird kiegészítő plug-in"
 
 #. module: base
 #: model:ir.module.module,summary:base.module_event
 msgid "Trainings, Conferences, Meetings, Exhibitions, Registrations"
-msgstr ""
+msgstr "Képzések, Konferenciák, Találkozók, Kiállítások, Regisztrációk"
 
 #. module: base
 #: model:ir.model,name:base.model_res_country
@@ -17454,7 +17669,7 @@ msgstr "Ország"
 #. module: base
 #: model:res.partner.category,name:base.res_partner_category_15
 msgid "Wholesaler"
-msgstr ""
+msgstr "Nagykereskedő"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_base_vat
@@ -17478,7 +17693,7 @@ msgstr ""
 #. module: base
 #: view:ir.values:0
 msgid "Action Bindings/Defaults"
-msgstr ""
+msgstr "Foglalások/alapértelmezett tevékenységek"
 
 #. module: base
 #: view:base.language.export:0
@@ -17486,6 +17701,8 @@ msgid ""
 "file encoding, please be sure to view and edit\n"
 "                           using the same encoding."
 msgstr ""
+"fájl kódolás, kérem nézze meg és szerkessze\n"
+"                           ugyanazzal a kódolással."
 
 #. module: base
 #: view:ir.rule:0
@@ -17504,7 +17721,7 @@ msgstr "Hollandia - Könyvelés"
 #. module: base
 #: model:res.country,name:base.gs
 msgid "South Georgia and the South Sandwich Islands"
-msgstr ""
+msgstr "Dél-Georgia és a Dél-Sandwich-szigetek"
 
 #. module: base
 #: view:res.lang:0
@@ -17519,12 +17736,12 @@ msgstr "Spanyol (SV) / Español (SV)"
 #. module: base
 #: model:ir.actions.act_window,name:base.open_module_tree
 msgid "Install a Module"
-msgstr ""
+msgstr "Egy modul telepítése"
 
 #. module: base
 #: field:ir.module.module,auto_install:0
 msgid "Automatic Installation"
-msgstr ""
+msgstr "Automata telepítés"
 
 #. module: base
 #: model:ir.module.module,description:base.module_l10n_hn
@@ -17539,6 +17756,18 @@ msgid ""
 "taxes\n"
 "and the Lempira currency."
 msgstr ""
+"\n"
+"Hondurasz számlatükör\n"
+"\n"
+"\n"
+"This is the base module to manage the accounting chart for Honduras.\n"
+"====================================================================\n"
+"    \n"
+"Agrega una nomenclatura contable para Honduras. También incluye impuestos y "
+"la\n"
+"moneda Lempira. -- Adds accounting chart for Honduras. It also includes "
+"taxes\n"
+"and the Lempira currency."
 
 #. module: base
 #: model:res.country,name:base.jp
@@ -17589,6 +17818,29 @@ msgid ""
 "gives \n"
 "       the spreading, for the selected Analytic Accounts of Budgets.\n"
 msgstr ""
+"\n"
+"Ez a modul lehetővé teszi könyvelők részére az analitika/elemzés szervezést "
+"és a keresztváltós költségvetéseket.\n"
+"==========================================================================\n"
+"\n"
+"Ha már a költségvetés meg van határozva (a "
+"Számlák/Költségvetés/Költségvetések alatt), a terv irányító vezető "
+"beállíthatja a tervezett összeget mindegyik analitikai/elemző számlán.\n"
+"\n"
+"A könyvelő láthatja a teljes tervezetet mindegyik költségvetésre annak "
+"biztosítására, hogy ne legyen több/kevesebb költségvetés mint amennyi a "
+"tervezett volt.\n"
+"\n"
+"Három kimutatás lehetséges:\n"
+"----------------------------\n"
+"    1. Az első a költségvetés listákból áll elő. Ez az elemző számlák "
+"költségeinek a kiterjesztése.\n"
+"\n"
+"    2. A második az első összegzése, ez csak az válogatott elemző számlák "
+"költségeinek a kiterjesztése.\n"
+"\n"
+"    3. Az utolsó az elérhető az analitikus/elemző számlatükörből .Ez a "
+"költségek  kiterjesztése a válogatott elemző számlákon.\n"
 
 #. module: base
 #: selection:ir.actions.act_window.view,view_mode:0
@@ -17637,11 +17889,13 @@ msgid ""
 "Ambiguous specification for field '%(field)s', only provide one of name, "
 "external id or database id"
 msgstr ""
+"Kétértelmű meghatározás a mezőre '%(field)s', csak egy nevet adjon meg, "
+"külső azonosító vagy adatbázis azonosító"
 
 #. module: base
 #: field:ir.sequence,implementation:0
 msgid "Implementation"
-msgstr ""
+msgstr "Végrehajtás"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_l10n_ve
@@ -17656,7 +17910,7 @@ msgstr "Chile"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_web_view_editor
 msgid "View Editor"
-msgstr ""
+msgstr "Nézet szerkesztő"
 
 #. module: base
 #: view:ir.cron:0
@@ -17673,7 +17927,7 @@ msgstr "Feltétel"
 #. module: base
 #: help:res.currency,rate:0
 msgid "The rate of the currency to the currency of rate 1."
-msgstr ""
+msgstr "Deviza árfolyam az 1 deviza árfolyamához."
 
 #. module: base
 #: field:ir.ui.view,name:0
@@ -17683,7 +17937,7 @@ msgstr "Nézet neve"
 #. module: base
 #: model:ir.model,name:base.model_res_groups
 msgid "Access Groups"
-msgstr ""
+msgstr "Csoportok hozzáférése"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -17718,6 +17972,22 @@ msgid ""
 "In that case, you can not use priorities any more on the different picking.\n"
 "    "
 msgstr ""
+"\n"
+"Ez a modul lehetővé teszi a Just In Time számítást a beszerzési "
+"megrendelésekhez.\n"
+"==================================================================\n"
+"\n"
+"Ha telepíti ezt a modult, akkor nem kell az általános beszerzési ütemezőt\n"
+"futtatnia többé (de még mindig kell a minimum rendelési pont szabály\n"
+"ütemező, vagy például futtassa naponta).\n"
+"Minden beszerzési megrendelés azonnal futtatva lesz, ami egyes esetekben\n"
+"teljesítmény eséshez vezethet.\n"
+"\n"
+"Ez megemelheti a raktárkészletet mivel a termék le lesz foglalva amint "
+"lehet\n"
+"és az ütemezési idő nem lesz figyelembe véve többé.\n"
+"Ebben az esetben, nem használhat prioritásokat a különböző kiválogatásokon.\n"
+"    "
 
 #. module: base
 #: model:res.country,name:base.hr
@@ -17746,7 +18016,7 @@ msgstr "Rendszer frissítés"
 #: 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 tartalom"
 
 #. module: base
 #: help:ir.sequence,prefix:0
@@ -17761,7 +18031,7 @@ msgstr "Seychelle-szigetek"
 #. module: base
 #: model:res.partner.category,name:base.res_partner_category_4
 msgid "Gold"
-msgstr ""
+msgstr "Arany"
 
 #. module: base
 #: code:addons/base/res/res_company.py:159
@@ -17788,7 +18058,7 @@ msgstr "Általános információk"
 #. module: base
 #: field:ir.model.data,complete_name:0
 msgid "Complete ID"
-msgstr ""
+msgstr "Teljes azonosító"
 
 #. module: base
 #: model:res.country,name:base.tc
@@ -17801,6 +18071,8 @@ msgid ""
 "Tax Identification Number. Check the box if this contact is subjected to "
 "taxes. Used by the some of the legal statements."
 msgstr ""
+"Adó azonosító szám. Jelölje be a négyzetet, ha a kapcsolat adóköteles. Egyes "
+"jogi kifejezések használják."
 
 #. module: base
 #: field:res.partner.bank,partner_id:0
@@ -17827,6 +18099,26 @@ msgid ""
 "depending on the product's configuration.\n"
 "    "
 msgstr ""
+"\n"
+"A beszerzések kiszámítására használ modul.\n"
+"==============================================\n"
+"\n"
+"Az MRP eljárásban, beszerzési rendeléseket a gyártási rendelések, "
+"megrendelések, \n"
+"raktári elhelyezés elindításához használják. Beszerzési rendelések "
+"automatikusan\n"
+"generáltak a rendszerből és ha hiba nem jön közbe, a felhasználó nem\n"
+"is lesz figyelmeztetve. Hiba esetén a rendszer egyes beszerzési kivételt "
+"visz\n"
+"fel az akadályozó problémáról információt küldve a felhasználónak, hogy azt\n"
+"kézzel kell megoldani (mint, darabjegyzék BoM hiánya vagy nem létező "
+"beszállító).\n"
+"\n"
+"A beszerzési rendelés elindít egy javaslatot a feltölteni kívánt termék\n"
+"automatikus beszerzésére. Ez a beszerzés elindít egy tervet, \n"
+"ami vagy a szállító felé egy beszerzés, vagy a termék beállítása szerinti \n"
+"beszerzést.\n"
+"    "
 
 #. module: base
 #: code:addons/base/res/res_users.py:174
@@ -17887,7 +18179,7 @@ msgstr ""
 #. module: base
 #: view:res.partner:0
 msgid "Internal Notes"
-msgstr ""
+msgstr "Belső jegyzetek"
 
 #. module: base
 #: selection:res.partner.address,type:0
@@ -17903,12 +18195,12 @@ msgstr "NyRt."
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_purchase_requisition
 msgid "Purchase Requisitions"
-msgstr ""
+msgstr "Beszerzési igénylések"
 
 #. module: base
 #: selection:ir.actions.act_window,target:0
 msgid "Inline Edit"
-msgstr ""
+msgstr "Lineáris szerkesztés"
 
 #. module: base
 #: selection:ir.cron,interval_type:0
@@ -17951,7 +18243,7 @@ msgstr "Objektum létrehozása"
 #. module: base
 #: model:res.country,name:base.ss
 msgid "South Sudan"
-msgstr ""
+msgstr "Dél-Szudán"
 
 #. module: base
 #: field:ir.filters,context:0
@@ -17961,7 +18253,7 @@ msgstr "Kontextus"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_sale_mrp
 msgid "Sales and MRP Management"
-msgstr ""
+msgstr "Eladás és MRP (Anyagszükséglet Tervezés) szervezése"
 
 #. module: base
 #: model:ir.actions.act_window,help:base.action_partner_form
@@ -17975,6 +18267,15 @@ msgid ""
 "              </p>\n"
 "            "
 msgstr ""
+"<p class=\"oe_view_nocontent_create\">\n"
+"                Kattintson egy kapcsolat hozzáadásához a címtárba.\n"
+"              </p><p>\n"
+"                OpenERP segítséget nyújt az ügyfél tevékenységek könnyű "
+"nyomon követéséhez; \n"
+"                megbeszélések, az üzleti lehetőségek története,\n"
+"                dokumentumok, stb.\n"
+"              </p>\n"
+"            "
 
 #. module: base
 #: model:res.partner.category,name:base.res_partner_category_2
@@ -17984,7 +18285,7 @@ msgstr "Érdeklődő"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_stock_invoice_directly
 msgid "Invoice Picking Directly"
-msgstr ""
+msgstr "Árukiválogatás számlázása közvetlenül"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -18018,6 +18319,15 @@ msgid ""
 "on a supplier purchase order into several accounts and analytic plans.\n"
 "    "
 msgstr ""
+"\n"
+"alap modul az elemző megoszlások és beszerzési megrendelésekhez.\n"
+"====================================================================\n"
+"\n"
+"Lehetővé teszi a felhasználók egyes elemző terveinek karbantartását. Ez "
+"lehetővé\n"
+"teszi a beszállító beszerzési megrendelés sorainak szétválasztását több "
+"számlára és elemző tervekre.\n"
+"    "
 
 #. module: base
 #: model:res.country,name:base.lk
index 6903502..3aad5ec 100644 (file)
@@ -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-18 23:39+0000\n"
+"PO-Revision-Date: 2012-12-20 23:39+0000\n"
 "Last-Translator: Sergio Corato <Unknown>\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-20 04:42+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:38+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
@@ -158,7 +158,7 @@ msgstr ""
 #. module: base
 #: help:res.partner,employee:0
 msgid "Check this box if this contact is an Employee."
-msgstr "Seleziona questo box se il contatto è un Impiegato."
+msgstr "Seleziona questo box se il contatto è un Dipendente."
 
 #. module: base
 #: help:ir.model.fields,domain:0
index 837d51e..e265e98 100644 (file)
@@ -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-19 19:34+0000\n"
+"PO-Revision-Date: 2012-12-20 20:38+0000\n"
 "Last-Translator: Fekete Mihai <mihai@erpsystems.ro>\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-20 04:42+0000\n"
+"X-Launchpad-Export-Date: 2012-12-21 04:38+0000\n"
 "X-Generator: Launchpad (build 16378)\n"
 
 #. module: base
@@ -375,7 +375,7 @@ msgstr ""
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_sale
 msgid "Sales Management"
-msgstr ""
+msgstr "Gestionarea vanzarilor"
 
 #. module: base
 #: help:res.partner,user_id:0
@@ -647,7 +647,7 @@ msgstr "Wizardul urmator"
 #. module: base
 #: field:res.lang,date_format:0
 msgid "Date Format"
-msgstr "Format data"
+msgstr "Formatul Datei"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_base_report_designer
@@ -833,7 +833,7 @@ msgstr "Columbia"
 #. module: base
 #: model:res.partner.title,name:base.res_partner_title_mister
 msgid "Mister"
-msgstr ""
+msgstr "Domnul"
 
 #. module: base
 #: help:res.country,code:0
@@ -862,7 +862,7 @@ msgstr "Netradus(e)"
 #. module: base
 #: view:ir.mail_server:0
 msgid "Outgoing Mail Server"
-msgstr ""
+msgstr "Server Iesire E-mail-uri"
 
 #. module: base
 #: help:ir.actions.act_window,context:0
@@ -896,7 +896,7 @@ msgstr "Mexic - Contabilitate"
 #: help:ir.actions.server,action_id:0
 msgid "Select the Action Window, Report, Wizard to be executed."
 msgstr ""
-"Selectati Fereastra de Actiune, Raport sau Asistent care urmeaza a fi "
+"Selectati Fereastra de Actiune, Raportul sau Asistentul care urmeaza a fi "
 "executat(a)."
 
 #. module: base
@@ -940,6 +940,33 @@ msgid ""
 "module named account_voucher.\n"
 "    "
 msgstr ""
+"\n"
+"Contabilitate si Management Financiar.\n"
+"====================================\n"
+"\n"
+"Modulul Finante si contabilitate acopera:\n"
+"--------------------------------------------\n"
+"    * Contabilitatea Generala\n"
+"    * Costuri/Contabilitatea analitica\n"
+"    * Contabilitatea partii terte\n"
+"    * Gestonarea taxelor si impozitelor\n"
+"    * Bugete\n"
+"    * Facturile Clientului si ale Furnizorului\n"
+"    * Extrase bancare\n"
+"    * Procesul de reconciliere dupa partener\n"
+"\n"
+"Creeaza un panou pentru contabili care include:\n"
+"--------------------------------------------------\n"
+"    Lista cu Facturile Clientilor care trebuie aprobate\n"
+"    Analiza Companiei\n"
+"    Grafic Trezorerie\n"
+"\n"
+"Procesele precum pastrarea unui registru contabil general sunt efectuate "
+"prin Jurnalele financiare definite (linia inregistrarii sau gruparea se face "
+"prin jurnal) \n"
+"pentru un anumit an financiar, iar pentru pregatirea voucher-elor exista un "
+"modul numit account_voucher (cont_voucher).\n"
+"    "
 
 #. module: base
 #: view:ir.model:0
@@ -959,6 +986,16 @@ msgid ""
 "              </p>\n"
 "            "
 msgstr ""
+"<p clasa=\"oe_vizualizare_niciuncontinut_creeaza\">\n"
+"                Faceti click pentru a adauga un contact in agenda "
+"dumneavoastra.\n"
+"              </p><p>\n"
+"                OpenERP va ajuta sa tineti evidenta cu usurinta a tuturor "
+"activitatilor legate de\n"
+"                un client: discutii, istoricul oportunitatilor de afaceri,\n"
+"                documente, etc.\n"
+"              </p>\n"
+"            "
 
 #. module: base
 #: model:ir.module.module,description:base.module_web_linkedin
@@ -969,6 +1006,11 @@ msgid ""
 "This module provides the Integration of the LinkedIn with OpenERP.\n"
 "        "
 msgstr ""
+"\n"
+"Modulul OpenERP Web LinkedIn.\n"
+"============================\n"
+"Acest modul asigura Integrarea lui LinkedIn in OpenERP.\n"
+"        "
 
 #. module: base
 #: help:ir.actions.act_window,src_model:0
@@ -991,7 +1033,7 @@ msgstr "Iordania"
 #. module: base
 #: help:ir.cron,nextcall:0
 msgid "Next planned execution date for this job."
-msgstr "Data urmatoarei executii planificate pentru acest proiect"
+msgstr "Data urmatoarei executii planificate pentru aceasta sarcina."
 
 #. module: base
 #: model:res.country,name:base.er
@@ -1006,7 +1048,7 @@ msgstr "Numele companiei trebuie sa fie unic !"
 #. module: base
 #: model:ir.ui.menu,name:base.menu_base_action_rule_admin
 msgid "Automated Actions"
-msgstr "Actiuni automate"
+msgstr "Actiuni Automate"
 
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_l10n_ro
@@ -1016,7 +1058,7 @@ msgstr "Romania - Contabilitate"
 #. module: base
 #: model:ir.model,name:base.model_res_config_settings
 msgid "res.config.settings"
-msgstr ""
+msgstr "res.configurare.setari"
 
 #. module: base
 #: help:res.partner,image_small:0
@@ -1025,6 +1067,9 @@ msgid ""
 "image, with aspect ratio preserved. Use this field anywhere a small image is "
 "required."
 msgstr ""
+"Imagine de dimensiune mica a acestui contact. Este redimensionata automat ca "
+"o imagine de 64x64px, cu raportul aspect pastrat. Folositi acest camp "
+"oriunde este necesara o imagine mica."
 
 #. module: base
 #: help:ir.actions.server,mobile:0
@@ -1046,7 +1091,7 @@ msgstr "Securitate si Autentificare"
 #. module: base
 #: model:ir.module.module,shortdesc:base.module_web_calendar
 msgid "Web Calendar"
-msgstr ""
+msgstr "Calendar Web"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -1057,7 +1102,7 @@ msgstr "Suedeza / svenska"
 #: field:base.language.export,name:0
 #: field:ir.attachment,datas_fname:0
 msgid "File Name"
-msgstr ""
+msgstr "Nume Fisier"
 
 #. module: base
 #: model:res.country,name:base.rs
@@ -1108,6 +1153,33 @@ msgid ""
 "also possible in order to automatically create a meeting when a holiday "
 "request is accepted by setting up a type of meeting in Leave Type.\n"
 msgstr ""
+"\n"
+"Gestioneaza concediile si cererile de alocare\n"
+"=====================================\n"
+"\n"
+"Aceasta aplicatie controleaza programul de concedii al companiei "
+"dumneavoastra. Le permite angajatilor sa solicite concedii. Astfel, "
+"managerii pot verifica cererile pentru concedii si le pot aproba sau "
+"respinge. In acest mod puteti controla planificarea in ansamblu a "
+"concediilor pentru companie sau departament.\n"
+"\n"
+"Puteti configura diverse tipuri de concedii (de boala, de odihna, zile "
+"platite, ...) si aloca repede concedii unui angajat sau departament folosind "
+"cererile de alocare. Un angajat poate de asemenea sa faca o cerere pentru "
+"mai multe zile libere facand o noua ALocare. Acest lucru va mari totalul "
+"zilelor disponibile pentru acel tip de concediu (daca cererea este "
+"acceptata).\n"
+"\n"
+"Puteti tine evidenta concediilor in diverse moduri urmarind rapoartele: \n"
+"\n"
+"* Rezumat Concedii \n"
+"* Concedii pe Departamente\n"
+"* Analiza Concediilor\n"
+"\n"
+"O sincronizare cu o agenda interna (Intalnirile modulului MRC) este de "
+"asemenea posibila pentru a crea in mod automat o intalnire atunci cand o "
+"cerere de concediu este acceptata prin setarea unui tip de intalnire in "
+"Tipul Concediului.\n"
 
 #. module: base
 #: selection:base.language.install,lang:0
@@ -1155,7 +1227,7 @@ msgstr "Preferinte 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' nu pare a fi o data valabila pentru campul '%%(field)s'"
 
 #. module: base
 #: view:res.partner:0
index a10b38c..47a4cfc 100644 (file)
@@ -24,12 +24,22 @@ from docutils.transforms import Transform, writer_aux
 from docutils.writers.html4css1 import Writer
 import imp
 import logging
+import os
 import re
+import shutil
+import tempfile
 import urllib
+import urllib2
+import zipfile
 import zipimport
 
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO   # NOQA
+
 import openerp
-from openerp import modules, pooler, release, tools, addons
+from openerp import modules, pooler, tools, addons
 from openerp.modules.db import create_categories
 from openerp.tools.parse_version import parse_version
 from openerp.tools.translate import _
@@ -43,14 +53,29 @@ ACTION_DICT = {
     'res_model': 'base.module.upgrade',
     'target': 'new',
     'type': 'ir.actions.act_window',
-    'nodestroy':True,
+    'nodestroy': True,
 }
 
+def backup(path, raise_exception=True):
+    path = os.path.normpath(path)
+    if not os.path.exists(path):
+        if not raise_exception:
+            return None
+        raise OSError('path does not exists')
+    cnt = 1
+    while True:
+        bck = '%s~%d' % (path, cnt)
+        if not os.path.exists(bck):
+            shutil.move(path, bck)
+            return bck
+        cnt += 1
+
+
 class module_category(osv.osv):
     _name = "ir.module.category"
     _description = "Application"
 
-    def _module_nbr(self,cr,uid, ids, prop, unknow_none, context):
+    def _module_nbr(self, cr, uid, ids, prop, unknow_none, context):
         cr.execute('SELECT category_id, COUNT(*) \
                       FROM ir_module_module \
                      WHERE category_id IN %(ids)s \
@@ -58,7 +83,7 @@ class module_category(osv.osv):
                                              FROM ir_module_category \
                                             WHERE parent_id IN %(ids)s) \
                      GROUP BY category_id', {'ids': tuple(ids)}
-                    )
+                   )
         result = dict(cr.fetchall())
         for id in ids:
             cr.execute('select id from ir_module_category where parent_id=%s', (id,))
@@ -71,16 +96,16 @@ class module_category(osv.osv):
         'parent_id': fields.many2one('ir.module.category', 'Parent Application', select=True),
         'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Child Applications'),
         'module_nr': fields.function(_module_nbr, string='Number of Modules', type='integer'),
-        'module_ids' : fields.one2many('ir.module.module', 'category_id', 'Modules'),
-        'description' : fields.text("Description", translate=True),
-        'sequence' : fields.integer('Sequence'),
-        'visible' : fields.boolean('Visible'),
+        'module_ids': fields.one2many('ir.module.module', 'category_id', 'Modules'),
+        'description': fields.text("Description", translate=True),
+        'sequence': fields.integer('Sequence'),
+        'visible': fields.boolean('Visible'),
         'xml_id': fields.function(osv.osv.get_external_id, type='char', size=128, string="External ID"),
     }
     _order = 'name'
 
     _defaults = {
-        'visible' : 1,
+        'visible': 1,
     }
 
 class MyFilterMessages(Transform):
@@ -119,7 +144,6 @@ class module(osv.osv):
         info = {}
         try:
             info = modules.load_information_from_description_file(name)
-            info['version'] = release.major_version + '.' + info['version']
         except Exception:
             _logger.debug('Error when trying to fetch informations for '
                           'module %s', name, exc_info=True)
@@ -134,9 +158,10 @@ class module(osv.osv):
         return res
 
     def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context=None):
-        res = dict.fromkeys(ids, '')
+        default_version = modules.adapt_version('1.0')
+        res = dict.fromkeys(ids, default_version)
         for m in self.browse(cr, uid, ids):
-            res[m.id] = self.get_module_info(m.name).get('version', '')
+            res[m.id] = self.get_module_info(m.name).get('version', default_version)
         return res
 
     def _get_views(self, cr, uid, ids, field_name=None, arg=None, context=None):
@@ -167,9 +192,11 @@ class module(osv.osv):
                 continue
 
             # then, search and group ir.model.data records
-            imd_models = dict( [(m,[]) for m in dmodels])
-            imd_ids = model_data_obj.search(cr,uid,[('module','=', module_rec.name),
-                ('model','in',tuple(dmodels))])
+            imd_models = dict([(m, []) for m in dmodels])
+            imd_ids = model_data_obj.search(cr, uid, [
+                ('module', '=', module_rec.name),
+                ('model', 'in', tuple(dmodels))
+            ])
 
             for imd_res in model_data_obj.read(cr, uid, imd_ids, ['model', 'res_id'], context=context):
                 imd_models[imd_res['model']].append(imd_res['res_id'])
@@ -181,7 +208,7 @@ class module(osv.osv):
                 view_ids = imd_models.get('ir.ui.view', [])
                 for v in view_obj.browse(cr, uid, view_ids, context=context):
                     aa = v.inherit_id and '* INHERIT ' or ''
-                    res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')')
+                    res_mod_dic['views_by_module'].append('%s%s (%s)' % (aa, v.name, v.type))
 
                 report_ids = imd_models.get('ir.actions.report.xml', [])
                 for rx in report_obj.browse(cr, uid, report_ids, context=context):
@@ -191,15 +218,13 @@ class module(osv.osv):
                 for um in menu_obj.browse(cr, uid, menu_ids, context=context):
                     res_mod_dic['menus_by_module'].append(um.complete_name)
             except KeyError, e:
-                _logger.warning(
-                      'Data not found for items of %s', module_rec.name)
+                _logger.warning('Data not found for items of %s', module_rec.name)
             except AttributeError, e:
-                _logger.warning(
-                      'Data not found for items of %s %s', module_rec.name, str(e))
+                _logger.warning('Data not found for items of %s %s', module_rec.name, str(e))
             except Exception, e:
-                _logger.warning('Unknown error while fetching data of %s',
-                      module_rec.name, exc_info=True)
-        for key, _ in res.iteritems():
+                _logger.warning('Unknown error while fetching data of %s', module_rec.name, exc_info=True)
+
+        for key in res.iterkeys():
             for k, v in res[key].iteritems():
                 res[key][k] = "\n".join(sorted(v))
         return res
@@ -232,36 +257,34 @@ class module(osv.osv):
         #   installed_version refer the latest version (the one on disk)
         #   latest_version refer the installed version (the one in database)
         #   published_version refer the version available on the repository
-        'installed_version': fields.function(_get_latest_version,
-            string='Latest Version', type='char'),
+        'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'),
         'latest_version': fields.char('Installed Version', size=64, readonly=True),
         'published_version': fields.char('Published Version', size=64, readonly=True),
 
         'url': fields.char('URL', size=128, readonly=True),
         'sequence': fields.integer('Sequence'),
-        'dependencies_id': fields.one2many('ir.module.module.dependency',
-            'module_id', 'Dependencies', readonly=True),
+        'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True),
         'auto_install': fields.boolean('Automatic Installation',
-            help='An auto-installable module is automatically installed by the '
-            'system when all its dependencies are satisfied. '
-            'If the module has no dependency, it is always installed.'),
+                                       help='An auto-installable module is automatically installed by the '
+                                            'system when all its dependencies are satisfied. '
+                                            'If the module has no dependency, it is always installed.'),
         'state': fields.selection([
-            ('uninstallable','Not Installable'),
-            ('uninstalled','Not Installed'),
-            ('installed','Installed'),
-            ('to upgrade','To be upgraded'),
-            ('to remove','To be removed'),
-            ('to install','To be installed')
+            ('uninstallable', 'Not Installable'),
+            ('uninstalled', 'Not Installed'),
+            ('installed', 'Installed'),
+            ('to upgrade', 'To be upgraded'),
+            ('to remove', 'To be removed'),
+            ('to install', 'To be installed')
         ], string='Status', readonly=True, select=True),
         'demo': fields.boolean('Demo Data', readonly=True),
         'license': fields.selection([
-                ('GPL-2', 'GPL Version 2'),
-                ('GPL-2 or any later version', 'GPL-2 or later version'),
-                ('GPL-3', 'GPL Version 3'),
-                ('GPL-3 or any later version', 'GPL-3 or later version'),
-                ('AGPL-3', 'Affero GPL-3'),
-                ('Other OSI approved licence', 'Other OSI Approved Licence'),
-                ('Other proprietary', 'Other Proprietary')
+            ('GPL-2', 'GPL Version 2'),
+            ('GPL-2 or any later version', 'GPL-2 or later version'),
+            ('GPL-3', 'GPL Version 3'),
+            ('GPL-3 or any later version', 'GPL-3 or later version'),
+            ('AGPL-3', 'Affero GPL-3'),
+            ('Other OSI approved licence', 'Other OSI Approved Licence'),
+            ('Other proprietary', 'Other Proprietary')
         ], string='License', readonly=True),
         'menus_by_module': fields.function(_get_views, string='Menus', type='text', multi="meta", store=True),
         'reports_by_module': fields.function(_get_views, string='Reports', type='text', multi="meta", store=True),
@@ -283,7 +306,7 @@ class module(osv.osv):
         return _('The name of the module must be unique !')
 
     _sql_constraints = [
-        ('name_uniq', 'UNIQUE (name)',_name_uniq_msg ),
+        ('name_uniq', 'UNIQUE (name)', _name_uniq_msg),
     ]
 
     def unlink(self, cr, uid, ids, context=None):
@@ -292,10 +315,9 @@ class module(osv.osv):
         if isinstance(ids, (int, long)):
             ids = [ids]
         mod_names = []
-        for mod in self.read(cr, uid, ids, ['state','name'], context):
+        for mod in self.read(cr, uid, ids, ['state', 'name'], context):
             if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'):
-                raise orm.except_orm(_('Error'),
-                        _('You try to remove a module that is installed or will be installed'))
+                raise orm.except_orm(_('Error'), _('You try to remove a module that is installed or will be installed'))
             mod_names.append(mod['name'])
         #Removing the entry from ir_model_data
         #ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)])
@@ -340,7 +362,7 @@ class module(osv.osv):
             raise orm.except_orm(_('Error'), msg % (module_name, e.args[0]))
 
     def state_update(self, cr, uid, ids, newstate, states_to_update, context=None, level=100):
-        if level<1:
+        if level < 1:
             raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !'))
         demo = False
         for module in self.browse(cr, uid, ids, context=context):
@@ -348,9 +370,9 @@ class module(osv.osv):
             for dep in module.dependencies_id:
                 if dep.state == 'unknown':
                     raise orm.except_orm(_('Error'), _("You try to install module '%s' that depends on module '%s'.\nBut the latter module is not available in your system.") % (module.name, dep.name,))
-                ids2 = self.search(cr, uid, [('name','=',dep.name)])
+                ids2 = self.search(cr, uid, [('name', '=', dep.name)])
                 if dep.state != newstate:
-                    mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level-1,) or mdemo
+                    mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level - 1) or mdemo
                 else:
                     od = self.browse(cr, uid, ids2)[0]
                     mdemo = od.demo or mdemo
@@ -359,7 +381,7 @@ class module(osv.osv):
             if not module.dependencies_id:
                 mdemo = module.demo
             if module.state in states_to_update:
-                self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo})
+                self.write(cr, uid, [module.id], {'state': newstate, 'demo': mdemo})
             demo = demo or mdemo
         return demo
 
@@ -403,7 +425,7 @@ class module(osv.osv):
         return self._button_immediate_function(cr, uid, ids, self.button_install, context=context)
 
     def button_install_cancel(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
+        self.write(cr, uid, ids, {'state': 'uninstalled', 'demo': False})
         return True
 
     def module_uninstall(self, cr, uid, ids, context=None):
@@ -421,12 +443,13 @@ class module(osv.osv):
         return True
 
     def downstream_dependencies(self, cr, uid, ids, known_dep_ids=None,
-                                exclude_states=['uninstalled','uninstallable','to remove'],
+                                exclude_states=['uninstalled', 'uninstallable', 'to remove'],
                                 context=None):
         """Return the ids of all modules that directly or indirectly depend
         on the given module `ids`, and that satisfy the `exclude_states`
         filter"""
-        if not ids: return []
+        if not ids:
+            return []
         known_dep_ids = set(known_dep_ids or [])
         cr.execute('''SELECT DISTINCT m.id
                         FROM
@@ -437,13 +460,13 @@ class module(osv.osv):
                             d.name IN (SELECT name from ir_module_module where id in %s) AND
                             m.state NOT IN %s AND
                             m.id NOT IN %s ''',
-                   (tuple(ids),tuple(exclude_states), tuple(known_dep_ids or ids)))
+                   (tuple(ids), tuple(exclude_states), tuple(known_dep_ids or ids)))
         new_dep_ids = set([m[0] for m in cr.fetchall()])
         missing_mod_ids = new_dep_ids - known_dep_ids
         known_dep_ids |= new_dep_ids
         if missing_mod_ids:
             known_dep_ids |= set(self.downstream_dependencies(cr, uid, list(missing_mod_ids),
-                                                          known_dep_ids, exclude_states,context))
+                                                              known_dep_ids, exclude_states, context))
         return list(known_dep_ids)
 
     def _button_immediate_function(self, cr, uid, ids, function, context=None):
@@ -460,9 +483,9 @@ class module(osv.osv):
         menu_obj = self.pool.get('ir.ui.menu')
         menu_ids = menu_obj.search(cr, uid, [('parent_id', '=', False)], context=context)
         return {
-            'type' : 'ir.actions.client',
-            'tag' : 'reload',
-            'params' : {'menu_id' : menu_ids and menu_ids[0] or False}
+            'type': 'ir.actions.client',
+            'tag': 'reload',
+            'params': {'menu_id': menu_ids and menu_ids[0] or False}
         }
 
     def button_immediate_uninstall(self, cr, uid, ids, context=None):
@@ -496,20 +519,19 @@ class module(osv.osv):
         self.update_list(cr, uid)
 
         i = 0
-        while i<len(todo):
+        while i < len(todo):
             mod = todo[i]
             i += 1
-            if mod.state not in ('installed','to upgrade'):
-                raise orm.except_orm(_('Error'),
-                        _("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
+            if mod.state not in ('installed', 'to upgrade'):
+                raise orm.except_orm(_('Error'), _("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
             self.check_external_dependencies(mod.name, 'to upgrade')
             iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context)
             for dep in depobj.browse(cr, uid, iids, context=context):
-                if dep.module_id.state=='installed' and dep.module_id not in todo:
+                if dep.module_id.state == 'installed' and dep.module_id not in todo:
                     todo.append(dep.module_id)
 
         ids = map(lambda x: x.id, todo)
-        self.write(cr, uid, ids, {'state':'to upgrade'}, context=context)
+        self.write(cr, uid, ids, {'state': 'to upgrade'}, context=context)
 
         to_install = []
         for mod in todo:
@@ -517,7 +539,7 @@ class module(osv.osv):
                 if dep.state == 'unknown':
                     raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,))
                 if dep.state == 'uninstalled':
-                    ids2 = self.search(cr, uid, [('name','=',dep.name)])
+                    ids2 = self.search(cr, uid, [('name', '=', dep.name)])
                     to_install.extend(ids2)
 
         self.button_install(cr, uid, to_install, context=context)
@@ -550,8 +572,9 @@ class module(osv.osv):
 
     # update the list of available packages
     def update_list(self, cr, uid, context=None):
-        res = [0, 0] # [update, add]
+        res = [0, 0]    # [update, add]
 
+        default_version = modules.adapt_version('1.0')
         known_mods = self.browse(cr, uid, self.search(cr, uid, []))
         known_mods_names = dict([(m.name, m) for m in known_mods])
 
@@ -570,7 +593,7 @@ class module(osv.osv):
                         updated_values[key] = values[key]
                 if terp.get('installable', True) and mod.state == 'uninstallable':
                     updated_values['state'] = 'uninstalled'
-                if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
+                if parse_version(terp.get('version', default_version)) > parse_version(mod.latest_version or default_version):
                     res[0] += 1
                 if updated_values:
                     self.write(cr, uid, mod.id, updated_values)
@@ -587,24 +610,32 @@ class module(osv.osv):
             self._update_dependencies(cr, uid, mod, terp.get('depends', []))
             self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
 
+        # Trigger load_addons if new module have been discovered it exists on
+        # wsgi handlers, so they can react accordingly
+        if tuple(res) != (0, 0):
+            for handler in openerp.service.wsgi_server.module_handlers:
+                if hasattr(handler,'load_addons'):
+                    handler.load_addons()
+
         return res
 
     def download(self, cr, uid, ids, download=True, context=None):
         res = []
+        default_version = modules.adapt_version('1.0')
         for mod in self.browse(cr, uid, ids, context=context):
             if not mod.url:
                 continue
             match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
-            version = '0'
+            version = default_version
             if match:
                 version = match.group(1)
-            if parse_version(mod.installed_version or '0') >= parse_version(version):
+            if parse_version(mod.installed_version) >= parse_version(version):
                 continue
             res.append(mod.url)
             if not download:
                 continue
             zip_content = urllib.urlopen(mod.url).read()
-            fname = modules.get_module_path(str(mod.name)+'.zip', downloaded=True)
+            fname = modules.get_module_path(str(mod.name) + '.zip', downloaded=True)
             try:
                 with open(fname, 'wb') as fp:
                     fp.write(zip_content)
@@ -614,17 +645,77 @@ class module(osv.osv):
                 raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
             terp = self.get_module_info(mod.name)
             self.write(cr, uid, mod.id, self.get_values_from_terp(terp))
-            cr.execute('DELETE FROM ir_module_module_dependency ' \
-                    'WHERE module_id = %s', (mod.id,))
-            self._update_dependencies(cr, uid, mod, terp.get('depends',
-                []))
-            self._update_category(cr, uid, mod, terp.get('category',
-                'Uncategorized'))
+            cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (mod.id,))
+            self._update_dependencies(cr, uid, mod, terp.get('depends', []))
+            self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
             # Import module
             zimp = zipimport.zipimporter(fname)
             zimp.load_module(mod.name)
         return res
 
+    def install_from_urls(self, cr, uid, urls, context=None):
+        OPENERP = 'openerp'
+        tmp = tempfile.mkdtemp()
+        try:
+            for module_name, url in urls.items():
+                if not url:
+                    continue    # nothing to download, local version is already the last one
+                try:
+                    content = urllib2.urlopen(url).read()
+                except Exception, e:
+                    _logger.exception('ggr')
+                    raise osv.except_osv('grrr', e)
+                else:
+                    zipfile.ZipFile(StringIO(content)).extractall(tmp)
+                    assert os.path.isdir(os.path.join(tmp, module_name))
+
+            for module_name in urls:
+                if module_name == OPENERP:
+                    continue    # special case. handled below
+                module_path = modules.get_module_path(module_name, downloaded=True, display_warning=False)
+                bck = backup(module_path, False)
+                shutil.move(os.path.join(tmp, module_name), module_path)
+                if bck:
+                    shutil.rmtree(bck)
+
+            if urls.get(OPENERP, None):
+                # special case. it containt the server and the base module.
+                # extract path is not the same
+
+                base_path = os.path.dirname(modules.get_module_path('base'))
+
+                # copy all modules in the SERVER/openerp/addons directory to the new "openerp" module (except base itself)
+                for d in os.listdir(base_path):
+                    if d != 'base' and os.path.isdir(os.path.join(base_path, d)):
+                        destdir = os.path.join(tmp, OPENERP, 'addons', d)    # XXX 'openerp' subdirectory ?
+                        shutil.copytree(os.path.join(base_path, d), destdir)
+
+                # then replace the server by the new "base" module
+                server_dir = openerp.tools.config['root_path']      # XXX or dirname()
+                bck = backup(server_dir)
+                shutil.move(os.path.join(tmp, OPENERP), server_dir)
+                #if bck:
+                #    shutil.rmtree(bck)
+
+            self.update_list(cr, uid, context=context)
+
+            ids = self.search(cr, uid, [('name', 'in', urls.keys())], context=context)
+            if self.search_count(cr, uid, [('id', 'in', ids), ('state', '=', 'installed')], context=context):
+                # if any to update
+                cr.commit()
+                openerp.service.restart_server()
+                return {
+                    'type': 'ir.actions.client',
+                    'tag': 'home',
+                    'params': {'wait': True},
+                }
+            return self.button_immediate_install(cr, uid, ids, context=context)
+        finally:
+            shutil.rmtree(tmp)
+
+    def install_by_names(self, cr, uid, names, context=None):
+        raise NotImplementedError('# TODO')
+
     def _update_dependencies(self, cr, uid, mod_browse, depends=None):
         if depends is None:
             depends = []
@@ -679,20 +770,20 @@ class module_dependency(osv.osv):
 
     _columns = {
         # The dependency name
-        'name': fields.char('Name',  size=128, select=True),
+        'name': fields.char('Name', size=128, select=True),
 
         # The module that depends on it
         'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'),
 
         'state': fields.function(_state, type='selection', selection=[
-            ('uninstallable','Uninstallable'),
-            ('uninstalled','Not Installed'),
-            ('installed','Installed'),
-            ('to upgrade','To be upgraded'),
-            ('to remove','To be removed'),
-            ('to install','To be installed'),
+            ('uninstallable', 'Uninstallable'),
+            ('uninstalled', 'Not Installed'),
+            ('installed', 'Installed'),
+            ('to upgrade', 'To be upgraded'),
+            ('to remove', 'To be removed'),
+            ('to install', 'To be installed'),
             ('unknown', 'Unknown'),
-            ], string='Status', readonly=True, select=True),
+        ], string='Status', readonly=True, select=True),
     }
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index 5f33a43..3a43a25 100644 (file)
@@ -1,9 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <openerp>
     <data>
-
         <!-- Modules Categories -->
-
         <record id="view_module_category_form" model="ir.ui.view">
             <field name="name">ir.module.category.form</field>
             <field name="model">ir.module.category</field>
@@ -32,7 +30,6 @@
         </record>
 
         <!-- Click on a category -->
-
         <record id="view_module_filter" model="ir.ui.view">
             <field name="name">ir.module.module.list.select</field>
             <field name="model">ir.module.module</field>
@@ -43,7 +40,7 @@
                     <filter name="app" icon="terp-check" string="Apps" domain="[('application', '=', 1)]"/>
                     <filter name="extra" icon="terp-check" string="Extra" domain="[('application', '=', 0)]"/>
                     <separator/>
-                    <filter icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
+                    <filter name="installed" icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
                     <filter icon="terp-dialog-close" string="Not Installed" domain="[('state', 'in', ['uninstalled', 'uninstallable', 'to install'])]"/>
                     <field name="category_id"/>
                     <group expand="0" string="Group By...">
                </search>
             </field>
         </record>
-
-        <record model="ir.ui.view" id="module_view_kanban">
-            <field name="name">Modules Kanban</field>
-            <field name="model">ir.module.module</field>
-            <field name="arch" type="xml">
-                <kanban create="false">
-                  <field name="icon"/>
-                  <field name="name"/>
-                  <field name="state"/>
-                  <field name="summary"/>
-                  <templates>
-                    <t t-name="kanban-box">
-                      <div class="oe_module_vignette">
-                        <t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
-                        <img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
-                        <div class="oe_module_desc">
-                          <h4><a type="open"><field name="shortdesc"/></a></h4>
-                          <p class="oe_module_name">
-                             <t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
-                             <i><field name="name" groups="base.group_no_one"/></i>
-                          </p>
-                          <button type="object" name="button_immediate_install" states="uninstalled">Install</button>
-                          <button t-if="installed" disabled="disabled">Installed</button>
-                        </div>
-                      </div>
-                    </t>
-                  </templates>
-                </kanban>
-            </field>
-        </record>
-
         <record id="action_module_open_categ" model="ir.actions.act_window">
             <field name="name">Modules</field>
             <field name="res_model">ir.module.module</field>
 
 
         <!-- Modules -->
-
         <record id="module_form" model="ir.ui.view">
             <field name="name">ir.module.module.form</field>
             <field name="model">ir.module.module</field>
                 </tree>
             </field>
         </record>
+        <record model="ir.ui.view" id="module_view_kanban">
+            <field name="name">Modules Kanban</field>
+            <field name="model">ir.module.module</field>
+            <field name="arch" type="xml">
+                <kanban create="false">
+                  <field name="icon"/>
+                  <field name="name"/>
+                  <field name="state"/>
+                  <field name="summary"/>
+                  <templates>
+                    <t t-name="kanban-box">
+                      <div class="oe_module_vignette">
+                        <t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
+                        <img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
+                        <div class="oe_module_desc">
+                          <h4><a type="open"><field name="shortdesc"/></a></h4>
+                          <p class="oe_module_name">
+                             <t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
+                             <i><field name="name" groups="base.group_no_one"/></i>
+                          </p>
+                          <button type="object" name="button_immediate_install" states="uninstalled">Install</button>
+                          <button t-if="installed" disabled="disabled">Installed</button>
+                        </div>
+                      </div>
+                    </t>
+                  </templates>
+                </kanban>
+            </field>
+        </record>
         <record id="open_module_tree" model="ir.actions.act_window">
-            <field name="name">Install a Module</field>
+            <!-- uncomment on released
+            <field name="name">Installed Modules</field>
+            -->
+            <field name="name">Modules</field>
             <field name="res_model">ir.module.module</field>
             <field name="view_type">form</field>
             <field name="view_mode">kanban,tree,form</field>
-            <field name="context">{'search_default_app':1}</field>
+            <!-- uncomment on released
+            <field name="context">{'search_default_installed':1}</field>
+            -->
             <field name="search_view_id" ref="view_module_filter"/>
             <field name="help" type="html">
               <p><b>No module found!</b></p>
               <p>You should try others search criteria.</p>
             </field>
         </record>
-        <menuitem id="menu_module_tree" parent="base.menu_management" name="Modules"
-            sequence="1" action="open_module_tree"/>
+        <menuitem id="menu_module_tree" parent="menu_management" name="Installed Modules" sequence="10" action="open_module_tree"/>
+
+
+        <!-- Apps modules -->
+        <record model="ir.actions.client" id="modules_act_cl">
+            <field name="name">Apps</field>
+            <field name="tag">apps</field>
+        </record>
+        <!-- uncomment on released
+        <menuitem id="module_mi" parent="base.menu_management" sequence="3" action="modules_act_cl"/>
+        -->
+        <menuitem id="module_mi" parent="base.menu_management" sequence="20" action="modules_act_cl"/>
+
+        <record model="ir.actions.client" id="modules_updates_act_cl">
+            <field name="name">Updates</field>
+            <field name="tag">apps.updates</field>
+            <field name="params">{}</field>
+        </record>
+        <!-- uncomment on released
+        <menuitem id="menu_module_updates" parent="base.menu_management" sequence="7" action="modules_updates_act_cl"/>
+        -->
+        <menuitem id="menu_module_updates" parent="base.menu_management" sequence="30" action="modules_updates_act_cl"/>
 
     </data>
 </openerp>
index cbf7104..f184186 100644 (file)
@@ -11,7 +11,7 @@
                     <group states="choose" string="Export Settings">
                         <field name="lang"/>
                         <field name="format"/>
-                        <field name="modules"/>
+                        <field name="modules" widget="many2many_tags"/>
                     </group>
                     <div states="get">
                         <h2>Export Complete</h2>
index 192bf6c..d9d6bb6 100644 (file)
@@ -43,7 +43,7 @@
             id="menu_view_base_module_import"
             parent="menu_management"
             groups="base.group_no_one"
-            sequence="1"/>
+            sequence="6"/>
     -->
 
     </data>
index 75d2b13..cb9b909 100644 (file)
                     </group>
                     <footer>
                         <div states="init">
-                            <button name="update_module" string="Update" type="object" class="oe_highlight"/> or 
+                            <button name="update_module" string="Update" type="object" class="oe_highlight"/> or
                             <button special="cancel" string="Cancel" class="oe_link"/>
                         </div>
                         <div states="done">
-                            <button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or 
+                            <button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or
                             <button special="cancel" string="Close" class="oe_link"/>
                         </div>
                     </footer>
                 </form>
             </field>
-        </record>        
+        </record>
 
         <record id="action_view_base_module_update" model="ir.actions.act_window">
             <field name="name">Module Update</field>
@@ -45,7 +45,7 @@
             id="menu_view_base_module_update"
             groups="base.group_no_one"
             parent="menu_management"
-            sequence="2"
+            sequence="40"
             icon="STOCK_CONVERT"/>
 
     </data>
index afd3a2e..1a1225b 100644 (file)
@@ -35,7 +35,7 @@
            groups="base.group_no_one"
            id="menu_view_base_module_upgrade"
            parent="menu_management"
-           sequence="3"/>
+           sequence="50"/>
 
        <record id="view_base_module_upgrade_install" model="ir.ui.view">
             <field name="name">Module Upgrade Install</field>
index 752bb03..5940354 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
-#    
+#
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
 #
@@ -15,7 +15,7 @@
 #    GNU Affero General Public License for more details.
 #
 #    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
@@ -32,6 +32,7 @@ import res_lang
 import ir_property
 
 import report
+import wizard
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
index 9513f48..e9c813c 100644 (file)
@@ -466,7 +466,8 @@ class res_config_settings(osv.osv_memory):
                 groups.append((name, ref(field_group), ref(field.implied_group)))
             elif name.startswith('module_') and isinstance(field, fields.boolean):
                 mod_ids = ir_module.search(cr, uid, [('name', '=', name[7:])])
-                modules.append((name, ir_module.browse(cr, uid, mod_ids[0], context)))
+                record = ir_module.browse(cr, uid, mod_ids[0], context) if mod_ids else None
+                modules.append((name, record))
             else:
                 others.append(name)
 
@@ -490,7 +491,7 @@ class res_config_settings(osv.osv_memory):
 
         # modules: which modules are installed/to install
         for name, module in classified['module']:
-            res[name] = module.state in ('installed', 'to install', 'to upgrade')
+            res[name] = module and module.state in ('installed', 'to install', 'to upgrade')
 
         # other fields: call all methods that start with 'get_default_'
         for method in dir(self):
@@ -501,9 +502,7 @@ class res_config_settings(osv.osv_memory):
 
     def execute(self, cr, uid, ids, context=None):
         ir_values = self.pool.get('ir.values')
-        ir_model_data = self.pool.get('ir.model.data')
         ir_module = self.pool.get('ir.module.module')
-        res_groups = self.pool.get('res.groups')
         classified = self._get_classified_fields(cr, uid, context)
 
         config = self.browse(cr, uid, ids[0], context)
@@ -526,17 +525,26 @@ class res_config_settings(osv.osv_memory):
                 getattr(self, method)(cr, uid, ids, context)
 
         # module fields: install/uninstall the selected modules
-        to_install_ids = []
+        to_install_names = []
         to_uninstall_ids = []
+        lm = len('module_')
         for name, module in classified['module']:
             if config[name]:
-                if module.state == 'uninstalled': to_install_ids.append(module.id)
+                if not module or module.state == 'uninstalled':
+                    to_install_names.append(name[lm:])
             else:
-                if module.state in ('installed','upgrade'): to_uninstall_ids.append(module.id)
-
-        if to_install_ids or to_uninstall_ids:
-            ir_module.button_uninstall(cr, uid, to_uninstall_ids, context=context)
-            ir_module.button_immediate_install(cr, uid, to_install_ids, context=context)
+                if module and module.state in ('installed', 'to upgrade'):
+                    to_uninstall_ids.append(module.id)
+
+        if to_uninstall_ids:
+            ir_module.button_immediate_uninstall(cr, uid, to_uninstall_ids, context=context)
+
+        if to_install_names:
+            return {
+                'type': 'ir.actions.client',
+                'tag': 'apps',
+                'params': {'modules': to_install_names},
+            }
 
         config = self.pool.get('res.config').next(cr, uid, [], context=context) or {}
         if config.get('type') not in ('ir.actions.act_window_close',):
index d236d86..65bcf18 100644 (file)
@@ -402,6 +402,8 @@ class res_partner(osv.osv, format_address):
                 name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context)
                 name = name.replace('\n\n','\n')
                 name = name.replace('\n\n','\n')
+            if context.get('show_email') and record.email:
+                name = "%s <%s>" % (name, record.email)
             res.append((record.id, name))
         return res
 
@@ -437,18 +439,23 @@ class res_partner(osv.osv, format_address):
     def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
         if not args:
             args = []
-        if name and operator in ('=', 'ilike', '=ilike', 'like'):
+        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
             # search on the name of the contacts and of its company
-            name2 = operator == '=' and name or '%' + name + '%'
+            search_name = name
+            if operator in ('ilike', 'like'):
+                search_name = '%%%s%%' % name
+            if operator in ('=ilike', '=like'):
+                operator = operator[1:]
+            query_args = {'name': search_name}
             limit_str = ''
-            query_args = [name2]
             if limit:
-                limit_str = ' limit %s'
-                query_args += [limit]
+                limit_str = ' limit %(limit)s'
+                query_args['limit'] = limit
             cr.execute('''SELECT partner.id FROM res_partner partner
                           LEFT JOIN res_partner company ON partner.parent_id = company.id
-                          WHERE partner.name || ' (' || COALESCE(company.name,'') || ')'
-                          ''' + operator + ''' %s ''' + limit_str, query_args)
+                          WHERE partner.email ''' + operator +''' %(name)s
+                             OR partner.name || ' (' || COALESCE(company.name,'') || ')'
+                          ''' + operator + ' %(name)s ' + limit_str, query_args)
             ids = map(lambda x: x[0], cr.fetchall())
             if args:
                 ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
index 9a4f88c..7e83b43 100644 (file)
                 <form string="Users" version="7.0">
                     <field name="id" invisible="1"/>
                     <sheet>
+                        <div class="oe_right oe_button_box">
+                            <button string="Change Password" type="action" name="%(change_password_wizard_action)d"
+                                help="Change the user password."/>
+                        </div>
                         <field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/>
                         <div class="oe_title">
                             <label for="name" class="oe_edit_only"/>
                         </div>
                         <group>
                             <group>
-                                <field name="new_password" password="True" attrs="{'required': [('id','=',False)]}"/>
                                 <field name="company_id" context="{'user_preference': 0}"/>
                             </group>
                             <group>
diff --git a/openerp/addons/base/res/wizard/__init__.py b/openerp/addons/base/res/wizard/__init__.py
new file mode 100644 (file)
index 0000000..f572814
--- /dev/null
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import change_password_wizard
\ No newline at end of file
diff --git a/openerp/addons/base/res/wizard/change_password_wizard.py b/openerp/addons/base/res/wizard/change_password_wizard.py
new file mode 100644 (file)
index 0000000..4d1bfe6
--- /dev/null
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, osv
+
+class change_password_wizard(osv.TransientModel):
+    """
+        A wizard to manage the change of users' passwords
+    """
+
+    _name = "change.password.wizard"
+    _description = "Change Password Wizard"
+    _columns = {
+        'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'),
+    }
+
+    def default_get(self, cr, uid, fields, context=None):
+        if context == None:
+            context = {}
+        user_ids = context.get('active_ids', [])
+        wiz_id = context.get('active_id', None)
+        res = []
+        users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context)
+        for user in users:
+            res.append((0, 0, {
+                'wizard_id': wiz_id,
+                'user_id': user.id,
+                'user_login': user.login,
+            }))
+        return {'user_ids': res}
+
+
+    def change_password_button(self, cr, uid, id, context=None):
+        wizard = self.browse(cr, uid, id, context=context)[0]
+        user_ids = []
+        for user in wizard.user_ids:
+            user_ids.append(user.id)
+        self.pool.get('change.password.user').change_password_button(cr, uid, user_ids, context=context)
+        return {
+            'type': 'ir.actions.act_window_close',
+        }
+
+class change_password_user(osv.TransientModel):
+    """
+        A model to configure users in the change password wizard
+    """
+
+    _name = 'change.password.user'
+    _description = 'Change Password Wizard User'
+    _columns = {
+        'wizard_id': fields.many2one('change.password.wizard', string='Wizard', required=True),
+        'user_id': fields.many2one('res.users', string='User', required=True),
+        'user_login': fields.char('User Login', readonly=True),
+        'new_passwd': fields.char('New Password'),
+    }
+    _defaults = {
+        'new_passwd': '',
+    }
+
+    def change_password_button(self, cr, uid, ids, context=None):
+        for user in self.browse(cr, uid, ids, context=context):
+            self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd})
+
diff --git a/openerp/addons/base/res/wizard/change_password_wizard_view.xml b/openerp/addons/base/res/wizard/change_password_wizard_view.xml
new file mode 100644 (file)
index 0000000..c5bd5c9
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <!-- wizard action on res.users -->
+        <act_window id="change_password_wizard_action"
+            name="Change Password"
+            src_model="res.users"
+            res_model="change.password.wizard"
+            view_type="form" view_mode="form"
+            key2="client_action_multi" target="new"
+            groups="base.group_erp_manager"/>
+
+        <!-- wizard view -->
+        <record id="change_password_wizard_view" model="ir.ui.view">
+            <field name="name">Change Password</field>
+            <field name="model">change.password.wizard</field>
+            <field name="arch" type="xml">
+                <form string="Change Password" version="7.0">
+                    <field name="user_ids"/>
+                    <footer>
+                        <button string="Change Password" name="change_password_button" type="object" class="oe_highlight"/>
+                        or
+                        <button string="Cancel" class="oe_link" special="cancel" />
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+        <!-- wizard user list view -->
+        <record id="change_password_wizard_user_tree_view" model="ir.ui.view">
+            <field name="name">Change Password Users</field>
+            <field name="model">change.password.user</field>
+            <field name="arch" type="xml">
+                <!-- the user list is editable, but one cannot add or delete rows -->
+                <tree string="Users" editable="bottom" create="false" delete="false">
+                    <field name="user_login"/>
+                    <field name="new_passwd" required="True"/>
+                </tree>
+            </field>
+        </record>
+
+    </data>
+</openerp>
diff --git a/openerp/addons/base/static/src/js/apps.js b/openerp/addons/base/static/src/js/apps.js
new file mode 100644 (file)
index 0000000..397f028
--- /dev/null
@@ -0,0 +1,117 @@
+openerp.base = function(instance) {
+
+    instance.base.apps_remote = null;
+    instance.base.apps_client = null;
+
+    instance.base.Apps = instance.web.Widget.extend({
+        template: 'EmptyComponent',
+        remote_action_id: 'loempia.action_embed',
+        failback_action_id: 'base.open_module_tree',
+
+        init: function(parent, action) {
+            this._super(parent, action);
+            var options = action.params || {};
+
+            if (options.apps_user) {
+                sessionStorage.setItem('apps.login', options.apps_user);
+            }
+            if (options.apps_access_token) {
+                sessionStorage.setItem('apps.access_token', options.apps_access_token);
+            }
+
+            this.params = options; // NOTE read by embedded client action
+        },
+
+        get_client: function() {
+            // return the client via a deferred, resolved or rejected depending if the remote host is available or not.
+            var check_client_available = function(client) {
+                var d = $.Deferred();
+                var i = new Image();
+                i.onerror = function() {
+                    d.reject(client);
+                };
+                i.onload = function() {
+                    client.session.session_bind(client.origin).then(function() {
+                        // check if client can authenticate
+                        client.authenticate().then(
+                           function() {     /* done */
+                            d.resolve(client);
+                        }, function() {     /* fail */
+                            if (client.login === 'anonymous') {
+                                d.reject(client);
+                            } else {
+                                sessionStorage.removeItem('apps.login');
+                                sessionStorage.removeItem('apps.access_token');
+                                client.bind_crendentials(client.dbname, 'anonymous', 'anonymous');
+                                client.authenticate().then(
+                                   function() {     /* done */
+                                    d.resolve(client);
+                                }, function() {     /* fail */
+                                    d.reject(client);
+                                });
+                            }
+                        });
+                    });
+
+                };
+                i.src = _.str.sprintf('%s/web/static/src/img/sep-a.gif', client.origin);
+                return d.promise();
+            };
+            if (instance.base.apps_client) {
+                return check_client_available(instance.base.apps_client);
+            } else {
+                var ICP = new instance.web.Model('ir.config_parameter');
+                return ICP.call('get_param', ['apps.server', 'https://apps.openerp.com/apps']).then(function(u) {
+                    var link = $(_.str.sprintf('<a href="%s"></a>', u))[0];
+                    var host = _.str.sprintf('%s//%s', link.protocol, link.host);
+                    var dbname = link.pathname;
+                    if (dbname[0] === '/') {
+                        dbname = dbname.substr(1);
+                    }
+                    var login = (sessionStorage ? sessionStorage.getItem('apps.login') : null) || 'anonymous';
+                    var passwd = (sessionStorage ? sessionStorage.getItem('apps.access_token') : null) || 'anonymous';
+                    if (_.isNull(instance.base.apps_remote)) {
+                        instance.base.apps_remote = new openerp.init();
+                    }
+                    var client = new instance.base.apps_remote.web.EmbeddedClient(null, host, dbname, login, passwd);
+                    instance.base.apps_client = client;
+                    return check_client_available(client);
+                });
+            }
+        },
+
+        destroy: function() {
+            if (instance.base.apps_client) {
+                instance.base.apps_client.destroy();
+            }
+            return this._super();
+        },
+
+        start: function() {
+            var self = this;
+            return self.get_client().
+                done(function(client) {
+                    client.replace(self.$el).
+                        done(function() {
+                            client.$el.removeClass('openerp');
+                            client.do_action(self.remote_action_id);
+                        });
+                }).
+                fail(function(client) {
+                    self.do_warn('Apps Server not reachable.', 'Showing local modules.', true);
+                    self.rpc('/web/action/load', {action_id: self.failback_action_id}).done(function(action) {
+                        self.do_action(action);
+                        instance.webclient.menu.open_action(action.id);
+                    });
+                });
+        },
+    });
+
+    instance.base.AppsUpdates = instance.base.Apps.extend({
+        remote_action_id: 'loempia.action_embed_updates'
+    });
+
+    instance.web.client_actions.add("apps", "instance.base.Apps");
+    instance.web.client_actions.add("apps.updates", "instance.base.AppsUpdates");
+
+};
index d97d4c8..bc83b73 100644 (file)
@@ -207,10 +207,15 @@ def quit_on_signals():
         pass
 
     config = openerp.tools.config
+    openerp.service.stop_services()
+
+    if getattr(openerp, 'phoenix', False):
+        # like the phoenix, reborn from ashes...
+        openerp.service._reexec()
+        return
+
     if config['pidfile']:
         os.unlink(config['pidfile'])
-
-    openerp.service.stop_services()
     sys.exit(0)
 
 def configure_babel_localedata_path():
index 56265e3..feaf014 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#    Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -32,7 +32,8 @@ from openerp.modules.module import \
     load_information_from_description_file, \
     get_module_resource, zip_directory, \
     get_module_path, initialize_sys_path, \
-    load_openerp_module, init_module_models
+    load_openerp_module, init_module_models, \
+    adapt_version
 
 from openerp.modules.loading import load_modules
 
index bb4ff48..98955af 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#    Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+#    Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -329,7 +329,7 @@ def load_information_from_description_file(module):
                 'license': 'AGPL-3',
                 'name': False,
                 'post_load': None,
-                'version': '0.0.0',
+                'version': '1.0',
                 'web': False,
                 'website': '',
                 'sequence': 100,
@@ -349,6 +349,7 @@ def load_information_from_description_file(module):
                 # 'active' has been renamed 'auto_install'
                 info['auto_install'] = info['active']
 
+            info['version'] = adapt_version(info['version'])
             return info
 
     #TODO: refactor the logger in this file to follow the logging guidelines
@@ -447,15 +448,22 @@ def get_modules():
 
 def get_modules_with_version():
     modules = get_modules()
-    res = {}
+    res = dict.fromkeys(modules, adapt_version('1.0'))
     for module in modules:
         try:
             info = load_information_from_description_file(module)
-            res[module] = "%s.%s" % (release.major_version, info['version'])
-        except Exception, e:
+            res[module] = info['version']
+        except Exception:
             continue
     return res
 
+def adapt_version(version):
+    serie = release.major_version
+    if version == serie or not version.startswith(serie + '.'):
+        version = '%s.%s' % (serie, version)
+    return version
+
+
 def get_test_modules(module, submodule, explode):
     """
     Return a list of submodules containing tests.
index 50d9b8a..e66d924 100644 (file)
@@ -50,4 +50,6 @@ author = 'OpenERP S.A.'
 author_email = 'info@openerp.com'
 license = 'AGPL-3'
 
+nt_service_name = "openerp-server-" + serie
+
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index f875273..307ee4a 100644 (file)
 ##############################################################################
 
 import logging
+import os
+import signal
+import subprocess
+import sys
 import threading
 import time
 
@@ -33,6 +37,7 @@ import wsgi_server
 import openerp.modules
 import openerp.netsvc
 import openerp.osv
+from openerp.release import nt_service_name
 import openerp.tools
 
 #.apidoc title: RPC Services
@@ -97,27 +102,58 @@ def stop_services():
 
     _logger.info("Initiating shutdown")
     _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.")
-    logging.shutdown()
 
     # Manually join() all threads before calling sys.exit() to allow a second signal
     # to trigger _force_quit() in case some non-daemon threads won't exit cleanly.
     # threading.Thread.join() should not mask signals (at least in python 2.5).
     me = threading.currentThread()
+    _logger.debug('current thread: %r', me)
     for thread in threading.enumerate():
+        _logger.debug('process %r (%r)', thread, thread.isDaemon())
         if thread != me and not thread.isDaemon() and thread.ident != main_thread_id:
             while thread.isAlive():
+                _logger.debug('join and sleep')
                 # Need a busyloop here as thread.join() masks signals
                 # and would prevent the forced shutdown.
                 thread.join(0.05)
                 time.sleep(0.05)
 
+    _logger.debug('--')
     openerp.modules.registry.RegistryManager.delete_all()
+    logging.shutdown()
 
 def start_services_workers():
     import openerp.service.workers
     openerp.multi_process = True
-
     openerp.service.workers.Multicorn(openerp.service.wsgi_server.application).run()
 
+def _reexec():
+    """reexecute openerp-server process with (nearly) the same arguments"""
+    if openerp.tools.osutil.is_running_as_nt_service():
+        subprocess.call('sc stop {0} && sc start {0}'.format(nt_service_name), shell=True)
+    exe = os.path.basename(sys.executable)
+    strip_args = ['-d', '-u']
+    a = sys.argv[:]
+    args = [x for i, x in enumerate(a) if x not in strip_args and a[max(i - 1, 0)] not in strip_args]
+    if not args or args[0] != exe:
+        args.insert(0, exe)
+    os.execv(sys.executable, args)
+
+def restart_server():
+    if openerp.multi_process:
+        raise NotImplementedError("Multicorn is not supported (but gunicorn was)")
+        pid = openerp.wsgi.core.arbiter_pid
+        os.kill(pid, signal.SIGHUP)
+    else:
+        if os.name == 'nt':
+            def reborn():
+                stop_services()
+                _reexec()
+
+            # run in a thread to let the current thread return response to the caller.
+            threading.Thread(target=reborn).start()
+        else:
+            openerp.phoenix = True
+            os.kill(os.getpid(), signal.SIGINT)
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index 5b88e0f..940ecdb 100644 (file)
@@ -54,7 +54,12 @@ from openerp import SUPERUSER_ID
 
 _logger = logging.getLogger(__name__)
 
-RPC_VERSION_1 = {'server_version': '6.1', 'protocol_version': 1}
+RPC_VERSION_1 = {
+        'server_version': release.version,
+        'server_version_info': release.version_info,
+        'server_serie': release.serie,
+        'protocol_version': 1,
+}
 
 # This should be moved to openerp.modules.db, along side initialize().
 def _initialize_db(serv, id, db_name, demo, lang, user_password):
@@ -120,6 +125,12 @@ class db(netsvc.ExportService):
         db = sql_db.db_connect('postgres')
         cr = db.cursor()
         chosen_template = tools.config['db_template']
+        cr.execute("""SELECT datname 
+                              FROM pg_database
+                              WHERE datname = %s """,
+                           (name,))
+        if cr.fetchall():
+            raise openerp.exceptions.Warning(" %s database already exists!" % name )
         try:
             cr.autocommit(True) # avoid transaction block
             cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "%s" """ % (name, chosen_template))
index f6d7a05..67436a1 100644 (file)
@@ -442,5 +442,6 @@ def stop_service():
     """
     if httpd:
         httpd.shutdown()
+        openerp.netsvc.close_socket(httpd.socket)
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index a8c806a..b3c11a1 100644 (file)
@@ -177,6 +177,10 @@ class TestCleaner(unittest2.TestCase):
         new_html = html_email_clean(False)
         self.assertEqual(new_html, False, 'html_email_cleaner did change a False in an other value.')
 
+        # Test6: Message with xml and doctype tags don't crash
+        new_html = html_email_clean(u'<?xml version="1.0" encoding="iso-8859-1"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n <head>\n  <title>404 - Not Found</title>\n </head>\n <body>\n  <h1>404 - Not Found</h1>\n </body>\n</html>\n')
+        self.assertNotIn('encoding', new_html, 'html_email_cleaner did not remove correctly encoding attributes')
+
 class TestHtmlTools(unittest2.TestCase):
     """ Test some of our generic utility functions about html """
 
index a54f99b..e6b471a 100644 (file)
@@ -130,11 +130,15 @@ def html_email_clean(html):
         dest += source[idx:]
         return dest
 
-    if not html:
+    if not html or not isinstance(html, basestring):
         return html
 
     html = ustr(html)
 
+    # 0. remove encoding attribute inside tags
+    doctype = re.compile(r'(<[^>]*\s)(encoding=(["\'][^"\']*?["\']|[^\s\n\r>]+)(\s[^>]*|/)?>)', re.IGNORECASE | re.DOTALL)
+    html = doctype.sub(r"", html)
+
     # 1. <br[ /]> -> \n, because otherwise the tree is obfuscated
     br_tags = re.compile(r'([<]\s*[bB][rR]\s*\/?[>])')
     html = _replace_matching_regex(br_tags, html, '__BR_TAG__')
index 67c586a..b5cff6b 100644 (file)
@@ -26,6 +26,12 @@ Some functions related to the os and os.path module
 import os
 from os.path import join as opj
 
+if os.name == 'nt':
+    import ctypes
+    import win32service as ws
+    import win32serviceutil as wsu
+
+
 def listdir(dir, recursive=False):
     """Allow to recursively get the file listing"""
     dir = os.path.normpath(dir)
@@ -56,6 +62,59 @@ def walksymlinks(top, topdown=True, onerror=None):
             yield dirpath, dirnames, filenames
 
 
+if os.name != 'nt':
+    getppid = os.getppid
+    is_running_as_nt_service = lambda: False
+else:
+    # based on http://mail.python.org/pipermail/python-win32/2007-June/006174.html
+    _TH32CS_SNAPPROCESS = 0x00000002
+    class _PROCESSENTRY32(ctypes.Structure):
+        _fields_ = [("dwSize", ctypes.c_ulong),
+                    ("cntUsage", ctypes.c_ulong),
+                    ("th32ProcessID", ctypes.c_ulong),
+                    ("th32DefaultHeapID", ctypes.c_ulong),
+                    ("th32ModuleID", ctypes.c_ulong),
+                    ("cntThreads", ctypes.c_ulong),
+                    ("th32ParentProcessID", ctypes.c_ulong),
+                    ("pcPriClassBase", ctypes.c_ulong),
+                    ("dwFlags", ctypes.c_ulong),
+                    ("szExeFile", ctypes.c_char * 260)]
+
+    def getppid():
+        CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
+        Process32First = ctypes.windll.kernel32.Process32First
+        Process32Next = ctypes.windll.kernel32.Process32Next
+        CloseHandle = ctypes.windll.kernel32.CloseHandle
+        hProcessSnap = CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
+        current_pid = os.getpid()
+        try:
+            pe32 = _PROCESSENTRY32()
+            pe32.dwSize = ctypes.sizeof(_PROCESSENTRY32)
+            if not Process32First(hProcessSnap, ctypes.byref(pe32)):
+                raise OSError('Failed getting first process.')
+            while True:
+                if pe32.th32ProcessID == current_pid:
+                    return pe32.th32ParentProcessID
+                if not Process32Next(hProcessSnap, ctypes.byref(pe32)):
+                    return None
+        finally:
+            CloseHandle(hProcessSnap)
+
+    from contextlib import contextmanager
+    from openerp.release import nt_service_name
+
+    def is_running_as_nt_service():
+        @contextmanager
+        def close_srv(srv):
+            try:
+                yield srv
+            finally:
+                ws.CloseServiceHandle(srv)
+
+        with close_srv(ws.OpenSCManager(None, None, ws.SC_MANAGER_ALL_ACCESS)) as hscm:
+            with close_srv(wsu.SmartOpenService(hscm, nt_service_name, ws.SERVICE_ALL_ACCESS)) as hs:
+                info = ws.QueryServiceStatusEx(hs)
+                return info['ProcessId'] == getppid()
 
 if __name__ == '__main__':
     from pprint import pprint as pp
index bf7c83e..8b3c117 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
-#    
+#
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
 #
 #    GNU Affero General Public License for more details.
 #
 #    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
-# Win32 python extensions modules
 import win32serviceutil
 import win32service
-import win32event
 import win32api
 import win32process
 import servicemanager
@@ -30,35 +28,32 @@ import servicemanager
 import sys
 import subprocess
 import os
-import thread
+
+try:
+    import meta
+except ImportError:
+    if hasattr(sys, 'frozen'):
+        raise
+    from setup import generate_files
+    generate_files()
+    import meta     # noqa
 
 class OpenERPServerService(win32serviceutil.ServiceFramework):
     # required info
-    _svc_name_ = "openerp-server-6.1"
-    _svc_display_name_ = "OpenERP Server 6.1"
-    # optionnal info
-    _svc_description_ = "OpenERP Server 6.1 service"
+    _svc_name_ = meta.nt_service_name
+    _svc_display_name_ = "%s %s" % (meta.description, meta.serie)
 
     def __init__(self, args):
         win32serviceutil.ServiceFramework.__init__(self, args)
-        # Create an event which we will use to wait on.
-        # The "service stop" request will set this event.
-        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
         # a reference to the server's process
         self.terpprocess = None
-        # info if the service terminates correctly or if the server crashed
-        self.stopping = False
-
 
     def SvcStop(self):
         # Before we do anything, tell the SCM we are starting the stop process.
         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
-        # stop the running TERP Server: say it's a normal exit
+        # stop the running OpenERP Server: say it's a normal exit
         win32api.TerminateProcess(int(self.terpprocess._handle), 0)
         servicemanager.LogInfoMsg("OpenERP Server stopped correctly")
-        # And set my event.
-        win32event.SetEvent(self.hWaitStop)
-
 
     def StartTERP(self):
         # The server finds now its configuration automatically on Windows
@@ -69,29 +64,19 @@ class OpenERPServerService(win32serviceutil.ServiceFramework):
         server_path = os.path.join(server_dir, 'server', 'openerp-server.exe')
         self.terpprocess = subprocess.Popen([server_path], cwd=server_dir, creationflags=win32process.CREATE_NO_WINDOW)
 
-
-    def StartControl(self,ws):
-        # this listens to the Service Manager's events
-        win32event.WaitForSingleObject(ws, win32event.INFINITE)
-        self.stopping = True
-
     def SvcDoRun(self):
-        # Start OpenERP Server itself
         self.StartTERP()
-        # start the loop waiting for the Service Manager's stop signal
-        thread.start_new_thread(self.StartControl, (self.hWaitStop,))
-        # Log a info message that the server is running
         servicemanager.LogInfoMsg("OpenERP Server up and running")
-        # verification if the server is really running, else quit with an error
-        self.terpprocess.wait()
-        if not self.stopping:
-            sys.exit("OpenERP Server check: server not running, check the logfile for more info")
+        # exit with same exit code as OpenERP process
+        sys.exit(self.terpprocess.wait())
 
 
+def option_handler(opts):
+    # configure the service to auto restart on failures...
+    subprocess.call(['sc', 'failure', meta.nt_service_name, 'reset=', '0', 'actions=', 'restart/0/restart/0/restart/0'])
 
-if __name__=='__main__':
+if __name__ == '__main__':
     # Do with the service whatever option is passed in the command line
-    win32serviceutil.HandleCommandLine(OpenERPServerService)
+    win32serviceutil.HandleCommandLine(OpenERPServerService, customOptionHandler=option_handler)
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
index 2dfb8ef..0feedce 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
-#    
+#
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
 #
@@ -15,7 +15,7 @@
 #    GNU Affero General Public License for more details.
 #
 #    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
@@ -30,15 +30,46 @@ def datas():
         r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*')))
     return r
 
-setup(service=["OpenERPServerService"],
-      options={"py2exe":{"excludes":["Tkconstants","Tkinter","tcl",
-                                     "_imagingtk","PIL._imagingtk",
-                                     "ImageTk", "PIL.ImageTk",
-                                     "FixTk"],
-                         "skip_archive": 1,
-                         "optimize": 2,}},
+meta = {}
+execfile(os.path.join(os.path.dirname(__file__), '..', 'openerp', 'release.py'), meta)
+
+def generate_files():
+    actions = {
+        'start': ['stop', 'start'],
+        'stop': ['stop'],
+    }
+
+    files = []
+    for action, steps in actions.items():
+        fname = action + '.bat'
+        files.append(fname)
+        with open(fname, 'w') as fp:
+            fp.write('@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.\n')
+            for step in steps:
+                fp.write('@net %s %s\n' % (step, meta['nt_service_name']))
+
+    files.append('meta.py')
+    with open('meta.py', 'w') as fp:
+        for m in 'description serie nt_service_name'.split():
+            fp.write("%s = %r\n" % (m, meta[m],))
+
+    return files
+
+excludes = "Tkconstants Tkinter tcl _imagingtk PIL._imagingtk ImageTk PIL.ImageTk FixTk".split()
+
+setup(service      = ["OpenERPServerService"],
+      version      = meta['version'],
+      license      = meta['license'],
+      url          = meta['url'],
+      author       = meta['author'],
+      author_email = meta['author_email'],
+      data_files   = generate_files(),
+      options      = {"py2exe": {
+                        "excludes": excludes,
+                        "skip_archive": 1,
+                        "optimize": 2,
+                     }},
       data_files=datas(),
       )
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
diff --git a/win32/start.bat b/win32/start.bat
deleted file mode 100644 (file)
index ff3c49b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.\r
-\r
-@net stop openerp-server-6.1\r
-\r
-@net start openerp-server-6.1\r
-\r
-cls\r
diff --git a/win32/stop.bat b/win32/stop.bat
deleted file mode 100644 (file)
index 76a35b7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.\r
-\r
-@net stop openerp-server-6.1\r
-\r
-cls\r