From 265f9ab5090e68ca4dc1e4147a262aaec1897a29 Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Thu, 14 Sep 2017 11:24:47 +0200 Subject: [PATCH 01/40] [FIX] payment_sips: allow to override the default atos url. Sips is generic, and others services that Atos use the same protocol. It is not user-friendly, but that allow user to use alternative service like 'Sogenactif'. In next version, we need to add field on config to specify it and the InterfaceVersion that can differ according to the provider. --- addons/payment_sips/models/payment.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index f7024d3b025..f7796bb5e2a 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -48,7 +48,8 @@ class AcquirerSips(models.Model): 'prod': 'https://payment-webinit.sips-atos.com/paymentInit', 'test': 'https://payment-webinit.simu.sips-atos.com/paymentInit', } - return {'sips_form_url': url.get(environment, url['test']), } + icp_value = self.env['ir.config_parameter'].sudo().get_param('acquirer_sips_url_%s' % environment) + return {'sips_form_url': icp_value or url.get(environment, url['test']), } def _sips_generate_shasign(self, values): """ Generate the shasign for incoming or outgoing communications. From 8f99b24f6cb1ea70b371e2944ff36b75a6f9c80e Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Thu, 14 Sep 2017 11:28:24 +0200 Subject: [PATCH 02/40] [FIX] payment_sips, payment_ogone: remove call to partner_reference. This field has been removed on transaction model in commit f8a98d9. --- addons/payment_ogone/tests/test_ogone.py | 3 --- addons/payment_sips/models/payment.py | 2 -- 2 files changed, 5 deletions(-) diff --git a/addons/payment_ogone/tests/test_ogone.py b/addons/payment_ogone/tests/test_ogone.py index ac32f0c4fe5..79a1d745325 100644 --- a/addons/payment_ogone/tests/test_ogone.py +++ b/addons/payment_ogone/tests/test_ogone.py @@ -174,7 +174,4 @@ class OgonePayment(PaymentAcquirerCommon): 'number': '4000000000000002', 'brand': 'VISA'}) - # check an alias is set, containing at least OPENERP - self.assertIn('OPENERP', tx.partner_reference, 'ogone: wrong partner reference after creating an alias') - res = tx.ogone_s2s_execute({}) diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index f7796bb5e2a..515bb08ee97 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -172,8 +172,6 @@ class TxSips(models.Model): # check what is bought if float_compare(float(data.get('amount', '0.0')) / 100, self.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % self.amount)) - if self.partner_reference and data.get('customerId') != self.partner_reference: - invalid_parameters.append(('customerId', data.get('customerId'), self.partner_reference)) return invalid_parameters From 8defed9536711a05f147f28916b7109854f9932c Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 15 Sep 2017 19:06:10 +0200 Subject: [PATCH 03/40] [REL] 10.saas~18 --- odoo/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo/release.py b/odoo/release.py index c563d9ff4cd..81059d81bf1 100644 --- a/odoo/release.py +++ b/odoo/release.py @@ -12,7 +12,7 @@ RELEASE_LEVELS_DISPLAY = {ALPHA: ALPHA, # properly comparable using normal operarors, for example: # (6,1,0,'beta',0) < (6,1,0,'candidate',1) < (6,1,0,'candidate',2) # (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0) -version_info = (11, 0, 0, ALPHA, 1, '') +version_info = (10, 'saas~18', 0, FINAL, 0, '') version = '.'.join(str(s) for s in version_info[:2]) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '') + version_info[5] series = serie = major_version = '.'.join(str(s) for s in version_info[:2]) From c2f2bea6c51914b1fadc66af90aac10e00fbeacc Mon Sep 17 00:00:00 2001 From: Odoo Translation Bot Date: Sun, 17 Sep 2017 04:40:19 +0200 Subject: [PATCH 04/40] [I18N] Update translation terms from Transifex --- addons/account/i18n/ar.po | 6 +++ addons/account/i18n/bg.po | 6 +++ addons/account/i18n/bs.po | 6 +++ addons/account/i18n/ca.po | 6 +++ addons/account/i18n/cs.po | 6 +++ addons/account/i18n/da.po | 6 +++ addons/account/i18n/de.po | 6 +++ addons/account/i18n/el.po | 6 +++ addons/account/i18n/es.po | 6 +++ addons/account/i18n/et.po | 6 +++ addons/account/i18n/fa.po | 8 ++- addons/account/i18n/fi.po | 6 +++ addons/account/i18n/fr.po | 8 ++- addons/account/i18n/he.po | 6 +++ addons/account/i18n/hr.po | 26 +++++---- addons/account/i18n/hu.po | 6 +++ addons/account/i18n/hy.po | 6 +++ addons/account/i18n/id.po | 6 +++ addons/account/i18n/it.po | 6 +++ addons/account/i18n/ja.po | 6 +++ addons/account/i18n/kab.po | 6 +++ addons/account/i18n/km.po | 6 +++ addons/account/i18n/lo.po | 6 +++ addons/account/i18n/lt.po | 10 +++- addons/account/i18n/lv.po | 6 +++ addons/account/i18n/mn.po | 6 +++ addons/account/i18n/my.po | 6 +++ addons/account/i18n/nb.po | 6 +++ addons/account/i18n/nl.po | 6 +++ addons/account/i18n/pl.po | 12 +++-- addons/account/i18n/pt.po | 6 +++ addons/account/i18n/pt_BR.po | 6 +++ addons/account/i18n/ro.po | 6 +++ addons/account/i18n/ru.po | 6 +++ addons/account/i18n/sk.po | 6 +++ addons/account/i18n/sl.po | 6 +++ addons/account/i18n/sq.po | 6 +++ addons/account/i18n/sr.po | 6 +++ addons/account/i18n/sv.po | 6 +++ addons/account/i18n/th.po | 6 +++ addons/account/i18n/tr.po | 13 ++++- addons/account/i18n/uk.po | 6 +++ addons/account/i18n/vi.po | 6 +++ addons/account/i18n/zh_CN.po | 10 +++- addons/auth_signup/i18n/ja.po | 10 ++-- addons/base_action_rule/i18n/hr.po | 6 +-- addons/base_gengo/i18n/hr.po | 8 +-- addons/base_geolocalize/i18n/hr.po | 7 +-- addons/base_import/i18n/de.po | 7 ++- addons/base_import_module/i18n/hr.po | 5 +- addons/base_setup/i18n/hr.po | 8 +-- addons/base_vat/i18n/hr.po | 5 +- addons/crm/i18n/hr.po | 2 +- addons/crm/i18n/pl.po | 14 ++--- addons/delivery/i18n/hr.po | 14 ++--- addons/delivery/i18n/pl.po | 4 +- addons/delivery/i18n/zh_CN.po | 2 +- addons/event_sale/i18n/hr.po | 11 ++-- addons/gamification_sale_crm/i18n/hr.po | 3 +- addons/hr_expense_check/i18n/de.po | 5 +- addons/hr_payroll/i18n/nl.po | 2 +- addons/hr_recruitment_survey/i18n/pl.po | 6 +-- addons/hr_timesheet/i18n/pl.po | 5 +- addons/hr_timesheet/i18n/zh_CN.po | 5 +- addons/im_livechat/i18n/zh_CN.po | 7 +-- addons/lunch/i18n/pl.po | 2 +- addons/mail/i18n/de.po | 2 +- addons/marketing_campaign/i18n/pl.po | 2 +- addons/mrp/i18n/de.po | 2 +- addons/mrp/i18n/hr.po | 18 +++---- addons/mrp/i18n/nl.po | 8 +-- addons/mrp/i18n/zh_CN.po | 9 ++-- addons/payment/i18n/hr.po | 2 +- addons/point_of_sale/i18n/hr.po | 2 +- addons/point_of_sale/i18n/pl.po | 2 +- addons/product/i18n/zh_CN.po | 9 ++-- addons/product_margin/i18n/zh_CN.po | 5 +- addons/project/i18n/hr.po | 2 +- addons/project/i18n/hu.po | 72 ++++++++++++------------- addons/project/i18n/zh_CN.po | 10 ++-- addons/purchase/i18n/hr.po | 6 +-- addons/purchase/i18n/pl.po | 4 +- addons/purchase/i18n/zh_CN.po | 5 +- addons/purchase_requisition/i18n/de.po | 56 ++++++++++--------- addons/report/i18n/zh_CN.po | 5 +- addons/sale/i18n/pl.po | 5 +- addons/sale_stock/i18n/hr.po | 4 +- addons/sale_stock/i18n/pl.po | 2 +- addons/sale_timesheet/i18n/pl.po | 3 +- addons/sales_team/i18n/fr.po | 2 +- addons/stock/i18n/hr.po | 16 +++--- addons/stock/i18n/nl.po | 8 +-- addons/stock/i18n/pl.po | 4 +- addons/web/i18n/pl.po | 2 +- addons/web_editor/i18n/zh_CN.po | 2 +- addons/website/i18n/de.po | 4 +- addons/website/i18n/pl.po | 4 +- addons/website_blog/i18n/de.po | 7 +-- addons/website_portal_sale/i18n/pl.po | 2 +- addons/website_quote/i18n/zh_CN.po | 5 +- addons/website_sale/i18n/nl.po | 2 +- addons/website_sale/i18n/pl.po | 3 +- addons/website_sale/i18n/zh_CN.po | 7 ++- addons/website_sale_delivery/i18n/hr.po | 18 +++---- addons/website_slides/i18n/de.po | 5 +- odoo/addons/base/i18n/hr.po | 63 +++++++++++----------- odoo/addons/base/i18n/pl.po | 4 +- odoo/addons/base/i18n/tr.po | 4 +- 108 files changed, 572 insertions(+), 272 deletions(-) diff --git a/addons/account/i18n/ar.po b/addons/account/i18n/ar.po index 0b27195eb43..99afd6f821f 100644 --- a/addons/account/i18n/ar.po +++ b/addons/account/i18n/ar.po @@ -10785,6 +10785,12 @@ msgstr "" msgid "You have" msgstr "لديك" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/bg.po b/addons/account/i18n/bg.po index cd5434a8762..cf9e5f7d97e 100644 --- a/addons/account/i18n/bg.po +++ b/addons/account/i18n/bg.po @@ -10231,6 +10231,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/bs.po b/addons/account/i18n/bs.po index 00663b73b86..ff556f97f03 100644 --- a/addons/account/i18n/bs.po +++ b/addons/account/i18n/bs.po @@ -10316,6 +10316,12 @@ msgstr "" msgid "You have" msgstr "Imate" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/ca.po b/addons/account/i18n/ca.po index 47b485a2277..2f52b491ce4 100644 --- a/addons/account/i18n/ca.po +++ b/addons/account/i18n/ca.po @@ -10939,6 +10939,12 @@ msgstr "" msgid "You have" msgstr "Té" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/cs.po b/addons/account/i18n/cs.po index 55a225f576a..9bb89c883f2 100644 --- a/addons/account/i18n/cs.po +++ b/addons/account/i18n/cs.po @@ -10236,6 +10236,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/da.po b/addons/account/i18n/da.po index 1b4fe91e694..8b83effa323 100644 --- a/addons/account/i18n/da.po +++ b/addons/account/i18n/da.po @@ -10849,6 +10849,12 @@ msgstr "" msgid "You have" msgstr "Du har" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/de.po b/addons/account/i18n/de.po index d89073ec141..903c49be01f 100644 --- a/addons/account/i18n/de.po +++ b/addons/account/i18n/de.po @@ -10806,6 +10806,12 @@ msgstr "" msgid "You have" msgstr "Sie haben" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/el.po b/addons/account/i18n/el.po index d29ed500c00..501864c7e74 100644 --- a/addons/account/i18n/el.po +++ b/addons/account/i18n/el.po @@ -10413,6 +10413,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/es.po b/addons/account/i18n/es.po index 61cc60c02c3..7a086c23bad 100644 --- a/addons/account/i18n/es.po +++ b/addons/account/i18n/es.po @@ -10957,6 +10957,12 @@ msgstr "" msgid "You have" msgstr "Tiene" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/et.po b/addons/account/i18n/et.po index 42a31b06e41..bc11944d350 100644 --- a/addons/account/i18n/et.po +++ b/addons/account/i18n/et.po @@ -10142,6 +10142,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/fa.po b/addons/account/i18n/fa.po index 9a593d0d4dd..8ee84e18f87 100644 --- a/addons/account/i18n/fa.po +++ b/addons/account/i18n/fa.po @@ -15,7 +15,7 @@ # ghasem yaghoubi , 2016 # elaheh pourrezaie , 2016 # Morovat Guivi , 2016 -# Faraz Sadri , 2016 +# ifaraz ir , 2016 # hamid k , 2016 # Zahed Alfak , 2016 # Sia Rezazadeh , 2017 @@ -10203,6 +10203,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/fi.po b/addons/account/i18n/fi.po index 4a2fdf266c3..3c3e9fa5b72 100644 --- a/addons/account/i18n/fi.po +++ b/addons/account/i18n/fi.po @@ -10518,6 +10518,12 @@ msgstr "" msgid "You have" msgstr "Sinulla on" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/fr.po b/addons/account/i18n/fr.po index 5199fc32482..e49a843eb84 100644 --- a/addons/account/i18n/fr.po +++ b/addons/account/i18n/fr.po @@ -13,7 +13,7 @@ # Olivier Dony , 2016 # Xavier Belmere , 2016 # Martin Trigaux , 2016 -# Nicolas JEUDY , 2016 +# Nicolas JEUDY , 2016 # Shark McGnark , 2016 # Sébastien Le Ray , 2016 # Florian Hatat , 2016 @@ -11011,6 +11011,12 @@ msgstr "" msgid "You have" msgstr "Vous avez" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/he.po b/addons/account/i18n/he.po index 31114b6beae..4b4e6572058 100644 --- a/addons/account/i18n/he.po +++ b/addons/account/i18n/he.po @@ -10264,6 +10264,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/hr.po b/addons/account/i18n/hr.po index e2474c939bb..5eed4496b28 100644 --- a/addons/account/i18n/hr.po +++ b/addons/account/i18n/hr.po @@ -673,7 +673,7 @@ msgid "" " This allows you to record the different payments that constitute your bank deposit. (You may need to" msgstr "" "Kreiraj uplatnicu
\n" -"Omogučuje pračenje različitih vrsta plačanja koji predstavljaju vaš bankovni depozit. (You may need to\n" +"Omogućuje praćenje različitih vrsta plaćanja koji predstavljaju Vaš bankovni depozit. (You may need to\n" "\n" " " @@ -3825,7 +3825,7 @@ msgstr "Razlika između izračunatog i upisanog završnog salda" #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Direct connection to your bank" -msgstr "Direktno povezivanje sa bankom" +msgstr "Direktno povezivanje s bankom" #. module: account #: model:ir.ui.view,arch_db:account.report_invoice_document @@ -4145,7 +4145,7 @@ msgstr "Završna blagajna" #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Enjoy your Odoo experience," -msgstr "Uživajte u vašem Odoo doživljaju," +msgstr "Uživajte u Vašem Odoo doživljaju," #. module: account #: model:ir.actions.act_window,name:account.action_move_line_form @@ -4527,9 +4527,9 @@ msgid "" "vendors. The search tool can also be used to personalise your Invoices " "reports and so, match this analysis to your needs." msgstr "" -"Iz ovog izvještaja imate pregled iznosa izdanih računa od strane vaših " -"prodavača. Alat pretrage može se također koristiti za personalizaciju vaših " -"izvještaja i priagođavanje analize vašim potrebama." +"Iz ovog izvještaja imate pregled iznosa izdanih računa od strane Vaših " +"prodavača. Alat pretrage može se također koristiti za personalizaciju Vaših " +"izvještaja i prilagođavanje analize Vašim potrebama." #. module: account #: model:ir.actions.act_window,help:account.action_account_invoice_report_all @@ -4538,9 +4538,9 @@ msgid "" "customers. The search tool can also be used to personalise your Invoices " "reports and so, match this analysis to your needs." msgstr "" -"Iz ovog izvještaja imate pregled iznosa izdanih računa vašem kupcu. Alat " -"pretrage može se također koristiti za personalizaciju vaših ispisa računa i " -"priagođavanje analize vašim potrebama." +"Iz ovog izvještaja imate pregled iznosa izdanih računa Vašem kupcu. Alat " +"pretrage može se također koristiti za personalizaciju Vaših ispisa računa i " +"prilagođavanje analize Vašim potrebama." #. module: account #: model:ir.model,name:account.model_account_full_reconcile @@ -4621,7 +4621,7 @@ msgid "" "Get your bank statements from your bank and import them in Odoo in the .CSV format.\n" "-This installs the module account_bank_statement_import_csv." msgstr "" -"Dohvatite vaše bankovne izvatke i importirajte ih u odoo u .CSV formatu.\n" +"Dohvatite bankovne izvatke i importirajte ih u odoo u .CSV formatu.\n" "Ovo instalira modul account_bank_statement_import_csv." #. module: account @@ -10751,6 +10751,12 @@ msgstr "" msgid "You have" msgstr "Imaš" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/hu.po b/addons/account/i18n/hu.po index e76ffe0d5b7..e7707f7ed88 100644 --- a/addons/account/i18n/hu.po +++ b/addons/account/i18n/hu.po @@ -10969,6 +10969,12 @@ msgstr "" msgid "You have" msgstr "Önnek van" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/hy.po b/addons/account/i18n/hy.po index 8768b342a0e..999b9e1d272 100644 --- a/addons/account/i18n/hy.po +++ b/addons/account/i18n/hy.po @@ -10136,6 +10136,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/id.po b/addons/account/i18n/id.po index a364e217f10..bb7e7028bae 100644 --- a/addons/account/i18n/id.po +++ b/addons/account/i18n/id.po @@ -10855,6 +10855,12 @@ msgstr "" msgid "You have" msgstr "Kamu punya" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/it.po b/addons/account/i18n/it.po index 6c211e4d586..2777e227df8 100644 --- a/addons/account/i18n/it.po +++ b/addons/account/i18n/it.po @@ -10812,6 +10812,12 @@ msgstr "" msgid "You have" msgstr "Ci sono" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/ja.po b/addons/account/i18n/ja.po index 0743bfcc431..e86b96ec168 100644 --- a/addons/account/i18n/ja.po +++ b/addons/account/i18n/ja.po @@ -10203,6 +10203,12 @@ msgstr "" msgid "You have" msgstr "この顧客には" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/kab.po b/addons/account/i18n/kab.po index d57ef2a91db..005c433788a 100644 --- a/addons/account/i18n/kab.po +++ b/addons/account/i18n/kab.po @@ -10306,6 +10306,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/km.po b/addons/account/i18n/km.po index 2b8598992bf..005e57cc101 100644 --- a/addons/account/i18n/km.po +++ b/addons/account/i18n/km.po @@ -10137,6 +10137,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/lo.po b/addons/account/i18n/lo.po index 776873327a8..b3852938100 100644 --- a/addons/account/i18n/lo.po +++ b/addons/account/i18n/lo.po @@ -10189,6 +10189,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/lt.po b/addons/account/i18n/lt.po index b7ddbb38e4b..f5e946c772a 100644 --- a/addons/account/i18n/lt.po +++ b/addons/account/i18n/lt.po @@ -13,14 +13,14 @@ # Valdemar St , 2016 # Monika Raciunaite , 2016 # Antanas Muliuolis , 2017 -# Aiste Sutkute , 2017 +# digitouch UAB , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-05-26 08:44+0000\n" "PO-Revision-Date: 2017-05-26 08:44+0000\n" -"Last-Translator: Aiste Sutkute , 2017\n" +"Last-Translator: digitouch UAB , 2017\n" "Language-Team: Lithuanian (https://www.transifex.com/odoo/teams/41243/lt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -10319,6 +10319,12 @@ msgstr "" msgid "You have" msgstr "Jūs turite" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/lv.po b/addons/account/i18n/lv.po index 66ad598be46..8a6f088839b 100644 --- a/addons/account/i18n/lv.po +++ b/addons/account/i18n/lv.po @@ -10168,6 +10168,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/mn.po b/addons/account/i18n/mn.po index 02ea3662a9a..3b9aa1191e3 100644 --- a/addons/account/i18n/mn.po +++ b/addons/account/i18n/mn.po @@ -10854,6 +10854,12 @@ msgstr "" msgid "You have" msgstr "Танд байгаа зүйл" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/my.po b/addons/account/i18n/my.po index 8095aed61c2..ef865b7d64b 100644 --- a/addons/account/i18n/my.po +++ b/addons/account/i18n/my.po @@ -10140,6 +10140,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/nb.po b/addons/account/i18n/nb.po index 058d31f1c36..615b09f5684 100644 --- a/addons/account/i18n/nb.po +++ b/addons/account/i18n/nb.po @@ -10256,6 +10256,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/nl.po b/addons/account/i18n/nl.po index 4b1a886e9f3..f9233b8da3d 100644 --- a/addons/account/i18n/nl.po +++ b/addons/account/i18n/nl.po @@ -10958,6 +10958,12 @@ msgstr "" msgid "You have" msgstr "U heeft" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "U dient een reeks aan te maken voor %s in uw bedrijf." + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/pl.po b/addons/account/i18n/pl.po index 378102d5181..3fe56706402 100644 --- a/addons/account/i18n/pl.po +++ b/addons/account/i18n/pl.po @@ -72,7 +72,7 @@ msgid "" "% endif\n" msgstr "" "\n" -"

Drogi ${object.partner_id.name}\n" +"

Drogi(a) ${object.partner_id.name}\n" "% set access_action = object.get_access_action()\n" "% set access_url = access_action['type'] == 'ir.actions.act_url' and access_action['url'] or '/report/pdf/account.report_invoice/' + str(object.id)\n" "% set is_online = access_action and access_action['type'] == 'ir.actions.act_url'\n" @@ -92,7 +92,7 @@ msgstr "" "% if is_online:\n" "

\n" "

\n" -" View Invoice\n" +" Zobacz fakturę\n" "
\n" "% endif\n" "

\n" @@ -4664,7 +4664,7 @@ msgstr "Przejdź do panelu konfiguracji" #. module: account #: selection:res.partner,trust:0 msgid "Good Debtor" -msgstr "dobry dłużnik" +msgstr "Dobry dłużnik" #. module: account #. openerp-web @@ -10730,6 +10730,12 @@ msgstr "" msgid "You have" msgstr "Masz" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/pt.po b/addons/account/i18n/pt.po index 47835d5f749..85eb6b037b1 100644 --- a/addons/account/i18n/pt.po +++ b/addons/account/i18n/pt.po @@ -10791,6 +10791,12 @@ msgstr "" msgid "You have" msgstr "Você tem" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/pt_BR.po b/addons/account/i18n/pt_BR.po index 78d8c65d749..5ef82cf458f 100644 --- a/addons/account/i18n/pt_BR.po +++ b/addons/account/i18n/pt_BR.po @@ -10946,6 +10946,12 @@ msgstr "" msgid "You have" msgstr "Você tem" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/ro.po b/addons/account/i18n/ro.po index f75e322f611..a782fe50f23 100644 --- a/addons/account/i18n/ro.po +++ b/addons/account/i18n/ro.po @@ -10486,6 +10486,12 @@ msgstr "" msgid "You have" msgstr "Aveți" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/ru.po b/addons/account/i18n/ru.po index bd06f90f0b2..ba616dc227f 100644 --- a/addons/account/i18n/ru.po +++ b/addons/account/i18n/ru.po @@ -10900,6 +10900,12 @@ msgstr "" msgid "You have" msgstr "Вы имеете" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/sk.po b/addons/account/i18n/sk.po index c92fc7949e5..306d809cd37 100644 --- a/addons/account/i18n/sk.po +++ b/addons/account/i18n/sk.po @@ -10707,6 +10707,12 @@ msgstr "" msgid "You have" msgstr "Máte" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/sl.po b/addons/account/i18n/sl.po index 1034d609c8c..015781eafef 100644 --- a/addons/account/i18n/sl.po +++ b/addons/account/i18n/sl.po @@ -10210,6 +10210,12 @@ msgstr "Nastavitve ne dovoljujejo uporabe tega konta." msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/sq.po b/addons/account/i18n/sq.po index ca01034651b..e4882165dc0 100644 --- a/addons/account/i18n/sq.po +++ b/addons/account/i18n/sq.po @@ -10260,6 +10260,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/sr.po b/addons/account/i18n/sr.po index ff54c67ee6d..ced5ca4f9eb 100644 --- a/addons/account/i18n/sr.po +++ b/addons/account/i18n/sr.po @@ -10154,6 +10154,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/sv.po b/addons/account/i18n/sv.po index 2cfa508b0e9..b571222bd1e 100644 --- a/addons/account/i18n/sv.po +++ b/addons/account/i18n/sv.po @@ -10291,6 +10291,12 @@ msgstr "" msgid "You have" msgstr "Du har" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/th.po b/addons/account/i18n/th.po index ad20240e310..f6e6557c4eb 100644 --- a/addons/account/i18n/th.po +++ b/addons/account/i18n/th.po @@ -10188,6 +10188,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/tr.po b/addons/account/i18n/tr.po index dcde3a8a218..25b2454f49d 100644 --- a/addons/account/i18n/tr.po +++ b/addons/account/i18n/tr.po @@ -7499,7 +7499,7 @@ msgstr "+Banka" #. module: account #: model:ir.ui.view,arch_db:account.view_account_form msgid "Plus Fixed Assets" -msgstr "" +msgstr "(+) Duran Varlıklar" #. module: account #: model:ir.ui.view,arch_db:account.view_account_form @@ -8434,6 +8434,8 @@ msgid "" "Sending customer statements (outstanding invoices) manually during the " "transition period" msgstr "" +"Geçiş döneminde müşteri hesap özeti bildirimlerini (ödenmemiş faturalar) " +"elle göndermek" #. module: account #: selection:account.payment,state:0 @@ -9548,7 +9550,7 @@ msgstr "" #: model:ir.model.fields,help:account.field_account_reconcile_model_journal_id #: model:ir.model.fields,help:account.field_account_reconcile_model_second_journal_id msgid "This field is ignored in a bank statement reconciliation." -msgstr "" +msgstr "Bu alan bir banka hesap özeti uzlaştırmasında dikkate alınmaz." #. module: account #: model:ir.model.fields,help:account.field_account_move_line_date_maturity @@ -10660,6 +10662,7 @@ msgstr "" #, python-format msgid "You cannot put/take money in/out for a bank statement which is closed." msgstr "" +"Kapalı bir banka hesap özetinde para gönderme ve alma işlemi yapamazsınız." #. module: account #: code:addons/account/models/account.py:198 @@ -10692,6 +10695,12 @@ msgstr "" msgid "You have" msgstr "Var" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/uk.po b/addons/account/i18n/uk.po index 3b834e1e6e5..b53f99535f0 100644 --- a/addons/account/i18n/uk.po +++ b/addons/account/i18n/uk.po @@ -10864,6 +10864,12 @@ msgstr "" msgid "You have" msgstr "Ви маєте" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/vi.po b/addons/account/i18n/vi.po index c4bcf32da31..2a5bee8132f 100644 --- a/addons/account/i18n/vi.po +++ b/addons/account/i18n/vi.po @@ -10282,6 +10282,12 @@ msgstr "" msgid "You have" msgstr "" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/account/i18n/zh_CN.po b/addons/account/i18n/zh_CN.po index 280a150cfbf..7e4785a15e1 100644 --- a/addons/account/i18n/zh_CN.po +++ b/addons/account/i18n/zh_CN.po @@ -3472,7 +3472,7 @@ msgstr "客户退款" #: model:ir.model.fields,field_description:account.field_product_product_taxes_id #: model:ir.model.fields,field_description:account.field_product_template_taxes_id msgid "Customer Taxes" -msgstr "客户税金" +msgstr "销项税" #. module: account #: model:ir.ui.view,arch_db:account.report_overdue_document @@ -9932,7 +9932,7 @@ msgstr "供应商退款" #: model:ir.model.fields,field_description:account.field_product_product_supplier_taxes_id #: model:ir.model.fields,field_description:account.field_product_template_supplier_taxes_id msgid "Vendor Taxes" -msgstr "供应商税" +msgstr "进项税" #. module: account #. openerp-web @@ -10336,6 +10336,12 @@ msgstr "你不能在这个日记账中用这个总账,在相关日记账中检 msgid "You have" msgstr "你有" +#. module: account +#: code:addons/account/models/account_payment.py:360 +#, python-format +msgid "You have to define a sequence for %s in your company." +msgstr "" + #. module: account #: code:addons/account/wizard/account_report_general_ledger.py:21 #, python-format diff --git a/addons/auth_signup/i18n/ja.po b/addons/auth_signup/i18n/ja.po index 33731705d08..9a1e985273c 100644 --- a/addons/auth_signup/i18n/ja.po +++ b/addons/auth_signup/i18n/ja.po @@ -121,15 +121,15 @@ msgstr "" "\n" "\n" "
\n" -"

${object.name},様

\n" +"

${object.name} 様

\n" "

\n" -"Odooであなたの書類にアクセスするために \"$ {object.company_id.name}\"に接続するように招待されました。\n" +"Odoo環境 \"${object.company_id.name}\" に招待いたします。\n" "

\n" "

\n" -"招待状を受け入れるには、次のリンクをクリックしてください:\n" +"Odooに接続するには、次のリンクをクリックしてください。\n" "

\n" "\n" "

以上、よろしくお願いいたします。

\n" "
\n" @@ -143,7 +143,7 @@ msgstr "" #. module: auth_signup #: model:mail.template,subject:auth_signup.set_password_email msgid "${object.company_id.name} invitation to connect on Odoo" -msgstr "${object.company_id.name} 弊社Odooポータル接続のご招待" +msgstr "${object.company_id.name} Odoo接続のご招待" #. module: auth_signup #: model:ir.ui.view,arch_db:auth_signup.res_users_form_view diff --git a/addons/base_action_rule/i18n/hr.po b/addons/base_action_rule/i18n/hr.po index 9971831092c..02efdd094b1 100644 --- a/addons/base_action_rule/i18n/hr.po +++ b/addons/base_action_rule/i18n/hr.po @@ -173,7 +173,7 @@ msgstr "Delay after trigger date" #. module: base_action_rule #: model:ir.model.fields,field_description:base_action_rule.field_base_action_rule_trg_date_range_type msgid "Delay type" -msgstr "Delay type" +msgstr "Tip kašnjenja" #. module: base_action_rule #: model:ir.model.fields,field_description:base_action_rule.field_base_action_rule_display_name @@ -195,7 +195,7 @@ msgstr "" #. module: base_action_rule #: model:ir.ui.view,arch_db:base_action_rule.view_base_action_rule_form msgid "Fields to Change" -msgstr "Fields to Change" +msgstr "Polja za promijeniti" #. module: base_action_rule #: model:ir.model.fields,field_description:base_action_rule.field_base_action_rule_filter_id @@ -259,7 +259,7 @@ msgstr "" #. module: base_action_rule #: model:ir.model.fields,field_description:base_action_rule.field_base_action_rule_lead_test_customer msgid "Is a Customer" -msgstr "je Kupac" +msgstr "je kupac" #. module: base_action_rule #: model:ir.model.fields,field_description:base_action_rule.field_base_action_rule_lead_test_date_action_last diff --git a/addons/base_gengo/i18n/hr.po b/addons/base_gengo/i18n/hr.po index 710fe6a20af..8b8a1913709 100644 --- a/addons/base_gengo/i18n/hr.po +++ b/addons/base_gengo/i18n/hr.po @@ -8,14 +8,14 @@ # Vladimir Olujić , 2016 # Karolina Tonković , 2016 # Đurđica Žarković , 2016 -# Tina Milas , 2017 +# Tina Milas , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-29 14:00+0000\n" "PO-Revision-Date: 2016-09-29 14:00+0000\n" -"Last-Translator: Tina Milas , 2017\n" +"Last-Translator: Tina Milas , 2016\n" "Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,7 +31,7 @@ msgstr "Dodaj Gengo privatni ključ..." #. module: base_gengo #: model:ir.ui.view,arch_db:base_gengo.view_general_configuration_form_inherit_base_gengo msgid "Add Gengo login Public Key..." -msgstr "Dodaj Gengo Javni ključ..." +msgstr "Dodaj Gengo javni ključ..." #. module: base_gengo #: model:ir.ui.view,arch_db:base_gengo.view_general_configuration_form_inherit_base_gengo @@ -128,7 +128,7 @@ msgstr "Gengo privatni ključ" #: model:ir.model.fields,field_description:base_gengo.field_base_config_settings_gengo_public_key #: model:ir.model.fields,field_description:base_gengo.field_res_company_gengo_public_key msgid "Gengo Public Key" -msgstr "Gengo Javni ključ" +msgstr "Gengo javni ključ" #. module: base_gengo #: model:ir.ui.view,arch_db:base_gengo.base_gengo_translation_wizard_from diff --git a/addons/base_geolocalize/i18n/hr.po b/addons/base_geolocalize/i18n/hr.po index 2585a390b48..fdffba4cf5d 100644 --- a/addons/base_geolocalize/i18n/hr.po +++ b/addons/base_geolocalize/i18n/hr.po @@ -7,13 +7,14 @@ # Karolina Tonković , 2016 # Martin Trigaux , 2016 # Vladimir Olujić , 2016 +# Tina Milas , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-07 08:56+0000\n" "PO-Revision-Date: 2016-09-07 08:56+0000\n" -"Last-Translator: Vladimir Olujić , 2016\n" +"Last-Translator: Tina Milas , 2016\n" "Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -43,8 +44,8 @@ msgid "" "Cannot contact geolocation servers. Please make sure that your Internet " "connection is up and running (%s)." msgstr "" -"Nije moguće kontaktirati geolokalizacijske sposlužitelje. Molim provjerite " -"vašu internet vezu (%s)." +"Nije moguće kontaktirati geolokalizacijske poslužitelje. Molimo provjerite " +"Vašu internet vezu (%s)." #. module: base_geolocalize #: model:ir.model.fields,field_description:base_geolocalize.field_res_partner_partner_latitude diff --git a/addons/base_import/i18n/de.po b/addons/base_import/i18n/de.po index 361416ad593..1a3416ca3b3 100644 --- a/addons/base_import/i18n/de.po +++ b/addons/base_import/i18n/de.po @@ -10,13 +10,14 @@ # Tina Rittmüller , 2016 # Henry Mineehen , 2016 # Thomas Neu , 2016 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: Thomas Neu , 2016\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -450,7 +451,7 @@ msgstr "Datei erneut laden" #: code:addons/base_import/static/src/xml/base_import.xml:11 #, python-format msgid "Select a CSV or Excel file to import." -msgstr "" +msgstr "Wählen Sie eine CSV- oder Excel-Datei zum Importieren aus." #. module: base_import #. openerp-web @@ -507,6 +508,8 @@ msgid "" "The first row\n" " contains the label of the column" msgstr "" +"Die erste Zeile\n" +" enthält das Label der Spalte" #. module: base_import #. openerp-web diff --git a/addons/base_import_module/i18n/hr.po b/addons/base_import_module/i18n/hr.po index c078921d149..5cccdbd8e6d 100644 --- a/addons/base_import_module/i18n/hr.po +++ b/addons/base_import_module/i18n/hr.po @@ -8,13 +8,14 @@ # Karolina Tonković , 2016 # Vladimir Olujić , 2016 # Đurđica Žarković , 2016 +# Tina Milas , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: Đurđica Žarković , 2016\n" +"Last-Translator: Tina Milas , 2016\n" "Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -63,7 +64,7 @@ msgstr "Datoteka '%s' prelazi maksimalno dozvoljenu veličinu." #: code:addons/base_import_module/models/ir_module.py:88 #, python-format msgid "File is not a zip file!" -msgstr "Datoteka nij eu zip formatu !" +msgstr "Datoteka nije u zip formatu!" #. module: base_import_module #: model:ir.model.fields,field_description:base_import_module.field_base_import_module_force diff --git a/addons/base_setup/i18n/hr.po b/addons/base_setup/i18n/hr.po index 9890ed57957..edd09f49b6b 100644 --- a/addons/base_setup/i18n/hr.po +++ b/addons/base_setup/i18n/hr.po @@ -175,12 +175,12 @@ msgstr "Dozvolite svojim partnerima pristup njihovim dokumentima." #. module: base_setup #: model:ir.ui.view,arch_db:base_setup.view_general_configuration msgid "Google Calendar" -msgstr "Google Calendar" +msgstr "Google kalendar" #. module: base_setup #: model:ir.ui.view,arch_db:base_setup.view_general_configuration msgid "Google Drive" -msgstr "Google Disk" +msgstr "Google disk" #. module: base_setup #: model:ir.ui.view,arch_db:base_setup.view_general_configuration @@ -308,7 +308,7 @@ msgstr "" #. module: base_setup #: model:ir.model.fields,help:base_setup.field_base_config_settings_module_share msgid "Share or embed any screen of Odoo." -msgstr "Dijeli ili uklopi bilokoji ekran openerpa" +msgstr "Dijeli ili uklopi bilo koji ekran Odoo-a." #. module: base_setup #: model:ir.model.fields,field_description:base_setup.field_base_config_settings_company_share_partner @@ -385,7 +385,7 @@ msgid "" "You will find more options in your company details: address for the header " "and footer, overdue payments texts, etc." msgstr "" -"Pronać ćete više mogućnosti u detaljima: adresu za zaglavlje i podnožje " +"Pronaći ćete više mogućnosti u detaljima: adresu za zaglavlje i podnožje " "dokumenata, upozorenja o zakašnjelim plaćanjima itd." #. module: base_setup diff --git a/addons/base_vat/i18n/hr.po b/addons/base_vat/i18n/hr.po index bbff7af4779..ae36bfc77c6 100644 --- a/addons/base_vat/i18n/hr.po +++ b/addons/base_vat/i18n/hr.po @@ -3,6 +3,7 @@ # * base_vat # # Translators: +# Tina Milas , 2016 # Martin Trigaux , 2016 # Vladimir Olujić , 2016 # Ivica Dimjašević , 2016 @@ -32,8 +33,8 @@ msgid "" "If checked, Partners VAT numbers will be fully validated against EU's VIES " "service rather than via a simple format validation (checksum)." msgstr "" -"Ako je označeno, porezni broj partnera biti će provjeren u EU VIES servisu, " -"umjesto jednostavne provjere fromata zapisa" +"Ako je označeno, porezni broj partnera bit će provjeren u EU VIES servisu, " +"umjesto jednostavne provjere formata zapisa." #. module: base_vat #: model:ir.model,name:base_vat.model_res_partner diff --git a/addons/crm/i18n/hr.po b/addons/crm/i18n/hr.po index 6b50bc8f745..3a7730aac4d 100644 --- a/addons/crm/i18n/hr.po +++ b/addons/crm/i18n/hr.po @@ -4585,7 +4585,7 @@ msgid "" "Use leads if you need a qualification step before creating an opportunity or" " a customer" msgstr "" -"Koristite potencijale ako trebale predkorak kvalifikacije prije kreiranja " +"Koristite potencijale ako trebate predkorak kvalifikacije prije kreiranja " "prilike ili kupca" #. module: crm diff --git a/addons/crm/i18n/pl.po b/addons/crm/i18n/pl.po index ee7e585a910..d111d17ccd8 100644 --- a/addons/crm/i18n/pl.po +++ b/addons/crm/i18n/pl.po @@ -562,7 +562,7 @@ msgstr "Na przykład: Etapy negocjacji" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Example: Qualified stage" -msgstr "" +msgstr "Na przykład: Etap kwalifikacji" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner @@ -638,7 +638,7 @@ msgstr "Propozycje:" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Qualified:" -msgstr "" +msgstr "Kwalifikacje:" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner @@ -835,7 +835,7 @@ msgstr "Aktywna" #: model:ir.ui.view,arch_db:crm.crm_activity_view_tree #: model:ir.ui.view,arch_db:crm.view_partners_form_crm1 msgid "Activities" -msgstr "Actywności" +msgstr "Działania" #. module: crm #: model:ir.actions.act_window,name:crm.crm_activity_report_action @@ -2376,7 +2376,7 @@ msgstr "Sygnał utworzony" #: model:ir.ui.view,arch_db:crm.crm_lead_tag_form #: model:ir.ui.view,arch_db:crm.crm_lead_tag_tree msgid "Lead Tags" -msgstr "" +msgstr "Tagi sygnałów" #. module: crm #: model:ir.model,name:crm.model_crm_lead2opportunity_partner @@ -2580,13 +2580,13 @@ msgstr "Porażka" #: model:ir.ui.view,arch_db:crm.crm_opportunity_report_view_search #: model:ir.ui.view,arch_db:crm.view_crm_case_opportunities_filter msgid "Lost Reason" -msgstr "" +msgstr "Powód utraty" #. module: crm #: model:ir.actions.act_window,name:crm.crm_lost_reason_action #: model:ir.ui.menu,name:crm.menu_crm_lost_reason msgid "Lost Reasons" -msgstr "" +msgstr "Powody utraty" #. module: crm #: selection:crm.lead,priority:0 selection:crm.opportunity.report,priority:0 @@ -3487,7 +3487,7 @@ msgstr "" #: model:crm.stage,name:crm.stage_lead2 #, python-format msgid "Qualified" -msgstr "" +msgstr "Kwalifikacje" #. module: crm #. openerp-web diff --git a/addons/delivery/i18n/hr.po b/addons/delivery/i18n/hr.po index cfd74a531a8..5e0f6d592ff 100644 --- a/addons/delivery/i18n/hr.po +++ b/addons/delivery/i18n/hr.po @@ -301,7 +301,7 @@ msgstr "Označiti ako artikl treba izvagati vagom" #. module: delivery #: model:ir.model.fields,help:delivery.field_delivery_carrier_available_in_pos msgid "Check if you want this product to appear in the Point of Sale" -msgstr "Označite ovdje ako ćelite da se proizvod pojavljuje na POS-u" +msgstr "Označite ovdje ako želite da se proizvod pojavljuje na POS-u" #. module: delivery #: model:ir.actions.act_window,help:delivery.action_delivery_carrier_form @@ -336,7 +336,7 @@ msgstr "Trošak" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_price_rule_standard_price msgid "Cost Price" -msgstr "Cijena Koštanja" +msgstr "Cijena koštanja" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_cost_method @@ -484,7 +484,7 @@ msgstr "Pravila dostave cijene" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_product_id msgid "Delivery Product" -msgstr "Proizvod za Isporuku" +msgstr "Proizvod za isporuku" #. module: delivery #: model:ir.model.fields,help:delivery.field_delivery_carrier_route_ids @@ -516,8 +516,8 @@ msgid "" "Determine if a product needs to create automatically an event registration " "at the confirmation of a sales order line." msgstr "" -"Odredite da li proizvod treba automatski stvoriti registraciju događaja ako " -"se potvrdi redak prodajnog naloga." +"Odredite treba li proizvod automatski stvoriti registraciju događaja ako se " +"potvrdi redak prodajnog naloga." #. module: delivery #: model:ir.model.fields,help:delivery.field_delivery_carrier_sequence @@ -942,7 +942,7 @@ msgstr "Maksimalna težina mora biti pozitivna" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_price_rule_max_value msgid "Maximum Value" -msgstr "Maksimalna Vrijednost" +msgstr "Maksimalna vrijednost" #. module: delivery #: model:ir.model.fields,help:delivery.field_product_packaging_max_weight @@ -1763,7 +1763,7 @@ msgstr "Varijabla" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_price_rule_variable_factor msgid "Variable Factor" -msgstr "Varijabilni Faktor" +msgstr "Varijabilni faktor" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_image_variant diff --git a/addons/delivery/i18n/pl.po b/addons/delivery/i18n/pl.po index 21ac4df9f67..8256b710a02 100644 --- a/addons/delivery/i18n/pl.po +++ b/addons/delivery/i18n/pl.po @@ -11,9 +11,9 @@ # Grzegorz Grzelak , 2016 # Grażyna Grzelak , 2016 # Jakobus Buntownikus , 2016 +# zbik2607 , 2016 # Zdzisław Krajewski , 2016 # Slawomir Adamus , 2016 -# zbik2607 , 2016 # Maciej Wichowski , 2016 msgid "" msgstr "" @@ -329,7 +329,7 @@ msgstr "Warunek" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_purchase_method msgid "Control Purchase Bills" -msgstr "kontrola rachunków zamówień" +msgstr "Kontrola rachunków zamówień" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_standard_price diff --git a/addons/delivery/i18n/zh_CN.po b/addons/delivery/i18n/zh_CN.po index 5088cfc5939..51a030d0732 100644 --- a/addons/delivery/i18n/zh_CN.po +++ b/addons/delivery/i18n/zh_CN.po @@ -1763,7 +1763,7 @@ msgstr "变体额外价格" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_supplier_taxes_id msgid "Vendor Taxes" -msgstr "供应商税" +msgstr "进项税" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_seller_ids diff --git a/addons/event_sale/i18n/hr.po b/addons/event_sale/i18n/hr.po index 9841d7fdd4e..c3b4480bf94 100644 --- a/addons/event_sale/i18n/hr.po +++ b/addons/event_sale/i18n/hr.po @@ -9,13 +9,14 @@ # Vladimir Olujić , 2016 # Ivica Dimjašević , 2016 # Đurđica Žarković , 2016 +# Tina Milas , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: Đurđica Žarković , 2016\n" +"Last-Translator: Tina Milas , 2016\n" "Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -109,8 +110,8 @@ msgid "" "Determine if a product needs to create automatically an event registration " "at the confirmation of a sales order line." msgstr "" -"Odredite da li proizvod treba automatski stvoriti registraciju događaja ako " -"se potvrdi redak prodajnog naloga." +"Odredite treba li proizvod automatski stvoriti registraciju događaja ako se " +"potvrdi redak prodajnog naloga." #. module: event_sale #: model:ir.model.fields,field_description:event_sale.field_event_event_ticket_display_name @@ -325,7 +326,7 @@ msgstr "Prodajni nalog" #: model:ir.model.fields,field_description:event_sale.field_event_registration_sale_order_line_id #: model:ir.model.fields,field_description:event_sale.field_registration_editor_line_sale_order_line_id msgid "Sale Order Line" -msgstr "Vezana Zaključnica" +msgstr "Vezana zaključnica" #. module: event_sale #: model:ir.model.fields,field_description:event_sale.field_event_event_ticket_deadline @@ -402,7 +403,7 @@ msgstr "VIP" #. module: event_sale #: model:ir.ui.view,arch_db:event_sale.view_event_registration_editor_form msgid "please give details about the registrations" -msgstr "molim vas detalje o registracijama" +msgstr "molim Vas detalje o registracijama" #. module: event_sale #: model:ir.model,name:event_sale.model_registration_editor diff --git a/addons/gamification_sale_crm/i18n/hr.po b/addons/gamification_sale_crm/i18n/hr.po index 61f64d36c02..b38ac6f370b 100644 --- a/addons/gamification_sale_crm/i18n/hr.po +++ b/addons/gamification_sale_crm/i18n/hr.po @@ -5,6 +5,7 @@ # Translators: # Bole , 2016 # Martin Trigaux , 2016 +# Tina Milas , 2016 # Karolina Tonković , 2016 # Marko Carević , 2016 msgid "" @@ -34,7 +35,7 @@ msgstr "Dani do zatvaranja posla" #. module: gamification_sale_crm #: model:gamification.challenge,name:gamification_sale_crm.challenge_crm_marketing msgid "Lead Acquisition" -msgstr "Akviz8icija potencijala" +msgstr "Akvizicija potencijala" #. module: gamification_sale_crm #: model:gamification.challenge,name:gamification_sale_crm.challenge_crm_sale diff --git a/addons/hr_expense_check/i18n/de.po b/addons/hr_expense_check/i18n/de.po index bf86c200d7e..8b56d2b1db4 100644 --- a/addons/hr_expense_check/i18n/de.po +++ b/addons/hr_expense_check/i18n/de.po @@ -3,8 +3,9 @@ # * hr_expense_check # # Translators: -# Wolfgang Taferner , 2017 +# Stefan Hartenfels , 2017 # Rudolf Schnapka , 2017 +# Wolfgang Taferner , 2017 # Martin Trigaux , 2017 # Thorsten Vocks , 2017 # darenkster , 2017 @@ -25,7 +26,7 @@ msgstr "" #. module: hr_expense_check #: model:ir.model.fields,field_description:hr_expense_check.field_hr_expense_register_payment_wizard_check_amount_in_words msgid "Amount in Words" -msgstr "Betrag in Worten" +msgstr "Anzahl in Worten" #. module: hr_expense_check #: model:ir.model.fields,field_description:hr_expense_check.field_hr_expense_register_payment_wizard_check_number diff --git a/addons/hr_payroll/i18n/nl.po b/addons/hr_payroll/i18n/nl.po index 05afef2839f..c60bb8d4b09 100644 --- a/addons/hr_payroll/i18n/nl.po +++ b/addons/hr_payroll/i18n/nl.po @@ -1382,7 +1382,7 @@ msgstr "Wordt gebruikt om de salarisregel weer te geven op het loonafschrift." #. module: hr_payroll #: selection:hr.payslip,state:0 msgid "Waiting" -msgstr "Wachten" +msgstr "Wachtend" #. module: hr_payroll #: selection:hr.contract,schedule_pay:0 diff --git a/addons/hr_recruitment_survey/i18n/pl.po b/addons/hr_recruitment_survey/i18n/pl.po index 18dfd17bd8c..0d864c24781 100644 --- a/addons/hr_recruitment_survey/i18n/pl.po +++ b/addons/hr_recruitment_survey/i18n/pl.po @@ -5,14 +5,14 @@ # Translators: # Martin Trigaux , 2016 # Piotr Szlązak , 2016 -# Grzegorz Grzelak , 2016 +# zbik2607 , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-07 08:57+0000\n" "PO-Revision-Date: 2016-09-07 08:57+0000\n" -"Last-Translator: Grzegorz Grzelak , 2016\n" +"Last-Translator: zbik2607 , 2016\n" "Language-Team: Polish (https://www.transifex.com/odoo/teams/41243/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,7 +77,7 @@ msgstr "" #. module: hr_recruitment_survey #: model:survey.question,question:hr_recruitment_survey.recruitment_2_4 msgid "Activities" -msgstr "Actywności" +msgstr "Działania" #. module: hr_recruitment_survey #: model:ir.ui.view,arch_db:hr_recruitment_survey.crm_case_form_view_job_inherit diff --git a/addons/hr_timesheet/i18n/pl.po b/addons/hr_timesheet/i18n/pl.po index e6063b81619..27409b8b5dd 100644 --- a/addons/hr_timesheet/i18n/pl.po +++ b/addons/hr_timesheet/i18n/pl.po @@ -6,8 +6,9 @@ # Marcin Młynarczyk , 2016 # Martin Trigaux , 2016 # Piotr Szlązak , 2016 -# Grzegorz Grzelak , 2016 +# zbik2607 , 2016 # Judyta Kaźmierczak , 2016 +# Grzegorz Grzelak , 2016 # Zdzisław Krajewski , 2016 msgid "" msgstr "" @@ -43,7 +44,7 @@ msgstr "Suma" #: model:ir.actions.act_window,name:hr_timesheet.act_hr_timesheet_line_by_project #: model:ir.actions.act_window,name:hr_timesheet.act_hr_timesheet_report msgid "Activities" -msgstr "Actywności" +msgstr "Działania" #. module: hr_timesheet #: model:ir.ui.menu,name:hr_timesheet.menu_hr_activity_analysis diff --git a/addons/hr_timesheet/i18n/zh_CN.po b/addons/hr_timesheet/i18n/zh_CN.po index 5f84cf58b74..c7323453f8b 100644 --- a/addons/hr_timesheet/i18n/zh_CN.po +++ b/addons/hr_timesheet/i18n/zh_CN.po @@ -5,13 +5,14 @@ # Translators: # Jeffery CHEN , 2016 # 卓忆科技 , 2016 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-29 13:59+0000\n" "PO-Revision-Date: 2016-09-29 13:59+0000\n" -"Last-Translator: 卓忆科技 , 2016\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -102,7 +103,7 @@ msgstr "计算:花费的时间 + 剩余的时间" #. module: hr_timesheet #: model:ir.model.fields,help:hr_timesheet.field_project_task_total_hours_spent msgid "Computed as: Time Spent + Sub-tasks Hours." -msgstr "" +msgstr "计算方式:花费时间 + 子任务时间" #. module: hr_timesheet #: model:ir.model.fields,help:hr_timesheet.field_project_task_effective_hours diff --git a/addons/im_livechat/i18n/zh_CN.po b/addons/im_livechat/i18n/zh_CN.po index 5bf8c94d67f..e696f229f1d 100644 --- a/addons/im_livechat/i18n/zh_CN.po +++ b/addons/im_livechat/i18n/zh_CN.po @@ -4,13 +4,14 @@ # # Translators: # Jeffery CHEN , 2016 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-07 08:58+0000\n" "PO-Revision-Date: 2016-09-07 08:58+0000\n" -"Last-Translator: Jeffery CHEN , 2016\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -349,7 +350,7 @@ msgstr "分组..." #. module: im_livechat #: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_tree msgid "Has a Rating" -msgstr "" +msgstr "已有评级" #. module: im_livechat #: selection:im_livechat.channel.rule,action:0 @@ -835,7 +836,7 @@ msgstr "" msgid "" "Your chatter history is empty. Create a channel and start chatting to fill " "up your history." -msgstr "" +msgstr "你的交谈记录为空,现在创建一个频道并开始交谈就可以生成你的交谈记录。" #. module: im_livechat #: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form diff --git a/addons/lunch/i18n/pl.po b/addons/lunch/i18n/pl.po index 2a29ccf32c8..65d651a7d2c 100644 --- a/addons/lunch/i18n/pl.po +++ b/addons/lunch/i18n/pl.po @@ -236,7 +236,7 @@ msgstr "Konfiguracja" #: model:ir.actions.act_window,name:lunch.lunch_cashmove_action_control_accounts #: model:ir.ui.menu,name:lunch.lunch_cashmove_menu_control_accounts msgid "Control Accounts" -msgstr "kontrola kont" +msgstr "Kontrola kont" #. module: lunch #: model:ir.actions.act_window,name:lunch.lunch_order_line_action_control_suppliers diff --git a/addons/mail/i18n/de.po b/addons/mail/i18n/de.po index 05ebb3cc49d..fbb6244cc85 100644 --- a/addons/mail/i18n/de.po +++ b/addons/mail/i18n/de.po @@ -4759,7 +4759,7 @@ msgstr "Abonnenten" #. module: mail #: model:ir.ui.view,arch_db:mail.message_origin_link msgid "from:" -msgstr "" +msgstr "von:" #. module: mail #: model:mail.channel,name:mail.channel_all_employees diff --git a/addons/marketing_campaign/i18n/pl.po b/addons/marketing_campaign/i18n/pl.po index 0efd4d9583d..28d24c90e6c 100644 --- a/addons/marketing_campaign/i18n/pl.po +++ b/addons/marketing_campaign/i18n/pl.po @@ -84,7 +84,7 @@ msgstr "Akcja" #: model:ir.ui.view,arch_db:marketing_campaign.view_marketing_campaign_activity_tree #: model:ir.ui.view,arch_db:marketing_campaign.view_marketing_campaign_form msgid "Activities" -msgstr "Actywności" +msgstr "Działania" #. module: marketing_campaign #: model:ir.model.fields,field_description:marketing_campaign.field_campaign_analysis_activity_id diff --git a/addons/mrp/i18n/de.po b/addons/mrp/i18n/de.po index 4ea1d22d117..490abe84270 100644 --- a/addons/mrp/i18n/de.po +++ b/addons/mrp/i18n/de.po @@ -3127,7 +3127,7 @@ msgstr "" #: code:addons/mrp/static/src/js/mrp.js:24 #, python-format msgid "Waiting Materials" -msgstr "" +msgstr "Wartende Materialien" #. module: mrp #: model:ir.model,name:mrp.model_stock_warehouse diff --git a/addons/mrp/i18n/hr.po b/addons/mrp/i18n/hr.po index 2c7bc430f87..deae046b8df 100644 --- a/addons/mrp/i18n/hr.po +++ b/addons/mrp/i18n/hr.po @@ -10,9 +10,9 @@ # Vladimir Olujić , 2016 # Marko Carević , 2016 # Tina Milas , 2016 -# KRISTINA PALAŠ , 2016 # Ivica Dimjašević , 2016 # Mario Jureša , 2016 +# KRISTINA PALAŠ , 2016 # Ana-Maria Olujić , 2016 # Stjepan Lovasić , 2017 msgid "" @@ -838,7 +838,7 @@ msgstr "Trenutna količina" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workorder_qty_producing msgid "Currently Produced Quantity" -msgstr "Trenutno proizvodena količina" +msgstr "Trenutno proizvedena količina" #. module: mrp #: model:ir.ui.menu,name:mrp.menu_mrp_dashboard @@ -1261,7 +1261,7 @@ msgstr "Je razlog blokiranja" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workorder_is_produced msgid "Is produced" -msgstr "Je proizvodeno" +msgstr "Je proizvedeno" #. module: mrp #: code:addons/mrp/models/mrp_workcenter.py:149 @@ -1450,7 +1450,7 @@ msgstr "Upravljanje operacijama radnih naloga" #. module: mrp #: selection:mrp.config.settings,module_mrp_plm:0 msgid "Manage engineering changes, versions and documents" -msgstr "Upravljajte izmjenama, verzijama i dokumentima" +msgstr "Upravljanje izmjenama, verzijama i dokumentima" #. module: mrp #: selection:mrp.config.settings,group_mrp_routings:0 @@ -1465,7 +1465,7 @@ msgstr "Upravljanje proizvodnjom prema radnim nalozima" #. module: mrp #: selection:mrp.config.settings,module_quality_mrp:0 msgid "Manage quality control points, checks and measures" -msgstr "Upravljajte kontrolnim točkama kvalitete, provjerama i mjerama" +msgstr "Upravljanje kontrolnim točkama kvalitete, provjerama i mjerama" #. module: mrp #: model:res.groups,name:mrp.group_mrp_manager @@ -2040,7 +2040,7 @@ msgstr "Proizvoed stavke" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_production_form_view msgid "Produced" -msgstr "Proizvoedeno" +msgstr "Proizvedeno" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_quant_produced_quant_ids @@ -2370,7 +2370,7 @@ msgstr "Povezane nabave" #. module: mrp #: model:ir.model.fields,help:mrp.field_mrp_workcenter_user_id msgid "Related user name for the resource to manage its access." -msgstr "Korisničko ime povezano je sa pristupom i upravljanjem modulima" +msgstr "Korisničko ime povezano je s pristupom i upravljanjem modulima" #. module: mrp #: model:ir.ui.menu,name:mrp.menu_mrp_reporting @@ -3085,7 +3085,7 @@ msgid "" "Use Master Production Schedule in order to create procurements based on " "forecasts" msgstr "" -"Koristite Master plan proizvodnje za kreiranje nabava prema predviđanjima " +"Koristi Master plan proizvodnje za kreiranje nabava prema predviđanjima " #. module: mrp #: model:ir.actions.act_window,help:mrp.mrp_message_action_main @@ -3376,7 +3376,7 @@ msgstr "" #. module: mrp #: model:ir.ui.view,arch_db:mrp.oee_search_view msgid "Workcenter" -msgstr "Radni Centar" +msgstr "Radni centar" #. module: mrp #: model:ir.ui.view,arch_db:mrp.oee_form_view diff --git a/addons/mrp/i18n/nl.po b/addons/mrp/i18n/nl.po index 09b354a0279..776bfb0d1f5 100644 --- a/addons/mrp/i18n/nl.po +++ b/addons/mrp/i18n/nl.po @@ -3163,24 +3163,24 @@ msgstr "Zeer urgent" #: model:ir.ui.view,arch_db:mrp.view_mrp_production_filter #: selection:mrp.production,availability:0 msgid "Waiting" -msgstr "Wachten" +msgstr "Wachtend" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_workcenter_kanban msgid "Waiting Availability" -msgstr "Wachten op beschikbaarheid" +msgstr "Wachtend op beschikbaarheid" #. module: mrp #: model:ir.actions.act_window,name:mrp.mrp_production_action_waiting msgid "Waiting Availability MO" -msgstr "Wachten beschikbaarheid productieorder" +msgstr "Wachten op beschikbaarheid productieorder" #. module: mrp #. openerp-web #: code:addons/mrp/static/src/js/mrp.js:24 #, python-format msgid "Waiting Materials" -msgstr "Wachten materialen" +msgstr "Wachtend op materialen" #. module: mrp #: model:ir.model,name:mrp.model_stock_warehouse diff --git a/addons/mrp/i18n/zh_CN.po b/addons/mrp/i18n/zh_CN.po index b98367dc01c..cf51812dd70 100644 --- a/addons/mrp/i18n/zh_CN.po +++ b/addons/mrp/i18n/zh_CN.po @@ -5,13 +5,14 @@ # Translators: # Jeffery CHEN , 2016 # Bo Cao , 2017 +# 苏州远鼎 , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: Bo Cao , 2017\n" +"Last-Translator: 苏州远鼎 , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2697,7 +2698,7 @@ msgstr "容量必须严格为正数." #. module: mrp #: selection:mrp.bom,ready_to_produce:0 msgid "The components of 1st operation" -msgstr "首次作业的部件" +msgstr "第一个作业的部件" #. module: mrp #: model:ir.model.fields,help:mrp.field_mrp_production_routing_id @@ -3445,7 +3446,7 @@ msgstr "你需要提供批次/序列号" #: code:addons/mrp/wizard/mrp_product_produce.py:78 #, python-format msgid "You should at least produce some quantity" -msgstr "" +msgstr "必须输入生产数量" #. module: mrp #: code:addons/mrp/models/mrp_workorder.py:287 @@ -3487,7 +3488,7 @@ msgstr "最后的" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_workcenter_view msgid "minute(s)" -msgstr "" +msgstr "分钟" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_production_workcenter_form_view_inherit diff --git a/addons/payment/i18n/hr.po b/addons/payment/i18n/hr.po index d5afb6950f8..6b3909514ec 100644 --- a/addons/payment/i18n/hr.po +++ b/addons/payment/i18n/hr.po @@ -239,7 +239,7 @@ msgstr "Otkazano" #. module: payment #: model:ir.ui.view,arch_db:payment.transaction_form msgid "Capture Transaction" -msgstr "" +msgstr "Zabilježi transakciju" #. module: payment #: model:ir.model.fields,field_description:payment.field_payment_transaction_partner_city diff --git a/addons/point_of_sale/i18n/hr.po b/addons/point_of_sale/i18n/hr.po index 1db6e7f5bae..ae78be8770a 100644 --- a/addons/point_of_sale/i18n/hr.po +++ b/addons/point_of_sale/i18n/hr.po @@ -178,7 +178,7 @@ msgstr "= Teoretski saldo zatvaranja" #: code:addons/point_of_sale/static/src/js/screens.js:1909 #, python-format msgid "? Clicking \"Confirm\" will validate the payment." -msgstr "? Klik na \"Potvrdi\" će potvrditi uplatu" +msgstr "? Klik na \"Potvrdi\" će potvrditi uplatu." #. module: point_of_sale #. openerp-web diff --git a/addons/point_of_sale/i18n/pl.po b/addons/point_of_sale/i18n/pl.po index ec3a6144eb0..4e594a481a1 100644 --- a/addons/point_of_sale/i18n/pl.po +++ b/addons/point_of_sale/i18n/pl.po @@ -1939,7 +1939,7 @@ msgstr "Zamówienie " #. module: point_of_sale #: model:ir.model.fields,field_description:point_of_sale.field_pos_order_date_order msgid "Order Date" -msgstr "data zamówienia" +msgstr "Data zamówienia" #. module: point_of_sale #: model:ir.model.fields,field_description:point_of_sale.field_pos_config_sequence_id diff --git a/addons/product/i18n/zh_CN.po b/addons/product/i18n/zh_CN.po index 897e425593f..7fdb18cce72 100644 --- a/addons/product/i18n/zh_CN.po +++ b/addons/product/i18n/zh_CN.po @@ -5,13 +5,14 @@ # Translators: # Jeffery CHEN , 2016 # Ted Wang , 2016 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: Ted Wang , 2016\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -749,7 +750,7 @@ msgstr "产品的成本,以产品的默认计量单位表示。" #: model:product.product,name:product.service_delivery #: model:product.template,name:product.service_delivery_product_template msgid "Cost-plus Contract" -msgstr "" +msgstr "成本加成合同" #. module: product #: model:ir.model,name:product.model_res_country_group @@ -1269,7 +1270,7 @@ msgstr "" msgid "" "How much bigger or smaller this unit is compared to the reference Unit of " "Measure for this category: 1 * (reference unit) = ratio * (this unit)" -msgstr "" +msgstr "本类别计量单位和参考计量单位相比,大或者小的倍数。1 * (参考单位)=比率 * (本单位)" #. module: product #: model:product.product,website_description:product.product_product_11 @@ -2736,7 +2737,7 @@ msgstr "USB端口允许软件更新,以确保持续的蓝牙设备兼容" #. module: product #: model:product.pricelist,name:product.list0 msgid "USD" -msgstr "" +msgstr "美元" #. module: product #: model:product.product,website_description:product.product_product_6 diff --git a/addons/product_margin/i18n/zh_CN.po b/addons/product_margin/i18n/zh_CN.po index f9ae548d9b7..9061d698ab0 100644 --- a/addons/product_margin/i18n/zh_CN.po +++ b/addons/product_margin/i18n/zh_CN.po @@ -4,13 +4,14 @@ # # Translators: # Jeffery CHEN , 2016 +# liAnGjiA , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-07 08:57+0000\n" "PO-Revision-Date: 2016-09-07 08:57+0000\n" -"Last-Translator: Jeffery CHEN , 2016\n" +"Last-Translator: liAnGjiA , 2016\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -382,7 +383,7 @@ msgstr "营业额 - 标准价格" #. module: product_margin #: model:ir.model.fields,field_description:product_margin.field_product_product_supplier_taxes_id msgid "Vendor Taxes" -msgstr "供应商税" +msgstr "进项税" #. module: product_margin #: model:ir.model.fields,help:product_margin.field_product_product_email_template_id diff --git a/addons/project/i18n/hr.po b/addons/project/i18n/hr.po index 6e311e5e419..beefcc0c3cc 100644 --- a/addons/project/i18n/hr.po +++ b/addons/project/i18n/hr.po @@ -2017,7 +2017,7 @@ msgstr "Predviđanja" #. module: project #: model:ir.model.fields,field_description:project.field_project_config_settings_module_project_forecast msgid "Forecasts, planning and Gantt charts" -msgstr "" +msgstr "Predviđanja, planiranje i Ganttov dijagram" #. module: project #: model:ir.ui.menu,name:project.menu_tasks_config diff --git a/addons/project/i18n/hu.po b/addons/project/i18n/hu.po index ecd24758732..d903b54481e 100644 --- a/addons/project/i18n/hu.po +++ b/addons/project/i18n/hu.po @@ -934,13 +934,13 @@ msgstr "" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "What Activities would you like to manage?" -msgstr "Milyen Tevékenységeket szeretne kezelni?" +msgstr "Milyen tevékenységeket szeretne kezelni?" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "What do you expect from using Odoo Project?" msgstr "" -"Mit vár el az Odoo rendszer Projekt alkalmazás " +"Mit vár el az Odoo rendszer projektalkalmazásának " "használatától?" #. module: project @@ -1305,9 +1305,9 @@ msgid "" " For example, you'll understand why you shouldn’t use Odoo to plan but instead to\n" " collaborate, or why organizing your projects by role is wrong." msgstr "" -"Azért mer a változás sohasem könnyű, létrehoztuk ezt a tervezőt az irányításhoz.
\n" -" Például, meg fogja érteni, hogy miért használja az Odoo rendszert inkább együttműködésre és nem\n" -" tervezésre, és miért hiba szerepkörönként szervezni a projekt témáit." +"Mivel a változás sohasem könnyű, létrehoztuk ezt az útmutatóként szolgáló tervezőt.
\n" +" Például meg fogja érteni, hogy miért ne használja az Odoo rendszert tervezésre,\n" +" hanem helyette együttműködésre, vagy miért helytelen szerepek szerint szerveznie a projekteket." #. module: project #: model:project.task,legend_done:project.project_task_10 @@ -1437,7 +1437,7 @@ msgstr "Szín jegyzék" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Communication campaign" -msgstr "Közlemény kampány" +msgstr "Kommunikációs kampány" #. module: project #: model:ir.model,name:project.model_res_company @@ -1484,8 +1484,8 @@ msgid "" "Congratulations on choosing Odoo Project to help running your company more " "efficiently!" msgstr "" -"Gratulálunk az Odoo rendszer Projekt alkalmazásának kiválasztásához! Az " -"alkalmazás segíti vállalatát hatékonyabban irányítani!" +"Gratulálunk az Odoo rendszer projektalkalmazásának kiválasztásához! Az " +"alkalmazás segíti Önt vállalatának hatékonyabb irányításában." #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -1495,7 +1495,7 @@ msgstr "Gratulálok, elvégezte !" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Consulting mission" -msgstr "Tanácsadó küldetés" +msgstr "Tanácsadói megbízás" #. module: project #: model:ir.model.fields,field_description:project.field_report_project_task_user_partner_id @@ -1512,7 +1512,7 @@ msgstr "Szerződés/Gyüjtő,elemző" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Control projects quality and satisfaction" -msgstr "Projekt témák minőségét és elégedettségét felügyelheti" +msgstr "A projektminőség és az elégedettség ellenőrzése" #. module: project #. openerp-web @@ -1672,7 +1672,7 @@ msgstr "Ügyfél szolgálat új ügyet talált" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Customer support tickets" -msgstr "Vásárlói támogató jegyek" +msgstr "Ügyféltámogatási kérések" #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -2039,7 +2039,7 @@ msgid "" "For the Odoo Team,
\n" " Fabien Pinckaers, Founder" msgstr "" -"Az Oddo rendszer csapatának,
\n" +"Az Oddo rendszer csapata nevében,
\n" " Fabien Pinckaers, Alapító" #. module: project @@ -2227,7 +2227,7 @@ msgstr "Ötletek" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Identify problems and blocking points more easily" -msgstr "Sokkal könnyebben határozza meg a problémákat és blokkoló pontokat" +msgstr "A problémák és blokkoló pontok sokkal könnyebb azonosítása" #. module: project #: model:ir.model.fields,help:project.field_project_task_type_mail_template_id @@ -2288,7 +2288,7 @@ msgstr "Fejlessze" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Improve collaboration with customers" -msgstr "Fejlessze az együttműködést a vásárlókkal" +msgstr "A vásárlókkal történő együttműködés fejlesztése" #. module: project #: selection:project.task,kanban_state:0 @@ -2408,8 +2408,8 @@ msgid "" "It's essential to be clear about why you want to use Odoo Project and what your goals are.\n" " Indeed, there are many ways to manage a project, to find the best one for you, you need to know exactly what you want to achieve. And later on, we will hopefully transform your objectives into real improvements for your company." msgstr "" -"Fontos tisztában lenni azzal, hogy miért használja az Odoo rendszer Projekt alkalmazását, hogy milyen céljai vannak vele.\n" -" Több útja is van a projektek szervezésének, pontosan tudnia kell, mit akar elérni ahhoz, hogy megtalálja a lehető legjobbat. Miután megismeri az alkalmazást, könnyebben tudja majd céljait elérni és fejleszteni vállalkozását." +"Fontos tisztában lennie azzal, hogy miért akarja használni az Odoo rendszer projektalkalmazását, és hogy milyen céljai vannak vele.\n" +" Több módja van a projektek kezelésének, pontosan tudnia kell, mit akar elérni ahhoz, hogy megtalálja az Ön számára legjobbat. Később remélhetőleg át tudjuk alakítani célkitűzéseit a vállalata valós fejlesztéseivé." #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -2467,12 +2467,12 @@ msgstr "Kanban tényleges magyarázata" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Keep track of messages and conversations" -msgstr "Kövesse nyomon az üzeneteit és párbeszédeit" +msgstr "Az üzenetek és beszélgetések nyomon követése" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Know what my employees are working on" -msgstr "Tudja az alkalmazottaim min dolgoznak" +msgstr "Tudjam, hogy min dolgoznak az alkalmazottaim" #. module: project #: model:ir.ui.view,arch_db:project.view_task_search_form @@ -2551,7 +2551,7 @@ msgstr "" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "List, plan and track things to do" -msgstr "Elvégzendő feladatok listája, terve és követése" +msgstr "Teendők listázása, tervezése és nyomon követése" #. module: project #: selection:report.project.task.user,priority:0 @@ -2620,7 +2620,7 @@ msgstr "További információ" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "More efficient communication between employees" -msgstr "Sokkal hatékonyabb munkavállaló közti kommunikáció" +msgstr "Hatékonyabb kommunikáció a munkavállalók között" #. module: project #: model:ir.ui.view,arch_db:project.view_project_project_filter @@ -2741,9 +2741,9 @@ msgid "" " everyone in your company. Follow how things progress, see when things are stuck, know\n" " who's in charge, all in one place." msgstr "" -"Odoo Projekt alkalmazás egy gyors és könnyen használható módja a vállalatán belül a tevékenységek és feladatok mindenki \n" -" számára láthatóvá tételéhez. Figyelje a dolgok alakulását, lássa, mi akadt el, tudja mindig, hogy ki\n" -" a felelős, kezelje a feladatokat egy helyen." +"Az Odoo projektalkalmazása egy gyors és könnyen használható módja annak, hogy a tevékenységek és feladatok mindenki \n" +" számára láthatóvá váljanak a vállalatán belül . Kövesse a dolgok előrehaladását, lássa, ha valami elakadt, legyen tisztában azzal, hogy\n" +" ki a felelős, mindezt egy helyen." #. module: project #: model:ir.model.fields,help:project.field_project_config_settings_generate_project_alias @@ -3291,7 +3291,7 @@ msgstr "" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Software development" -msgstr "Szoftver fejlesztés" +msgstr "Szoftverfejlesztés" #. module: project #. openerp-web @@ -3576,12 +3576,12 @@ msgid "" " mean it's always a good idea: let's start by helping you understand what " "can be a good project." msgstr "" -"Az Odoo Projekt alkalmazást több tevékenység kezelésére használhatja, egy új" -" termék fejlesztésén keresztül egészen a mindennapos ügyféltámogatáshoz. " -"Némi kreativitással a marketing kommunikációhoz is használható vagy akár " -"személyes projektekhez is. De csak azért, mert valami megoldható az " -"alkalmazással még nem jelenti azt, hogy jó ötlet is: Első lépésként ezért " -"segítünk megérteni, hogy mire lehet egy jó projekt." +"Az Odoo projektalkalmazását sok tevékenység kezelésére használhatja, egy új " +"termék fejlesztésétől a mindennapos ügyféltámogatásig. Némi kreativitással a" +" marketing kommunikációhoz is használható vagy akár személyes projektekhez " +"is. De csak azért, mert valami megoldható az alkalmazással még nem jelenti " +"azt, hogy mindig jó ötlet is: első lépésként ezért segítünk megérteni, hogy " +"milyen egy jó projekt." #. module: project #: model:ir.model.fields,help:project.field_project_project_alias_model @@ -3688,8 +3688,8 @@ msgid "" "This whole process might take you a few hours, but don't worry, you can take a break and\n" " return to it at any time: your progress is automatically saved." msgstr "" -"Ez az egész folyamat csak egy pár órát vesz igénybe, de ne bosszankodjon, tarthat szünetet és\n" -" visszatérhet bármikor: a folyamata automatikusan mentésre kerül." +"Ez az egész folyamat csak néhány órát vesz igénybe, de ne aggódjon, tarthat szünetet és\n" +" visszatérhet bármikor: az előrehaladása automatikusan mentésre kerül." #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -3893,7 +3893,7 @@ msgstr "Érvényesítés" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "View statistics (time spent, efficiency, etc.)" -msgstr "Nézettségi statisztika (eltöltött idő, hatékonyság, stb.)" +msgstr "Statisztika megtekintése (eltöltött idő, hatékonyság, stb.)" #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -3980,7 +3980,7 @@ msgstr "" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Welcome" -msgstr "Üdvözlet" +msgstr "Üdvözöljük" #. module: project #: model:ir.ui.view,arch_db:project.project_planner @@ -4117,12 +4117,12 @@ msgstr "" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Your Activities" -msgstr "Tevékenységei" +msgstr "Tevékenységek" #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "Your Objectives" -msgstr "Célkitűzései" +msgstr "Célkitűzések" #. module: project #: model:mail.template,subject:project.mail_template_data_module_install_project diff --git a/addons/project/i18n/zh_CN.po b/addons/project/i18n/zh_CN.po index 67a9a02fdb7..5992b076dc1 100644 --- a/addons/project/i18n/zh_CN.po +++ b/addons/project/i18n/zh_CN.po @@ -8,13 +8,15 @@ # liAnGjiA , 2016 # Bo Cao , 2016 # Yaorong Li <55yaorong.li@gmail.com>, 2017 +# 苏州远鼎 , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:26+0000\n" "PO-Revision-Date: 2017-06-23 13:26+0000\n" -"Last-Translator: Yaorong Li <55yaorong.li@gmail.com>, 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -213,7 +215,7 @@ msgstr "" #: code:addons/project/static/src/js/tour.js:83 #, python-format msgid "Click the save button to apply your changes to the task." -msgstr "" +msgstr "点击保存按钮 应用对任务的更改。" #. module: project #. openerp-web @@ -1877,7 +1879,7 @@ msgstr "最后的任务已经部署" #. module: project #: model:ir.model.fields,field_description:project.field_project_task_type_fold msgid "Folded in Kanban" -msgstr "" +msgstr "在看板中折叠" #. module: project #: model:ir.ui.view,arch_db:project.edit_project @@ -3811,7 +3813,7 @@ msgstr "你可以从你自己的邮件系统对一个消息进行回复;你回 #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "You can save your reports to easily reuse it later" -msgstr "" +msgstr "您可以将报表保存便于以后重复使用" #. module: project #: code:addons/project/models/project.py:70 diff --git a/addons/purchase/i18n/hr.po b/addons/purchase/i18n/hr.po index c844d7a66f1..dec1131d525 100644 --- a/addons/purchase/i18n/hr.po +++ b/addons/purchase/i18n/hr.po @@ -5,10 +5,10 @@ # Translators: # Karolina Tonković , 2016 # Martin Trigaux , 2016 +# Tina Milas , 2016 # Marko Carević , 2016 # Vladimir Olujić , 2016 # Đurđica Žarković , 2016 -# Tina Milas , 2016 # Bole , 2016 # Ivica Dimjašević , 2016 # Jasmina Otročak , 2016 @@ -230,7 +230,7 @@ msgstr "Dopusti uređivanje nabavnih naloga" #. module: purchase #: selection:purchase.config.settings,group_manage_vendor_price:0 msgid "Allow using and importing vendor pricelists" -msgstr "Dopustite korištenje i uvoz cjenika dobavljača" +msgstr "Dopusti korištenje i uvoz cjenika dobavljača" #. module: purchase #: selection:purchase.config.settings,module_purchase_requisition:0 @@ -585,7 +585,7 @@ msgstr "Dostaviti" #. module: purchase #: model:ir.ui.view,arch_db:purchase.purchase_order_form msgid "Deliveries & Invoices" -msgstr "Otpremnice i računi" +msgstr "Primke i računi" #. module: purchase #: model:ir.model.fields,help:purchase.field_purchase_order_date_order diff --git a/addons/purchase/i18n/pl.po b/addons/purchase/i18n/pl.po index 1787b262f16..b79fea4a044 100644 --- a/addons/purchase/i18n/pl.po +++ b/addons/purchase/i18n/pl.po @@ -565,7 +565,7 @@ msgstr "Kontrola" #: model:ir.model.fields,field_description:purchase.field_product_product_purchase_method #: model:ir.model.fields,field_description:purchase.field_product_template_purchase_method msgid "Control Purchase Bills" -msgstr "kontrola rachunków zamówień" +msgstr "Kontrola rachunków zamówień" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_purchase_config_settings_group_costing_method @@ -965,7 +965,7 @@ msgstr "Dla otrzymanych ilości" #: model:ir.model.fields,field_description:purchase.field_purchase_report_date_order #: model:ir.ui.view,arch_db:purchase.view_purchase_order_filter msgid "Order Date" -msgstr "data zamówienia" +msgstr "Data zamówienia" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_purchase_order_order_line diff --git a/addons/purchase/i18n/zh_CN.po b/addons/purchase/i18n/zh_CN.po index 098f12d3bca..bc001b8de53 100644 --- a/addons/purchase/i18n/zh_CN.po +++ b/addons/purchase/i18n/zh_CN.po @@ -9,13 +9,14 @@ # Bo Cao , 2016 # 林俊 <54773801@qq.com>, 2017 # guohuadeng , 2017 +# 苏州远鼎 , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: guohuadeng , 2017\n" +"Last-Translator: 苏州远鼎 , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1321,7 +1322,7 @@ msgstr "已接收数量" #: code:addons/purchase/models/purchase.py:580 #, python-format msgid "Received Quantity" -msgstr "" +msgstr "收到数量" #. module: purchase #: model:ir.actions.act_window,name:purchase.purchase_open_picking diff --git a/addons/purchase_requisition/i18n/de.po b/addons/purchase_requisition/i18n/de.po index fca66535b2f..d2fdc6e4b77 100644 --- a/addons/purchase_requisition/i18n/de.po +++ b/addons/purchase_requisition/i18n/de.po @@ -7,19 +7,20 @@ # darenkster , 2016 # Wolfgang Taferner , 2016 # Henry Mineehen , 2016 -# Thomas A. Jaeger , 2016 +# Renzo Meister , 2016 # Tina Rittmüller , 2016 # Philipp Hug , 2016 # Thorsten Vocks , 2016 # Rudolf Schnapka , 2016 # Ermin Trevisan , 2016 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-11-14 15:54+0000\n" "PO-Revision-Date: 2016-11-14 15:54+0000\n" -"Last-Translator: Ermin Trevisan , 2016\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -85,24 +86,24 @@ msgstr "Lieferant" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_date_end msgid "Agreement Deadline" -msgstr "" +msgstr "Vertragsfrist" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_name msgid "Agreement Reference" -msgstr "" +msgstr "Vertragsreferenz" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_exclusive msgid "Agreement Selection Type" -msgstr "" +msgstr "Vertrag Auswahltyp" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_id_10833 #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_name #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form msgid "Agreement Type" -msgstr "" +msgstr "Vertragsart" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_account_analytic_id @@ -118,7 +119,7 @@ msgstr "Gebotsauswahl" #. module: purchase_requisition #: model:purchase.requisition.type,name:purchase_requisition.type_single msgid "Blanket Order" -msgstr "" +msgstr "Blankoauftrag" #. module: purchase_requisition #: model:ir.actions.report.xml,name:purchase_requisition.action_report_purchase_requisitions @@ -140,12 +141,12 @@ msgstr "Abgebrochen" #: code:addons/purchase_requisition/models/purchase_requisition.py:76 #, python-format msgid "Cancelled by the agreement associated to this quotation." -msgstr "" +msgstr "Kündigt durch den mit diesem Angebot verbundenen Vertrag." #. module: purchase_requisition #: model:ir.actions.act_window,help:purchase_requisition.action_purchase_requisition msgid "Click to start a new purchase agreement." -msgstr "" +msgstr "Klicken Sie hier, um einen neuen Kaufvertrag abzuschließen." #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_company_id @@ -186,12 +187,12 @@ msgstr "Angelegt am" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form msgid "Data for new quotations" -msgstr "" +msgstr "Daten für neue Angebote" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_schedule_date msgid "Delivery Date" -msgstr "" +msgstr "Liefertermin" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_description @@ -208,7 +209,7 @@ msgstr "Anzeigename" #. module: purchase_requisition #: selection:purchase.requisition.type,line_copy:0 msgid "Do not create RfQ lines automatically" -msgstr "" +msgstr "Anfragepositionen nicht automatisch anlegen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter @@ -266,7 +267,7 @@ msgstr "" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "In negotiation" -msgstr "" +msgstr "In Verhandlung" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition___last_update @@ -307,7 +308,7 @@ msgstr "Multiple Bestellmeldung" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "New Agreements" -msgstr "" +msgstr "Neue Verträge" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form @@ -317,12 +318,12 @@ msgstr "Neues Angebot" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_order_count msgid "Number of Orders" -msgstr "" +msgstr "Anzahl der Aufträge" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_line_qty_ordered msgid "Ordered Quantities" -msgstr "" +msgstr "Bestellte Mengen" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_ordering_date @@ -377,12 +378,12 @@ msgstr "Eine Ausschreibung vorschlagen" #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_order_requisition_id #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_line_requisition_id msgid "Purchase Agreement" -msgstr "" +msgstr "Kaufvertrag" #. module: purchase_requisition #: model:ir.model,name:purchase_requisition.model_purchase_requisition_type msgid "Purchase Agreement Type" -msgstr "" +msgstr "Kaufvertragsart" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.tender_type_action @@ -390,7 +391,7 @@ msgstr "" #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_tree msgid "Purchase Agreement Types" -msgstr "" +msgstr "Kaufvertragsarten" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition @@ -399,7 +400,7 @@ msgstr "" #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_tree msgid "Purchase Agreements" -msgstr "" +msgstr "Kaufverträge" #. module: purchase_requisition #: model:ir.model,name:purchase_requisition.model_purchase_order @@ -440,7 +441,7 @@ msgstr "Bedarfsanfrage erstellt" #. module: purchase_requisition #: model:purchase.requisition.type,name:purchase_requisition.type_multi msgid "Purchase Tender" -msgstr "" +msgstr "Kauf-Ausschreibung" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.act_res_partner_2_purchase_order @@ -460,7 +461,7 @@ msgstr "Menge" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form msgid "RFQs/Orders" -msgstr "" +msgstr "Anfragen/Bestellungen" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition_to_so @@ -470,7 +471,7 @@ msgstr "Angebotsanfrage" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition_list msgid "Request for Quotations" -msgstr "" +msgstr "Angebotanfragen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.report_purchaserequisitions @@ -501,7 +502,7 @@ msgstr "Geplantes Datum" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "Search Purchase Agreements" -msgstr "" +msgstr "Suche Kaufverträge" #. module: purchase_requisition #: selection:purchase.requisition.type,exclusive:0 @@ -529,7 +530,7 @@ msgstr "Reihenfolge" #. module: purchase_requisition #: selection:purchase.requisition.type,quantity_copy:0 msgid "Set quantities manually" -msgstr "" +msgstr "Menge manuell festlegen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter @@ -578,7 +579,7 @@ msgstr "Preis pro ME" #. module: purchase_requisition #: selection:purchase.requisition.type,line_copy:0 msgid "Use lines of agreement" -msgstr "" +msgstr "Vertragspositionen verwenden" #. module: purchase_requisition #: selection:purchase.requisition.type,quantity_copy:0 @@ -605,6 +606,7 @@ msgstr "Lager" #, python-format msgid "You cannot confirm call because there is no product line." msgstr "" +"Sie können den Anfrage nicht bestätigen, weil es keine Produktposition gibt." #. module: purchase_requisition #: code:addons/purchase_requisition/models/purchase_requisition.py:99 @@ -613,6 +615,8 @@ msgid "" "You have to cancel or validate every RfQ before closing the purchase " "requisition." msgstr "" +"Sie müssen jede Anfrage stornieren oder validieren, bevor Sie die " +"Bestellanforderung abschließen." #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form diff --git a/addons/report/i18n/zh_CN.po b/addons/report/i18n/zh_CN.po index a1d35f0d3a7..9aa83e7f3e7 100644 --- a/addons/report/i18n/zh_CN.po +++ b/addons/report/i18n/zh_CN.po @@ -5,13 +5,14 @@ # Translators: # Jeffery CHEN , 2016 # liAnGjiA , 2016 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:27+0000\n" "PO-Revision-Date: 2017-06-23 13:27+0000\n" -"Last-Translator: liAnGjiA , 2016\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -522,7 +523,7 @@ msgstr "" #: code:addons/report/models/report.py:164 #, python-format msgid "Unable to find Wkhtmltopdf on this system. The PDF can not be created." -msgstr "" +msgstr "未找到 WKhtmltopdf 系统,无法创建 PDF。" #. module: report #: model:ir.ui.view,arch_db:report.external_layout_footer diff --git a/addons/sale/i18n/pl.po b/addons/sale/i18n/pl.po index db6ce995c37..41585cb04e8 100644 --- a/addons/sale/i18n/pl.po +++ b/addons/sale/i18n/pl.po @@ -336,6 +336,7 @@ msgstr "zaliczka: %s" #: selection:sale.config.settings,sale_pricelist_setting:0 msgid "Advanced pricing based on formulas (discounts, margins, rounding)" msgstr "" +"Zaawansowane cenniki bazujące na regułach (upusty, marże, zaokrąglenia) " #. module: sale #: selection:sale.config.settings,group_warning_sale:0 @@ -1333,7 +1334,7 @@ msgstr "zamówienie #" #. module: sale #: model:ir.model.fields,field_description:sale.field_sale_order_date_order msgid "Order Date" -msgstr "data zamówienia" +msgstr "Data zamówienia" #. module: sale #: model:ir.model.fields,field_description:sale.field_sale_order_order_line @@ -2044,7 +2045,7 @@ msgstr "Dokument źródłowy" #. module: sale #: selection:sale.config.settings,sale_pricelist_setting:0 msgid "Specific prices per customer segment, currency, etc." -msgstr "" +msgstr "Ceny ustalane dla klienta, waluty itp." #. module: sale #: model:ir.model.fields,field_description:sale.field_sale_order_state diff --git a/addons/sale_stock/i18n/hr.po b/addons/sale_stock/i18n/hr.po index 51ded9bd870..26e5ceb9ace 100644 --- a/addons/sale_stock/i18n/hr.po +++ b/addons/sale_stock/i18n/hr.po @@ -267,12 +267,12 @@ msgstr "Statistika prodajnih naloga" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_res_company_security_lead msgid "Sales Safety Days" -msgstr "" +msgstr "Sigurnosni dani prodaje" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_sale_config_settings_security_lead msgid "Sales Safety Days *" -msgstr "" +msgstr "Sigurnosni dani prodaje *" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_stock_location_route_sale_selectable diff --git a/addons/sale_stock/i18n/pl.po b/addons/sale_stock/i18n/pl.po index ada78694847..8694a0adea1 100644 --- a/addons/sale_stock/i18n/pl.po +++ b/addons/sale_stock/i18n/pl.po @@ -80,7 +80,7 @@ msgstr "Data" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_sale_config_settings_default_picking_policy msgid "Default Shipping Policy" -msgstr "brak zasad wysyłki" +msgstr "Zasady wysyłki" #. module: sale_stock #: selection:sale.order,picking_policy:0 diff --git a/addons/sale_timesheet/i18n/pl.po b/addons/sale_timesheet/i18n/pl.po index 7c0b7cf4bb6..8248ece1e9c 100644 --- a/addons/sale_timesheet/i18n/pl.po +++ b/addons/sale_timesheet/i18n/pl.po @@ -6,6 +6,7 @@ # Martin Trigaux , 2016 # Jaroslaw Kaczmarski , 2016 # Judyta Kaźmierczak , 2016 +# zbik2607 , 2016 # Piotr Szlązak , 2016 # Grzegorz Grzelak , 2016 msgid "" @@ -165,7 +166,7 @@ msgstr "" #. module: sale_timesheet #: model:ir.model.fields,field_description:sale_timesheet.field_hr_employee_timesheet_cost msgid "Timesheet Cost" -msgstr "koszt listy obecności" +msgstr "Koszt karty pracy" #. module: sale_timesheet #: model:ir.model.fields,field_description:sale_timesheet.project_time_mode_id_duplicate_xmlid diff --git a/addons/sales_team/i18n/fr.po b/addons/sales_team/i18n/fr.po index 56d4edf114a..bbb9a73610a 100644 --- a/addons/sales_team/i18n/fr.po +++ b/addons/sales_team/i18n/fr.po @@ -591,7 +591,7 @@ msgstr "" #. module: sales_team #: model:res.groups,name:sales_team.group_sale_salesman_all_leads msgid "User: All Documents" -msgstr "Utilisateur: tous les docments" +msgstr "Utilisateur: tous les documents" #. module: sales_team #: model:res.groups,name:sales_team.group_sale_salesman diff --git a/addons/stock/i18n/hr.po b/addons/stock/i18n/hr.po index ba47c8e5a40..a032ad6f3b6 100644 --- a/addons/stock/i18n/hr.po +++ b/addons/stock/i18n/hr.po @@ -374,7 +374,7 @@ msgstr "" #: model:ir.ui.view,arch_db:stock.inventory_planner msgid "Activate Track lots or serial numbers in your" msgstr "" -"Uključi Praćenje lotova i serijskih brojeva u vašem" +"Uključi praćenje lotova i serijskih brojeva u Vašem" #. module: stock #: model:ir.ui.view,arch_db:stock.inventory_planner @@ -666,7 +666,7 @@ msgstr "API dokumentacija" #. module: stock #: model:ir.ui.view,arch_db:stock.inventory_planner msgid "Accurate visibility on all your operations" -msgstr "Točna vidljivost na svim vašim operacijama" +msgstr "Točna vidljivost na svim Vašim operacijama" #. module: stock #: model:ir.model.fields,field_description:stock.field_report_stock_lines_date_active @@ -766,7 +766,7 @@ msgstr "Svi proizvodi" #. module: stock #: selection:stock.config.settings,group_stock_tracking_owner:0 msgid "All products in your warehouse belong to your company" -msgstr "Svi proizvodi u skladištu pripadaju vašoj tvrtki" +msgstr "Svi proizvodi u skladištu pripadaju Vašoj tvrtki" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_move_returned_move_ids @@ -793,7 +793,7 @@ msgstr "Dozvoli premještanje paketa" #. module: stock #: selection:stock.config.settings,module_stock_dropshipping:0 msgid "Allow suppliers to deliver directly to your customers" -msgstr "Dopusti dobavljačima direktnu dostavu vašim kupcima" +msgstr "Dopusti dobavljačima direktnu dostavu Vašim kupcima" #. module: stock #: model:ir.model.fields,help:stock.field_stock_config_settings_module_procurement_jit @@ -1798,9 +1798,9 @@ msgid "" msgstr "" "Poštovani Gospodine/Gospođo,\n" "\n" -"Naša evidencija pokazuje da nepodmiranih dugovanja. Molimo ispunite sljedeće podatke.\n" +"Naša evidencija pokazuje da ima nepodmiranih dugovanja. Molimo ispunite sljedeće podatke.\n" "Ukoliko je iznos već plaćen, molimo zanemarite ovu obavijest, u protivnom, molimo da uplatite ukupan navedeni iznos.\n" -"Ukoliko imate pitanja vezanih za vaš račun, molimo da nas kontaktirate.\n" +"Ukoliko imate pitanja vezanih za Vaš račun, molimo da nas kontaktirate.\n" "\n" "Unaprijed zahvaljujemo na suradnji.\n" "Srdačan pozdrav," @@ -3985,7 +3985,7 @@ msgstr "Dostupnost se nema za što provjeriti." #. module: stock #: model:ir.ui.view,arch_db:stock.inventory_planner msgid "Now, all your product quantities are correctly set." -msgstr "Sada, sve količina artikala su ispravno postavljene." +msgstr "Sada su sve količine artikala ispravno postavljene." #. module: stock #: model:ir.model.fields,field_description:stock.field_procurement_rule_delay @@ -6088,7 +6088,7 @@ msgid "" " the delivery of the finished products. It's the time you promise to your " "customers." msgstr "" -"Prosječni dani odgode od potvrđene načudđbe do isporuke gotovog proizvoda. " +"Prosječni dani odgode od potvrđene narudžbe do isporuke gotovog proizvoda. " "Ovo vrijeme jamčite kupcu kao rok isporuke." #. module: stock diff --git a/addons/stock/i18n/nl.po b/addons/stock/i18n/nl.po index f395cde152e..6362c889173 100644 --- a/addons/stock/i18n/nl.po +++ b/addons/stock/i18n/nl.po @@ -7247,23 +7247,23 @@ msgstr "Volume" #. module: stock #: model:ir.ui.view,arch_db:stock.stock_picking_type_kanban msgid "Waiting" -msgstr "Wachten" +msgstr "Wachtend" #. module: stock #: selection:stock.move,state:0 msgid "Waiting Another Move" -msgstr "Wachten op andere mutatie" +msgstr "Wachtend op andere mutatie" #. module: stock #: selection:stock.picking,state:0 msgid "Waiting Another Operation" -msgstr "Wachten op andere verwerking" +msgstr "Wachtend op andere verwerking" #. module: stock #: model:ir.ui.view,arch_db:stock.view_picking_internal_search #: selection:stock.move,state:0 selection:stock.picking,state:0 msgid "Waiting Availability" -msgstr "Wachten op beschikbaarheid" +msgstr "Wachtend op beschikbaarheid" #. module: stock #: model:ir.ui.view,arch_db:stock.view_picking_internal_search diff --git a/addons/stock/i18n/pl.po b/addons/stock/i18n/pl.po index fa640f57d30..c86da64dffb 100644 --- a/addons/stock/i18n/pl.po +++ b/addons/stock/i18n/pl.po @@ -4123,7 +4123,7 @@ msgstr "Opcjonalne: poprzednie przesunięcie jeśli powiązane" #. module: stock #: model:ir.ui.view,arch_db:stock.view_picking_internal_search msgid "Order Date" -msgstr "data zamówienia" +msgstr "Data zamówienia" #. module: stock #: model:stock.location,name:stock.location_order @@ -7277,6 +7277,8 @@ msgid "" "You haven't set processed (done) quantities. Click apply and\n" " Odoo will process all quantities to do." msgstr "" +"Nie ustalono pobranych (Wykonano) ilości. Kliknij przycisk Zastosuj \n" +"a Odoo przetworzy wszystkie ilości do wykonania." #. module: stock #: code:addons/stock/wizard/stock_picking_return.py:43 diff --git a/addons/web/i18n/pl.po b/addons/web/i18n/pl.po index 6c01190e63e..b3366791752 100644 --- a/addons/web/i18n/pl.po +++ b/addons/web/i18n/pl.po @@ -32,7 +32,7 @@ msgstr "" #: code:addons/web/static/src/js/views/form_common.js:874 #, python-format msgid " & Close" -msgstr " & Zamknięte" +msgstr " & Zamknij" #. module: web #. openerp-web diff --git a/addons/web_editor/i18n/zh_CN.po b/addons/web_editor/i18n/zh_CN.po index a13d8b2025a..0d05808c593 100644 --- a/addons/web_editor/i18n/zh_CN.po +++ b/addons/web_editor/i18n/zh_CN.po @@ -36,7 +36,7 @@ msgstr "(Youtube, Vimeo, Dailymotion)" #. module: web_editor #: model:ir.ui.view,arch_db:web_editor.colorpicker msgid "25% Black" -msgstr "25% 黑" +msgstr "黑色 25%" #. module: web_editor #: model:ir.ui.view,arch_db:web_editor.colorpicker diff --git a/addons/website/i18n/de.po b/addons/website/i18n/de.po index 3e5d1a7f3dc..b400539be77 100644 --- a/addons/website/i18n/de.po +++ b/addons/website/i18n/de.po @@ -2499,7 +2499,7 @@ msgstr "Ok" #: code:addons/website/static/src/xml/website.backend.xml:5 #, python-format msgid "On Website" -msgstr "" +msgstr "Auf Website" #. module: website #: model:ir.ui.view,arch_db:website.website_planner @@ -3452,7 +3452,7 @@ msgstr "" #: model:ir.ui.view,arch_db:website.publish_short #, python-format msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website #: model:ir.ui.view,arch_db:website.website_planner diff --git a/addons/website/i18n/pl.po b/addons/website/i18n/pl.po index 7187230b618..d727ddd6600 100644 --- a/addons/website/i18n/pl.po +++ b/addons/website/i18n/pl.po @@ -1611,7 +1611,7 @@ msgstr "" #. module: website #: model:res.groups,name:website.group_website_designer msgid "Editor and Designer" -msgstr "edytor i projektant" +msgstr "Edytor i projektant" #. module: website #: model:ir.ui.view,arch_db:website.s_comparisons @@ -2845,7 +2845,7 @@ msgstr "Resetuj szablony" #. module: website #: model:res.groups,name:website.group_website_publisher msgid "Restricted Editor" -msgstr "" +msgstr "Edytor z ograniczeniami" #. module: website #: model:ir.ui.view,arch_db:website.snippet_options diff --git a/addons/website_blog/i18n/de.po b/addons/website_blog/i18n/de.po index a786b9075d0..4247d54c4fa 100644 --- a/addons/website_blog/i18n/de.po +++ b/addons/website_blog/i18n/de.po @@ -17,13 +17,14 @@ # Mathias Neef , 2016 # Thorsten Vocks , 2016 # Torsten Wichmann , 2016 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:28+0000\n" "PO-Revision-Date: 2017-06-23 13:28+0000\n" -"Last-Translator: Torsten Wichmann , 2016\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -140,7 +141,7 @@ msgstr "" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.blog_post_template_new_post msgid "A new post" -msgstr "" +msgstr "Ein neuer Beitrag" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.opt_blog_rc_about_us @@ -896,7 +897,7 @@ msgstr "" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.opt_blog_rc_status msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.blog_post_short diff --git a/addons/website_portal_sale/i18n/pl.po b/addons/website_portal_sale/i18n/pl.po index 84ea87b95c0..d054b8be787 100644 --- a/addons/website_portal_sale/i18n/pl.po +++ b/addons/website_portal_sale/i18n/pl.po @@ -223,7 +223,7 @@ msgstr "Zamówienie" #. module: website_portal_sale #: model:ir.ui.view,arch_db:website_portal_sale.portal_my_orders msgid "Order Date" -msgstr "data zamówienia" +msgstr "Data zamówienia" #. module: website_portal_sale #: model:ir.ui.view,arch_db:website_portal_sale.portal_my_home_menu_sale diff --git a/addons/website_quote/i18n/zh_CN.po b/addons/website_quote/i18n/zh_CN.po index 54f5d81650e..97d6d5e6d58 100644 --- a/addons/website_quote/i18n/zh_CN.po +++ b/addons/website_quote/i18n/zh_CN.po @@ -4,13 +4,14 @@ # # Translators: # Jeffery CHEN , 2016 +# liAnGjiA , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:28+0000\n" "PO-Revision-Date: 2017-06-23 13:28+0000\n" -"Last-Translator: Jeffery CHEN , 2016\n" +"Last-Translator: liAnGjiA , 2016\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -81,7 +82,7 @@ msgstr "! 你可以" #: model:ir.ui.view,arch_db:website_quote.pricing #: model:ir.ui.view,arch_db:website_quote.report_saleorder_validity_date msgid "% discount" -msgstr "% discount" +msgstr "% 折扣" #. module: website_quote #: model:ir.ui.view,arch_db:website_quote.pricing diff --git a/addons/website_sale/i18n/nl.po b/addons/website_sale/i18n/nl.po index 3dbc79c9e7f..74e0b2f78eb 100644 --- a/addons/website_sale/i18n/nl.po +++ b/addons/website_sale/i18n/nl.po @@ -1069,7 +1069,7 @@ msgstr "Plaats" msgid "" "Click 'New' in the top-right corner to create your first product." msgstr "" -"Klik op 'Nieuw' in de rechter bovenhoek om uw eerst product aan te " +"Klik op 'Nieuw' in de rechter bovenhoek om uw eerste product aan te " "maken." #. module: website_sale diff --git a/addons/website_sale/i18n/pl.po b/addons/website_sale/i18n/pl.po index 01801d9c51b..8107e84b7c3 100644 --- a/addons/website_sale/i18n/pl.po +++ b/addons/website_sale/i18n/pl.po @@ -748,6 +748,7 @@ msgstr "" #: selection:website.config.settings,sale_pricelist_setting_split_2:0 msgid "Advanced pricing based on formulas (discounts, margins, rounding)" msgstr "" +"Zaawansowane cenniki bazujące na regułach (upusty, marże, zaokrąglenia) " #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.option_collapse_products_categories @@ -2381,7 +2382,7 @@ msgstr "Głośniki" #. module: website_sale #: selection:website.config.settings,sale_pricelist_setting_split_2:0 msgid "Specific prices per customer segment, currency, etc." -msgstr "" +msgstr "Ceny ustalane dla klienta, waluty itp." #. module: website_sale #: model:ir.model.fields,help:website_sale.field_website_config_settings_sale_pricelist_setting_split_2 diff --git a/addons/website_sale/i18n/zh_CN.po b/addons/website_sale/i18n/zh_CN.po index 7ce65d7aa36..e5003f701e8 100644 --- a/addons/website_sale/i18n/zh_CN.po +++ b/addons/website_sale/i18n/zh_CN.po @@ -13,13 +13,14 @@ # Bo Cao , 2017 # 老窦 北京 <2662059195@qq.com>, 2017 # waveyeung , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-18 14:21+0000\n" "PO-Revision-Date: 2017-07-18 14:21+0000\n" -"Last-Translator: waveyeung , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -99,6 +100,8 @@ msgid "" "\n" " My cart" msgstr "" +"\n" +" 我的购物车" #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.terms @@ -110,7 +113,7 @@ msgstr "" #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.cart_lines msgid " Remove" -msgstr "" +msgstr " 移除" #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.extra_info diff --git a/addons/website_sale_delivery/i18n/hr.po b/addons/website_sale_delivery/i18n/hr.po index 3cb8e52eaa4..0c68314656f 100644 --- a/addons/website_sale_delivery/i18n/hr.po +++ b/addons/website_sale_delivery/i18n/hr.po @@ -6,18 +6,18 @@ # Karolina Tonković , 2016 # Martin Trigaux , 2016 # Bole , 2016 +# Tina Milas , 2016 # Mario Jureša , 2016 # Đurđica Žarković , 2016 # Vladimir Olujić , 2016 # Davor Bojkić , 2016 -# Tina Milas , 2016 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-09-19 12:36+0000\n" "PO-Revision-Date: 2016-09-19 12:36+0000\n" -"Last-Translator: Tina Milas , 2016\n" +"Last-Translator: Davor Bojkić , 2016\n" "Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -175,7 +175,7 @@ msgstr "Slike" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_intrastat_id msgid "Intrastat code" -msgstr "Intrastat Kod" +msgstr "Intrastat kod" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_landed_cost_ok @@ -189,7 +189,7 @@ msgid "" "No shipping method is available for your current order and shipping address." " Please contact us for more information." msgstr "" -"Nijedna metoda dostave nije definirana za vašu trenutnu narudžbu i adresu " +"Nijedna metoda dostave nije definirana za Vašu trenutnu narudžbu i adresu " "isporuke. Molimo kontaktirajte nas za više informacija." #. module: website_sale_delivery @@ -204,7 +204,7 @@ msgid "" "(cross-sell strategy, e.g. for computers: warranty, software, etc.)." msgstr "" "Opcionalni proizvodi su predloženi kad god kupac klikne \"Dodaj u košaricu\"" -" (strategija križne prodaje, npr. za računala: jamstvo, programi itd...)" +" (strategija križne prodaje, npr. za računala: jamstvo, programi itd.)" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_purchase_requisition @@ -255,7 +255,7 @@ msgstr "Veličina Y" #: code:addons/website_sale_delivery/models/sale_order.py:98 #, python-format msgid "Sorry, we are unable to ship your order" -msgstr "Nažalost, nismo u mogućnosti poslati vašu narudžbu" +msgstr "Nažalost, nismo u mogućnosti poslati Vašu narudžbu" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_split_method @@ -304,7 +304,7 @@ msgstr "Kategorije web proizvoda" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_website_sequence msgid "Website Sequence" -msgstr "Sekvenca webstranica" +msgstr "Sekvenca web stranica" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_website_meta_description @@ -324,9 +324,9 @@ msgstr "Web meta naslov" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_website_price msgid "Website price" -msgstr "Cijena na webstranicama" +msgstr "Cijena na web stranicama" #. module: website_sale_delivery #: model:ir.model.fields,field_description:website_sale_delivery.field_delivery_carrier_website_public_price msgid "Website public price" -msgstr "Javna cijena na webstranicama" +msgstr "Javna cijena na web stranicama" diff --git a/addons/website_slides/i18n/de.po b/addons/website_slides/i18n/de.po index b4c17161811..b4c78af1153 100644 --- a/addons/website_slides/i18n/de.po +++ b/addons/website_slides/i18n/de.po @@ -16,13 +16,14 @@ # Tina Rittmüller , 2016 # Anja Funk , 2016 # Philipp Hug , 2016 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-06-23 13:28+0000\n" "PO-Revision-Date: 2017-06-23 13:28+0000\n" -"Last-Translator: Philipp Hug , 2016\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1314,7 +1315,7 @@ msgstr "Unbekanntes Dokument" #. module: website_slides #: model:ir.ui.view,arch_db:website_slides.slides_grid_view msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website_slides #: model:ir.model.fields,field_description:website_slides.field_slide_channel_upload_group_ids diff --git a/odoo/addons/base/i18n/hr.po b/odoo/addons/base/i18n/hr.po index 4a7b667bcc2..85cf7689aee 100644 --- a/odoo/addons/base/i18n/hr.po +++ b/odoo/addons/base/i18n/hr.po @@ -197,7 +197,7 @@ msgid "" msgstr "" "\n" "\n" -"Ovaj dodatak je već instaliran u vašem sustavu" +"Ovaj dodatak je već instaliran u Vašem sustavu" #. module: base #: model:ir.module.module,description:base.module_l10n_be_invoice_bba @@ -253,7 +253,7 @@ msgid "" " Bridge between HR and Maintenance." msgstr "" "\n" -"POveznica između ljudskih resursa i održavanja." +"Poveznica između ljudskih resursa i održavanja." #. module: base #: model:ir.module.module,description:base.module_pos_data_drinks @@ -338,7 +338,7 @@ msgid "" " " msgstr "" "\n" -" Korisiti različite oblike razgovora tjekom procesa selekcije.\n" +" Koristi različite oblike razgovora tijekom procesa selekcije.\n" " Ovaj modul je integriran u anketni modul\n" " koji definiraju razgovore za različite poslove. \n" " " @@ -9186,7 +9186,7 @@ msgstr "Honduras" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_hn msgid "Honduras - Accounting" -msgstr "Hondura - Računovodstvo" +msgstr "Honduras - Računovodstvo" #. module: base #: model:res.country,name:base.hk @@ -9568,7 +9568,7 @@ msgstr "" #: model:ir.ui.view,arch_db:base.view_base_module_upgrade msgid "If you wish to cancel the process, press the cancel button below" msgstr "" -"Ako želite prekinuti proces, kliknite na gumb otkaži kojie se nalazi ispod." +"Ako želite prekinuti proces, kliknite na gumb otkaži koji se nalazi ispod." #. module: base #: model:ir.model.fields,field_description:base.field_res_company_logo @@ -9649,7 +9649,7 @@ msgstr "Indeksirani sadržaj" #. module: base #: model:res.country,name:base.in msgid "India" -msgstr "India" +msgstr "Indija" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_in @@ -9839,7 +9839,7 @@ msgstr "Interni korisnici" #. module: base #: model:ir.ui.view,arch_db:base.view_partner_form msgid "Internal note..." -msgstr "Interna bilješka ..." +msgstr "Interna bilješka..." #. module: base #: model:ir.model.fields,field_description:base.field_ir_cron_interval_type @@ -10003,7 +10003,7 @@ msgstr "Irska" #: model:ir.model.fields,field_description:base.field_res_partner_is_company #: model:ir.model.fields,field_description:base.field_res_users_is_company msgid "Is a Company" -msgstr "je Tvrtka" +msgstr "je tvrtka" #. module: base #: model:ir.model.fields,field_description:base.field_res_partner_customer @@ -10608,7 +10608,7 @@ msgstr "Licenca" #. module: base #: model:res.country,name:base.li msgid "Liechtenstein" -msgstr "Linhenštajn" +msgstr "Lihtenštajn" #. module: base #: model:ir.model.fields,field_description:base.field_ir_act_window_limit @@ -10628,7 +10628,7 @@ msgstr "Praćenje linkova" #. module: base #: model:ir.model.fields,field_description:base.field_ir_act_server_link_field_id msgid "Link using field" -msgstr "POveži korštenjem polja" +msgstr "Poveži korištenjem polja" #. module: base #: model:ir.model.fields,help:base.field_ir_model_fields_modules @@ -11181,7 +11181,7 @@ msgstr "Model '%s' sadrži podatke modula i ne može se ukloniti!" #. module: base #: model:ir.model.fields,field_description:base.field_ir_values_model_id msgid "Model (change only)" -msgstr "Model( samo izmjene)" +msgstr "Model (samo izmjene)" #. module: base #: model:ir.actions.act_window,name:base.action_model_constraint @@ -13494,12 +13494,12 @@ msgstr "Evidencija prodaje" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_mrp msgid "Sales and MRP Management" -msgstr "Upravljanje Prodajom i Proizvodnjom" +msgstr "Upravljanje prodajom i proizvodnjom" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_stock msgid "Sales and Warehouse Management" -msgstr "Upravljanje Prodajom i Skladištem" +msgstr "Upravljanje prodajom i skladištem" #. module: base #: model:ir.model.fields,field_description:base.field_res_partner_user_id @@ -13631,7 +13631,7 @@ msgstr "" #. module: base #: model:ir.model.fields,help:base.field_ir_act_server_action_id msgid "Select the client action that has to be executed." -msgstr "Odabir klijentke radnje koja treba biti izvršena." +msgstr "Odabir klijentove radnje koja treba biti izvršena." #. module: base #: model:ir.model.fields,help:base.field_ir_act_server_wkf_transition_id @@ -13797,7 +13797,7 @@ msgstr "Postavi NULL" #. module: base #: model:ir.model.fields,field_description:base.field_res_users_new_password msgid "Set Password" -msgstr "Postavi Lozinku" +msgstr "Postavi lozinku" #. module: base #: model:ir.ui.view,arch_db:base.config_wizard_step_view_form @@ -14524,7 +14524,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_website_hr msgid "Team Page" -msgstr "Stranica Tima" +msgstr "Stranica tima" #. module: base #: model:ir.ui.menu,name:base.menu_custom @@ -14535,7 +14535,7 @@ msgstr "Tehnički" #: model:ir.ui.view,arch_db:base.ir_cron_view #: model:ir.ui.view,arch_db:base.module_form msgid "Technical Data" -msgstr "Tehnički Podaci" +msgstr "Tehnički podaci" #. module: base #: model:res.groups,name:base.group_no_one @@ -14706,12 +14706,12 @@ msgstr "Šifra jezika mora biti jedinstvena!" #. module: base #: sql_constraint:res.country.state:0 msgid "The code of the state must be unique by country !" -msgstr "Šifra države mora biti jedinstvena po državi !" +msgstr "Šifra države mora biti jedinstvena po državi!" #. module: base #: sql_constraint:res.company:0 msgid "The company name must be unique !" -msgstr "Naziv tvrtke mora biti jedinstven !" +msgstr "Naziv tvrtke mora biti jedinstven!" #. module: base #: model:ir.model.fields,help:base.field_res_users_company_id @@ -14825,8 +14825,7 @@ msgid "" "The internal user that is in charge of communicating with this contact if " "any." msgstr "" -"Korisnik koji je zadužen za komunikaciju za ovim kontaktom , ukoliko " -"postoji." +"Korisnik koji je zadužen za komunikaciju za ovim kontaktom, ukoliko postoji." #. module: base #: model:ir.model.fields,help:base.field_ir_model_inherited_model_ids @@ -14872,7 +14871,7 @@ msgstr "Model kojem ovo polje pripada" #. module: base #: sql_constraint:res.country:0 msgid "The name of the country must be unique !" -msgstr "Naziv države mora biti jedinstven !" +msgstr "Naziv države mora biti jedinstven!" #. module: base #: code:addons/base/res/res_users.py:150 @@ -14888,7 +14887,7 @@ msgstr "Naziv grupe mora biti jedinstven unutar aplikacije!" #. module: base #: sql_constraint:res.lang:0 msgid "The name of the language must be unique !" -msgstr "Naziv jezika mora biti jedinstven !" +msgstr "Naziv jezika mora biti jedinstven!" #. module: base #: sql_constraint:ir.module.module:0 @@ -15057,7 +15056,7 @@ msgstr "ISO oznaka je naziv PO datoteke za potrebe prijevoda" #. module: base #: selection:ir.actions.act_url,target:0 msgid "This Window" -msgstr "Ovaj Prozor" +msgstr "Ovaj prozor" #. module: base #: code:addons/base/ir/ir_model.py:449 @@ -15194,7 +15193,7 @@ msgstr "Naslov" #. module: base #: sql_constraint:res.partner.title:0 msgid "Title name already exists !" -msgstr "Naslov već postoji !" +msgstr "Naslov već postoji!" #. module: base #: model:ir.model.fields,field_description:base.field_ir_sequence_date_range_date_to @@ -15593,7 +15592,7 @@ msgstr "" #. module: base #: model:ir.module.category,name:base.module_category_uncategorized msgid "Uncategorized" -msgstr "Ne kategorizirano" +msgstr "Nije kategorizirano" #. module: base #: code:addons/base/module/module.py:514 @@ -15842,7 +15841,7 @@ msgstr "Korisnik" #. module: base #: model:ir.ui.menu,name:base.next_id_2 msgid "User Interface" -msgstr "Korisničko Sučelje" +msgstr "Korisničko sučelje" #. module: base #: model:ir.model.fields,field_description:base.field_change_password_user_user_login @@ -16056,7 +16055,7 @@ msgstr "Vezani pogled" #: model:ir.model.fields,field_description:base.field_ir_ui_view_type #: model:ir.ui.view,arch_db:base.view_window_action_search msgid "View Type" -msgstr "Tip Pogleda" +msgstr "Tip pogleda" #. module: base #: model:ir.model.fields,field_description:base.field_ir_ui_view_mode @@ -16186,7 +16185,7 @@ msgstr "Web" #. module: base #: model:ir.module.module,shortdesc:base.module_web_calendar msgid "Web Calendar" -msgstr "Web Kalendar" +msgstr "Web kalendar" #. module: base #: model:ir.module.module,shortdesc:base.module_web_editor @@ -16282,12 +16281,12 @@ msgstr "Web partner" #. module: base #: model:ir.module.module,shortdesc:base.module_website_portal msgid "Website Portal" -msgstr "Web Portal" +msgstr "Web portal" #. module: base #: model:ir.module.module,shortdesc:base.module_website_portal_sale msgid "Website Portal for Sales" -msgstr "Web Portal za prodaju" +msgstr "Web portal za prodaju" #. module: base #: model:ir.module.module,shortdesc:base.module_website_project @@ -16451,7 +16450,7 @@ msgstr "Signal radnog tijeka" #. module: base #: selection:ir.cron,interval_type:0 msgid "Work Days" -msgstr "Radni Dani" +msgstr "Radni dani" #. module: base #: model:ir.model.fields,field_description:base.field_wkf_activity_wkf_id diff --git a/odoo/addons/base/i18n/pl.po b/odoo/addons/base/i18n/pl.po index cfb016e8191..384de30de69 100644 --- a/odoo/addons/base/i18n/pl.po +++ b/odoo/addons/base/i18n/pl.po @@ -4372,7 +4372,7 @@ msgstr "Aktywna" #: model:ir.model.fields,field_description:base.field_wkf_activities #: model:ir.ui.menu,name:base.menu_workflow_activity msgid "Activities" -msgstr "Actywności" +msgstr "Działania" #. module: base #: model:ir.model.fields,field_description:base.field_wkf_workitem_act_id @@ -8359,7 +8359,7 @@ msgstr "" #: model:ir.module.module,description:base.module_website_form #: model:ir.module.module,summary:base.module_website_form msgid "Generic controller for web forms" -msgstr "standardowa kontrola dla formularzy strony" +msgstr "Standardowa kontrola dla formularzy strony" #. module: base #: model:res.country,name:base.ge diff --git a/odoo/addons/base/i18n/tr.po b/odoo/addons/base/i18n/tr.po index 765e1cad20f..82d1961b9cb 100644 --- a/odoo/addons/base/i18n/tr.po +++ b/odoo/addons/base/i18n/tr.po @@ -4232,7 +4232,7 @@ msgstr "Analitik Hesap Öndeğerleri" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import msgid "Account Bank Statement Import" -msgstr "" +msgstr "Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.module.category,name:base.module_category_localization_account_charts @@ -8487,7 +8487,7 @@ msgstr "Jenerik Formu Denetleyici" msgid "" "Generic Wizard to Import Bank Statements. Includes the import of files in " ".OFX format" -msgstr "" +msgstr "Banka Hesap Özeti İçe Aktarımı Sihirbazı" #. module: base #: model:ir.module.module,description:base.module_website_form From f087bb021ec088b25f8af3be32f646859c85f75e Mon Sep 17 00:00:00 2001 From: Odoo Translation Bot Date: Sun, 17 Sep 2017 07:07:45 +0200 Subject: [PATCH 05/40] [I18N] Update translation terms from Transifex --- addons/account/i18n/nl.po | 4 ++ addons/account/i18n/tr.po | 43 ++++++++------- addons/account_accountant/i18n/tr.po | 8 ++- addons/account_asset/i18n/tr.po | 20 +++---- .../account_bank_statement_import/i18n/tr.po | 9 ++-- addons/base_import/i18n/de.po | 7 ++- addons/delivery/i18n/zh_CN.po | 2 +- addons/event/i18n/nl.po | 2 +- addons/hr/i18n/zh_CN.po | 2 +- addons/hr_expense/i18n/nl.po | 4 +- addons/hr_recruitment/i18n/nl.po | 2 +- addons/hr_timesheet/i18n/zh_CN.po | 5 +- addons/im_livechat/i18n/zh_CN.po | 5 +- addons/mail/i18n/de.po | 6 +-- addons/mrp/i18n/de.po | 2 +- addons/mrp/i18n/zh_CN.po | 38 ++++++------- addons/payment/i18n/hr.po | 2 +- addons/point_of_sale/i18n/tr.po | 4 +- addons/point_of_sale/i18n/zh_CN.po | 2 +- addons/product/i18n/zh_CN.po | 12 +++-- addons/project/i18n/zh_CN.po | 11 ++-- addons/purchase/i18n/de.po | 2 +- addons/purchase/i18n/zh_CN.po | 6 +-- addons/purchase_requisition/i18n/de.po | 54 ++++++++++--------- addons/purchase_requisition/i18n/zh_CN.po | 2 +- addons/report/i18n/zh_CN.po | 5 +- addons/sale_stock/i18n/de.po | 5 +- addons/sale_stock/i18n/hr.po | 2 +- addons/sales_team/i18n/fr.po | 4 +- addons/stock/i18n/zh_CN.po | 12 ++--- addons/website/i18n/de.po | 6 +-- addons/website_blog/i18n/de.po | 7 +-- addons/website_blog/i18n/zh_CN.po | 3 +- addons/website_event_track/i18n/nl.po | 2 +- addons/website_event_track/i18n/zh_CN.po | 2 +- addons/website_sale/i18n/zh_CN.po | 5 +- addons/website_sale_wishlist/i18n/zh_CN.po | 5 +- addons/website_slides/i18n/de.po | 5 +- odoo/addons/base/i18n/de.po | 5 +- odoo/addons/base/i18n/tr.po | 17 +++--- 40 files changed, 187 insertions(+), 152 deletions(-) diff --git a/addons/account/i18n/nl.po b/addons/account/i18n/nl.po index b2e615c809e..9080570e850 100644 --- a/addons/account/i18n/nl.po +++ b/addons/account/i18n/nl.po @@ -978,6 +978,7 @@ msgstr "" #, python-format msgid "A Payment Terms should have its last line of type Balance." msgstr "" +"Een betalingsvoorwaarde moet zijn laatste lijn als type balans hebben." #. module: account #: code:addons/account/models/account_invoice.py:1428 @@ -1059,6 +1060,9 @@ msgid "" "A rounding per line is advised if your prices are tax-included. That way, " "the sum of line subtotals equals the total with taxes." msgstr "" +"Een afronding per lijn is aanbevolen indien uw prijzen inclusief belastingen" +" zijn. Hierdoor is de som van de lijnen gelijk aan de totale som met " +"belastingen." #. module: account #: code:addons/account/models/account_bank_statement.py:862 diff --git a/addons/account/i18n/tr.po b/addons/account/i18n/tr.po index 63b187c6f2e..f0d6c38ed2e 100644 --- a/addons/account/i18n/tr.po +++ b/addons/account/i18n/tr.po @@ -579,7 +579,7 @@ msgid "" msgstr "" "\n" "\n" -"Hesap Ekstreleri Uzlaştırma\n" +"Banka Hesap Özeti Uzlaştırma\n" "\n" "" @@ -699,8 +699,8 @@ msgid "" "Banking interface: with live bank feed synchronization and " "bank statement import." msgstr "" -"Anlık banka özet senkronizasyonu ve banka ekstresi içe aktarımı ile " -" bankacılık arayüzü. " +" Bankacılık Arayüzü : Anlık banka hesap özet " +"senkronizasyonu ve banka ekstresi içe aktarımı ile " #. module: account #: model:ir.ui.view,arch_db:account.account_planner @@ -928,7 +928,7 @@ msgstr "Satınalma" #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Reconcile Bank Statement" -msgstr "Banka Ekstresi Uzlaştır" +msgstr "Banka Hesap Özeti Uzlaştır" #. module: account #: model:ir.ui.view,arch_db:account.account_planner @@ -942,7 +942,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Reconcile your Bank Statements" -msgstr "Hesap özetinizi uzlaştırın" +msgstr "Hesap Özetinizi Uzlaştırın" #. module: account #: model:ir.ui.view,arch_db:account.account_planner @@ -956,7 +956,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Record Bank Statement" -msgstr "Kayıtlı Banka Ekstresi" +msgstr "Banka Hesap Özeti Kaydı" #. module: account #: model:ir.ui.view,arch_db:account.account_planner @@ -1256,7 +1256,7 @@ msgstr "Banka Hesap Özeti Kasa Detayı" #. module: account #: model:ir.model,name:account.model_account_bank_statement_closebalance msgid "Account Bank Statement closing balance" -msgstr "Banka Hesap Özeti kapanış bakiyesi" +msgstr "Banka Hesap Özeti Kapanış Bakiyesi" #. module: account #: model:ir.model,name:account.model_account_common_account_report @@ -2231,7 +2231,7 @@ msgstr "Bekleyen ödemeler" #: code:addons/account/models/chart_template.py:183 #, python-format msgid "BILL" -msgstr "FATURA" +msgstr "ALM" #. module: account #: selection:res.partner,trust:0 @@ -4173,7 +4173,7 @@ msgstr "AB Dijital Ürünler Katma Değer Vergisi" #: code:addons/account/models/chart_template.py:185 #, python-format msgid "EXCH" -msgstr "EXCH" +msgstr "KRFRK" #. module: account #. openerp-web @@ -4702,7 +4702,8 @@ msgstr "Faturayı gösterirken bu satırın sırasını verir." #: model:ir.model.fields,help:account.field_account_bank_statement_line_sequence msgid "" "Gives the sequence order when displaying a list of bank statement lines." -msgstr "Banka ekstre kalemleri listelenirken kullanılacak sıralamayı verir." +msgstr "" +"Banka hesap özeti kalemleri listelenirken kullanılacak sıralamayı verir." #. module: account #: model:ir.model.fields,help:account.field_account_invoice_tax_sequence @@ -5018,8 +5019,8 @@ msgstr "" msgid "" "If you want to be able to send customer statements from Odoo, you must:" msgstr "" -"Odoo'dan müşteri bakiye bildirimleri gönderebilmek istiyorsanız, şunları " -"yapmanız gerekir:" +"Odoo'dan müşteri hesap özeti bildirimleri gönderebilmek istiyorsanız, " +"şunları yapmanız gerekir:" #. module: account #: model:ir.ui.view,arch_db:account.account_planner @@ -5029,7 +5030,7 @@ msgid "" " in the payable and receivable accounts. These would be invoices \n" " that have not been paid or payments that have not been reconciled." msgstr "" -"Müşterilerinize bakiye bildirimlerini Odoo'dan gönderebilmek istiyorsanız, önce tüm ödenmemiş işlemleri borç ve alacak hesaplarına kaydetmeniz gerekir.\n" +"Müşterilerinize hesap özeti bildirimlerini Odoo'dan gönderebilmek istiyorsanız, önce tüm ödenmemiş işlemleri borç ve alacak hesaplarına kaydetmeniz gerekir.\n" "Bunlar ödenmemiş faturalar ya da uzlaştırılmamış ödemeler olacaktır." #. module: account @@ -5085,7 +5086,7 @@ msgstr "İçeri veri aktarmak için sol üstteki \"İçe Aktar\" butonunna bası #. module: account #: model:ir.ui.view,arch_db:account.account_config_settings_view_form msgid "Import your bank statements automatically" -msgstr "Banka ekstrelerinizi otomatik olarak içe aktarın" +msgstr "Banka hesap özetlerini otomatik olarak içe aktarın" #. module: account #: model:ir.ui.view,arch_db:account.account_config_settings_view_form @@ -6168,7 +6169,7 @@ msgstr "Döviz Kuru Oranı Kaybı Hesabı" #: code:addons/account/models/chart_template.py:184 #, python-format msgid "MISC" -msgstr "ÇEŞİTLİ" +msgstr "CSTL" #. module: account #: model:ir.ui.view,arch_db:account.account_config_settings_view_form @@ -8464,7 +8465,8 @@ msgid "" "Sending customer statements (outstanding invoices) manually during the " "transition period" msgstr "" -"Geçiş döneminde müşteri bildirimlerini (ödenmemiş faturalar) elle göndermek" +"Geçiş döneminde müşteri hesap özeti bildirimlerini (ödenmemiş faturalar) " +"elle göndermek" #. module: account #: selection:account.payment,state:0 @@ -9225,7 +9227,7 @@ msgstr "Bir banka günlüğünün banka hesabı aynı şirkete ait olmalıdır ( #. module: account #: model:ir.model.fields,help:account.field_account_move_line_statement_id msgid "The bank statement used for bank reconciliation" -msgstr "Banka uzlaşması için kullanılan banka hesap özeti" +msgstr "Banka uzlaştırması için kullanılan banka hesap özeti" #. module: account #: model:ir.model.fields,help:account.field_res_company_chart_template_id @@ -9669,7 +9671,7 @@ msgstr "" #: model:ir.model.fields,help:account.field_account_reconcile_model_journal_id #: model:ir.model.fields,help:account.field_account_reconcile_model_second_journal_id msgid "This field is ignored in a bank statement reconciliation." -msgstr "Bu alan bir banka dekontu mutabakatında dikkate alınmaz." +msgstr "Bu alan bir banka hesap özeti uzlaştırmasında dikkate alınmaz." #. module: account #: model:ir.model.fields,help:account.field_account_move_line_date_maturity @@ -9687,7 +9689,7 @@ msgid "" "statement in electronic format, when the partner doesn't exist yet in the " "database (or cannot be found)." msgstr "" -"Bu alan, elektronik biçimde banka hesap özeti içeaktarılırken, eğer İş " +"Bu alan, elektronik biçimde banka hesap özeti içe aktarılırken, eğer İş " "Ortağı veritabanında yoksa (yada bulunamazsa) üçüncü partinin adını " "kaydetmek için kullanılır." @@ -10848,7 +10850,8 @@ msgstr "" #: code:addons/account/wizard/pos_box.py:36 #, python-format msgid "You cannot put/take money in/out for a bank statement which is closed." -msgstr "Kapatılan bir banka dekontuna para yatırıp / koyamazsınız." +msgstr "" +"Kapalı bir banka hesap özetinde para gönderme ve alma işlemi yapamazsınız." #. module: account #: code:addons/account/models/account.py:156 diff --git a/addons/account_accountant/i18n/tr.po b/addons/account_accountant/i18n/tr.po index 27adead057a..35e42e50799 100644 --- a/addons/account_accountant/i18n/tr.po +++ b/addons/account_accountant/i18n/tr.po @@ -7,13 +7,14 @@ # Ediz Duman , 2017 # Fırat Kaya , 2017 # Martin Trigaux , 2017 +# Ertuğrul Güreş , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~14\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-02-15 09:49+0000\n" "PO-Revision-Date: 2017-02-15 09:49+0000\n" -"Last-Translator: Martin Trigaux , 2017\n" +"Last-Translator: Ertuğrul Güreş , 2017\n" "Language-Team: Turkish (https://www.transifex.com/odoo/teams/41243/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -71,7 +72,7 @@ msgstr "Mali Yıl Son Ay" #. module: account_accountant #: model:ir.ui.view,arch_db:account_accountant.account_config_settings_view_form_inherit_account_accountant msgid "Inter-Banks Transfers" -msgstr "" +msgstr "Bankalararası Transferler" #. module: account_accountant #: model:ir.model.fields,help:account_accountant.field_account_config_settings_transfer_account_id @@ -190,6 +191,9 @@ msgid "" "keeps track of the installments occurred on those revenue recognitions, and " "creates account moves for those installment lines." msgstr "" +"Bu, ürün satışı üzerindeki geliri tahakkukunu yönetmenizi sağlar. Gelir " +"tahakkuklarında gerçekleşen taksitleri takip eder ve bu taksit kalemleri " +"için yevmiye kayıtları oluşturur." #. module: account_accountant #: model:ir.model.fields,field_description:account_accountant.field_account_config_settings_transfer_account_id diff --git a/addons/account_asset/i18n/tr.po b/addons/account_asset/i18n/tr.po index fbf872defe3..0150b60b56c 100644 --- a/addons/account_asset/i18n/tr.po +++ b/addons/account_asset/i18n/tr.po @@ -49,12 +49,12 @@ msgstr "Demirbaş Girişi Sayısı" #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_asset_asset_report_depreciation_nbr msgid "# of Depreciation Lines" -msgstr "Amortisman kalemleri sayısı" +msgstr "Amortisman Kalemleri Sayısı" #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_asset_asset_report_installment_nbr msgid "# of Installment Lines" -msgstr "Taksitli Hatlar" +msgstr "Amortisman Kalemleri Sayısı" #. module: account_asset #: model:ir.actions.server,name:account_asset.account_asset_cron_ir_actions_server @@ -121,7 +121,7 @@ msgstr "Amortisman Satırları Tutarı" #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_asset_asset_report_installment_value msgid "Amount of Installment Lines" -msgstr "Taksitlendirme Hattı Miktarı" +msgstr "Amortisman Kalemleri Tutarı" #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_account_asset_category_account_analytic_id @@ -206,7 +206,7 @@ msgstr "Demirbaş oluşturuldu" #. module: account_asset #: model:ir.model,name:account_asset.model_account_asset_depreciation_line msgid "Asset depreciation line" -msgstr "Demirbaş amortisman satırı" +msgstr "Demirbaş amortisman kalemi" #. module: account_asset #: code:addons/account_asset/models/account_asset.py:319 @@ -219,7 +219,7 @@ msgstr "" #. module: account_asset #: model:ir.model,name:account_asset.model_account_asset_asset msgid "Asset/Revenue Recognition" -msgstr "Demirbaş/Gelir Tahhakkuku" +msgstr "Demirbaş/Gelir Tahakkuku" #. module: account_asset #: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_form @@ -242,7 +242,7 @@ msgstr "Demirbaş Analizi" #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_account_move_asset_depreciation_ids msgid "Assets Depreciation Lines" -msgstr "Demirbaş Amortisman Satırları" +msgstr "Demirbaş Amortisman Kalemleri" #. module: account_asset #: model:ir.ui.menu,name:account_asset.menu_finance_config_assets @@ -813,7 +813,7 @@ msgstr "Bir dönemdeki ay sayısı" #. module: account_asset #: model:ir.ui.view,arch_db:account_asset.view_account_asset_category_form msgid "One Entry Every" -msgstr "Her Giriş Tek Bir Giriş" +msgstr "Her Bir Giriş" #. module: account_asset #: code:addons/account_asset/models/account_asset.py:593 @@ -999,8 +999,8 @@ msgid "" "This wizard will post installment/depreciation lines for the selected month.
\n" " This will generate journal entries for all related installment lines on this period of asset/revenue recognition as well." msgstr "" -"Bu sihirbaz, seçilen ay için taksitlendirme / amortisman satırları gönderir.
\n" -"Bu, bu varlık / gelir tanıma döneminde de ilgili tüm taksit hatları için günlük girdileri oluşturacaktır." +"Bu sihirbaz, seçilen ay için amortisman kalemlerinin yevmiye kayıtlarını " +"oluşturur." #. module: account_asset #: model:ir.model.fields,field_description:account_asset.field_account_asset_asset_method_time @@ -1078,7 +1078,7 @@ msgstr "İşlenmiş amortisman kalemleri içeren bir varlığı silemezsiniz." #: code:addons/account_asset/models/account_asset.py:604 #, python-format msgid "You cannot delete posted installment lines." -msgstr "Gönderilen taksit satırlarını silemezsiniz." +msgstr "Onaylanmış amortisman kalemlerini silemezsiniz." #. module: account_asset #: model:ir.model,name:account_asset.model_asset_depreciation_confirmation_wizard diff --git a/addons/account_bank_statement_import/i18n/tr.po b/addons/account_bank_statement_import/i18n/tr.po index 6d790b2e7ff..de8ae0fb5dc 100644 --- a/addons/account_bank_statement_import/i18n/tr.po +++ b/addons/account_bank_statement_import/i18n/tr.po @@ -216,7 +216,7 @@ msgid "" "Download a bank statement from your bank and import it here. Supported " "formats:" msgstr "" -"Bankanızdan bir banka dekontu indirin ve buraya aktarınız. Desteklenen " +"Bankanızdan bir banka hesap özeti indirin ve buraya aktarın. Desteklenen " "formatlar:" #. module: account_bank_statement_import @@ -235,8 +235,7 @@ msgid "" "Get you bank statements in electronic format from your bank and select them " "here." msgstr "" -"Bankanızdan elektronik formatta banka açıklamalarınızı alın ve buradan " -"seçin." +"Bankanızdan elektronik formatta banka hesap özetini alın ve buradan seçin." #. module: account_bank_statement_import #: model:ir.model.fields,field_description:account_bank_statement_import.field_account_bank_statement_import_journal_creation_group_invoice_lines @@ -422,7 +421,7 @@ msgstr "" #. module: account_bank_statement_import #: model:ir.ui.view,arch_db:account_bank_statement_import.account_bank_statement_import_view msgid "Select a bank statement file to import" -msgstr "İçe aktarım için bir banka ekstre dosyası seçiniz" +msgstr "İçe aktarım için bir banka hesap özeti dosyası seçiniz" #. module: account_bank_statement_import #: model:ir.model.fields,field_description:account_bank_statement_import.field_account_bank_statement_import_journal_creation_sequence @@ -464,7 +463,7 @@ msgid "" "The currency of the bank statement (%s) is not the same as the currency of " "the journal (%s) !" msgstr "" -"Banka dekontunun para birimi (% s) günlüğün para birimi (% s) ile aynı " +"Banka hesap özetinin para birimi (% s) günlüğün para birimi (% s) ile aynı " "değil!" #. module: account_bank_statement_import diff --git a/addons/base_import/i18n/de.po b/addons/base_import/i18n/de.po index bb2512fffeb..362636ad277 100644 --- a/addons/base_import/i18n/de.po +++ b/addons/base_import/i18n/de.po @@ -12,13 +12,14 @@ # Tina Rittmüller , 2017 # Niki Waibel , 2017 # Renzo Meister , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~14\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-02-15 09:49+0000\n" "PO-Revision-Date: 2017-02-15 09:49+0000\n" -"Last-Translator: Renzo Meister , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -452,7 +453,7 @@ msgstr "Datei erneut laden" #: code:addons/base_import/static/src/xml/base_import.xml:11 #, python-format msgid "Select a CSV or Excel file to import." -msgstr "" +msgstr "Wählen Sie eine CSV- oder Excel-Datei zum Importieren aus." #. module: base_import #. openerp-web @@ -509,6 +510,8 @@ msgid "" "The first row\n" " contains the label of the column" msgstr "" +"Die erste Zeile\n" +" enthält das Label der Spalte" #. module: base_import #. openerp-web diff --git a/addons/delivery/i18n/zh_CN.po b/addons/delivery/i18n/zh_CN.po index ea59a17e04d..7ae950044fd 100644 --- a/addons/delivery/i18n/zh_CN.po +++ b/addons/delivery/i18n/zh_CN.po @@ -1185,7 +1185,7 @@ msgstr "价格表" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_pricelist_item_ids msgid "Pricelist Item" -msgstr "" +msgstr "价格表项目" #. module: delivery #: model:ir.model.fields,field_description:delivery.field_delivery_carrier_item_ids diff --git a/addons/event/i18n/nl.po b/addons/event/i18n/nl.po index 5a7eed0286b..402411a60d9 100644 --- a/addons/event/i18n/nl.po +++ b/addons/event/i18n/nl.po @@ -1083,7 +1083,7 @@ msgstr "Mail planners" #. module: event #: model:ir.model,name:event.model_event_type_mail msgid "Mail Scheduling on Event Type" -msgstr "" +msgstr "Mail planner op soort evenement" #. module: event #: model:ir.model.fields,field_description:event.field_event_mail_registration_mail_sent diff --git a/addons/hr/i18n/zh_CN.po b/addons/hr/i18n/zh_CN.po index 923dd292c95..75a9c5bad27 100644 --- a/addons/hr/i18n/zh_CN.po +++ b/addons/hr/i18n/zh_CN.po @@ -820,7 +820,7 @@ msgstr "随着Odoo员工的屏幕上只是一个快速浏览,你可以很容 #. module: hr #: model:ir.model.fields,field_description:hr.field_hr_employee_address_id msgid "Work Address" -msgstr "" +msgstr "工作地址" #. module: hr #: model:ir.model.fields,field_description:hr.field_hr_employee_work_email diff --git a/addons/hr_expense/i18n/nl.po b/addons/hr_expense/i18n/nl.po index 234331199aa..41f5c631be3 100644 --- a/addons/hr_expense/i18n/nl.po +++ b/addons/hr_expense/i18n/nl.po @@ -863,7 +863,7 @@ msgstr "Algemene informatie" #. module: hr_expense #: model:ir.ui.view,arch_db:hr_expense.hr_expense_planner msgid "Grant such accountants with following access rights:" -msgstr "" +msgstr "Sta zulke boekhouders toe met de volgende toegangsrechten:" #. module: hr_expense #: model:ir.ui.view,arch_db:hr_expense.hr_expense_planner @@ -923,7 +923,7 @@ msgstr "" #. module: hr_expense #: model:ir.ui.view,arch_db:hr_expense.hr_expense_planner msgid "Install Analytic Accounting add-on" -msgstr "" +msgstr "Installeer kostenplaatsen module" #. module: hr_expense #: model:ir.ui.view,arch_db:hr_expense.hr_expense_planner diff --git a/addons/hr_recruitment/i18n/nl.po b/addons/hr_recruitment/i18n/nl.po index f09ce413de1..4378117830b 100644 --- a/addons/hr_recruitment/i18n/nl.po +++ b/addons/hr_recruitment/i18n/nl.po @@ -876,7 +876,7 @@ msgstr "Functies" #. module: hr_recruitment #: model:ir.ui.view,arch_db:hr_recruitment.hr_recruitment_config_settings_view_form msgid "Job Posting" -msgstr "" +msgstr "Job publicatie" #. module: hr_recruitment #: model:ir.model.fields,field_description:hr_recruitment.field_hr_recruitment_stage_job_id diff --git a/addons/hr_timesheet/i18n/zh_CN.po b/addons/hr_timesheet/i18n/zh_CN.po index 5f601fd7827..2921e79101d 100644 --- a/addons/hr_timesheet/i18n/zh_CN.po +++ b/addons/hr_timesheet/i18n/zh_CN.po @@ -7,13 +7,14 @@ # 苏州远鼎 , 2016 # liAnGjiA , 2017 # zyx , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:45+0000\n" "PO-Revision-Date: 2017-04-18 14:45+0000\n" -"Last-Translator: zyx , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -129,7 +130,7 @@ msgstr "计算:花费的时间 + 剩余的时间" #. module: hr_timesheet #: model:ir.model.fields,help:hr_timesheet.field_project_task_total_hours_spent msgid "Computed as: Time Spent + Sub-tasks Hours." -msgstr "" +msgstr "计算方式:花费时间 + 子任务时间" #. module: hr_timesheet #: model:ir.model.fields,help:hr_timesheet.field_project_task_effective_hours diff --git a/addons/im_livechat/i18n/zh_CN.po b/addons/im_livechat/i18n/zh_CN.po index 71105b59920..eacb354e883 100644 --- a/addons/im_livechat/i18n/zh_CN.po +++ b/addons/im_livechat/i18n/zh_CN.po @@ -5,13 +5,14 @@ # Translators: # Jeffery CHEN , 2016 # ZIHAN LI , 2016 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:47+0000\n" "PO-Revision-Date: 2017-04-18 14:47+0000\n" -"Last-Translator: ZIHAN LI , 2016\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -842,7 +843,7 @@ msgstr "" msgid "" "Your chatter history is empty. Create a channel and start chatting to fill " "up your history." -msgstr "" +msgstr "你的交谈记录为空,现在创建一个频道并开始交谈就可以生成交谈记录。" #. module: im_livechat #: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form diff --git a/addons/mail/i18n/de.po b/addons/mail/i18n/de.po index beb6817f884..3508ebbebba 100644 --- a/addons/mail/i18n/de.po +++ b/addons/mail/i18n/de.po @@ -3606,7 +3606,7 @@ msgstr "Alter textueller Wert" #. module: mail #: selection:ir.model.fields,track_visibility:0 msgid "On Change" -msgstr "" +msgstr "Bei Änderung" #. module: mail #. openerp-web @@ -3635,7 +3635,7 @@ msgstr "Online" #: code:addons/mail/models/ir_model.py:21 #, python-format msgid "Only custom models can be modified." -msgstr "" +msgstr "Nur das Kunden-Model kann modifiziert werden." #. module: mail #: selection:mail.channel.partner,fold_state:0 @@ -5424,7 +5424,7 @@ msgstr "" #. module: mail #: model:ir.ui.view,arch_db:mail.message_origin_link msgid "from:" -msgstr "" +msgstr "von:" #. module: mail #: model:mail.channel,name:mail.channel_all_employees diff --git a/addons/mrp/i18n/de.po b/addons/mrp/i18n/de.po index 66e58fa947e..fdd8f7a7f69 100644 --- a/addons/mrp/i18n/de.po +++ b/addons/mrp/i18n/de.po @@ -3024,7 +3024,7 @@ msgstr "" #: code:addons/mrp/static/src/js/mrp.js:24 #, python-format msgid "Waiting Materials" -msgstr "" +msgstr "Wartende Materialien" #. module: mrp #: model:ir.model,name:mrp.model_stock_warehouse diff --git a/addons/mrp/i18n/zh_CN.po b/addons/mrp/i18n/zh_CN.po index 0d379f107c9..875175c65c2 100644 --- a/addons/mrp/i18n/zh_CN.po +++ b/addons/mrp/i18n/zh_CN.po @@ -487,7 +487,7 @@ msgstr "BoM" #. module: mrp #: model:ir.ui.view,arch_db:mrp.product_template_search_view_procurment msgid "BoM Components" -msgstr "" +msgstr "BoM组件" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_move_bom_line_id @@ -687,7 +687,7 @@ msgstr "已确认" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_unbuild_consume_line_ids msgid "Consume Line" -msgstr "" +msgstr "投料明细" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_move_consume_unbuild_id @@ -712,7 +712,7 @@ msgstr "" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_bom_line_operation_id msgid "Consumed in Operation" -msgstr "消耗在操作" +msgstr "消耗在作业" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_production_workcenter_form_view_inherit @@ -727,17 +727,17 @@ msgstr "成本结构" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_picking_type_count_mo_late msgid "Count Mo Late" -msgstr "" +msgstr "延迟Mo数量" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_picking_type_count_mo_todo msgid "Count Mo Todo" -msgstr "" +msgstr "待办Mo数量" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_picking_type_count_mo_waiting msgid "Count Mo Waiting" -msgstr "" +msgstr "等待中Mo数量" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_production_form_view @@ -1198,7 +1198,7 @@ msgstr "当前用户工作中" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workorder_is_produced msgid "Is Produced" -msgstr "" +msgstr "已生产" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workcenter_productivity_loss_manual @@ -1355,7 +1355,7 @@ msgstr "保养" #. module: mrp #: model:res.groups,name:mrp.group_mrp_routings msgid "Manage Work Order Operations" -msgstr "管理工单操作" +msgstr "管理工单作业" #. module: mrp #: model:ir.ui.view,arch_db:mrp.view_mrp_config @@ -1587,7 +1587,7 @@ msgstr "新的" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_routing_workcenter_batch msgid "Next Operation" -msgstr "下一操作" +msgstr "下一作业" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workorder_next_work_order_id @@ -1705,18 +1705,18 @@ msgstr "所有产品处理完" #: model:ir.model.fields,field_description:mrp.field_mrp_workorder_operation_id #: model:ir.ui.view,arch_db:mrp.mrp_bom_form_view msgid "Operation" -msgstr "操作" +msgstr "作业" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_stock_move_operation_id msgid "Operation To Consume" -msgstr "待消耗的操作" +msgstr "待消耗的作业" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_bom_picking_type_id #: model:ir.model.fields,field_description:mrp.field_mrp_production_picking_type_id msgid "Operation Type" -msgstr "" +msgstr "作业类型" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_routing_operation_ids @@ -1730,7 +1730,7 @@ msgstr "" #: model:ir.ui.view,arch_db:mrp.workcenter_line_graph #: model:ir.ui.view,arch_db:mrp.workcenter_line_pivot msgid "Operations" -msgstr "操作" +msgstr "作业" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_workcenter_order_ids @@ -1924,7 +1924,7 @@ msgstr "产品" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_config_settings_module_mrp_plm msgid "Product Lifecycle Management" -msgstr "" +msgstr "产品生命周期管理" #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_bom_line_product_qty @@ -2407,7 +2407,7 @@ msgstr "" #: model:ir.model.fields,help:mrp.field_mrp_config_settings_manufacturing_lead #: model:ir.model.fields,help:mrp.field_res_company_manufacturing_lead msgid "Security days for each manufacturing operation." -msgstr "每个制造操作的确保天数" +msgstr "每个制造作业的确保天数" #. module: mrp #. openerp-web @@ -2585,7 +2585,7 @@ msgstr "容量必须严格为正数." #. module: mrp #: selection:mrp.bom,ready_to_produce:0 msgid "The components of 1st operation" -msgstr "首次操作的部件" +msgstr "第一作业的部件" #. module: mrp #: model:ir.model.fields,help:mrp.field_mrp_production_routing_id @@ -2594,7 +2594,7 @@ msgid "" "product. The routing is mainly used to compute work center costs during " "operations and to plan future loads on work centers based on production " "planning." -msgstr "生产产成品需要的一系列操作(发生在一系列工作中心上)。工艺主要用于计算工作中心成本和根据生产计划来规划工作中心负载。" +msgstr "生产产成品需要的一系列作业(发生在一系列工作中心上)。工艺主要用于计算工作中心成本和根据生产计划来规划工作中心负载。" #. module: mrp #: model:ir.model.fields,help:mrp.field_mrp_bom_line_routing_id @@ -3323,7 +3323,7 @@ msgstr "你需要提供批次/序列号" #: code:addons/mrp/wizard/mrp_product_produce.py:80 #, python-format msgid "You should at least produce some quantity" -msgstr "" +msgstr "必须输入生产数量" #. module: mrp #: code:addons/mrp/models/mrp_workorder.py:288 @@ -3366,7 +3366,7 @@ msgstr "最后的" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_workcenter_view msgid "minute(s)" -msgstr "" +msgstr "分钟" #. module: mrp #: model:ir.ui.view,arch_db:mrp.mrp_production_workcenter_form_view_inherit diff --git a/addons/payment/i18n/hr.po b/addons/payment/i18n/hr.po index 457e887b2d7..82a14276de1 100644 --- a/addons/payment/i18n/hr.po +++ b/addons/payment/i18n/hr.po @@ -253,7 +253,7 @@ msgstr "Otkazano" #. module: payment #: model:ir.ui.view,arch_db:payment.transaction_form msgid "Capture Transaction" -msgstr "" +msgstr "Zabilježi transakciju" #. module: payment #: model:ir.model.fields,field_description:payment.field_payment_transaction_partner_city diff --git a/addons/point_of_sale/i18n/tr.po b/addons/point_of_sale/i18n/tr.po index 14fd941767a..e5ab70e035c 100644 --- a/addons/point_of_sale/i18n/tr.po +++ b/addons/point_of_sale/i18n/tr.po @@ -1737,8 +1737,8 @@ msgstr "Sonraki Sipariş" msgid "" "No cash statement found for this session. Unable to record returned cash." msgstr "" -"Bu oturum için nakit açıklamada bulunamadı. Geri nakit kaydetmek için " -"açılamıyor." +"Oturuma bağlı nakit hesap özeti bulunamadığı için nakit iadesi " +"kaydedilemedi." #. module: point_of_sale #: code:addons/point_of_sale/report/pos_invoice.py:25 diff --git a/addons/point_of_sale/i18n/zh_CN.po b/addons/point_of_sale/i18n/zh_CN.po index 3e983f5bfa6..42447e071f3 100644 --- a/addons/point_of_sale/i18n/zh_CN.po +++ b/addons/point_of_sale/i18n/zh_CN.po @@ -1840,7 +1840,7 @@ msgstr "开张日期" #: model:ir.model.fields,field_description:point_of_sale.field_pos_config_picking_type_id #: model:ir.model.fields,field_description:point_of_sale.field_pos_order_picking_type_id msgid "Operation Type" -msgstr "" +msgstr "作业类型" #. module: point_of_sale #. openerp-web diff --git a/addons/product/i18n/zh_CN.po b/addons/product/i18n/zh_CN.po index 69254f00bf0..74d23aee420 100644 --- a/addons/product/i18n/zh_CN.po +++ b/addons/product/i18n/zh_CN.po @@ -8,13 +8,15 @@ # Yuan Xulei , 2017 # Talway <9010446@qq.com>, 2017 # liAnGjiA , 2017 +# 苏州远鼎 , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-17 08:17+0000\n" "PO-Revision-Date: 2017-07-17 08:17+0000\n" -"Last-Translator: liAnGjiA , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -488,7 +490,7 @@ msgstr "国家分组" #. module: product #: model:ir.model.fields,field_description:product.field_product_attribute_create_variant msgid "Create Variant" -msgstr "" +msgstr "创建变体" #. module: product #: model:ir.model.fields,field_description:product.field_product_attribute_create_uid @@ -747,7 +749,7 @@ msgstr "全球" #: code:addons/product/models/product_template.py:31 #, python-format msgid "Go to Internal Categories" -msgstr "" +msgstr "进入内部分类" #. module: product #: model:ir.ui.view,arch_db:product.product_supplierinfo_search_view @@ -771,7 +773,7 @@ msgstr "" msgid "" "How much bigger or smaller this unit is compared to the reference Unit of " "Measure for this category: 1 * (reference unit) = ratio * (this unit)" -msgstr "" +msgstr "本类别计量单位和参考计量单位相比,大或者小的倍数。1 * (参考单位)=比率 *(本单位)" #. module: product #: model:ir.model.fields,field_description:product.field_product_attribute_id @@ -1161,7 +1163,7 @@ msgstr "价格表" #. module: product #: model:ir.model.fields,field_description:product.field_product_product_pricelist_item_ids msgid "Pricelist Item" -msgstr "" +msgstr "价格表明细" #. module: product #: model:ir.model.fields,help:product.field_product_pricelist_item_applied_on diff --git a/addons/project/i18n/zh_CN.po b/addons/project/i18n/zh_CN.po index 8234a312107..59fcd99cc03 100644 --- a/addons/project/i18n/zh_CN.po +++ b/addons/project/i18n/zh_CN.po @@ -17,13 +17,14 @@ # zyx , 2017 # 菜小蛇 , 2017 # fausthuang , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:45+0000\n" "PO-Revision-Date: 2017-04-18 14:45+0000\n" -"Last-Translator: fausthuang , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -211,7 +212,7 @@ msgstr "" #: code:addons/project/static/src/js/tour.js:80 #, python-format msgid "Click the save button to apply your changes to the task." -msgstr "" +msgstr "点击保存按钮 接受对任务的更改。" #. module: project #. openerp-web @@ -1428,7 +1429,7 @@ msgstr "文案/设计" #. module: project #: model:ir.model.fields,field_description:project.field_project_task_displayed_image_id msgid "Cover Image" -msgstr "" +msgstr "封面图像" #. module: project #: model:ir.ui.view,arch_db:project.project_project_view_form_simplified @@ -1905,7 +1906,7 @@ msgstr "最后的任务已经部署" #. module: project #: model:ir.model.fields,field_description:project.field_project_task_type_fold msgid "Folded in Kanban" -msgstr "" +msgstr "在看板中折叠" #. module: project #: model:ir.ui.view,arch_db:project.edit_project @@ -3981,7 +3982,7 @@ msgstr "你可以从你自己的邮件系统对一个消息进行回复;你回 #. module: project #: model:ir.ui.view,arch_db:project.project_planner msgid "You can save your reports to easily reuse it later" -msgstr "" +msgstr "您可以将报表保存便于以后重复使用" #. module: project #: code:addons/project/models/project.py:70 diff --git a/addons/purchase/i18n/de.po b/addons/purchase/i18n/de.po index ca294812ff9..f4db7975be2 100644 --- a/addons/purchase/i18n/de.po +++ b/addons/purchase/i18n/de.po @@ -1259,7 +1259,7 @@ msgstr "Einkauf" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_purchase_config_settings_module_purchase_requisition msgid "Purchase Agreements" -msgstr "" +msgstr "Kaufverträge" #. module: purchase #: model:ir.actions.act_window,name:purchase.action_purchase_order_report_all diff --git a/addons/purchase/i18n/zh_CN.po b/addons/purchase/i18n/zh_CN.po index 1bcc508f899..0be4c8ddcf4 100644 --- a/addons/purchase/i18n/zh_CN.po +++ b/addons/purchase/i18n/zh_CN.po @@ -1102,7 +1102,7 @@ msgstr "收到数量" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_purchase_config_settings_po_order_approval msgid "Order Approval" -msgstr "" +msgstr "订单审批" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_purchase_order_date_order @@ -1318,7 +1318,7 @@ msgstr "采购需求能让你快捷的检查分析公司的采购记录和绩效 #. module: purchase #: model:ir.ui.view,arch_db:purchase.account_config_settings_view_form_inherit_purchase msgid "Purchase Analytics" -msgstr "" +msgstr "采购分析" #. module: purchase #: model:ir.model.fields,field_description:purchase.field_res_company_po_lead @@ -1521,7 +1521,7 @@ msgstr "已接收数量" #: code:addons/purchase/models/purchase.py:577 #, python-format msgid "Received Quantity" -msgstr "" +msgstr "收到数量" #. module: purchase #: model:ir.actions.act_window,name:purchase.purchase_open_picking diff --git a/addons/purchase_requisition/i18n/de.po b/addons/purchase_requisition/i18n/de.po index e24e3517369..63b99772298 100644 --- a/addons/purchase_requisition/i18n/de.po +++ b/addons/purchase_requisition/i18n/de.po @@ -15,13 +15,14 @@ # Ermin Trevisan , 2017 # Henry Mineehen , 2017 # Philipp Hug , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:46+0000\n" "PO-Revision-Date: 2017-04-18 14:46+0000\n" -"Last-Translator: Philipp Hug , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -87,24 +88,24 @@ msgstr "Lieferant" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_date_end msgid "Agreement Deadline" -msgstr "" +msgstr "Vereinbarungsfrist" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_name msgid "Agreement Reference" -msgstr "" +msgstr "Vertragsreferenz" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_exclusive msgid "Agreement Selection Type" -msgstr "" +msgstr "Vereinbarung Auswahltyp" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_id_11163 #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_type_name #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form msgid "Agreement Type" -msgstr "" +msgstr "Vereinbarungsart" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_configuration_inherit_purchase_requisition @@ -125,7 +126,7 @@ msgstr "Gebotsauswahl" #. module: purchase_requisition #: model:purchase.requisition.type,name:purchase_requisition.type_single msgid "Blanket Order" -msgstr "" +msgstr "Blankoauftrag" #. module: purchase_requisition #: model:ir.actions.report.xml,name:purchase_requisition.action_report_purchase_requisitions @@ -147,12 +148,12 @@ msgstr "Abgebrochen" #: code:addons/purchase_requisition/models/purchase_requisition.py:76 #, python-format msgid "Cancelled by the agreement associated to this quotation." -msgstr "" +msgstr "Kündigt durch den mit diesem Angebot verbundenen Vertrag." #. module: purchase_requisition #: model:ir.actions.act_window,help:purchase_requisition.action_purchase_requisition msgid "Click to start a new purchase agreement." -msgstr "" +msgstr "Klicken Sie hier, um einen neuen Kaufvertrag abzuschließen." #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_company_id @@ -193,12 +194,12 @@ msgstr "Erstellt am" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form msgid "Data for new quotations" -msgstr "" +msgstr "Daten für neue Angebote" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_schedule_date msgid "Delivery Date" -msgstr "" +msgstr "Liefertermin" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_description @@ -215,7 +216,7 @@ msgstr "Anzeigename" #. module: purchase_requisition #: selection:purchase.requisition.type,line_copy:0 msgid "Do not create RfQ lines automatically" -msgstr "" +msgstr "RfQ-Zeilen nicht automatisch anlegen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter @@ -273,7 +274,7 @@ msgstr "" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "In negotiation" -msgstr "" +msgstr "In Verhandlung" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition___last_update @@ -314,7 +315,7 @@ msgstr "Multiple Bestellmeldung" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "New Agreements" -msgstr "" +msgstr "Neue Vereinbarungen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form @@ -324,7 +325,7 @@ msgstr "Neues Angebot" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_order_count msgid "Number of Orders" -msgstr "" +msgstr "Anzahl der Aufträge" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_picking_type_id @@ -334,7 +335,7 @@ msgstr "" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_line_qty_ordered msgid "Ordered Quantities" -msgstr "" +msgstr "Bestellte Mengen" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_ordering_date @@ -384,12 +385,12 @@ msgstr "Eine Ausschreibung vorschlagen" #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_order_requisition_id #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_line_requisition_id msgid "Purchase Agreement" -msgstr "" +msgstr "Kaufvertrag" #. module: purchase_requisition #: model:ir.model,name:purchase_requisition.model_purchase_requisition_type msgid "Purchase Agreement Type" -msgstr "" +msgstr "Kaufvertragsart" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.tender_type_action @@ -397,7 +398,7 @@ msgstr "" #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_form #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_type_tree msgid "Purchase Agreement Types" -msgstr "" +msgstr "Kaufvertragsarten" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition @@ -406,7 +407,7 @@ msgstr "" #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_tree msgid "Purchase Agreements" -msgstr "" +msgstr "Kaufverträge" #. module: purchase_requisition #: model:ir.model,name:purchase_requisition.model_purchase_order @@ -447,7 +448,7 @@ msgstr "Bedarfsanfrage erstellt" #. module: purchase_requisition #: model:purchase.requisition.type,name:purchase_requisition.type_multi msgid "Purchase Tender" -msgstr "" +msgstr "Kauf-Ausschreibung" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.act_res_partner_2_purchase_order @@ -467,7 +468,7 @@ msgstr "Menge" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form msgid "RFQs/Orders" -msgstr "" +msgstr "Anfragen/Bestellungen" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition_to_so @@ -477,7 +478,7 @@ msgstr "Angebotsanfrage" #. module: purchase_requisition #: model:ir.actions.act_window,name:purchase_requisition.action_purchase_requisition_list msgid "Request for Quotations" -msgstr "" +msgstr "Angebot anfordern" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.report_purchaserequisitions @@ -508,7 +509,7 @@ msgstr "Geplantes Datum" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter msgid "Search Purchase Agreements" -msgstr "" +msgstr "Suche Kaufverträge" #. module: purchase_requisition #: selection:purchase.requisition.type,exclusive:0 @@ -536,7 +537,7 @@ msgstr "Reihenfolge" #. module: purchase_requisition #: selection:purchase.requisition.type,quantity_copy:0 msgid "Set quantities manually" -msgstr "" +msgstr "Menge manuell festlegen" #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_filter @@ -585,7 +586,7 @@ msgstr "Preis pro ME" #. module: purchase_requisition #: selection:purchase.requisition.type,line_copy:0 msgid "Use lines of agreement" -msgstr "" +msgstr "Vereinbarungspositionen verwenden" #. module: purchase_requisition #: selection:purchase.requisition.type,quantity_copy:0 @@ -612,6 +613,7 @@ msgstr "Lager" #, python-format msgid "You cannot confirm call because there is no product line." msgstr "" +"Sie können den Anfrage nicht bestätigen, weil es keine Produktposition gibt." #. module: purchase_requisition #: code:addons/purchase_requisition/models/purchase_requisition.py:99 @@ -620,6 +622,8 @@ msgid "" "You have to cancel or validate every RfQ before closing the purchase " "requisition." msgstr "" +"Sie müssen jede Anfrage stornieren oder validieren, bevor Sie die " +"Bestellanforderung abschließen." #. module: purchase_requisition #: model:ir.ui.view,arch_db:purchase_requisition.view_purchase_requisition_form diff --git a/addons/purchase_requisition/i18n/zh_CN.po b/addons/purchase_requisition/i18n/zh_CN.po index ba170b22c09..6fd960ff279 100644 --- a/addons/purchase_requisition/i18n/zh_CN.po +++ b/addons/purchase_requisition/i18n/zh_CN.po @@ -318,7 +318,7 @@ msgstr "订单的号码" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_picking_type_id msgid "Operation Type" -msgstr "" +msgstr "作业类型" #. module: purchase_requisition #: model:ir.model.fields,field_description:purchase_requisition.field_purchase_requisition_line_qty_ordered diff --git a/addons/report/i18n/zh_CN.po b/addons/report/i18n/zh_CN.po index 4c9847a6c0e..f5fd73753b5 100644 --- a/addons/report/i18n/zh_CN.po +++ b/addons/report/i18n/zh_CN.po @@ -12,13 +12,14 @@ # xiaobin wu , 2017 # Talway <9010446@qq.com>, 2017 # Siyuan Gu , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:46+0000\n" "PO-Revision-Date: 2017-04-18 14:46+0000\n" -"Last-Translator: Siyuan Gu , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -645,7 +646,7 @@ msgstr "" #: code:addons/report/models/report.py:155 #, python-format msgid "Unable to find Wkhtmltopdf on this system. The PDF can not be created." -msgstr "" +msgstr "未找到 WKhtmltopdf 系统,无法创建 PDF。" #. module: report #: model:ir.ui.view,arch_db:report.external_layout_boxed diff --git a/addons/sale_stock/i18n/de.po b/addons/sale_stock/i18n/de.po index 7b07f1c8914..cf23d7fb57e 100644 --- a/addons/sale_stock/i18n/de.po +++ b/addons/sale_stock/i18n/de.po @@ -14,13 +14,14 @@ # Alexander Klockhaus , 2017 # Fabian Liesch , 2017 # Anja Funk , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-18 14:46+0000\n" "PO-Revision-Date: 2017-04-18 14:46+0000\n" -"Last-Translator: Anja Funk , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -80,7 +81,7 @@ msgstr "Lieferung" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_sale_config_settings_module_sale_order_dates msgid "Delivery Date" -msgstr "" +msgstr "Liefertermin" #. module: sale_stock #: model:ir.model.fields,field_description:sale_stock.field_sale_order_delivery_count diff --git a/addons/sale_stock/i18n/hr.po b/addons/sale_stock/i18n/hr.po index 3d4b28f4078..2dec42656ea 100644 --- a/addons/sale_stock/i18n/hr.po +++ b/addons/sale_stock/i18n/hr.po @@ -257,7 +257,7 @@ msgstr "Statistika prodajnih naloga" #: model:ir.model.fields,field_description:sale_stock.field_res_company_security_lead #: model:ir.model.fields,field_description:sale_stock.field_stock_config_settings_security_lead msgid "Sales Safety Days" -msgstr "" +msgstr "Sigurnosni dani prodaje" #. module: sale_stock #: model:ir.ui.view,arch_db:sale_stock.stock_config_settings_view_form_inherit_sale_stock diff --git a/addons/sales_team/i18n/fr.po b/addons/sales_team/i18n/fr.po index 36f5fc29dd1..e6e35691c2a 100644 --- a/addons/sales_team/i18n/fr.po +++ b/addons/sales_team/i18n/fr.po @@ -7,7 +7,7 @@ # Martin Trigaux , 2016 # Henri Cornuau , 2016 # Maxime Chambreuil , 2016 -# Nicolas JEUDY , 2016 +# Nicolas JEUDY , 2016 # Lucas Deliege , 2016 # Olivier Lenoir , 2016 # Clo , 2016 @@ -777,7 +777,7 @@ msgstr "" #. module: sales_team #: model:res.groups,name:sales_team.group_sale_salesman_all_leads msgid "User: All Documents" -msgstr "Utilisateur: tous les docments" +msgstr "Utilisateur: tous les documents" #. module: sales_team #: model:res.groups,name:sales_team.group_sale_salesman diff --git a/addons/stock/i18n/zh_CN.po b/addons/stock/i18n/zh_CN.po index 85489d05a37..1a8e360a239 100644 --- a/addons/stock/i18n/zh_CN.po +++ b/addons/stock/i18n/zh_CN.po @@ -3061,7 +3061,7 @@ msgstr "最近的盘点及移动" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_picking_launch_pack_operations msgid "Launch Pack Operations" -msgstr "开始包装作业" +msgstr "启动包装作业" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_warehouse_orderpoint_lead_days @@ -3842,7 +3842,7 @@ msgstr "作业名称" #: model:ir.ui.view,arch_db:stock.view_picking_internal_search #: model:ir.ui.view,arch_db:stock.view_pickingtype_filter msgid "Operation Type" -msgstr "" +msgstr "作业类型" #. module: stock #: model:ir.model.fields,help:stock.field_procurement_rule_picking_type_id @@ -3854,7 +3854,7 @@ msgstr "" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_picking_type_return_picking_type_id msgid "Operation Type for Returns" -msgstr "" +msgstr "退回的作业类型" #. module: stock #: model:ir.ui.view,arch_db:stock.view_picking_type_form @@ -3867,7 +3867,7 @@ msgstr "作业类型" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_picking_type_name msgid "Operation Types Name" -msgstr "" +msgstr "作业类型名称" #. module: stock #: model:ir.ui.menu,name:stock.menu_stock_warehouse_mgmt @@ -4268,7 +4268,7 @@ msgstr "分拣清单" #. module: stock #: model:ir.actions.report.xml,name:stock.action_report_picking msgid "Picking Operations" -msgstr "分拣作业" +msgstr "拣货作业" #. module: stock #: model:ir.model.fields,field_description:stock.field_stock_config_settings_module_stock_picking_wave @@ -7377,7 +7377,7 @@ msgstr "带有确认 按钮" #. module: stock #: model:ir.ui.view,arch_db:stock.view_picking_form msgid "↳Put in Pack" -msgstr "↳放置在包裹中" +msgstr "↳放入包裹" #. module: stock #: model:ir.ui.view,arch_db:stock.view_inventory_form diff --git a/addons/website/i18n/de.po b/addons/website/i18n/de.po index 6ab78c7bc33..d7609fbfd9a 100644 --- a/addons/website/i18n/de.po +++ b/addons/website/i18n/de.po @@ -21,7 +21,7 @@ # Thorsten Vocks , 2017 # Krakataua Katarajtu , 2017 # Stefan Hartenfels , 2017 -# Andreas Nährich , 2017 +# Andi , 2017 # jonas , 2017 # Renzo Meister , 2017 # key six , 2017 @@ -2544,7 +2544,7 @@ msgstr "Ok" #: code:addons/website/static/src/xml/website.backend.xml:5 #, python-format msgid "On Website" -msgstr "" +msgstr "Auf Website" #. module: website #: model:ir.ui.view,arch_db:website.website_planner @@ -3494,7 +3494,7 @@ msgstr "" #: model:ir.ui.view,arch_db:website.publish_short #, python-format msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website #: model:ir.ui.view,arch_db:website.website_planner diff --git a/addons/website_blog/i18n/de.po b/addons/website_blog/i18n/de.po index 90be7221d47..3f58e915603 100644 --- a/addons/website_blog/i18n/de.po +++ b/addons/website_blog/i18n/de.po @@ -18,13 +18,14 @@ # Thorsten Vocks , 2017 # Henry Mineehen , 2017 # Rudolf Schnapka , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~14\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-02-15 09:50+0000\n" "PO-Revision-Date: 2017-02-15 09:50+0000\n" -"Last-Translator: Rudolf Schnapka , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -90,7 +91,7 @@ msgstr "" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.blog_post_template_new_post msgid "A new post" -msgstr "" +msgstr "Ein neuer Beitrag" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.opt_blog_rc_about_us @@ -633,7 +634,7 @@ msgstr "Titel" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.opt_blog_rc_status msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.blog_post_short diff --git a/addons/website_blog/i18n/zh_CN.po b/addons/website_blog/i18n/zh_CN.po index 35948492de1..9418392151e 100644 --- a/addons/website_blog/i18n/zh_CN.po +++ b/addons/website_blog/i18n/zh_CN.po @@ -13,6 +13,7 @@ # 菜小蛇 , 2016 # glovebx , 2016 # SHOM , 2016 +# n37r06u3 , 2016 # 苏州远鼎 , 2016 # THL , 2017 msgid "" @@ -204,7 +205,7 @@ msgstr "博客标签" #: model:ir.ui.menu,name:website_blog.menu_blog #: model:ir.ui.view,arch_db:website_blog.view_blog_blog_list msgid "Blogs" -msgstr "博文" +msgstr "博客" #. module: website_blog #: model:ir.ui.view,arch_db:website_blog.website_blog diff --git a/addons/website_event_track/i18n/nl.po b/addons/website_event_track/i18n/nl.po index cef73a092ad..f4e3062829b 100644 --- a/addons/website_event_track/i18n/nl.po +++ b/addons/website_event_track/i18n/nl.po @@ -823,7 +823,7 @@ msgstr "Parallelsessie" #. module: website_event_track #: model:mail.message.subtype,name:website_event_track.mt_track_blocked msgid "Track Blocked" -msgstr "" +msgstr "Volg geblokkeerd" #. module: website_event_track #: model:ir.model.fields,field_description:website_event_track.field_event_track_date diff --git a/addons/website_event_track/i18n/zh_CN.po b/addons/website_event_track/i18n/zh_CN.po index 28a7b184729..0b845f6b174 100644 --- a/addons/website_event_track/i18n/zh_CN.po +++ b/addons/website_event_track/i18n/zh_CN.po @@ -394,7 +394,7 @@ msgstr "" #. module: website_event_track #: model:ir.model.fields,field_description:website_event_track.field_event_track_stage_fold msgid "Folded in Kanban" -msgstr "" +msgstr "在看板中折叠" #. module: website_event_track #: model:event.sponsor.type,name:website_event_track.event_sponsor_type3 diff --git a/addons/website_sale/i18n/zh_CN.po b/addons/website_sale/i18n/zh_CN.po index edf4b884830..7ce9910d612 100644 --- a/addons/website_sale/i18n/zh_CN.po +++ b/addons/website_sale/i18n/zh_CN.po @@ -28,13 +28,14 @@ # Bo Cao , 2017 # 老窦 北京 <2662059195@qq.com>, 2017 # Liping Wang , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-17 08:17+0000\n" "PO-Revision-Date: 2017-07-17 08:17+0000\n" -"Last-Translator: Liping Wang , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -150,7 +151,7 @@ msgstr "" #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.cart_lines msgid " Remove" -msgstr "" +msgstr " 移除" #. module: website_sale #: model:ir.ui.view,arch_db:website_sale.total diff --git a/addons/website_sale_wishlist/i18n/zh_CN.po b/addons/website_sale_wishlist/i18n/zh_CN.po index fb530f012e6..03934f5a404 100644 --- a/addons/website_sale_wishlist/i18n/zh_CN.po +++ b/addons/website_sale_wishlist/i18n/zh_CN.po @@ -6,13 +6,14 @@ # Jeffery CHEN , 2017 # waveyeung , 2017 # liAnGjiA , 2017 +# Maie , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-17 08:18+0000\n" "PO-Revision-Date: 2017-07-17 08:18+0000\n" -"Last-Translator: liAnGjiA , 2017\n" +"Last-Translator: Maie , 2017\n" "Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,7 +31,7 @@ msgstr "" #. module: website_sale_wishlist #: model:ir.ui.view,arch_db:website_sale_wishlist.product_wishlist msgid " Remove" -msgstr "" +msgstr " 移除" #. module: website_sale_wishlist #: model:ir.model.fields,field_description:website_sale_wishlist.field_product_wishlist_active diff --git a/addons/website_slides/i18n/de.po b/addons/website_slides/i18n/de.po index 2ecd27ab6af..1e69ae8a775 100644 --- a/addons/website_slides/i18n/de.po +++ b/addons/website_slides/i18n/de.po @@ -16,13 +16,14 @@ # JackTheHunter , 2017 # Renzo Meister , 2017 # Thorsten Vocks , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~14\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-02-15 09:50+0000\n" "PO-Revision-Date: 2017-02-15 09:50+0000\n" -"Last-Translator: Thorsten Vocks , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1185,7 +1186,7 @@ msgstr "Unbekanntes Dokument" #. module: website_slides #: model:ir.ui.view,arch_db:website_slides.slides_grid_view msgid "Unpublished" -msgstr "" +msgstr "Unveröffentlicht" #. module: website_slides #: model:ir.model.fields,field_description:website_slides.field_slide_channel_upload_group_ids diff --git a/odoo/addons/base/i18n/de.po b/odoo/addons/base/i18n/de.po index a69365f0eb8..a4f83eb0054 100644 --- a/odoo/addons/base/i18n/de.po +++ b/odoo/addons/base/i18n/de.po @@ -33,13 +33,14 @@ # Christian Oechsner , 2017 # Tom , 2017 # aNj , 2017 +# Andi , 2017 msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.saas~15\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-17 08:45+0000\n" "PO-Revision-Date: 2017-07-17 08:45+0000\n" -"Last-Translator: aNj , 2017\n" +"Last-Translator: Andi , 2017\n" "Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -15269,7 +15270,7 @@ msgstr "Einkauf" #. module: base #: model:ir.module.module,shortdesc:base.module_purchase_requisition msgid "Purchase Agreements" -msgstr "" +msgstr "Kaufverträge" #. module: base #: model:ir.module.module,shortdesc:base.module_purchase diff --git a/odoo/addons/base/i18n/tr.po b/odoo/addons/base/i18n/tr.po index 1b1112e1e4b..5ecdf7adf42 100644 --- a/odoo/addons/base/i18n/tr.po +++ b/odoo/addons/base/i18n/tr.po @@ -641,6 +641,8 @@ msgid "" "\n" " Use Plaid.com to retrieve bank statements" msgstr "" +"\n" +" Banka hesap özetini almak için Plaid.com servisi kullan." #. module: base #: model:ir.module.module,description:base.module_account_plaid @@ -649,6 +651,9 @@ msgid "" " Use Plaid.com to retrieve bank statements.\n" " " msgstr "" +"\n" +" Banka hesap özetini almak için Plaid.com servisi kullan..\n" +" " #. module: base #: model:ir.module.module,description:base.module_hr_recruitment_survey @@ -5354,7 +5359,7 @@ msgstr "Analitik Hesap Öndeğerleri" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import msgid "Account Bank Statement Import" -msgstr "" +msgstr "Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.module.category,name:base.module_category_localization_account_charts @@ -9774,7 +9779,7 @@ msgstr "Jenerik Formu Denetleyici" msgid "" "Generic Wizard to Import Bank Statements. Includes the import of files in " ".OFX format" -msgstr "" +msgstr "Banka Hesap Özeti İçe Aktarım Sihirbazı" #. module: base #: model:ir.module.module,description:base.module_website_form @@ -10671,22 +10676,22 @@ msgstr "İçe Aktar / Dışa Aktar" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import_camt msgid "Import CAMT Bank Statement" -msgstr "" +msgstr "CAMT Formatında Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import_csv msgid "Import CSV Bank Statement" -msgstr "" +msgstr "CSV Formatında Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import_ofx msgid "Import OFX Bank Statement" -msgstr "" +msgstr "QFX Formatında Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.module.module,shortdesc:base.module_account_bank_statement_import_qif msgid "Import QIF Bank Statement" -msgstr "" +msgstr "QIF Formatında Banka Hesap Özeti İçe Aktarımı" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_import_language From 52c57b4f1192590b987ce9e1a2cdffb99eb5add4 Mon Sep 17 00:00:00 2001 From: Cedric Snauwaert Date: Mon, 18 Sep 2017 09:52:32 +0200 Subject: [PATCH 06/40] [FIX] account: reconciliation, stupid mistake when trying to open reconciliation for accounts should take context.account_ids and not model.account_ids as model is not an object --- .../static/src/js/reconciliation/reconciliation_model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index b136af9a4ed..9caea6d8712 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -1073,7 +1073,7 @@ var ManualModel = StatementModel.extend({ return self._rpc({ model: 'account.move.line', method: 'get_data_for_manual_reconciliation', - args: ['account', model.account_ids || self.account_ids], + args: ['account', context.account_ids || self.account_ids], context: context, }) .then(function (result) { From 6b511f38c0f4ca7ac657c824e3be60cabbb7cfa1 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 15 Sep 2017 14:24:51 +0200 Subject: [PATCH 07/40] [FIX] point_of_sale: format date on receipt The date printed on the receipt is not printed according to the language settings. opw-769862 --- addons/point_of_sale/static/src/js/models.js | 2 ++ addons/point_of_sale/static/src/xml/pos.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 4edff2ce8ea..336e3b32848 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1943,6 +1943,8 @@ exports.Order = Backbone.Model.extend({ initialize_validation_date: function () { this.validation_date = new Date(); + this.formatted_validation_date = formats.format_value( + this.validation_date, {type: 'datetime'}); }, set_tip: function(tip) { diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index 995a27ddd3b..ee5bef3456d 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -1402,7 +1402,7 @@
-
+


From 58c5b1cfd83a947a3b9d621ed20db9a118d88662 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 15 Sep 2017 14:40:31 +0200 Subject: [PATCH 08/40] [FIX] payment: onchange partner - Go in Accounting > Sales > Payment - Fill the mandatory info, and create a "Payment Transaction" - On the form view, change the Partner - The Customer Details are empty, and saving is not possible since the country (mandatory) is not filled in Closes #15708 opw-771753 --- addons/payment/models/payment_acquirer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index f451b7ee93e..a56d0692819 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -446,7 +446,7 @@ class PaymentTransaction(models.Model): @api.onchange('partner_id') def _onchange_partner_id(self): onchange_vals = self.on_change_partner_id(self.partner_id.id).get('value', {}) - self.write(onchange_vals) + self.update(onchange_vals) @api.multi def on_change_partner_id(self, partner_id): From 313f69e9487e991e4db33c75682342b185da5c73 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 18 Sep 2017 10:13:54 +0200 Subject: [PATCH 09/40] [ADD] doc: JS document extraction system * Fix a bunch of ill-documented/incomplete/incorrect method docs * add start of Sphinx extension to extract & integrate jsdoc into Sphinx documentation: - parse JS files (and don't blow up), uses a fork of pyjsparser as the project currently does not parse comments - extract cross-module dependency information - parse JsDoc comments using pyjsdoc and infer structure from code & jsdoc - ``ast`` CLI printing a simplified AST of the input files - ``dependencies`` creating a dependency graph of either all modules in the provided input files or the modules matching the specified filters (warning: will not work if missing dependencies), generates a .dot file - ``extractor`` generating a plain text module documentation (mix of rst and markdown styles, not anything formal) * sphinx extension with an "automodule" directive taking a module name and generating the documentation for it --- doc/_extensions/autojsdoc/README.rst | 87 + doc/_extensions/autojsdoc/__init__.py | 1 + doc/_extensions/autojsdoc/__main__.py | 154 + doc/_extensions/autojsdoc/ext/__init__.py | 13 + doc/_extensions/autojsdoc/ext/directives.py | 686 ++++ doc/_extensions/autojsdoc/ext/extractor.py | 87 + doc/_extensions/autojsdoc/parser/__init__.py | 1 + doc/_extensions/autojsdoc/parser/jsdoc.py | 324 ++ doc/_extensions/autojsdoc/parser/parser.py | 552 ++++ .../autojsdoc/parser/tests/README.rst | 6 + .../autojsdoc/parser/tests/support.py | 73 + .../autojsdoc/parser/tests/test_class.py | 227 ++ .../autojsdoc/parser/tests/test_crap.py | 75 + .../autojsdoc/parser/tests/test_module.py | 173 + .../autojsdoc/parser/tests/test_namespace.py | 177 + .../autojsdoc/parser/tests/test_params.py | 116 + .../autojsdoc/parser/tests/test_typespec.py | 81 + doc/_extensions/autojsdoc/parser/types.py | 191 ++ doc/_extensions/autojsdoc/parser/utils.py | 295 ++ doc/_extensions/autojsdoc/parser/visitor.py | 126 + doc/_extensions/conftest.py | 0 doc/_extensions/odoo_ext/static/style.css | 577 ++-- doc/_extensions/odoo_ext/static/style.less | 4 +- doc/_extensions/pyjsparser/LICENSE | 21 + doc/_extensions/pyjsparser/README | 4 + doc/_extensions/pyjsparser/__init__.py | 4 + doc/_extensions/pyjsparser/parser.py | 2928 +++++++++++++++++ doc/_extensions/pyjsparser/pyjsparserdata.py | 303 ++ doc/_extensions/pyjsparser/std_nodes.py | 470 +++ doc/conf.py | 6 +- doc/reference/javascript.rst | 1401 +------- doc/requirements.txt | 3 +- odoo/api.py | 6 +- 33 files changed, 7482 insertions(+), 1690 deletions(-) create mode 100644 doc/_extensions/autojsdoc/README.rst create mode 100644 doc/_extensions/autojsdoc/__init__.py create mode 100644 doc/_extensions/autojsdoc/__main__.py create mode 100644 doc/_extensions/autojsdoc/ext/__init__.py create mode 100644 doc/_extensions/autojsdoc/ext/directives.py create mode 100644 doc/_extensions/autojsdoc/ext/extractor.py create mode 100644 doc/_extensions/autojsdoc/parser/__init__.py create mode 100644 doc/_extensions/autojsdoc/parser/jsdoc.py create mode 100644 doc/_extensions/autojsdoc/parser/parser.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/README.rst create mode 100644 doc/_extensions/autojsdoc/parser/tests/support.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_class.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_crap.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_module.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_namespace.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_params.py create mode 100644 doc/_extensions/autojsdoc/parser/tests/test_typespec.py create mode 100644 doc/_extensions/autojsdoc/parser/types.py create mode 100644 doc/_extensions/autojsdoc/parser/utils.py create mode 100644 doc/_extensions/autojsdoc/parser/visitor.py create mode 100644 doc/_extensions/conftest.py create mode 100644 doc/_extensions/pyjsparser/LICENSE create mode 100644 doc/_extensions/pyjsparser/README create mode 100644 doc/_extensions/pyjsparser/__init__.py create mode 100644 doc/_extensions/pyjsparser/parser.py create mode 100644 doc/_extensions/pyjsparser/pyjsparserdata.py create mode 100644 doc/_extensions/pyjsparser/std_nodes.py diff --git a/doc/_extensions/autojsdoc/README.rst b/doc/_extensions/autojsdoc/README.rst new file mode 100644 index 00000000000..ef7681778a1 --- /dev/null +++ b/doc/_extensions/autojsdoc/README.rst @@ -0,0 +1,87 @@ +:orphan: + +====================================== +JSDoc parser/Sphinx extension for Odoo +====================================== + +Why? +==== + +Spent about a week trying to coerce "standard" javascript tools (jsdoc_ with +the hope of using sphinx-js_ for integration or `documentation.js`_) and +failed to ever get a sensible result: failed to get any result with the +current state of the documentation, significant changes/additions/fixes to +docstrings brought this up to "garbage output" level. + +Bug reports and mailing list posts didn't show any path to improvement on the +ES5 codebase (if we ever go whole-hog on ES6 modules and classes things could +be different, in fact most of JSDoc's current effort seem focused on +ES6/ES2015 features) but both experience and looking at the mailing lists +told me that spending more time would be wasted. + +Even more so as I was writing visitors/rewriters to generate documentation +from our existing structure, which broadly speaking is relatively strict, and +thus + +What? +===== + +If it were possible to generate JSDoc annotations from our relatively +well-defined code structures, it was obviously possible to extract documentary +information directly from it, hence this Odoo-specific package/extension +trying to do exactly that. + +This package should eventually provide: + +* a command-line interface which can be invoked via ``-m autojsdoc`` (assuming + your ``PYTHONPATH`` can find it) which should allow dumping the parsed AST + in a convenient-ish form, possibly doing searches through the AST, a + dependency graph extractor/analysis and a text dumper for the + documentation. + +* a sphinx extension (``autojsdoc.sphinx``) which can be used to integrate the + parsed JSDoc information into the Sphinx doc. + +How? +==== + +Sphinx-aside, the package relies on 3 libraries: + +* pyjsparser_, an Esprima-compliant ES5.1 parser (with bits of ES6 support), + sadly it does not support comments in its current form so I had to fork it. + Fed a javascript source file, pyjsparser_ simply generates a bunch of nested + dicts representing an Esprima ast, ast-types_ does a reasonably good job of + describing it once you understand that "bases" are basically just structural + mixins. + + Because the original does not, this package provides a ``visitor`` module + for pyjsparser_ ASTs. + +* pyjsdoc_, a one-file "port" of jsdoc, can actually do much of the JS parsing + (using string munging) but its core semantics don't fit our needs so I'm + only using it to parse the actual JSDoc content, and the ``jsdoc`` module + contains some replacement classes, extensions & monkey patches for things + `pyjsdoc`_ itself does not support, at the time of this writing: + + - a bug in FunctionDoc.return_val + - a type on FunctionDoc so it's compatible with ParamDoc + - a more reliable comments-parsing function + - a replacement ModuleDoc as the original does not materialise AMD modules + - a ClassDoc extension to support mixins + - two additional CommentDoc extensions for "namespaces" objects (bag of + attributes without any more information) and mixin objects + +* pytest_ to configure and run the test suite, which you can run by invoking + ``pytest doc/_extensions`` from the project top-level, the tests represent + both "happy path" things we want to parse and various code patterns which + tripped the happy path because e.g. they were matched and should not have, + they were not matched and should have, or they were more complex than the + happy path had expected + +.. _ast-types: _https://github.com/benjamn/ast-types/blob/master/def/core.js +.. _documentation.js: http://documentation.js.org +.. _jsdoc: http://usejsdoc.org +.. _pyjsdoc: https://github.com/nostrademons/pyjsdoc +.. _pyjsparser: https://github.com/PiotrDabkowski/pyjsparser +.. _pytest: https://pytest.org/ +.. _sphinx-js: https://sphinx-js-howto.readthedocs.io diff --git a/doc/_extensions/autojsdoc/__init__.py b/doc/_extensions/autojsdoc/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/doc/_extensions/autojsdoc/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/doc/_extensions/autojsdoc/__main__.py b/doc/_extensions/autojsdoc/__main__.py new file mode 100644 index 00000000000..20ab65c2c37 --- /dev/null +++ b/doc/_extensions/autojsdoc/__main__.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +import cgitb +import fnmatch +import io +import logging + +import click + +import pyjsdoc +import pyjsparser +import sys + +from .parser.parser import ModuleMatcher +from .parser.visitor import Visitor, SKIP +from . import jsdoc + +class Printer(Visitor): + def __init__(self, level=0): + super(Printer, self).__init__() + self.level = level + + def _print(self, text): + print ' ' * self.level, text + + def enter_generic(self, node): + self._print(node['type']) + self.level += 1 + + def exit_generic(self, node): + self.level -= 1 + + def enter_Identifier(self, node): + self._print(node['name']) + return SKIP + + def enter_Literal(self, node): + self._print(node['value']) + return SKIP + + def enter_BinaryExpression(self, node): + self._print(node['operator']) + self.level += 1 + +def visit_files(files, visitor, ctx): + for name in files: + with io.open(name) as f: + ctx.logger.info("%s", name) + try: + yield visitor().visit(pyjsparser.parse(f.read())) + except Exception as e: + if ctx.logger.isEnabledFor(logging.DEBUG): + ctx.logger.exception("while visiting %s", name) + else: + ctx.logger.error("%s while visiting %s", e, name) + +# bunch of modules various bits depend on which are not statically defined +# (or are outside the scope of the system) +ABSTRACT_MODULES = [ + jsdoc.ModuleDoc({ + 'module': 'web.web_client', + 'dependency': {'web.AbstractWebClient'}, + 'exports': jsdoc.NSDoc({ + 'name': 'web_client', + 'doc': 'instance of AbstractWebClient', + }), + }), + jsdoc.ModuleDoc({ + 'module': 'web.Tour', + 'dependency': {'web_tour.TourManager'}, + 'exports': jsdoc.NSDoc({ + 'name': 'Tour', + 'doc': 'maybe tourmanager instance?', + }), + }), + # OH FOR FUCK'S SAKE + jsdoc.ModuleDoc({ + 'module': 'summernote/summernote', + 'exports': jsdoc.NSDoc({'doc': "totally real summernote"}), + }) +] + +@click.group(context_settings={'help_option_names': ['-h', '--help']}) +@click.option('-v', '--verbose', count=True) +@click.option('-q', '--quiet', count=True) +@click.pass_context +def autojsdoc(ctx, verbose, quiet): + logging.basicConfig( + level=logging.INFO + (quiet - verbose) * 10, + format="[%(levelname)s %(created)f] %(message)s", + ) + ctx.logger = logging.getLogger('autojsdoc') + ctx.visitor = None + ctx.files = [] + ctx.kw = {} + +@autojsdoc.command() +@click.argument('files', type=click.Path(exists=True), nargs=-1) +@click.pass_context +def ast(ctx, files): + """ Prints a structure tree of the provided files + """ + if not files: + print(ctx.get_help()) + visit_files(files, lambda: Printer(level=1), ctx.parent) + +@autojsdoc.command() +@click.option('-m', '--module', multiple=True, help="Only shows dependencies matching any of the patterns") +@click.argument('files', type=click.Path(exists=True), nargs=-1) +@click.pass_context +def dependencies(ctx, module, files): + """ Prints a dot file of all modules to stdout + """ + if not files: + print(ctx.get_help()) + byname = { + mod.name: mod.dependencies + for mod in ABSTRACT_MODULES + } + for modules in visit_files(files, ModuleMatcher, ctx.parent): + for mod in modules: + byname[mod.name] = mod.dependencies + + print('digraph dependencies {') + + todo = set() + # if module filters, roots are only matching modules + if module: + for f in module: + todo.update(fnmatch.filter(byname.keys(), f)) + + for m in todo: + # set a different box for selected roots + print(' "%s" [color=orangered]' % m) + else: + # otherwise check all modules + todo.update(byname) + + done = set() + while todo: + node = todo.pop() + if node in done: + continue + + done.add(node) + deps = byname[node] + todo.update(deps - done) + for dep in deps: + print(' "%s" -> "%s";' % (node, dep)) + print('}') + +try: + autojsdoc.main(prog_name='autojsdoc') +except Exception: + print(cgitb.text(sys.exc_info())) diff --git a/doc/_extensions/autojsdoc/ext/__init__.py b/doc/_extensions/autojsdoc/ext/__init__.py new file mode 100644 index 00000000000..e27a9e3d318 --- /dev/null +++ b/doc/_extensions/autojsdoc/ext/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from .directives import automodule_bound, autodirective_bound +from .extractor import _get_roots + + +def setup(app): + app.add_config_value('js_roots', _get_roots, 'env') + modules = {} + app.add_directive_to_domain('js', 'automodule', automodule_bound(app, modules) + ) + autodirective = autodirective_bound(app, modules) + for n in ['autonamespace', 'automixin', 'autoclass', 'autofunction']: + app.add_directive_to_domain('js', n, autodirective) diff --git a/doc/_extensions/autojsdoc/ext/directives.py b/doc/_extensions/autojsdoc/ext/directives.py new file mode 100644 index 00000000000..98b3f9e8322 --- /dev/null +++ b/doc/_extensions/autojsdoc/ext/directives.py @@ -0,0 +1,686 @@ +# -*- coding: utf-8 -*- +import abc +import collections +import contextlib +import fnmatch +import io +import re + +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.statemachine import StringList +from sphinx import addnodes +from sphinx.ext.autodoc import members_set_option, bool_option, ALL + +from autojsdoc.ext.extractor import read_js +from ..parser import jsdoc, types + + +@contextlib.contextmanager +def addto(parent, newnode): + assert isinstance(newnode, nodes.Node), \ + "Expected newnode to be a Node, got %s" % (type(newnode)) + yield newnode + parent.append(newnode) + + +def documenter_for(directive, doc): + if isinstance(doc, jsdoc.FunctionDoc): + return FunctionDocumenter(directive, doc) + if isinstance(doc, jsdoc.ClassDoc): + return ClassDocumenter(directive, doc) + if isinstance(doc, jsdoc.MixinDoc): + return MixinDocumenter(directive, doc) + if isinstance(doc, (jsdoc.PropertyDoc, jsdoc.LiteralDoc)): + return PropertyDocumenter(directive, doc) + if isinstance(doc, jsdoc.InstanceDoc): + return InstanceDocumenter(directive, doc) + if isinstance(doc, jsdoc.Unknown): + return UnknownDocumenter(directive, doc) + if isinstance(doc, jsdoc.NSDoc): + return NSDocumenter(directive, doc) + + raise TypeError("No documenter for %s" % type(doc)) + +def to_list(doc, source=None): + return StringList([ + line.rstrip('\n') + for line in io.StringIO(doc) + ], source=source) + +DIRECTIVE_OPTIONS = { + 'members': members_set_option, + 'undoc-members': bool_option, + 'private-members': bool_option, + 'undoc-matches': bool_option, +} +def automodule_bound(app, modules): + class AutoModuleDirective(Directive): + required_arguments = 1 + has_content = True + option_spec = DIRECTIVE_OPTIONS + + # self.state.nested_parse(string, offset, node) => parse context for sub-content (body which can contain RST data) + # => needed for doc (converted?) and for actual directive body + def run(self): + self.env = self.state.document.settings.env + modname = self.arguments[0].strip() + + # TODO: cache/memoize modules & symbols? + if not modules: + read_js(app, modules) + + mods = [ + (name, mod) + for name, mod in modules.items() + if fnmatch.fnmatch(name, modname) + ] + ret = [] + for name, mod in mods: + if mod.is_private: + continue + if name != modname and not (mod.doc or mod.exports): + # this module has no documentation, no exports and was + # not specifically requested through automodule -> skip + # unless requested + if not self.options.get('undoc-matches'): + continue + modsource = mod['sourcefile'] + if modsource: + self.env.note_dependency(modsource) + # not sure what that's used for as normal xrefs are resolved using the id directly + target = nodes.target('', '', ids=['module-' + name], ismod=True) + self.state.document.note_explicit_target(target) + + documenter = ModuleDocumenter(self, mod) + + ret.append(target) + ret.extend(documenter.generate()) + return ret + + return AutoModuleDirective + +def autodirective_bound(app, modules): + documenters = { + 'js:autoclass': ClassDocumenter, + 'js:autonamespace': NSDocumenter, + 'js:autofunction': FunctionDocumenter, + 'js:automixin': MixinDocumenter, + } + class AutoDirective(Directive): + required_arguments = 1 + has_content = True + option_spec = DIRECTIVE_OPTIONS + + def run(self): + self.env = self.state.document.settings.env + + # strip 'js:auto' + objname = self.arguments[0].strip() + + path = self.env.temp_data.get('autojs:prefix', []) + [objname] + item = modules[path[0]] + # deref' namespaces until we reach the object we're looking for + for k in path[1:]: + item = item.get_property(k) + + docclass = documenters[self.name] + return docclass(self, item).generate() + + return AutoDirective + +class Documenter(object): + objtype = None + def __init__(self, directive, doc): + self.directive = directive + self.env = directive.env + self.item = doc + + @property + def modname(self): + return self.env.temp_data.get('autojs:module', '') + @property + def classname(self): + return self.env.temp_data.get('autojs:class', '') + def generate(self, all_members=False): + """ + :rtype: List[nodes.Node] + """ + objname = self.item.name + prefixed = (self.item['sourcemodule'].name + '.' + objname) if self.item['sourcemodule'] else None + objtype = self.objtype + assert objtype, '%s has no objtype' % type(self) + root = addnodes.desc(domain='js', desctype=objtype, objtype=objtype) + with addto(root, addnodes.desc_signature( + module=self.modname or '', + fullname=objname, + )) as s: + s['class'] = self.classname + + s['ids'] = [] + if objname: + s['ids'].append(objname) + if prefixed: + s['ids'].append(prefixed) + + if objtype: + s += addnodes.desc_annotation( + objtype, objtype, + nodes.Text(' '), + ) + + env = self.env + if objname: + env.domaindata['js']['objects'][objname] = (env.docname, objtype) + if prefixed: + env.domaindata['js']['objects'][prefixed] = (env.docname, objtype) + + # TODO: linkcode_resolve + s += self.make_signature() + with addto(root, addnodes.desc_content()) as c: + # must be here otherwise nested_parse(self.content) will not have + # the prefix set + self.env.temp_data.setdefault('autojs:prefix', []).append(self.item.name) + c += self.make_content(all_members=all_members) + self.env.temp_data['autojs:prefix'].pop() + return [root] + + def make_signature(self): + """ + :rtype: List[nodes.Node] + """ + return [addnodes.desc_name(self.item.name, self.item.name)] + + @abc.abstractmethod + def make_content(self, all_members): + """ + :rtype: List[nodes.Node] + """ + + def document_subtypes(self, subtypes): + docs = [] + with with_mapping_value(self.directive.options, 'undoc-members', True): + for cls in subtypes: + docs += ClassDocumenter(self.directive, cls).generate(all_members=True) + return docs + + +class NSDocumenter(Documenter): + objtype = 'namespace' + def make_content(self, all_members): + doc = self.item + ret = nodes.section() + if doc.doc: + self.directive.state.nested_parse(to_list(doc.doc), 0, ret) + ret += self.document_properties(all_members) + return ret.children + + def should_document(self, member, name, all_members): + """ + :type member: jsdoc.CommentDoc + :type name: str + :type all_members: bool + :rtype: bool + """ + options = self.directive.options + + members = options.get('members') or [] + if not (all_members or members is ALL): + # if a member is requested by name, it's always documented + return name in members + + # ctor params are merged into the class doc + if member.is_constructor: + return False + + # only document "private" members if option is set + if self.is_private(member, name) and not options.get('private-members'): + return False + + # TODO: what if member doesn't have a description but has non-desc tags set? + # TODO: add @public to force documenting symbol? => useful for implicit typedef + return bool(member.doc or options.get('undoc-members')) + + def is_private(self, member, name): + return member.is_private + + def document_properties(self, all_members): + ret = nodes.section() + # TODO: :member-order: [alphabetical | groupwise | bysource] + for (n, p) in self.item.properties: + if not self.should_document(p, n, all_members): + continue + # FIXME: maybe should use property name as name inside? + ret += documenter_for(self.directive, p).generate(all_members=True) + return ret.children + +_NONE = object() +@contextlib.contextmanager +def with_mapping_value(mapping, key, value, restore_to=_NONE): + """ Sets ``key`` to ``value`` for the duration of the context. + + If ``restore_to`` is not provided, restores ``key``'s old value + afterwards, removes it entirely if there was no value for ``key`` in the + mapping. + + .. warning:: for defaultdict & similar mappings, may restore the default + value (depends how the collections' .get behaves) + """ + if restore_to is _NONE: + restore_to = mapping.get(key, _NONE) + mapping[key] = value + try: + yield + finally: + if restore_to is _NONE: + del mapping[key] + else: + mapping[key] = restore_to +class ModuleDocumenter(NSDocumenter): + objtype = 'module' + def document_properties(self, all_members): + with with_mapping_value(self.env.temp_data, 'autojs:module', self.item.name, ''): + return super(ModuleDocumenter, self).document_properties(all_members) + + def make_content(self, all_members): + doc = self.item + content = addnodes.desc_content() + + if doc.exports or doc.dependencies: + with addto(content, nodes.field_list()) as fields: + if doc.exports: + with addto(fields, nodes.field()) as field: + field += nodes.field_name('Exports', 'Exports') + with addto(field, nodes.field_body()) as body: + ref = doc['exports'] # warning: not the same as doc.exports + label = ref or '' + link = addnodes.pending_xref( + ref, nodes.paragraph(ref, label), + refdomain='js', + reftype='any', + reftarget=ref, + ) + link['js:module'] = doc.name + body += link + + if doc.dependencies: + with addto(fields, nodes.field()) as field: + self.make_dependencies(field, doc) + + self.directive.state.nested_parse(self.directive.content, 0, content) + + if doc.doc: + # FIXME: source offset + self.directive.state.nested_parse(to_list(doc.doc, source=doc['sourcefile']), 0, content) + + content += self.document_properties(all_members) + + return content + + def make_dependencies(self, field, doc): + field += nodes.field_name("Depends On", "Depends On") + with addto(field, nodes.field_body()) as body: + with addto(body, nodes.bullet_list()) as deps: + for dep in sorted(doc.dependencies): + ref = addnodes.pending_xref( + dep, nodes.paragraph(dep, dep), + refdomain='js', + reftype='module', + reftarget=dep, + ) + deps += nodes.list_item(dep, ref) + + def should_document(self, member, name, all_members): + # member can be Nothing? + if not member: + return False + modname = getattr(member['sourcemodule'], 'name', None) + doc = self.item + + # always document exported symbol (regardless undoc, private, ...) + # otherwise things become... somewhat odd + if name == doc['exports']: + return True + + # if doc['exports'] the module is exporting a "named" item which + # does not need to be documented twice, if not doc['exports'] it's + # exporting an anonymous item (e.g. object literal) which needs to + # be documented on its own + if name == '' and not doc['exports']: + return True + + # TODO: :imported-members: + # FIXME: *directly* re-exported "foreign symbols"? + return (not modname or modname == doc.name) \ + and super(ModuleDocumenter, self).should_document(member, name, all_members) + + +class ClassDocumenter(NSDocumenter): + objtype = 'class' + + def document_properties(self, all_members): + with with_mapping_value(self.env.temp_data, 'autojs:class', self.item.name, ''): + return super(ClassDocumenter, self).document_properties(all_members) + + def make_signature(self): + sig = super(ClassDocumenter, self).make_signature() + sig.append(self.make_parameters()) + return sig + + def make_parameters(self): + params = addnodes.desc_parameterlist('', '') + ctor = self.item.constructor + if ctor: + params += make_desc_parameters(ctor.params) + + return params + + def make_content(self, all_members): + doc = self.item + ret = nodes.section() + + ctor = self.item.constructor + params = subtypes = [] + if ctor: + check_parameters(self, ctor) + params, subtypes = extract_subtypes(doc.name, ctor) + + fields = nodes.field_list() + fields += self.make_super() + fields += self.make_mixins() + fields += self.make_params(params) + if fields.children: + ret += fields + + if doc.doc: + self.directive.state.nested_parse(to_list(doc.doc), 0, ret) + + ret += self.document_properties(all_members) + + ret += self.document_subtypes(subtypes) + + return ret.children + + def is_private(self, member, name): + return name.startswith('_') or super(ClassDocumenter, self).is_private(member, name) + + def make_super(self): + doc = self.item + if not doc.superclass: + return [] + + sup_link = addnodes.pending_xref( + doc.superclass.name, nodes.paragraph(doc.superclass.name, doc.superclass.name), + refdomain='js', reftype='class', reftarget=doc.superclass.name, + ) + sup_link['js:module'] = doc.superclass['sourcemodule'].name + return nodes.field( + '', + nodes.field_name("Extends", "Extends"), + nodes.field_body(doc.superclass.name, sup_link), + ) + + def make_mixins(self): + doc = self.item + if not doc.mixins: + return [] + + ret = nodes.field('', nodes.field_name("Mixes", "Mixes")) + with addto(ret, nodes.field_body()) as body: + with addto(body, nodes.bullet_list()) as mixins: + for mixin in sorted(doc.mixins, key=lambda m: m.name): + mixin_link = addnodes.pending_xref( + mixin.name, nodes.paragraph(mixin.name, mixin.name), + refdomain='js', reftype='mixin', reftarget=mixin.name + ) + mixin_link['js:module'] = mixin['sourcemodule'].name + mixins += nodes.list_item('', mixin_link) + return ret + + def make_params(self, params): + if not params: + return [] + + ret = nodes.field('', nodes.field_name('Parameters', 'Parameters')) + with addto(ret, nodes.field_body()) as body,\ + addto(body, nodes.bullet_list()) as holder: + holder += make_parameters(params, mod=self.modname) + return ret + +class InstanceDocumenter(Documenter): + objtype = 'object' + def make_signature(self): + cls = self.item.cls + ret = super(InstanceDocumenter, self).make_signature() + if cls: + super_ref = addnodes.pending_xref( + cls.name, nodes.Text(cls.name, cls.name), + refdomain='js', reftype='class', reftarget=cls.name + ) + super_ref['js:module'] = cls['sourcemodule'].name + ret.append(addnodes.desc_annotation(' instance of ', ' instance of ')) + ret.append(addnodes.desc_type(cls.name, '', super_ref)) + if not ret: + return [addnodes.desc_name('???', '???')] + return ret + + def make_content(self, all_members): + ret = nodes.section() + if self.item.doc: + self.directive.state.nested_parse(to_list(self.item.doc), 0, ret) + return ret.children + return ret.children + +class FunctionDocumenter(Documenter): + @property + def objtype(self): + return 'method' if self.classname else 'function' + def make_signature(self): + ret = super(FunctionDocumenter, self).make_signature() + with addto(ret, addnodes.desc_parameterlist()) as params: + params += make_desc_parameters(self.item.params) + retval = self.item.return_val + if retval.type or retval.doc: + ret.append(addnodes.desc_returns(retval.type or '*', retval.type or '*')) + return ret + + def make_content(self, all_members): + ret = nodes.section() + doc = self.item + if doc.doc: + self.directive.state.nested_parse(to_list(doc.doc), 0, ret) + + check_parameters(self, doc) + + params, subtypes = extract_subtypes(self.item.name, self.item) + rdoc = doc.return_val.doc + rtype = doc.return_val.type + if params or rtype or rdoc: + with addto(ret, nodes.field_list()) as fields: + if params: + with addto(fields, nodes.field()) as field: + field += nodes.field_name('Parameters', 'Parameters') + with addto(field, nodes.field_body()) as body,\ + addto(body, nodes.bullet_list()) as holder: + holder.extend(make_parameters(params, mod=doc['sourcemodule'].name)) + if rdoc: + with addto(fields, nodes.field()) as field: + field += nodes.field_name("Returns", "Returns") + with addto(field, nodes.field_body()) as body,\ + addto(body, nodes.paragraph()) as p: + p += nodes.inline(rdoc, rdoc) + if rtype: + with addto(fields, nodes.field()) as field: + field += nodes.field_name("Return Type", "Return Type") + with addto(field, nodes.field_body()) as body, \ + addto(body, nodes.paragraph()) as p: + p += make_types(rtype, mod=doc['sourcemodule'].name) + + ret += self.document_subtypes(subtypes) + + return ret.children + +def pascal_case_ify(name): + """ + Uppercase first letter of ``name``, or any letter following an ``_``. In + the latter case, also strips out the ``_``. + + => key_for becomes KeyFor + => options becomes Options + """ + return re.sub(r'(^|_)\w', lambda m: m.group(0)[-1].upper(), name) +def extract_subtypes(parent_name, doc): + """ Extracts composite parameters (a.b) into sub-types for the parent + parameter, swaps the parent's type from whatever it is to the extracted + one, and returns the extracted type for inclusion into the parent. + + :arg parent_name: name of the containing symbol (function, class), will + be used to compose subtype names + :type parent_name: str + :type doc: FunctionDoc + :rtype: (List[ParamDoc], List[ClassDoc]) + """ + # map of {param_name: [ParamDoc]} (from complete doc) + subparams = collections.defaultdict(list) + for p in map(jsdoc.ParamDoc, doc.get_as_list('param')): + pair = p.name.split('.', 1) + if len(pair) == 2: + k, p.name = pair # remove prefix from param name + subparams[k].append(p) + + # keep original params order as that's the order of formal parameters in + # the function signature + params = collections.OrderedDict((p.name, p) for p in doc.params) + subtypes = [] + # now we can use the subparams map to extract "compound" parameter types + # and swap the new type for the original param's type + for param_name, subs in subparams.items(): + typename = '%s%s' % ( + pascal_case_ify(parent_name), + pascal_case_ify(param_name), + ) + param = params[param_name] + param.type = typename + subtypes.append(jsdoc.ClassDoc({ + 'name': typename, + 'doc': param.doc, + '_members': [ + (sub.name, jsdoc.PropertyDoc(dict(sub.to_dict(), sourcemodule=doc['sourcemodule']))) + for sub in subs + ], + 'sourcemodule': doc['sourcemodule'], + })) + return params.values(), subtypes + +def check_parameters(documenter, doc): + """ + Check that all documented parameters match a formal parameter for the + function. Documented params which don't match the actual function may be + typos. + """ + guessed = set(doc['guessed_params'] or []) + if not guessed: + return + + documented = { + # param name can be of the form [foo.bar.baz=default]\ndescription + jsdoc.ParamDoc(text).name.split('.')[0] + for text in doc.get_as_list('param') + } + odd = documented - guessed + if not odd: + return + + app = documenter.directive.env.app + app.warn("Found documented params %s not in formal parameter list " + "of function %s in module %s (%s)" % ( + ', '.join(odd), + doc.name, + documenter.modname, + doc['sourcemodule']['sourcefile'], + )) + +def make_desc_parameters(params): + for p in params: + if '.' in p.name: + continue + + node = addnodes.desc_parameter(p.name, p.name) + if p.optional: + node = addnodes.desc_optional('', '', node) + yield node + +def make_parameters(params, mod=None): + for param in params: + p = nodes.paragraph('', '', nodes.strong(param.name, param.name)) + if param.default is not None: + p += nodes.Text('=', '=') + p += nodes.emphasis(param.default, param.default) + if param.type: + p += nodes.Text(' (') + p += make_types(param.type, mod=mod) + p += nodes.Text(')') + if param.doc: + p += [ + nodes.Text(' -- '), + nodes.inline(param.doc, param.doc) + ] + yield p + + +def _format_value(v): + if v == '|': + return nodes.emphasis(' or ', ' or ') + if v == ',': + return nodes.Text(', ', ', ') + return nodes.Text(v, v) +def make_types(typespec, mod=None): + # TODO: in closure notation {type=} => optional, do we care? + def format_type(t): + ref = addnodes.pending_xref( + t, addnodes.literal_emphasis(t, t), + refdomain='js', reftype='class', reftarget=t, + ) + if mod: + ref['js:module'] = mod + return ref + + try: + return types.iterate( + types.parse(typespec), + format_type, + _format_value + ) + except ValueError as e: + raise ValueError("%s in '%s'" % (e, typespec)) + + +class MixinDocumenter(NSDocumenter): + objtype = 'mixin' + +class PropertyDocumenter(Documenter): + objtype = 'attribute' + def make_signature(self): + ret = super(PropertyDocumenter, self).make_signature() + proptype = self.item.type + if proptype: + typeref = addnodes.pending_xref( + proptype, nodes.Text(proptype, proptype), + refdomain='js', reftype='class', reftarget=proptype + ) + typeref['js:module'] = self.item['sourcemodule'].name + ret.append(nodes.Text(' ')) + ret.append(typeref) + return ret + + def make_content(self, all_members): + doc = self.item + ret = nodes.section() + if doc.doc: + self.directive.state.nested_parse(to_list(doc.doc), 0, ret) + return ret.children + +class UnknownDocumenter(Documenter): + objtype = 'unknown' + def make_content(self, all_members): + return [] diff --git a/doc/_extensions/autojsdoc/ext/extractor.py b/doc/_extensions/autojsdoc/ext/extractor.py new file mode 100644 index 00000000000..36211cfd3b3 --- /dev/null +++ b/doc/_extensions/autojsdoc/ext/extractor.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +import io +import os + +import pyjsdoc +import pyjsparser + +try: + from sphinx.util import status_iterator + def it(app): return status_iterator +except ImportError: + # 1.2: Builder.status_iterator + # 1.3: Application.status_iterator (with alias on Builder) + # 1.6: sphinx.util.status_iterator (with *deprecated* aliases on Application and Builder) + # 1.7: removed Application and Builder aliases + # => if no sphinx.util.status_iterator, fallback onto the builder one for + # 1.2 compatibility, remove this entirely if we ever require 1.6+ + status_iterator = None + def it(app): return app.builder.status_iterator + +from ..parser import jsdoc, parser + + +def _get_roots(conf): + env_roots = os.environ.get('AUTOJSDOC_ROOTS_PATH') + if env_roots: + return env_roots.split(':') + return [] + +def read_js(app, modules): + """ + :type app: sphinx.application.Sphinx + :type modules: Dict[str, jsdoc.ModuleDoc] + """ + roots = map(os.path.normpath, app.config.js_roots or [os.path.join(app.confdir, '..')]) + files = [ + os.path.join(r, f) + for root in roots + for r, _, fs in os.walk(root) + if 'static/src/js' in r + for f in fs + if f.endswith('.js') + ] + + modules.update((mod.name, mod) for mod in ABSTRACT_MODULES) + for name in it(app)(files, "Parsing javascript files...", length=len(files)): + with io.open(name) as f: + ast = pyjsparser.parse(f.read()) + modules.update( + (mod.name, mod) + for mod in parser.ModuleMatcher(name).visit(ast) + ) + _resolve_references(modules) + +def _resolve_references(byname): + # must be done in topological order otherwise the dependent can't + # resolve non-trivial references to a dependency properly + for name in pyjsdoc.topological_sort( + *pyjsdoc.build_dependency_graph( + list(byname.keys()), + byname + ) + ): + byname[name].post_process(byname) + +ABSTRACT_MODULES = [ + jsdoc.ModuleDoc({ + 'module': u'web.web_client', + 'dependency': {u'web.AbstractWebClient'}, + 'exports': jsdoc.NSDoc({ + 'name': u'web_client', + 'doc': u'instance of AbstractWebClient', + }), + }), + jsdoc.ModuleDoc({ + 'module': u'web.Tour', + 'dependency': {u'web_tour.TourManager'}, + 'exports': jsdoc.NSDoc({ + 'name': u'Tour', + 'doc': u'maybe tourmanager instance?', + }), + }), + jsdoc.ModuleDoc({ + 'module': u'summernote/summernote', + 'exports': jsdoc.NSDoc({'doc': u"totally real summernote"}), + }) +] diff --git a/doc/_extensions/autojsdoc/parser/__init__.py b/doc/_extensions/autojsdoc/parser/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/doc/_extensions/autojsdoc/parser/jsdoc.py b/doc/_extensions/autojsdoc/parser/jsdoc.py new file mode 100644 index 00000000000..00406df42c1 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/jsdoc.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- +import re + +import collections + +import pyjsdoc + +def strip_stars(doc_comment): + """ + Version of jsdoc.strip_stars which always removes 1 space after * if + one is available. + """ + return re.sub('\n\s*?\*[\t ]?', '\n', doc_comment[3:-2]).strip() + +class ParamDoc(pyjsdoc.ParamDoc): + """ + Replace ParamDoc because FunctionDoc doesn't properly handle optional + params or default values (TODO: or compounds) if guessed_params is used + + => augment paramdoc with "required" and "default" items to clean up name + """ + def __init__(self, text): + super(ParamDoc, self).__init__(text) + # param name and doc can be separated by - or :, strip it + self.doc = self.doc.strip().lstrip('-:').lstrip() + self.optional = False + self.default = None + # there may not be a space between the param name and the :, in which + # case the : gets attached to the name, strip *again* + # TODO: formal @param/@property parser to handle this crap properly once and for all + self.name = self.name.strip().rstrip(':') + if self.name.startswith('['): + self.name = self.name.strip('[]') + self.optional = True + if '=' in self.name: + self.name, self.default = self.name.rsplit('=', 1) + def to_dict(self): + d = super(ParamDoc, self).to_dict() + d['optional'] = self.optional + d['default'] = self.default + return d +pyjsdoc.ParamDoc = ParamDoc + +class CommentDoc(pyjsdoc.CommentDoc): + namekey = object() + is_constructor = False + + @property + def name(self): + return self[self.namekey] or self['name'] or self['guessed_name'] + def set_name(self, name): + # not great... + if name != '': + self.parsed['guessed_name'] = name + + @property + def is_private(self): + return 'private' in self.parsed + + def to_dict(self): + d = super(CommentDoc, self).to_dict() + d['name'] = self.name + return d + +class PropertyDoc(CommentDoc): + @classmethod + def from_param(cls, s, sourcemodule=None): + parsed = ParamDoc(s).to_dict() + parsed['sourcemodule'] = sourcemodule + return cls(parsed) + + @property + def type(self): + return self['type'].strip('{}') + + def to_dict(self): + d = super(PropertyDoc, self).to_dict() + d['type'] = self.type + d['is_private'] = self.is_private + return d + +class InstanceDoc(CommentDoc): + @property + def cls(self): + return self['cls'] + + def to_dict(self): + return dict(super(InstanceDoc, self).to_dict(), cls=self.cls) + +class LiteralDoc(CommentDoc): + @property + def type(self): + if self['type']: + return self['type'] + valtype = type(self['value']) + if valtype is bool: + return 'Boolean' + elif valtype is float: + return 'Number' + elif valtype is type(u''): + return 'String' + return '' + + @property + def value(self): + return self['value'] + + def to_dict(self): + d = super(LiteralDoc, self).to_dict() + d['type'] = self.type + d['value'] = self.value + return d + +class FunctionDoc(CommentDoc): + type = 'Function' + namekey = 'function' + + @property + def is_constructor(self): + return self.name == 'init' + + @property + def params(self): + tag_texts = self.get_as_list('param') + if self.get('guessed_params') is None: + return [ParamDoc(text) for text in tag_texts] + else: + param_dict = {} + for text in tag_texts: + param = ParamDoc(text) + param_dict[param.name] = param + return [param_dict.get(name) or ParamDoc('{} ' + name) + for name in self.get('guessed_params')] + @property + def return_val(self): + ret = self.get('return') or self.get('returns') + type = self.get('type') + if '{' in ret and '}' in ret: + if not '} ' in ret: + # Ensure that name is empty + ret = re.sub(r'\}\s*', '} ', ret) + return ParamDoc(ret) + if ret and type: + return ParamDoc('{%s} %s' % (type, ret)) + return ParamDoc(ret) + + def to_dict(self): + d = super(FunctionDoc, self).to_dict() + d['name'] = self.name + d['params'] = [param.to_dict() for param in self.params] + d['return_val']= self.return_val.to_dict() + return d + +class NSDoc(CommentDoc): + namekey = 'namespace' + def __init__(self, parsed_comment): + super(NSDoc, self).__init__(parsed_comment) + self.members = collections.OrderedDict() + def add_member(self, name, member): + """ + :type name: str + :type member: CommentDoc + """ + member.set_name(name) + self.members[name] = member + + @property + def properties(self): + if self.get('property'): + return [ + (p.name, p) + for p in ( + PropertyDoc.from_param(p, self['sourcemodule']) + for p in self.get_as_list('property') + ) + ] + return self.members.items() or self['_members'] or [] + + def has_property(self, name): + return self.get_property(name) is not None + + def get_property(self, name): + return next((p for n, p in self.properties if n == name), None) + + def to_dict(self): + d = super(NSDoc, self).to_dict() + d['properties'] = [(n, p.to_dict()) for n, p in self.properties] + return d + +class MixinDoc(NSDoc): + namekey = 'mixin' + +class ModuleDoc(NSDoc): + namekey = 'module' + def __init__(self, parsed_comment): + super(ModuleDoc, self).__init__(parsed_comment) + #: callbacks to run with the modules mapping once every module is resolved + self._post_process = [] + + def post_process(self, modules): + for callback in self._post_process: + callback(modules) + + @property + def module(self): + return self # lol + + @property + def dependencies(self): + """ + Returns the immediate dependencies of a module (only those explicitly + declared/used). + """ + return self.get('dependency', None) or set() + + @property + def exports(self): + """ + Returns the actual item exported from the AMD module, can be a + namespace, a class, a function, an instance, ... + """ + return self.get_property('') + + def to_dict(self): + vars = super(ModuleDoc, self).to_dict() + vars['dependencies'] = self.dependencies + vars['exports'] = self.exports + return vars + +class ClassDoc(NSDoc): + namekey = 'class' + @property + def constructor(self): + return self.get_property('init') + + @property + def superclass(self): + return self['extends'] or self['base'] + + def get_property(self, method_name): + if method_name == 'extend': + return FunctionDoc({ + 'doc': 'Create subclass for %s' % self.name, + 'guessed_function': 'extend', + }) + # FIXME: should ideally be a proxy namespace + if method_name == 'prototype': + return self + return super(ClassDoc, self).get_property(method_name) + + @property + def mixins(self): + return self.get_as_list('mixes') + + def to_dict(self): + d = super(ClassDoc, self).to_dict() + d['mixins'] = self.mixins + return d + +class UnknownNS(NSDoc): + def get_property(self, name): + return super(UnknownNS, self).get_property(name) or \ + UnknownNS({'name': '{}.{}'.format(self.name, name)}) + +class Unknown(CommentDoc): + @classmethod + def from_(cls, source): + def builder(parsed): + inst = cls(parsed) + inst.parsed['source'] = source + return inst + return builder + + @property + def name(self): + return self['name'] + ' ' + self['source'] + + @property + def type(self): + return "Unknown" + + def get_property(self, p): + return Unknown(dict(self.parsed, source=self.name, name=p + '<')) + +def parse_comments(comments, doctype=None): + # find last comment which starts with a * + docstring = next(( + c['value'] + for c in reversed(comments or []) + if c['value'].startswith(u'*') + ), None) or u"" + + # \n prefix necessary otherwise parse_comment fails to take first + # block comment parser strips delimiters, but strip_stars fails without + # them + extract = '\n' + strip_stars('/*' + docstring + '\n*/') + parsed = pyjsdoc.parse_comment(extract, u'') + + if doctype == 'FunctionExpression': + doctype = FunctionDoc + elif doctype == 'ObjectExpression' or doctype is None: + doctype = guess + + if doctype is guess: + return doctype(parsed) + + # in case a specific doctype is given, allow overriding it anyway + return guess(parsed, default=doctype) + +def guess(parsed, default=NSDoc): + if 'class' in parsed: + return ClassDoc(parsed) + if 'function' in parsed: + return FunctionDoc(parsed) + if 'mixin' in parsed: + return MixinDoc(parsed) + if 'namespace' in parsed: + return NSDoc(parsed) + if 'module' in parsed: + return ModuleDoc(parsed) + if 'type' in parsed: + return PropertyDoc(parsed) + + return default(parsed) diff --git a/doc/_extensions/autojsdoc/parser/parser.py b/doc/_extensions/autojsdoc/parser/parser.py new file mode 100644 index 00000000000..d91b9f22596 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/parser.py @@ -0,0 +1,552 @@ +# -*- coding: utf-8 -*- +import collections + +import pyjsdoc +from attr import attrs, Factory, attr, astuple + +from . import jsdoc +from . import utils +from .visitor import Visitor, SKIP + +DECLARATOR_INIT_TO_REF = ('Literal', 'Identifier', 'MemberExpression') + + +class ModuleMatcher(Visitor): + """Looks for structures of the form:: + + odoo.define($string, function ($name) { + + These are *Odoo module definitions*, upon encountering one the + matcher: + + * creates a module entry, optionally associated with the module comment + * spawns off a :class:`ModuleBodyMatcher` on the function's body with the + module name and the $name as "require" function + """ + def __init__(self, filename): + super(ModuleMatcher, self).__init__() + self.filename = filename + self.result = [] + def enter_Program(self, node): + pass # allows visiting toplevel + def enter_ExpressionStatement(self, node): + # we're interested in expression statements (toplevel call) + if utils.match(node, {'expression': { + 'callee': { + 'object': {'name': 'odoo'}, + 'property': {'name': 'define'}, + }, + }}): + [module, func] = node['expression']['arguments'] + mod = jsdoc.parse_comments(node.get('comments'), jsdoc.ModuleDoc) + # set module name + mod.set_name(module['value']) + mod.parsed['sourcefile'] = self.filename + self.result.append(mod) + + # get name of require parameter + require = None # a module can have no dependencies + if func['params']: + require = func['params'][0]['name'] + mod.parsed['dependency'], post = ModuleExtractor(mod, require).visit(func['body']) + mod._post_process.extend(post) + # don't recurse since we've fired off a sub-visitor for the + # bits we're interested in + return SKIP + def enter_generic(self, node): + # skip all other toplevel statements + return SKIP + +ref = collections.namedtuple('Ref', 'object property') +def _name(r): + bits = [] + while isinstance(r, ref): + bits.append(r.property) + r = r.object + return '.'.join(reversed(bits)) +def deref(item, prop=None): + assert isinstance(item, ref) + + while isinstance(item, ref): + obj = item.object + if isinstance(obj, ref): + obj = deref(obj) + + if isinstance(obj, (jsdoc.NSDoc, jsdoc.Unknown)): + item = obj.get_property(item.property) + elif isinstance(obj, dict): + item = obj[item.property] + elif isinstance(obj, jsdoc.PropertyDoc): + # f'n dynamic crap + item = jsdoc.Unknown(obj.to_dict()).get_property(item.property) + else: + raise ValueError("%r (%s) should be a dict or namespace" % (obj, type(obj))) + return item + +def m2r(me, scope): + # create a ref to the scope in case it's a hoisted function declaration, + # this may false-positive on other hoisting but w/e + if me['type'] == 'Literal': + return jsdoc.LiteralDoc({'value': me['value']}) + if me['type'] == 'Identifier': + return ref(scope, me['name']) + if me['type'] != 'MemberExpression': + raise ValueError(me) + return ref( + m2r(me['object'], scope), + utils._value(me['property'], strict=True) + ) + +@attrs(slots=True) +class Declaration(object): + id = attr(default=None) + comments = attr(default=Factory(list)) +@attrs(slots=True) +class ModuleContent(object): + dependencies = attr(default=Factory(set)) + post = attr(default=Factory(list)) + def __iter__(self): + yield self.dependencies + yield self.post + +@attrs # needs dict as it's replacing a ModuleProxy +class Nothing(object): + name = attr() + def __bool__(self): + return False + __nonzero__ = __bool__ + +class RefProxy(object): + def __init__(self, r): + self._ref = r + def become(self, modules): + s = self + other = deref(self._ref) or Nothing(_name(self._ref)) + # ??? shouldn't all previous refs have been resolved? + if isinstance(other, (RefProxy, ModuleProxy)): + other = other.become(modules) + self.__class__ = other.__class__ + self.__dict__ = other.__dict__ + return self + def set_name(self, name): + pass # ??? +class ModuleProxy(object): + def __init__(self, name): + self._name = name + + # replace the ModuleProxy by the module's exports + def become(self, modules): + s = self + m = modules[self._name].get_property('') or Nothing(self._name) + self.__class__ = m.__class__ + self.__dict__ = m.__dict__ + return self + + def set_name(self, name): + pass # FIXME: ??? + +jq = jsdoc.UnknownNS({ + 'name': u'jQuery', + 'doc': u'', +}) +window = jsdoc.UnknownNS({ + 'doc': '', + 'name': 'window', +}) +BASE_SCOPE = { + '_': jsdoc.UnknownNS({'doc': u'', 'name': u'_'}), + '$': jq, 'jQuery': jq, + 'nv': jsdoc.UnknownNS({ + 'doc': u'', + 'name': u'nv', + }), + 'window': window, + 'document': window.get_property('document'), + 'Date': jsdoc.ClassDoc({ + 'name': u'Date', + 'doc': u'', + }), + 'Backbone': jsdoc.UnknownNS({ + '_members': [ + ('Model', jsdoc.ClassDoc({ + 'name': u'Model', + 'doc': u'', + })), + ('Collection', jsdoc.ClassDoc({ + 'name': u'Collection', + 'doc': u'', + })), + ] + }), + 'odoo': jsdoc.UnknownNS({ + 'name': u'odoo', + 'doc': u"Odoo", + '_members': [ + ('name', jsdoc.PropertyDoc({'name': u'csrf_token', 'type': u'{String}'})), + ] + }), + 'undefined': jsdoc.LiteralDoc({'name': u'undefined', 'value': None}) +} + +class Scope(object): + """ + Add hoc scope versioning/SSA such that rebinding a symbol in a module + scope does not screw everything up e.g. "Foo = Foo.extend({})" should not + have the final Foo extending itself... + """ + def __init__(self, mapping): + self._namemap = {} + self._targets = [] + for k, v in mapping.items(): + self[k] = v + + def __setitem__(self, k, v): + self._namemap[k] = len(self._targets) + self._targets.append(v) + + def freeze(self): + return { + k: self._targets[v] + for k, v in self._namemap.items() + } + +class ModuleExtractor(Visitor): + def __init__(self, module, requirefunc): + super(ModuleExtractor, self).__init__() + self.module = module + self.requirefunc = requirefunc + self.result = ModuleContent() + self.scope = Scope(BASE_SCOPE) + self.declaration = None + + def enter_BlockStatement(self, node): + Hoistifier(self).visit(node) + def exit_BlockStatement(self, node): + for k, v in self.scope._namemap.items(): + if k not in BASE_SCOPE: + self.module.add_member(k, self.scope._targets[v]) + for t in TypedefMatcher(self).visit(node): + self.module.add_member(t.name, t) + + def enter_VariableDeclaration(self, node): + self.declaration = Declaration(comments=node.get('comments')) + def enter_VariableDeclarator(self, node): + # otherwise we've already hoisted the declaration so the variable + # already exist initialised to undefined, and ValueExtractor does not + # handle a None input node so it returns None which makes no sense + if node['init']: + self.declaration.id = node['id']['name'] + self.scope[self.declaration.id] = ValueExtractor( + self, self.declaration + ).visit(node['init'] or []) + self.declaration.id = None + return SKIP + def exit_VariableDeclaration(self, node): + self.declaration = None + + # as the name denotes, AssignmentExpression is an *expression*, which + # means at the module toplevel it is wrapped into an ExpressionStatement + # which is where the comments get attached + def enter_ExpressionStatement(self, node): + self.declaration = Declaration(comments=node.get('comments')) + def exit_ExpressionStatement(self, node): + self.declaration = None + def enter_AssignmentExpression(self, node): + target = node['left'] + if target['type'] == 'Identifier': + self.declaration.id = target['name'] + self.scope[self.declaration.id] = ValueExtractor( + self, self.declaration + ).visit(node['right']) + self.declaration.id = None + return SKIP + + if target['type'] != 'MemberExpression': + raise ValueError("Unhandled assign to %s" % target['type']) + + # only assign to straight a.b.c patterns (OK and trivial literals) + if target['computed'] and target['property']['type'] != 'Literal': + return SKIP + + name = utils._value(target['property'], strict=True) + if isinstance(name, type(u'')) and name.endswith('.extend'): + return SKIP # ignore overwrite of .extend (WTF) + self.declaration.id = name + it = ValueExtractor( + self, self.declaration + ).visit(node['right']) + self.declaration.id = None + assert it, "assigned a non-value from %s to %s" % (node['right'], name) + + @self.result.post.append + def _augment_module(modules): + try: + t = deref(m2r(target['object'], self.scope.freeze())) + except ValueError: + return # f'n extension of global libraries garbage + if not isinstance(t, jsdoc.NSDoc): + # function Foo(){}; Foo.prototype = bar + # fuck that yo + return + # TODO: note which module added this + m = it + if isinstance(m, jsdoc.LiteralDoc): + m = jsdoc.PropertyDoc(m.to_dict()) + t.add_member(name, m) + return SKIP + + def enter_FunctionDeclaration(self, node): + """ Already processed by hoistitifier + """ + return SKIP + + def enter_ReturnStatement(self, node): + self.declaration = Declaration(comments=node.get('comments')) + if node['argument']: + export = ValueExtractor(self, self.declaration).visit(node['argument']) + if isinstance(export, RefProxy): + self.module.parsed['exports'] = _name(export._ref) + self.scope[''] = export + self.declaration = None + return SKIP + + def enter_CallExpression(self, node): + if utils.match(node, { + 'callee': { + 'type': 'MemberExpression', + 'object': lambda n: ( + n['type'] in ('Identifier', 'MemberExpression') + # _.str.include + and not utils._name(n).startswith('_') + ), + 'property': {'name': 'include'}, + } + }): + target = RefProxy(m2r(node['callee']['object'], self.scope.freeze())) + target_name = utils._name(node['callee']['object']) + items = ClassProcessor(self).visit(node['arguments']) + @self.result.post.append + def resolve_extension(modules): + t = target.become(modules) + if not isinstance(t, jsdoc.ClassDoc): + raise ValueError("include() subjects should be classes, %s is %s" % (target_name, type(t))) + # TODO: note which module added these + for it in items: + if isinstance(it, dict): + for n, member in it.items(): + t.add_member(n, member) + else: + t.parsed.setdefault('mixes', []).append(it.become(modules)) + + return SKIP + + def refify(self, node, also=None): + it = m2r(node, self.scope.freeze()) + assert isinstance(it, ref), "Expected ref, got {}".format(it) + px = RefProxy(it) + @self.result.post.append + def resolve(modules): + p = px.become(modules) + if also: also(p) + return px + +class ValueExtractor(Visitor): + def __init__(self, parent, declaration=None): + super(ValueExtractor, self).__init__() + self.parent = parent + self.declaration = declaration or Declaration() + + def enter_generic(self, node): + self.result = jsdoc.parse_comments( + self.declaration.comments, + jsdoc.Unknown.from_(node['type']) + ) + self._update_result_meta() + return SKIP + + def _update_result_meta(self, name=None): + self.result.parsed['sourcemodule'] = self.parent.module + n = name or self.declaration.id + if n: + self.result.set_name(n) + + def enter_Literal(self, node): + self.result = jsdoc.parse_comments( + self.declaration.comments, jsdoc.LiteralDoc) + self._update_result_meta() + self.result.parsed['value'] = node['value'] + return SKIP + def enter_Identifier(self, node): + self.result = self.parent.refify(node) + return SKIP + + def enter_MemberExpression(self, node): + self.result = RefProxy(ref( + ValueExtractor(self.parent).visit(node['object']), + utils._value(node['property'], strict=True) + )) + self.parent.result.post.append(self.result.become) + return SKIP + + def enter_FunctionExpression(self, node): + name, comments = astuple(self.declaration) + self.result = jsdoc.parse_comments(comments, jsdoc.FunctionDoc) + self.result.parsed['name'] = node['id'] and node['id']['name'] + self._update_result_meta() + self.result.parsed['guessed_params'] = [p['name'] for p in node['params']] + return SKIP + + def enter_NewExpression(self, node): + comments = self.declaration.comments if self.declaration else node.get('comments') + self.result = ns = jsdoc.parse_comments(comments, jsdoc.InstanceDoc) + self._update_result_meta() + + def _update_contents(cls): + if not isinstance(cls, jsdoc.ClassDoc): + return + ns.parsed['cls'] = cls + self.parent.refify(node['callee'], also=_update_contents) + return SKIP + + def enter_ObjectExpression(self, node): + self.result = obj = jsdoc.parse_comments(self.declaration.comments) + self._update_result_meta() + for n, p in MemberExtractor(parent=self.parent).visit(node['properties']).items(): + obj.add_member(n, p) + return SKIP + + def enter_CallExpression(self, node): + # require(a_module_name) + if utils.match(node, {'callee': {'type': 'Identifier', 'name': self.parent.requirefunc}}): + depname = node['arguments'][0]['value'] + # TODO: clean this up + self.parent.result.dependencies.add(depname) + self.result = ModuleProxy(name=depname) + self.parent.result.post.append(self.result.become) + + # Class.extend(..mixins, {}) + elif utils.match(node, { + 'callee': { + 'type': 'MemberExpression', + 'object': lambda n: ( + n['type'] in ('Identifier', 'MemberExpression') + # $.extend, $.fn.extend, _.extend + and not utils._name(n).startswith(('_', '$')) + ), + 'property': {'name': 'extend'}, + }, + }): # creates a new class, but may not actually return it + obj = node['callee']['object'] + _, comments = astuple(self.declaration) + self.result = cls = jsdoc.parse_comments(comments, jsdoc.ClassDoc) + cls.parsed['extends'] = self.parent.refify(obj) + self._update_result_meta() + items = ClassProcessor(self.parent).visit(node['arguments']) + + @self.parent.result.post.append + def add_to_class(modules): + for item in items: + if isinstance(item, dict): + # methods/attributes + for n, method in item.items(): + cls.add_member(n, method) + else: + cls.parsed.setdefault('mixes', []).append(item) + + # other function calls + else: + self.result = jsdoc.parse_comments(self.declaration.comments, jsdoc.guess) + self._update_result_meta() + + return SKIP + +class ClassProcessor(Visitor): + def __init__(self, parent): + super(ClassProcessor, self).__init__() + self.result = [] + self.parent = parent + + def enter_generic(self, node): + self.result.append(self.parent.refify(node)) + return SKIP + def enter_ObjectExpression(self, node): + self.result.append(MemberExtractor(parent=self.parent, for_class=True).visit(node['properties'])) + return SKIP + +String = type(u'') +class MemberExtractor(Visitor): + def __init__(self, parent, for_class=False): + super(MemberExtractor, self).__init__() + self.result = collections.OrderedDict() + self.parent = parent + self.for_class = for_class + + def enter_Property(self, node): + name = utils._value(node['key']) + prop = ValueExtractor( + self.parent, + Declaration(id=name, comments=node.get('comments')) + ).visit(node['value']) + + if isinstance(prop, jsdoc.LiteralDoc): + prop = jsdoc.PropertyDoc(prop.to_dict()) + + # ValueExtractor can return a Ref, maybe this should be sent as part + # of the decl/comments? + if name.startswith('_') and hasattr(prop, 'parsed'): + prop.parsed['private'] = True + self.result[name] = prop + + return SKIP + +class Hoistifier(Visitor): + """ + Processor for variable and function declarations properly hoisting them + to the "top" of a module such that they are available with the relevant + value afterwards. + """ + def __init__(self, parent): + super(Hoistifier, self).__init__() + self.parent = parent + + def enter_generic(self, node): + return SKIP + + # nodes to straight recurse into, others are just skipped + enter_BlockStatement = enter_VariableDeclaration = lambda self, node: None + + def enter_VariableDeclarator(self, node): + self.parent.scope[node['id']['name']] = BASE_SCOPE['undefined'] + + def enter_FunctionDeclaration(self, node): + funcname = node['id']['name'] + self.parent.scope[funcname] = fn = jsdoc.parse_comments( + node.get('comments'), + jsdoc.FunctionDoc, + ) + fn.parsed['sourcemodule'] = self.parent.module + fn.parsed['name'] = funcname + fn.parsed['guessed_params'] = [p['name'] for p in node['params']] + return SKIP + +class TypedefMatcher(Visitor): + def __init__(self, parent): + super(TypedefMatcher, self).__init__() + self.parent = parent + self.result = [] + + enter_BlockStatement = lambda self, node: None + def enter_generic(self, node): + # just traverse all top-level statements, check their comments, and + # bail + for comment in node.get('comments') or []: + if '@typedef' in comment['value']: + extract = '\n' + jsdoc.strip_stars('/*' + comment['value'] + '\n*/') + parsed = pyjsdoc.parse_comment(extract, u'') + p = jsdoc.ParamDoc(parsed['typedef']) + parsed['name'] = p.name + parsed['sourcemodule'] = self.parent.module + # TODO: add p.type as superclass somehow? Builtin types not in scope :( + self.result.append(jsdoc.ClassDoc(parsed)) + + return SKIP diff --git a/doc/_extensions/autojsdoc/parser/tests/README.rst b/doc/_extensions/autojsdoc/parser/tests/README.rst new file mode 100644 index 00000000000..dd862beae66 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/README.rst @@ -0,0 +1,6 @@ +:orphan: + +These files should be run via pytest_, simply install pytest and from the top +of the Odoo project run ``pytest doc/_extensions``. + +.. _pytest: https://pytest.org/ diff --git a/doc/_extensions/autojsdoc/parser/tests/support.py b/doc/_extensions/autojsdoc/parser/tests/support.py new file mode 100644 index 00000000000..f533f98d90c --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/support.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +import operator + +import pyjsparser + +from autojsdoc.parser import jsdoc, parser + +params = operator.attrgetter('name', 'type', 'doc') + + +def parse(s, source=None): + tree = pyjsparser.parse(s) + mods = parser.ModuleMatcher(source).visit(tree) + post(mods) + return mods + +def post(mods): + modules = dict(BASE_MODULES) + modules.update((m.name, m) for m in mods) + + for mod in mods: + mod.post_process(modules) + +BASE_MODULES = { + 'other': jsdoc.ModuleDoc({ + 'module': 'other', + '_members': [ + ('', jsdoc.LiteralDoc({'name': 'value', 'value': "ok"})), + ], + }), + 'dep2': jsdoc.ModuleDoc({ + 'module': 'dep2', + '_members': [ + ('', jsdoc.LiteralDoc({'value': 42.})), + ], + }), + 'dep3': jsdoc.ModuleDoc({ + 'module': 'dep3', + '_members': [ + ('', jsdoc.LiteralDoc({'value': 56.})), + ], + }), + 'Class': jsdoc.ModuleDoc({ + 'module': 'Class', + '_members': [ + ('', jsdoc.ClassDoc({ + 'name': 'Class', + 'doc': "Base Class" + })), + ], + }), + 'mixins': jsdoc.ModuleDoc({ + 'module': 'mixins', + '_members': [ + ('', jsdoc.NSDoc({ + 'name': 'mixins', + '_members': [ + ('Bob', jsdoc.ClassDoc({'class': "Bob"})), + ] + })), + ], + }), + 'Mixin': jsdoc.ModuleDoc({ + 'module': 'Mixin', + '_members': [ + ('', jsdoc.MixinDoc({ + '_members': [ + ('a', jsdoc.FunctionDoc({'function': 'a'})), + ] + })), + ], + }) +} diff --git a/doc/_extensions/autojsdoc/parser/tests/test_class.py b/doc/_extensions/autojsdoc/parser/tests/test_class.py new file mode 100644 index 00000000000..403ae9b48b7 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_class.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +import pytest + +from autojsdoc.parser import jsdoc +from support import params, parse + +def test_classvar(): + [mod] = parse(""" + odoo.define('a.A', function(require) { + var Class = require('Class'); + /** + * This is my class-kai + */ + var A = Class.extend({}); + return A; + }); + """) + cls = mod.exports + assert type(cls) == jsdoc.ClassDoc + + assert type(cls.superclass) == jsdoc.ClassDoc + assert cls.superclass.name == 'Class' + + assert cls.name == 'A' + assert cls.constructor is None + assert cls.properties == [] + assert cls['doc'] == 'This is my class-kai' + +def test_classret(): + [mod] = parse(""" + odoo.define('a.A', function(require) { + var Class = require('Class'); + /** + * This is my class-kai + */ + return Class.extend({}); + }); + """) + cls = mod.exports + assert type(cls) == jsdoc.ClassDoc + + assert cls.name == '' + assert cls.constructor is None + assert cls.properties == [] + assert cls['doc'] == 'This is my class-kai' + +def test_methods(): + [mod] = parse(""" + odoo.define('a.A', function(require) { + var Class = require('Class'); + return Class.extend({ + /** + * @param {Widget} parent + */ + init: function (parent) {}, + /** + * @returns {Widget} + */ + itself: function () { return this; }, + /** + * @param {MouseEvent} e + */ + _onValidate: function (e) {}, + }); + }); + """) + cls = mod.exports + assert len(cls.properties) == 3 + assert cls.constructor + # assume methods are in source order + [_, init] = cls.properties[0] + assert init == cls.constructor + assert init.name == 'init' + assert not init.is_private + assert init.is_constructor + [param] = init.params + assert params(param) == ('parent', 'Widget', '') + + [_, itself] = cls.properties[1] + assert itself.name == 'itself' + assert not itself.is_private + assert not itself.is_constructor + assert not itself.params + assert params(itself.return_val) == ('', 'Widget', '') + + [_, _on] = cls.properties[2] + assert _on.name == '_onValidate' + assert _on.is_private + assert not _on.is_constructor + [param] = _on.params + assert params(param) == ('e', 'MouseEvent', '') + +def test_mixin_explicit(): + [mod] = parse(""" + odoo.define('a.A', function (require) { + var Class = require('Class'); + var mixins = require('mixins'); + /** + * This is my class-kai + * @mixes mixins.Bob + */ + return Class.extend({}); + }); + """) + cls = mod.exports + # FIXME: ClassDoc may want to m2r(mixin, scope)? + assert cls.mixins == ['mixins.Bob'] + +def test_mixin_implicit(): + [mod] = parse(""" + odoo.define('a.A', function(require) { + var Class = require('Class'); + var Mixin = require('Mixin'); + /** + * This is my class-kai + */ + return Class.extend(Mixin, { foo: function() {} }); + }); + """) + cls = mod.exports + [mixin] = cls.mixins + assert type(mixin) == jsdoc.MixinDoc + assert params(mixin.properties[0][1]) == ('a', 'Function', '') + assert params(mixin.get_property('a')) == ('a', 'Function', '') + + assert params(cls.get_property('foo')) == ('foo', 'Function', '') + +def test_instanciation(): + [A, a] = parse(""" + odoo.define('A', function (r) { + var Class = r('Class'); + /** + * @class A + */ + return Class.extend({ + foo: function () {} + }); + }); + odoo.define('a', function (r) { + var A = r('A'); + var a = new A; + return a; + }); + """) + assert type(a.exports) == jsdoc.InstanceDoc + assert a.exports.cls.name == A.exports.name + +def test_non_function_properties(): + [A] = parse(""" + odoo.define('A', function (r) { + var Class = r('Class'); + return Class.extend({ + template: 'thing', + a_prop: [1, 2, 3], + 'other': {a: 7} + }); + }); + """) + t = A.exports.get_property('template') + assert type(t) == jsdoc.PropertyDoc + assert params(t) == ('template', 'String', '') + assert not t.is_private + +def test_non_extend_classes(): + [mod] = parse(""" + odoo.define('A', function () { + /** + * @class + */ + var Class = function () {} + return Class; + }); + """) + assert type(mod.exports) == jsdoc.ClassDoc + +def test_extend(): + [a, _] = parse(""" + odoo.define('A', function (require) { + var Class = require('Class'); + return Class.extend({}); + }); + odoo.define('B', function (require) { + var A = require('A'); + A.include({ + /** A property */ + a: 3, + /** A method */ + b: function () {} + }); + }); + """) + cls = a.exports + assert type(cls) == jsdoc.ClassDoc + a = cls.get_property('a') + assert type(a) == jsdoc.PropertyDoc + assert params(a) == ('a', 'Number', 'A property') + b = cls.get_property('b') + assert type(b) == jsdoc.FunctionDoc + assert params(b) == ('b', 'Function', 'A method') + +# TODO: also support virtual members? +# TODO: computed properties? +@pytest.mark.skip(reason="Need to implement member/var-parsing?") +def test_members(): + [mod] = parse(""" + odoo.define('A', function (r) { + var Class = r('Class'); + return Class.extend({ + init: function () { + /** + * This is bob + * @var {Foo} + */ + this.foo = 3; + this.bar = 42; + /** + * @member {Baz} + */ + this.baz = null; + } + }); + }); + """) + cls = mod.exports + assert params(cls.members[0]) == ('foo', 'Foo', 'This is bob') + assert params(cls.members[1]) == ('bar', '', '') + assert params(cls.members[2]) == ('baz', 'Baz', '') diff --git a/doc/_extensions/autojsdoc/parser/tests/test_crap.py b/doc/_extensions/autojsdoc/parser/tests/test_crap.py new file mode 100644 index 00000000000..70063e6dd47 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_crap.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +""" +Test various crap patterns found in Odoo code to ensure they don't blow up +the parser thingie +""" +from autojsdoc.parser import jsdoc +from support import parse + +def test_export_external(): + [mod] = parse(""" + odoo.define('module', function () { + return $.Deferred().reject(); + }); + """) + assert isinstance(mod.exports, jsdoc.CommentDoc) + assert mod.exports.doc == '' + +def test_extend_jq(): + parse(""" + odoo.define('a', function (r) { + $.extend($.expr[':'], { a: function () {} }); + $.fn.extend({ a: function () {} }); + }); + """) + +def test_extend_dynamic(): + parse(""" + odoo.define('a', function () { + foo.bar.baz[qux + '_external'] = function () {}; + }); + """) + +def test_extend_deep(): + parse(""" + odoo.define('a', function () { + var eventHandler = $.summernote.eventHandler; + var dom = $.summernote.core.dom; + dom.thing = function () {}; + + var fn_editor_currentstyle = eventHandler.modules.editor.currentStyle; + eventHandler.modules.editor.currentStyle = function () {} + }); + """) + +def test_arbitrary(): + parse(""" + odoo.define('bob', function () { + var page = window.location.href.replace(/^.*\/\/[^\/]+/, ''); + var mailWidgets = ['mail_followers', 'mail_thread', 'mail_activity', 'kanban_activity']; + var bob; + var fldj = foo.getTemplate().baz; + }); + """) + +def test_prototype(): + [A, B] = parse(""" + odoo.define('mod1', function () { + var exports = {}; + exports.Foo = Backbone.Model.extend({}); + exports.Bar = Backbone.Model.extend({}); + var BarCollection = Backbone.Collection.extend({ + model: exports.Bar, + }); + exports.Baz = Backbone.Model.extend({}); + return exports; + }); + odoo.define('mod2', function (require) { + var models = require('mod1'); + var _super_orderline = models.Bar.prototype; + models.Foo = models.Bar.extend({}); + var _super_order = models.Baz.prototype; + models.Bar = models.Baz.extend({}); + }); + """) + diff --git a/doc/_extensions/autojsdoc/parser/tests/test_module.py b/doc/_extensions/autojsdoc/parser/tests/test_module.py new file mode 100644 index 00000000000..2a63cc1754c --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_module.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- + +from autojsdoc.parser import jsdoc +from support import params, parse, BASE_MODULES + + +def test_single(): + [mod] = parse(""" + /** + * This is a super module! + */ + odoo.define('supermodule', function (req) { + var other = req('other'); + }); + """) + assert mod.name == 'supermodule' + assert mod.dependencies == {'other'} + assert mod.exports is None + assert mod.doc == "This is a super module!" + m = mod.get_property('other') + assert m.name == 'value', "property is exported value not imported module" + +def test_multiple(): + [mod1, mod2, mod3] = parse(""" + odoo.define('module1', function (req) { + return 1; + }); + odoo.define('module2', function (req) { + return req('dep2'); + }); + odoo.define('module3', function (req) { + var r = req('dep3'); + return r; + }); + """) + assert mod1.name == 'module1' + assert mod1.dependencies == set() + assert isinstance(mod1.exports, jsdoc.LiteralDoc) + assert mod1.exports.value == 1.0 + assert mod1.exports['sourcemodule'] is mod1 + assert mod1.doc == "" + + assert mod2.name == 'module2' + assert mod2.dependencies == {'dep2'} + assert isinstance(mod2.exports, jsdoc.LiteralDoc) + assert mod2.exports.value == 42.0 + assert mod2.doc == "" + + assert mod3.name == 'module3' + assert mod3.dependencies == {'dep3'} + assert isinstance(mod3.exports, jsdoc.LiteralDoc) + assert mod3.exports.value == 56.0 + assert mod3.doc == '' + +def test_func(): + [mod] = parse(""" + odoo.define('module', function (d) { + /** + * @param {Foo} bar this is a bar + * @param {Baz} qux this is a qux + */ + return function (bar, qux) { + return 42; + } + }); + """) + exports = mod.exports + assert type(exports) == jsdoc.FunctionDoc + assert exports['sourcemodule'] is mod + + assert exports.name == '' + assert exports.is_constructor == False + assert exports.is_private == False + + assert params(exports.params[0]) == ('bar', 'Foo', 'this is a bar') + assert params(exports.params[1]) == ('qux', 'Baz', 'this is a qux') + assert params(exports.return_val) == ('', '', '') + +def test_hoist(): + [mod] = parse(""" + odoo.define('module', function() { + return foo; + /** + * @param a_thing + */ + function foo(a_thing) { + return 42; + } + }); + """) + actual = mod.exports + assert type(actual) == jsdoc.FunctionDoc + [param] = actual.params + assert params(param) == ('a_thing', '', '') + +def test_export_instance(): + [mod] = parse(""" + odoo.define('module', function (require) { + var Class = require('Class'); + /** + * Provides an instance of Class + */ + return new Class(); + }); + """) + assert type(mod.exports) == jsdoc.InstanceDoc + assert mod.exports.doc == 'Provides an instance of Class' + assert mod.exports['sourcemodule'] is mod + +def test_bounce(): + [m2, m1] = parse(""" + odoo.define('m2', function (require) { + var Item = require('m1'); + return { + Item: Item + }; + }); + odoo.define('m1', function (require) { + var Class = require('Class'); + var Item = Class.extend({}); + return Item; + }); + """) + assert type(m2.exports) == jsdoc.NSDoc + it = m2.exports.get_property('Item') + assert type(it) == jsdoc.ClassDoc + assert it['sourcemodule'] is m1 + assert sorted([n for n, _ in m1.properties]) == ['', 'Class', 'Item'] + +def test_reassign(): + [m] = parse(""" + odoo.define('m', function (require) { + var Class = require('Class'); + /** local class */ + var Class = Class.extend({}); + return Class + }); + """) + assert m.exports.doc == 'local class' + # can't use equality or identity so use class comment... + assert m.exports.superclass.doc == 'Base Class' + +def test_attr(): + [m1, m2] = parse(""" + odoo.define('m1', function (require) { + var Class = require('Class'); + var Item = Class.extend({}); + return {Item: Item}; + }); + odoo.define('m2', function (require) { + var Item = require('m1').Item; + Item.include({}); + return Item.extend({}); + }); + """) + assert type(m2.exports) == jsdoc.ClassDoc + # that these two are resolved separately may be an issue at one point (?) + assert m2.exports.superclass.to_dict() == m1.exports.get_property('Item').to_dict() + +def test_nothing_implicit(): + [m] = parse(""" + odoo.define('m', function () { + }); + """) + assert m.exports is None + +def test_nothing_explicit(): + [m] = parse(""" + odoo.define('m', function () { + return; + }); + """) + assert m.exports is None diff --git a/doc/_extensions/autojsdoc/parser/tests/test_namespace.py b/doc/_extensions/autojsdoc/parser/tests/test_namespace.py new file mode 100644 index 00000000000..54cbcf8cbb4 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_namespace.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +from autojsdoc.parser import jsdoc +from support import parse, params + + +def test_empty(): + [mod] = parse(""" + odoo.define('a.ns', function (r) { + return {}; + }); + """) + assert type(mod.exports) == jsdoc.NSDoc + assert mod.exports.properties == [] + +def test_inline(): + [mod] = parse(""" + odoo.define('a.ns', function (r) { + return { + /** + * a thing + * @type {Boolean} + */ + a: true + } + }); + """) + assert isinstance(mod.exports, jsdoc.NSDoc) + [(n, p)] = mod.exports.properties + assert n == 'a' + assert params(p) == ('a', 'Boolean', 'a thing') + +def test_header(): + [mod] = parse(""" + odoo.define('a.ns', function (r) { + /** + * @property {Boolean} a a thing + */ + return { a: true } + }); + """) + assert isinstance(mod.exports, jsdoc.NSDoc) + [(_, p)] = mod.exports.properties + assert params(p) == ('a', 'Boolean', 'a thing') + +def test_header_conflict(): + """ should the header or the inline comment take precedence? """ + [mod] = parse(""" + odoo.define('a.ns', function (r) { + /** + * @property {Boolean} a a thing + */ + return { + /** @type {String} */ + a: true + } + }); + """) + assert isinstance(mod.exports, jsdoc.NSDoc) + [(_, p)] = mod.exports.properties + assert params(p) == ('a', 'Boolean', 'a thing') + +def test_mixin(): + [mod] = parse(""" + odoo.define('a.mixin', function (r) { + /** + * @mixin + */ + return { + /** + * @returns {Number} a number + */ + do_thing: function other() { return 42; } + } + }); + """) + assert isinstance(mod.exports, jsdoc.MixinDoc) + [(n, p)] = mod.exports.properties + assert n == 'do_thing' + assert params(p) == ('other', 'Function', '') + assert params(p.return_val) == ('', 'Number', 'a number') + +def test_literal(): + [mod] = parse(""" + odoo.define('a.ns', function (r) { + /** whop whop */ + return { + 'a': 1, + /** wheee */ + 'b': 2, + }; + }); + """) + assert mod.exports.doc == 'whop whop' + [(_1, a), (_2, b)] = mod.exports.properties + assert params(a) == ('a', 'Number', '') + assert params(b) == ('b', 'Number', 'wheee') + +def test_fill_ns(): + [mod] = parse(""" + odoo.define('a.ns', function (r) { + var Class = r('Class'); + var ns = {}; + /** ok */ + ns.a = 1; + /** @type {String} */ + ns['b'] = 2; + /** Ike */ + ns.c = Class.extend({}); + ns.d = function () {} + return ns; + }); + """) + ns = mod.exports + assert type(ns) == jsdoc.NSDoc + [(_a, a), (_b, b), (_c, c), (_d, d)] = ns.properties + assert params(a) == ('a', 'Number', 'ok') + assert params(b) == ('b', 'String', '') + assert type(c) == jsdoc.ClassDoc + assert type(d) == jsdoc.FunctionDoc + +def test_extend_other(): + [o, b] = parse(""" + odoo.define('a.ns', function () { + /** @name outer */ + return { + /** @name inner */ + a: {} + }; + }); + odoo.define('b', function (r) { + var o = r('a.ns'); + var Class = r('Class'); + /** Class 1 */ + o.a.b = Class.extend({m_b: 1}); + /** Class 2 */ + o.a['c'] = Class.extend({m_c: 1}); + }); + """) + [(_, m)] = o.exports.properties + assert type(m) == jsdoc.NSDoc + + b = m.get_property('b') + assert type(b) == jsdoc.ClassDoc + assert b.get_property('m_b') + assert b.doc == 'Class 1' + + c = m.get_property('c') + assert type(c) == jsdoc.ClassDoc + assert c.get_property('m_c') + assert c.doc == 'Class 2' + +def test_ns_variables(): + [mod] = parse(""" + odoo.define('A', function (r) { + var Class = r('Class'); + var Thing = Class.extend({}); + return { + Thing: Thing + }; + }); + """) + p = mod.exports.get_property('Thing') + assert type(p) == jsdoc.ClassDoc + +def test_diff(): + """ Have the NS key and the underlying object differ + """ + [mod] = parse(""" + odoo.define('mod', function (r) { + var Class = r('Class'); + var Foo = Class.extend({}); + return { Class: Foo }; + }); + """) + c = mod.exports.get_property('Class') + assert type(c) == jsdoc.ClassDoc + assert c.name == 'Foo' diff --git a/doc/_extensions/autojsdoc/parser/tests/test_params.py b/doc/_extensions/autojsdoc/parser/tests/test_params.py new file mode 100644 index 00000000000..c51139b8cb3 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_params.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +from autojsdoc.parser.jsdoc import ParamDoc + +"Lorem ipsum dolor sit amet, consectetur adipiscing elit." + +def test_basic(): + d = ParamDoc("Lorem ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'Lorem', + 'type': '', + 'optional': False, + 'default': None, + 'doc': 'ipsum dolor sit amet, consectetur adipiscing elit.', + } + + d = ParamDoc("{Lorem} ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'ipsum', + 'type': 'Lorem', + 'optional': False, + 'default': None, + 'doc': 'dolor sit amet, consectetur adipiscing elit.', + } + +def test_optional(): + d = ParamDoc("[Lorem] ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'Lorem', + 'type': '', + 'optional': True, + 'default': None, + 'doc': 'ipsum dolor sit amet, consectetur adipiscing elit.', + } + + d = ParamDoc("[Lorem=42] ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'Lorem', + 'type': '', + 'optional': True, + 'default': "42", + 'doc': 'ipsum dolor sit amet, consectetur adipiscing elit.', + } + + d = ParamDoc("{Lorem} [ipsum] dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'ipsum', + 'type': 'Lorem', + 'optional': True, + 'default': None, + 'doc': 'dolor sit amet, consectetur adipiscing elit.', + } + + d = ParamDoc("{Lorem} [ipsum=42] dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': 'ipsum', + 'type': 'Lorem', + 'optional': True, + 'default': '42', + 'doc': 'dolor sit amet, consectetur adipiscing elit.', + } + +def test_returns(): + d = ParamDoc("{} ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': '', + 'type': '', + 'optional': False, + 'default': None, + 'doc': 'ipsum dolor sit amet, consectetur adipiscing elit.', + } + d = ParamDoc("{Lorem} ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d == { + 'name': '', + 'type': 'Lorem', + 'optional': False, + 'default': None, + 'doc': 'ipsum dolor sit amet, consectetur adipiscing elit.', + } + +def test_odd(): + d = ParamDoc("{jQuery} [$target] the node where content will be prepended").to_dict() + assert d == { + 'name': '$target', + 'type': 'jQuery', + 'optional': True, + 'default': None, + 'doc': 'the node where content will be prepended', + } + + d = ParamDoc("""{htmlString} [content] DOM element, + array of elements, HTML string or jQuery object to prepend to $target""").to_dict() + assert d == { + 'name': 'content', + 'type': 'htmlString', + 'optional': True, + 'default': None, + 'doc': "DOM element,\n array of elements, HTML string or jQuery object to prepend to $target", + } + + d = ParamDoc("{Boolean} [options.in_DOM] true if $target is in the DOM").to_dict() + assert d == { + 'name': 'options.in_DOM', + 'type': 'Boolean', + 'optional': True, + 'default': None, + 'doc': 'true if $target is in the DOM', + } + + d = ParamDoc("Lorem\n ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d['doc'] == 'ipsum dolor sit amet, consectetur adipiscing elit.' + + d = ParamDoc("Lorem - ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d['doc'] == 'ipsum dolor sit amet, consectetur adipiscing elit.' + + d = ParamDoc("Lorem : ipsum dolor sit amet, consectetur adipiscing elit.").to_dict() + assert d['doc'] == 'ipsum dolor sit amet, consectetur adipiscing elit.' diff --git a/doc/_extensions/autojsdoc/parser/tests/test_typespec.py b/doc/_extensions/autojsdoc/parser/tests/test_typespec.py new file mode 100644 index 00000000000..d90fe7995dd --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/tests/test_typespec.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import pytest + +from autojsdoc.parser import types + +def test_parser(): + assert types.parse("MouseEvent|TouchEvent") == types.Alt([ + types.Type('MouseEvent', []), + types.Type('TouchEvent', []), + ]) + + assert types.parse('Deferred') == types.Alt([ + types.Type('Deferred', [ + types.Alt([types.Type('Object', [])]) + ]) + ]) + + assert types.parse('Object|undefined') == types.Alt([ + types.Type('Object', []), + types.Literal('undefined'), + ]) + assert types.parse('any[]') == types.Alt([ + types.Type('Array', [types.Type('any', [])]) + ]) + assert types.parse("'xml' | 'less'") == types.Alt([ + types.Literal('xml'), + types.Literal('less'), + ]) + assert types.parse('Foo') == types.Alt([ + types.Type('Foo', [types.Alt([ + types.Type('Bar', []), + types.Type('Array', [types.Type('Bar', [])]), + types.Literal('null'), + ])]) + ]) + +def test_tokens(): + toks = list(types.tokenize('A')) + assert toks == [(types.NAME, 'A')] + + toks = list(types.tokenize('"foo" | "bar"')) + assert toks == [(types.LITERAL, 'foo'), (types.OP, '|'), (types.LITERAL, 'bar')] + + toks = list(types.tokenize('1 or 2')) + assert toks == [(types.LITERAL, 1), (types.OP, '|'), (types.LITERAL, 2)] + + toks = list(types.tokenize('a.b.c.d')) + assert toks == [ + (types.NAME, 'a'), (types.OP, '.'), + (types.NAME, 'b'), (types.OP, '.'), + (types.NAME, 'c'), (types.OP, '.'), + (types.NAME, 'd'), + ] + + toks = list(types.tokenize('Function')) + assert toks == [ + (types.NAME, 'Function'), + (types.OP, '<'), + (types.NAME, 'String'), + (types.OP, ','), + (types.NAME, 'Object'), + (types.OP, '>') + ] + +def test_peekable(): + p = types.Peekable(range(5)) + + assert p.peek() == 0 + assert next(p) == 0, "consuming should yield previously peeked value" + next(p) + next(p) + assert next(p) == 3 + assert p.peek() == 4 + next(p) + assert p.peek(None) is None + with pytest.raises(StopIteration): + p.peek() + with pytest.raises(StopIteration): + next(p) diff --git a/doc/_extensions/autojsdoc/parser/types.py b/doc/_extensions/autojsdoc/parser/types.py new file mode 100644 index 00000000000..ecbccfe8651 --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/types.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +import ast +import collections +import io +import token +from tokenize import generate_tokens + +LITERAL_NAME = ('null', 'undefined', 'true', 'false') + +__all__ = ['tokenize', 'parse', 'iterate', 'Alt', 'Type', 'Literal'] + +class _Marker(object): + __slots__ = ['name'] + def __init__(self, name): self.name = name + def __repr__(self): return '<%s>' % self.name + +OP = _Marker('OP') +NAME = _Marker('NAME') +LITERAL = _Marker('LITERAL') +def tokenize(typespec): + typespec = typespec.replace('$', 'jQuery') + for toktype, string, _, _, _ in generate_tokens(io.StringIO(typespec).readline): + if toktype == token.NAME: + if string == 'or': # special case "A or B" + # TODO: deprecation warning + yield (OP, '|') + else: + yield (NAME, string) + elif toktype == token.OP: + if string in '|<>[].,': + yield (OP, string) + elif string == '*': # maybe? + yield (NAME, 'any') + elif string in '()': + # TODO: deprecation warning + # seems useless unless we add support for "..." + continue + else: + raise ValueError("Unknown typespec operator %r" % string) + elif toktype in (token.STRING, token.NUMBER): # enum-ish + yield (LITERAL, ast.literal_eval(string)) + elif toktype == token.ENDMARKER: + return + else: + raise ValueError("Unknown typespec token %s" % token.tok_name[toktype]) + +Alt = collections.namedtuple('Alt', ['params']) +Literal = collections.namedtuple('Literal', ['value']) +Type = collections.namedtuple('Type', ['name', 'params']) + +def iterate(t, fortype, forliteral): + if isinstance(t, Alt): + ps = Peekable(t.params) + for param in ps: + for it in iterate(param, fortype, forliteral): + yield it + if ps.peek(None): + yield forliteral('|') + elif isinstance(t, Type): + yield fortype(t.name) + if not t.params: + return + yield forliteral('<') + ps = Peekable(t.params) + for param in ps: + for it in iterate(param, fortype, forliteral): + yield it + if ps.peek(None): + yield forliteral(',') + yield forliteral('>') + elif isinstance(t, Literal): + yield forliteral(t.value) + else: + raise ValueError('Unknown item %s' % t) + +def parse(typespec): + tokens = Peekable(tokenize(typespec)) + return parse_alt(tokens) + +# alt = param +# | param '|' alt +def parse_alt(tokens): + alt = Alt([]) + while True: + alt.params.append(parse_param(tokens)) + if not next_is(tokens, (OP, '|')): + break + return alt + +# param = 'null' | 'undefined' | 'true' | 'false' +# | number +# | string +# | typename '[]' +# X '[' alt ']' +# | typename '<' params '>' +# params = alt | alt ',' params +def parse_param(tokens): + t, v = tokens.peek() + if t == LITERAL or (t == NAME and v in LITERAL_NAME): + next(tokens) + return Literal(str(v)) + + # # [typespec] # should this be Array or an n-uple allowing multiple items? + # if tok == (OP, '['): + # next(tokens) + # t = Type('Array', [parse_alt(tokens)]) + # rest = next(tokens) + # expect(rest, (OP, ']')) + # return t + + t = Type(parse_typename(tokens), []) + # type[] + peek = tokens.peek(None) + if peek == (OP, '['): + next(tokens) # skip peeked + expect(next(tokens), (OP, ']')) + return Type('Array', [t]) + # type + if peek == (OP, '<'): + next(tokens) # skip peeked + while True: + t.params.append(parse_alt(tokens)) + n = next(tokens) + if n == (OP, ','): + continue + if n == (OP, '>'): + break + raise ValueError("Expected OP ',' or OP ',', got %s '%s'" % n) + return t + +# typename = name | name '.' typename +def parse_typename(tokens): + typename = [] + while True: + (t, n) = next(tokens) + if t != NAME: + raise ValueError("Expected a name token, got %s '%s'" % (t, n)) + if n in LITERAL_NAME: + raise ValueError("Expected a type name, got literal %s" % n) + typename.append(n) + if not next_is(tokens, (OP, '.')): + break + return '.'.join(typename) + +def next_is(tokens, expected): + """ + Consumes the next token if it's `expected` otherwise does not touch the + tokens. + + Returns whether it consumed a token + """ + if tokens.peek(None) == expected: + next(tokens) + return True + return False + +def expect(actual, expected): + """ Raises ValueError if `actual` and `expected` are different + + :type actual: (object, str) + :type expected: (object, str) + """ + if actual != expected: + raise ValueError("Expected %s '%s', got %s '%s'" % (expected + actual)) + + +NONE = object() +class Peekable(object): + __slots__ = ['_head', '_it'] + def __init__(self, iterable): + self._head = NONE + self._it = iter(iterable) + + def __iter__(self): + return self + def __next__(self): + if self._head is not NONE: + r, self._head = self._head, NONE + return r + return next(self._it) + next = __next__ + + def peek(self, default=NONE): + if self._head is NONE: + try: + self._head = next(self._it) + except StopIteration: + if default is not NONE: + return default + raise + return self._head diff --git a/doc/_extensions/autojsdoc/parser/utils.py b/doc/_extensions/autojsdoc/parser/utils.py new file mode 100644 index 00000000000..b8b1a97e7aa --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/utils.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +def _name(node): + if node['type'] == 'Identifier': + return node['name'] + if node['type'] == 'MemberExpression': + return "%s.%s" % (_name(node['object']), _name(node['property'])) + raise ValueError("Unnamable node type %s" % node['type']) + +def _value(node, strict=False): + t = node['type'] + if t == 'Identifier': + return node['name'] + elif t == 'Literal': + return node['value'] + msg = '<%s has no value>' % _identify(node, {}) + if strict: + raise ValueError(msg) + return msg + +def _identify(valnode, ns): + if valnode is None: + return "None" + # already identified and re-set in the ns? + if isinstance(valnode, Printable): + return valnode + + # check other non-empty returns + t = valnode['type'] + if t == "Literal": + if valnode.get('regex'): + return valnode['regex']['pattern'] + return valnode['value'] + elif t == "Identifier": + n = valnode['name'] + return ns.get(n, Global(n)) + elif t == "NewExpression": + return Instance(_identify(valnode['callee'], ns)) + elif t == "ObjectExpression": + return Namespace({ + _value(prop['key']): _identify(prop['value'], ns) + for prop in valnode['properties'] + }) + elif t == "MemberExpression": + return Deref( + _identify(valnode['object'], ns), + _identify(valnode['property'], ns) if valnode['computed'] else valnode['property']['name'], + ) + elif t == "CallExpression": + return Call( + _identify(valnode['callee'], ns), + [_identify(arg, ns) for arg in valnode['arguments']], + ) + elif t == 'BinaryExpression': + return "%s %s %s" % ( + _identify(valnode['left'], ns), + valnode['operator'], + _identify(valnode['right'], ns), + ) + else: + return t + +class Counter(object): + __slots__ = ['_number'] + def __init__(self): + self._number = 0 + + def __bool__(self): + return bool(self._number) + __nonzero__ = __bool__ + def __int__(self): + return self._number + + def get(self): + return self._number + def increment(self): + self._number += 1 + return self._number + def decrement(self): + self._number -= 1 + return self._number + + def __enter__(self): + self._number += 1 + return self._number + def __exit__(self, *args): + self._number -= 1 + +class Printable(object): + __slots__ = [] + depth = Counter() + def __repr__(self): + with self.depth as i: + if i > 2: + return "%s(...)" % type(self).__name__ + return "%s(%s)" % (type(self).__name__, ', '.join( + "%s=%r" % (k, getattr(self, k)) + for k in self.__slots__ + if not k.startswith('_') + if getattr(self, k) + )) + + +def resolve(obj, store): + if obj is None: + return None + + if isinstance(obj, (unicode, bool, int, float)): + return obj + + if isinstance(obj, ModuleProxy): + return resolve(obj.get(), store) + + try: + if getattr(obj, 'resolved', False): + return obj + return obj.resolve(store) + except AttributeError: + raise TypeError("Unresolvable {!r}".format(obj)) + +class Resolvable(Printable): + """ + For types resolved in place + """ + __slots__ = ['resolved'] + + def __init__(self): + super(Resolvable, self).__init__() + self.resolved = False + def resolve(self, store): + self.resolved = True + return self + +class Namespace(Resolvable): + __slots__ = ['attrs'] + def __init__(self, attrs): + super(Namespace, self).__init__() + self.attrs = attrs + def resolve(self, store): + r = super(Namespace, self).resolve(store) + self.attrs = { + k: resolve(v, store) + for k, v in self.attrs.iteritems() + } + return r + def __getitem__(self, key): + assert isinstance(key, unicode), "%r is not a namespace key" % key + try: + return self.attrs[key] + except KeyError: + return Global(self)[key] + +class Module(Resolvable): + __slots__ = ('name', 'comments', 'exports', 'augments', 'dependencies', '_store') + def __init__(self, name, store, comments=()): + super(Module, self).__init__() + self.name = name + self._store = store + self.comments = tuple(comments) + self.exports = None + self.augments = [] + self.dependencies = set() + store[name] = self + def add_dependency(self, depname): + dep = ModuleProxy(depname, self._store) + self.dependencies.add(dep) + return dep + def get(self): + return self + def resolve(self, store=None): + r = super(Module, self).resolve(store) + self.exports = resolve(self.exports, self._store) + self.augments = [resolve(a, self._store) for a in self.augments] + self.dependencies = { + resolve(d, self._store) + for d in self.dependencies + } + return r + def __getitem__(self, k): + try: + return self.exports[k] + except KeyError: + return Global(self)[k] + +class ModuleProxy(object): + def __init__(self, name, store): + self.name = name + self.store = store + def get(self): + # web.web_client is not an actual module + return self.store.get(self.name, '' % self.name) + def __repr__(self): + return repr(self.get()) + def __hash__(self): + return hash(self.name) + def __eq__(self, other): + return self.name == other.name + +class Class(Resolvable): + __slots__ = ['name', 'members', 'extends', 'mixins', 'comments'] + def __init__(self, name, extends): + super(Class, self).__init__() + self.name = name + self.extends = extends + self.members = {} + self.mixins = [] + self.comments = [] + + def resolve(self, store): + r = super(Class, self).resolve(store) + self.extends = resolve(self.extends, store) + self.mixins = [resolve(m, store) for m in self.mixins] + return r + +class Instance(Resolvable): + __slots__ = ['type'] + def __init__(self, type): + super(Instance, self).__init__() + self.type = type + + def resolve(self, store): + r = super(Instance, self).resolve(store) + self.type = resolve(self.type, store) + if isinstance(self.type, Module): + self.type = self.type.exports + return r + + def __getitem__(self, key): + return Global(self)['key'] + +class Function(Resolvable): + __slots__ = ['comments'] + def __init__(self, comments): + super(Function, self).__init__() + self.comments = comments + +class Deref(Printable): + __slots__ = ['object', 'property'] + def __init__(self, object, property): + self.object = object + self.property = property + def resolve(self, store): + return resolve(self.object, store)[self.property] + +class Call(Resolvable): + __slots__ = ['callable'] + def __init__(self, callable, arguments): + super(Call, self).__init__() + self.callable = callable + def resolve(self, store): + r = super(Call, self).resolve(store) + self.callable = resolve(self.callable, store) + return r + def __getitem__(self, item): + return Global(self)[item] + +def get(node, it, *path): + if not path: + return node[it] + return get(node[it], *path) + + +def match(node, pattern): + """Checks that ``pattern`` is a subset of ``node``. + + If a sub-pattern is a callable it will be called with the current + sub-node and its result is the match's. Other sub-patterns are + checked by equality against the correspoding sub-node. + + Can be used to quickly check the descendants of a node of suitable + type. + + TODO: support checking list content? Would be convenient to + constraint e.g. CallExpression based on their parameters + + """ + if node is None and pattern is not None: + return + if callable(pattern): + return pattern(node) + if isinstance(node, list): + return all(len(node) > i and match(node[i], v) for i, v in pattern.items()) + if isinstance(pattern, dict): + return all(match(node.get(k), v) for k, v in pattern.items()) + return node == pattern + + +class Global(object): + def __init__(self, name): + self.name = name + def __repr__(self): + return '' % self.name + def __getitem__(self, name): + return Global('%s.%s' % (self.name, name)) + def resolve(self, store): + return self diff --git a/doc/_extensions/autojsdoc/parser/visitor.py b/doc/_extensions/autojsdoc/parser/visitor.py new file mode 100644 index 00000000000..e5529d511dc --- /dev/null +++ b/doc/_extensions/autojsdoc/parser/visitor.py @@ -0,0 +1,126 @@ +from pyjsparser.pyjsparserdata import Syntax + +_binary = lambda n: [n['left'], n['right']] +_function = lambda n: n['params'] + n['defaults'] + [n['body']] +# yields children in visitation order +_children = { + Syntax.ArrayExpression: lambda n: n['elements'], + Syntax.ArrayPattern: lambda n: n['elements'], + Syntax.ArrowFunctionExpression: _function, + Syntax.AssignmentExpression: _binary, + Syntax.AssignmentPattern: _binary, + Syntax.BinaryExpression: _binary, + Syntax.BlockStatement: lambda n: n['body'], + Syntax.BreakStatement: lambda n: [], + Syntax.CallExpression: lambda n: [n['callee']] + n['arguments'], + Syntax.CatchClause: lambda n: [n['param'], n['body']], + Syntax.ClassBody: lambda n: [n['body']], + Syntax.ClassDeclaration: lambda n: [n['superClass'], n['body']], + Syntax.ClassExpression: lambda n: [n['superClass'], n['body']], + Syntax.ConditionalExpression: lambda n: [n['test'], n['consequent'], n['alternate']], + Syntax.ContinueStatement: lambda n: [], + Syntax.DebuggerStatement: lambda n: [], + Syntax.DoWhileStatement: lambda n: [n['body'], n['test']], + Syntax.EmptyStatement: lambda n: [], + Syntax.ExportAllDeclaration: lambda n: [n['source']], + Syntax.ExportDefaultDeclaration: lambda n: [n['declaration']], + Syntax.ExportNamedDeclaration: lambda n: ([n['declaration']] if n['declaration'] else n['specifiers']) + [n['source']], + Syntax.ExportSpecifier: lambda n: [n['local'], n['exported']], + Syntax.ExpressionStatement: lambda n: [n['expression']], + Syntax.ForStatement: lambda n: [n['init'], n['test'], n['update'], n['body']], + Syntax.ForInStatement: lambda n: [n['left'], n['right'], n['body']], + Syntax.FunctionDeclaration: _function, + Syntax.FunctionExpression: _function, + Syntax.Identifier: lambda n: [], + Syntax.IfStatement: lambda n: [n['test'], n['consequent'], n['alternate']], + Syntax.ImportDeclaration: lambda n: n['specifiers'] + [n['source']], + Syntax.ImportDefaultSpecifier: lambda n: [n['local']], + Syntax.ImportNamespaceSpecifier: lambda n: [n['local']], + Syntax.ImportSpecifier: lambda n: [n['local'], n['imported']], + Syntax.LabeledStatement: lambda n: [n['body']], + Syntax.Literal: lambda n: [], + Syntax.LogicalExpression: _binary, + Syntax.MemberExpression: lambda n: [n['object'], n['property']], + #Syntax.MethodDefinition: lambda n: [], + Syntax.NewExpression: lambda n: [n['callee']] + n['arguments'], + Syntax.ObjectExpression: lambda n: n['properties'], + Syntax.ObjectPattern: lambda n: n['properties'], + Syntax.Program: lambda n: n['body'], + Syntax.Property: lambda n: [n['key'], n['value']], + Syntax.RestElement: lambda n: [n['argument']], + Syntax.ReturnStatement: lambda n: [n['argument']], + Syntax.SequenceExpression: lambda n: n['expressions'], + Syntax.SpreadElement: lambda n: [n['argument']], + Syntax.Super: lambda n: [], + Syntax.SwitchCase: lambda n: [n['test'], n['consequent']], + Syntax.SwitchStatement: lambda n: [n['discriminant']] + n['cases'], + Syntax.TaggedTemplateExpression: lambda n: [n['tag'], n['quasi']], + Syntax.TemplateElement: lambda n: [], + Syntax.TemplateLiteral: lambda n: n['quasis'] + n['expressions'], + Syntax.ThisExpression: lambda n: [], + Syntax.ThrowStatement: lambda n: [n['argument']], + Syntax.TryStatement: lambda n: [n['block'], n['handler'], n['finalizer']], + Syntax.UnaryExpression: lambda n: [n['argument']], + Syntax.UpdateExpression: lambda n: [n['argument']], + Syntax.VariableDeclaration: lambda n: n['declarations'], + Syntax.VariableDeclarator: lambda n: [n['id'], n['init']], + Syntax.WhileStatement: lambda n: [n['test'], n['body']], + Syntax.WithStatement: lambda n: [n['object'], n['body']], +} + +SKIP = object() +class Visitor(object): + """ + Generic visitor for the pyjsparser AST. + + Visitation is driven by the ``visit`` method, which iterates the tree in + depth-first pre-order. + + For each node, calls ``enter_$NODETYPE``, visits the children then calls + ``exit_$NODETYPE``. If the enter or exit methods are not present on the + visitor, falls back on ``enter_generic`` and ``exit_generic``. + + Any ``enter_`` method can return ``SKIP`` to suppress both the traversal + of the subtree *and* the call to the corresponding ``exit_`` method + (whether generic or specific). + + For convenience, ``visit`` will return whatever is set as the visitor's + ``result`` attribute, ``None`` by default. + + ``visit`` can be given multiple root nodes, and it can be called multiple + times. The ``result`` attribute is cleared at each call but not between + two roots of the same ``visit`` call. + """ + def __init__(self): + super(Visitor, self).__init__() + self.result = None + + def enter_generic(self, node): pass + def exit_generic(self, node): pass + + def visit(self, nodes): + if isinstance(nodes, dict): + nodes = [nodes] + # if multiple nodes are passed in, we need to reverse the order in + # order to traverse front-to-back rather than the other way around + nodes = list(reversed(nodes)) + + while nodes: + node = nodes.pop() + # should probably filter None descendants in _children... + if node is None: + continue + node_type = node['type'] + if node_type == '_exit': + node = node['node'] + getattr(self, 'exit_' + node['type'], self.exit_generic)(node) + continue + + if getattr(self, 'enter_' + node_type, self.enter_generic)(node) is SKIP: + continue + + nodes.append({'type': '_exit', 'node': node}) + nodes.extend(reversed(_children[node_type](node))) + + return self.result + diff --git a/doc/_extensions/conftest.py b/doc/_extensions/conftest.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/doc/_extensions/odoo_ext/static/style.css b/doc/_extensions/odoo_ext/static/style.css index d521ff30677..ead78f9101d 100644 --- a/doc/_extensions/odoo_ext/static/style.css +++ b/doc/_extensions/odoo_ext/static/style.css @@ -1076,7 +1076,7 @@ body { font-size: 15px; line-height: 1.42857143; color: #666c75; - background-color: #f9f9f9; + background-color: #F9F9F9; } input, button, @@ -1087,7 +1087,7 @@ textarea { line-height: inherit; } a { - color: #875a7b; + color: #875A7B; text-decoration: none; } a:hover, @@ -1122,8 +1122,8 @@ img { .img-thumbnail { padding: 4px; line-height: 1.42857143; - background-color: #f9f9f9; - border: 1px solid #dddddd; + background-color: #F9F9F9; + border: 1px solid #ddd; border-radius: 4px; -webkit-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; @@ -1139,7 +1139,7 @@ hr { margin-top: 21px; margin-bottom: 21px; border: 0; - border-top: 1px solid #f2f2f2; + border-top: 1px solid #F2F2F2; } .sr-only { position: absolute; @@ -1402,7 +1402,7 @@ a.bg-danger:focus { .page-header { padding-bottom: 9.5px; margin: 42px 0 21px; - border-bottom: 1px solid #f2f2f2; + border-bottom: 1px solid #F2F2F2; } ul, ol { @@ -1470,7 +1470,7 @@ blockquote { padding: 10.5px 21px; margin: 0 0 21px; font-size: 18.75px; - border-left: 5px solid #f2f2f2; + border-left: 5px solid #F2F2F2; } blockquote p:last-child, blockquote ul:last-child, @@ -1494,7 +1494,7 @@ blockquote .small:before { blockquote.pull-right { padding-right: 15px; padding-left: 0; - border-right: 5px solid #f2f2f2; + border-right: 5px solid #F2F2F2; border-left: 0; text-align: right; } @@ -1535,8 +1535,8 @@ code { kbd { padding: 2px 4px; font-size: 90%; - color: #ffffff; - background-color: #333333; + color: #fff; + background-color: #333; border-radius: 3px; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); } @@ -1554,9 +1554,9 @@ pre { line-height: 1.42857143; word-break: break-all; word-wrap: break-word; - color: #6b6d70; + color: #6B6D70; background-color: #f5f5f5; - border: 1px solid #cccccc; + border: 1px solid #ccc; border-radius: 4px; } pre code { @@ -2264,11 +2264,11 @@ th { padding: 8px; line-height: 1.42857143; vertical-align: top; - border-top: 1px solid #dddddd; + border-top: 1px solid #ddd; } .table > thead > tr > th { vertical-align: bottom; - border-bottom: 2px solid #dddddd; + border-bottom: 2px solid #ddd; } .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > th, @@ -2279,10 +2279,10 @@ th { border-top: 0; } .table > tbody + tbody { - border-top: 2px solid #dddddd; + border-top: 2px solid #ddd; } .table .table { - background-color: #f9f9f9; + background-color: #F9F9F9; } .table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, @@ -2293,7 +2293,7 @@ th { padding: 5px; } .table-bordered { - border: 1px solid #dddddd; + border: 1px solid #ddd; } .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, @@ -2301,7 +2301,7 @@ th { .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td { - border: 1px solid #dddddd; + border: 1px solid #ddd; } .table-bordered > thead > tr > th, .table-bordered > thead > tr > td { @@ -2439,7 +2439,7 @@ table th[class*="col-"] { margin-bottom: 15.75px; overflow-y: hidden; -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #dddddd; + border: 1px solid #ddd; } .table-responsive > .table { margin-bottom: 0; @@ -2491,7 +2491,7 @@ legend { margin-bottom: 21px; font-size: 22.5px; line-height: inherit; - color: #6b6d70; + color: #6B6D70; border: 0; border-bottom: 1px solid #e5e5e5; } @@ -2545,9 +2545,9 @@ output { font-size: 15px; line-height: 1.42857143; color: #888888; - background-color: #ffffff; + background-color: #fff; background-image: none; - border: 1px solid #cccccc; + border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); @@ -2562,14 +2562,14 @@ output { box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); } .form-control::-moz-placeholder { - color: #999999; + color: #999; opacity: 1; } .form-control:-ms-input-placeholder { - color: #999999; + color: #999; } .form-control::-webkit-input-placeholder { - color: #999999; + color: #999; } .form-control::-ms-expand { border: 0; @@ -2578,7 +2578,7 @@ output { .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - background-color: #f2f2f2; + background-color: #F2F2F2; opacity: 1; } .form-control[disabled], @@ -3024,7 +3024,7 @@ select[multiple].input-lg { .btn:hover, .btn:focus, .btn.focus { - color: #333333; + color: #333; text-decoration: none; } .btn:active, @@ -3048,25 +3048,25 @@ fieldset[disabled] a.btn { pointer-events: none; } .btn-default { - color: #333333; - background-color: #ffffff; - border-color: #cccccc; + color: #333; + background-color: #fff; + border-color: #ccc; } .btn-default:focus, .btn-default.focus { - color: #333333; + color: #333; background-color: #e6e6e6; border-color: #8c8c8c; } .btn-default:hover { - color: #333333; + color: #333; background-color: #e6e6e6; border-color: #adadad; } .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default { - color: #333333; + color: #333; background-color: #e6e6e6; border-color: #adadad; } @@ -3079,7 +3079,7 @@ fieldset[disabled] a.btn { .btn-default:active.focus, .btn-default.active.focus, .open > .dropdown-toggle.btn-default.focus { - color: #333333; + color: #333; background-color: #d4d4d4; border-color: #8c8c8c; } @@ -3097,33 +3097,33 @@ fieldset[disabled] .btn-default:focus, .btn-default.disabled.focus, .btn-default[disabled].focus, fieldset[disabled] .btn-default.focus { - background-color: #ffffff; - border-color: #cccccc; + background-color: #fff; + border-color: #ccc; } .btn-default .badge { - color: #ffffff; - background-color: #333333; + color: #fff; + background-color: #333; } .btn-primary { - color: #ffffff; + color: #fff; background-color: #21b799; border-color: #1da187; } .btn-primary:focus, .btn-primary.focus { - color: #ffffff; + color: #fff; background-color: #198c75; border-color: #0a352d; } .btn-primary:hover { - color: #ffffff; + color: #fff; background-color: #198c75; border-color: #146e5c; } .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { - color: #ffffff; + color: #fff; background-color: #198c75; border-color: #146e5c; } @@ -3136,7 +3136,7 @@ fieldset[disabled] .btn-default.focus { .btn-primary:active.focus, .btn-primary.active.focus, .open > .dropdown-toggle.btn-primary.focus { - color: #ffffff; + color: #fff; background-color: #146e5c; border-color: #0a352d; } @@ -3159,28 +3159,28 @@ fieldset[disabled] .btn-primary.focus { } .btn-primary .badge { color: #21b799; - background-color: #ffffff; + background-color: #fff; } .btn-success { - color: #ffffff; - background-color: #50af51; + color: #fff; + background-color: #50AF51; border-color: #489e49; } .btn-success:focus, .btn-success.focus { - color: #ffffff; + color: #fff; background-color: #408c41; border-color: #204620; } .btn-success:hover { - color: #ffffff; + color: #fff; background-color: #408c41; border-color: #357435; } .btn-success:active, .btn-success.active, .open > .dropdown-toggle.btn-success { - color: #ffffff; + color: #fff; background-color: #408c41; border-color: #357435; } @@ -3193,7 +3193,7 @@ fieldset[disabled] .btn-primary.focus { .btn-success:active.focus, .btn-success.active.focus, .open > .dropdown-toggle.btn-success.focus { - color: #ffffff; + color: #fff; background-color: #357335; border-color: #204620; } @@ -3211,33 +3211,33 @@ fieldset[disabled] .btn-success:focus, .btn-success.disabled.focus, .btn-success[disabled].focus, fieldset[disabled] .btn-success.focus { - background-color: #50af51; + background-color: #50AF51; border-color: #489e49; } .btn-success .badge { - color: #50af51; - background-color: #ffffff; + color: #50AF51; + background-color: #fff; } .btn-info { - color: #ffffff; - background-color: #4b9eb6; + color: #fff; + background-color: #4B9EB6; border-color: #438fa5; } .btn-info:focus, .btn-info.focus { - color: #ffffff; + color: #fff; background-color: #3b7f93; border-color: #1e404a; } .btn-info:hover { - color: #ffffff; + color: #fff; background-color: #3b7f93; border-color: #316979; } .btn-info:active, .btn-info.active, .open > .dropdown-toggle.btn-info { - color: #ffffff; + color: #fff; background-color: #3b7f93; border-color: #316979; } @@ -3250,7 +3250,7 @@ fieldset[disabled] .btn-success.focus { .btn-info:active.focus, .btn-info.active.focus, .open > .dropdown-toggle.btn-info.focus { - color: #ffffff; + color: #fff; background-color: #316979; border-color: #1e404a; } @@ -3268,33 +3268,33 @@ fieldset[disabled] .btn-info:focus, .btn-info.disabled.focus, .btn-info[disabled].focus, fieldset[disabled] .btn-info.focus { - background-color: #4b9eb6; + background-color: #4B9EB6; border-color: #438fa5; } .btn-info .badge { - color: #4b9eb6; - background-color: #ffffff; + color: #4B9EB6; + background-color: #fff; } .btn-warning { - color: #ffffff; - background-color: #f0ad4e; + color: #fff; + background-color: #F0AD4E; border-color: #eea236; } .btn-warning:focus, .btn-warning.focus { - color: #ffffff; + color: #fff; background-color: #ec971f; border-color: #985f0d; } .btn-warning:hover { - color: #ffffff; + color: #fff; background-color: #ec971f; border-color: #d58512; } .btn-warning:active, .btn-warning.active, .open > .dropdown-toggle.btn-warning { - color: #ffffff; + color: #fff; background-color: #ec971f; border-color: #d58512; } @@ -3307,7 +3307,7 @@ fieldset[disabled] .btn-info.focus { .btn-warning:active.focus, .btn-warning.active.focus, .open > .dropdown-toggle.btn-warning.focus { - color: #ffffff; + color: #fff; background-color: #d58512; border-color: #985f0d; } @@ -3325,33 +3325,33 @@ fieldset[disabled] .btn-warning:focus, .btn-warning.disabled.focus, .btn-warning[disabled].focus, fieldset[disabled] .btn-warning.focus { - background-color: #f0ad4e; + background-color: #F0AD4E; border-color: #eea236; } .btn-warning .badge { - color: #f0ad4e; - background-color: #ffffff; + color: #F0AD4E; + background-color: #fff; } .btn-danger { - color: #ffffff; - background-color: #d9534f; + color: #fff; + background-color: #D9534F; border-color: #d43f3a; } .btn-danger:focus, .btn-danger.focus { - color: #ffffff; + color: #fff; background-color: #c9302c; border-color: #761c19; } .btn-danger:hover { - color: #ffffff; + color: #fff; background-color: #c9302c; border-color: #ac2925; } .btn-danger:active, .btn-danger.active, .open > .dropdown-toggle.btn-danger { - color: #ffffff; + color: #fff; background-color: #c9302c; border-color: #ac2925; } @@ -3364,7 +3364,7 @@ fieldset[disabled] .btn-warning.focus { .btn-danger:active.focus, .btn-danger.active.focus, .open > .dropdown-toggle.btn-danger.focus { - color: #ffffff; + color: #fff; background-color: #ac2925; border-color: #761c19; } @@ -3382,15 +3382,15 @@ fieldset[disabled] .btn-danger:focus, .btn-danger.disabled.focus, .btn-danger[disabled].focus, fieldset[disabled] .btn-danger.focus { - background-color: #d9534f; + background-color: #D9534F; border-color: #d43f3a; } .btn-danger .badge { - color: #d9534f; - background-color: #ffffff; + color: #D9534F; + background-color: #fff; } .btn-link { - color: #875a7b; + color: #875A7B; font-weight: normal; border-radius: 0; } @@ -3518,8 +3518,8 @@ tbody.collapse.in { list-style: none; font-size: 15px; text-align: left; - background-color: #ffffff; - border: 1px solid #cccccc; + background-color: #fff; + border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); @@ -3542,7 +3542,7 @@ tbody.collapse.in { clear: both; font-weight: normal; line-height: 1.42857143; - color: #6b6d70; + color: #6B6D70; white-space: nowrap; } .dropdown-menu > li > a:hover, @@ -3554,7 +3554,7 @@ tbody.collapse.in { .dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus { - color: #ffffff; + color: #fff; text-decoration: none; outline: 0; background-color: #21b799; @@ -3889,8 +3889,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn { line-height: 1; color: #888888; text-align: center; - background-color: #f2f2f2; - border: 1px solid #cccccc; + background-color: #F2F2F2; + border: 1px solid #ccc; border-radius: 4px; } .input-group-addon.input-sm { @@ -3975,7 +3975,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav > li > a:hover, .nav > li > a:focus { text-decoration: none; - background-color: #f2f2f2; + background-color: #F2F2F2; } .nav > li.disabled > a { color: #dcddde; @@ -3990,8 +3990,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav .open > a, .nav .open > a:hover, .nav .open > a:focus { - background-color: #f2f2f2; - border-color: #875a7b; + background-color: #F2F2F2; + border-color: #875A7B; } .nav .nav-divider { height: 1px; @@ -4003,7 +4003,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { max-width: none; } .nav-tabs { - border-bottom: 1px solid #dddddd; + border-bottom: 1px solid #ddd; } .nav-tabs > li { float: left; @@ -4016,14 +4016,14 @@ select[multiple].input-group-sm > .input-group-btn > .btn { border-radius: 4px 4px 0 0; } .nav-tabs > li > a:hover { - border-color: #f2f2f2 #f2f2f2 #dddddd; + border-color: #F2F2F2 #F2F2F2 #ddd; } .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { color: #888888; - background-color: #f9f9f9; - border: 1px solid #dddddd; + background-color: #F9F9F9; + border: 1px solid #ddd; border-bottom-color: transparent; cursor: default; } @@ -4058,17 +4058,17 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #dddddd; + border: 1px solid #ddd; } @media (min-width: 768px) { .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #dddddd; + border-bottom: 1px solid #ddd; border-radius: 4px 4px 0 0; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #f9f9f9; + border-bottom-color: #F9F9F9; } } .nav-pills > li { @@ -4083,7 +4083,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { - color: #ffffff; + color: #fff; background-color: #21b799; } .nav-stacked > li { @@ -4126,17 +4126,17 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { - border: 1px solid #dddddd; + border: 1px solid #ddd; } @media (min-width: 768px) { .nav-tabs-justified > li > a { - border-bottom: 1px solid #dddddd; + border-bottom: 1px solid #ddd; border-radius: 4px 4px 0 0; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { - border-bottom-color: #f9f9f9; + border-bottom-color: #F9F9F9; } } .tab-content > .tab-pane { @@ -4481,7 +4481,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { border-color: #e7e7e7; } .navbar-default .navbar-brand { - color: #777777; + color: #777; } .navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus { @@ -4489,37 +4489,37 @@ select[multiple].input-group-sm > .input-group-btn > .btn { background-color: transparent; } .navbar-default .navbar-text { - color: #777777; + color: #777; } .navbar-default .navbar-nav > li > a { - color: #777777; + color: #777; } .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus { - color: #333333; + color: #333; background-color: transparent; } .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { - color: #555555; + color: #555; background-color: #e7e7e7; } .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, .navbar-default .navbar-nav > .disabled > a:focus { - color: #cccccc; + color: #ccc; background-color: transparent; } .navbar-default .navbar-toggle { - border-color: #dddddd; + border-color: #ddd; } .navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus { - background-color: #dddddd; + background-color: #ddd; } .navbar-default .navbar-toggle .icon-bar { - background-color: #888888; + background-color: #888; } .navbar-default .navbar-collapse, .navbar-default .navbar-form { @@ -4529,51 +4529,51 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { background-color: #e7e7e7; - color: #555555; + color: #555; } @media (max-width: 767px) { .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #777777; + color: #777; } .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #333333; + color: #333; background-color: transparent; } .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #555555; + color: #555; background-color: #e7e7e7; } .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #cccccc; + color: #ccc; background-color: transparent; } } .navbar-default .navbar-link { - color: #777777; + color: #777; } .navbar-default .navbar-link:hover { - color: #333333; + color: #333; } .navbar-default .btn-link { - color: #777777; + color: #777; } .navbar-default .btn-link:hover, .navbar-default .btn-link:focus { - color: #333333; + color: #333; } .navbar-default .btn-link[disabled]:hover, fieldset[disabled] .navbar-default .btn-link:hover, .navbar-default .btn-link[disabled]:focus, fieldset[disabled] .navbar-default .btn-link:focus { - color: #cccccc; + color: #ccc; } .navbar-inverse { - background-color: #222222; + background-color: #222; border-color: #080808; } .navbar-inverse .navbar-brand { @@ -4581,7 +4581,7 @@ fieldset[disabled] .navbar-default .btn-link:focus { } .navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus { - color: #ffffff; + color: #fff; background-color: transparent; } .navbar-inverse .navbar-text { @@ -4592,30 +4592,30 @@ fieldset[disabled] .navbar-default .btn-link:focus { } .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { - color: #ffffff; + color: #fff; background-color: transparent; } .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus { - color: #ffffff; + color: #fff; background-color: #080808; } .navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:hover, .navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444444; + color: #444; background-color: transparent; } .navbar-inverse .navbar-toggle { - border-color: #333333; + border-color: #333; } .navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { - background-color: #333333; + background-color: #333; } .navbar-inverse .navbar-toggle .icon-bar { - background-color: #ffffff; + background-color: #fff; } .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { @@ -4625,7 +4625,7 @@ fieldset[disabled] .navbar-default .btn-link:focus { .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus { background-color: #080808; - color: #ffffff; + color: #fff; } @media (max-width: 767px) { .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { @@ -4639,19 +4639,19 @@ fieldset[disabled] .navbar-default .btn-link:focus { } .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ffffff; + color: #fff; background-color: transparent; } .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ffffff; + color: #fff; background-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444444; + color: #444; background-color: transparent; } } @@ -4659,20 +4659,20 @@ fieldset[disabled] .navbar-default .btn-link:focus { color: #ffffff; } .navbar-inverse .navbar-link:hover { - color: #ffffff; + color: #fff; } .navbar-inverse .btn-link { color: #ffffff; } .navbar-inverse .btn-link:hover, .navbar-inverse .btn-link:focus { - color: #ffffff; + color: #fff; } .navbar-inverse .btn-link[disabled]:hover, fieldset[disabled] .navbar-inverse .btn-link:hover, .navbar-inverse .btn-link[disabled]:focus, fieldset[disabled] .navbar-inverse .btn-link:focus { - color: #444444; + color: #444; } .breadcrumb { padding: 8px 15px; @@ -4687,7 +4687,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .breadcrumb > li + li:before { content: "/\00a0"; padding: 0 5px; - color: #cccccc; + color: #ccc; } .breadcrumb > .active { color: #dcddde; @@ -4708,9 +4708,9 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { padding: 6px 12px; line-height: 1.42857143; text-decoration: none; - color: #875a7b; - background-color: #ffffff; - border: 1px solid #dddddd; + color: #875A7B; + background-color: #fff; + border: 1px solid #ddd; margin-left: -1px; } .pagination > li:first-child > a, @@ -4730,8 +4730,8 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination > li > span:focus { z-index: 2; color: #926485; - background-color: #f2f2f2; - border-color: #dddddd; + background-color: #F2F2F2; + border-color: #ddd; } .pagination > .active > a, .pagination > .active > span, @@ -4740,7 +4740,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination > .active > a:focus, .pagination > .active > span:focus { z-index: 3; - color: #ffffff; + color: #fff; background-color: #21b799; border-color: #21b799; cursor: default; @@ -4752,8 +4752,8 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination > .disabled > a:hover, .pagination > .disabled > a:focus { color: #dcddde; - background-color: #ffffff; - border-color: #dddddd; + background-color: #fff; + border-color: #ddd; cursor: not-allowed; } .pagination-lg > li > a, @@ -4801,14 +4801,14 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pager li > span { display: inline-block; padding: 5px 14px; - background-color: #ffffff; - border: 1px solid #dddddd; + background-color: #fff; + border: 1px solid #ddd; border-radius: 15px; } .pager li > a:hover, .pager li > a:focus { text-decoration: none; - background-color: #f2f2f2; + background-color: #F2F2F2; } .pager .next > a, .pager .next > span { @@ -4823,7 +4823,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pager .disabled > a:focus, .pager .disabled > span { color: #dcddde; - background-color: #ffffff; + background-color: #fff; cursor: not-allowed; } .label { @@ -4832,7 +4832,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { font-size: 75%; font-weight: bold; line-height: 1; - color: #ffffff; + color: #fff; text-align: center; white-space: nowrap; vertical-align: baseline; @@ -4840,7 +4840,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { } a.label:hover, a.label:focus { - color: #ffffff; + color: #fff; text-decoration: none; cursor: pointer; } @@ -4866,28 +4866,28 @@ a.label:focus { background-color: #198c75; } .label-success { - background-color: #50af51; + background-color: #50AF51; } .label-success[href]:hover, .label-success[href]:focus { background-color: #408c41; } .label-info { - background-color: #4b9eb6; + background-color: #4B9EB6; } .label-info[href]:hover, .label-info[href]:focus { background-color: #3b7f93; } .label-warning { - background-color: #f0ad4e; + background-color: #F0AD4E; } .label-warning[href]:hover, .label-warning[href]:focus { background-color: #ec971f; } .label-danger { - background-color: #d9534f; + background-color: #D9534F; } .label-danger[href]:hover, .label-danger[href]:focus { @@ -4899,7 +4899,7 @@ a.label:focus { padding: 3px 7px; font-size: 13px; font-weight: bold; - color: #ffffff; + color: #fff; line-height: 1; vertical-align: middle; white-space: nowrap; @@ -4921,14 +4921,14 @@ a.label:focus { } a.badge:hover, a.badge:focus { - color: #ffffff; + color: #fff; text-decoration: none; cursor: pointer; } .list-group-item.active > .badge, .nav-pills > .active > a > .badge { - color: #875a7b; - background-color: #ffffff; + color: #875A7B; + background-color: #fff; } .list-group-item > .badge { float: right; @@ -4944,7 +4944,7 @@ a.badge:focus { padding-bottom: 30px; margin-bottom: 30px; color: inherit; - background-color: #f2f2f2; + background-color: #F2F2F2; } .jumbotron h1, .jumbotron .h1 { @@ -4987,8 +4987,8 @@ a.badge:focus { padding: 4px; margin-bottom: 21px; line-height: 1.42857143; - background-color: #f9f9f9; - border: 1px solid #dddddd; + background-color: #F9F9F9; + border: 1px solid #ddd; border-radius: 4px; -webkit-transition: border 0.2s ease-in-out; -o-transition: border 0.2s ease-in-out; @@ -5002,7 +5002,7 @@ a.badge:focus { a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active { - border-color: #875a7b; + border-color: #875A7B; } .thumbnail .caption { padding: 9px; @@ -5114,7 +5114,7 @@ a.thumbnail.active { height: 100%; font-size: 13px; line-height: 21px; - color: #ffffff; + color: #fff; text-align: center; background-color: #21b799; -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); @@ -5137,7 +5137,7 @@ a.thumbnail.active { animation: progress-bar-stripes 2s linear infinite; } .progress-bar-success { - background-color: #50af51; + background-color: #50AF51; } .progress-striped .progress-bar-success { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -5145,7 +5145,7 @@ a.thumbnail.active { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-info { - background-color: #4b9eb6; + background-color: #4B9EB6; } .progress-striped .progress-bar-info { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -5153,7 +5153,7 @@ a.thumbnail.active { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-warning { - background-color: #f0ad4e; + background-color: #F0AD4E; } .progress-striped .progress-bar-warning { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -5161,7 +5161,7 @@ a.thumbnail.active { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-danger { - background-color: #d9534f; + background-color: #D9534F; } .progress-striped .progress-bar-danger { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -5225,8 +5225,8 @@ a.thumbnail.active { display: block; padding: 10px 15px; margin-bottom: -1px; - background-color: #ffffff; - border: 1px solid #dddddd; + background-color: #fff; + border: 1px solid #ddd; } .list-group-item:first-child { border-top-right-radius: 4px; @@ -5239,18 +5239,18 @@ a.thumbnail.active { } a.list-group-item, button.list-group-item { - color: #555555; + color: #555; } a.list-group-item .list-group-item-heading, button.list-group-item .list-group-item-heading { - color: #333333; + color: #333; } a.list-group-item:hover, button.list-group-item:hover, a.list-group-item:focus, button.list-group-item:focus { text-decoration: none; - color: #555555; + color: #555; background-color: #f5f5f5; } button.list-group-item { @@ -5260,7 +5260,7 @@ button.list-group-item { .list-group-item.disabled, .list-group-item.disabled:hover, .list-group-item.disabled:focus { - background-color: #f2f2f2; + background-color: #F2F2F2; color: #dcddde; cursor: not-allowed; } @@ -5278,7 +5278,7 @@ button.list-group-item { .list-group-item.active:hover, .list-group-item.active:focus { z-index: 2; - color: #ffffff; + color: #fff; background-color: #21b799; border-color: #21b799; } @@ -5424,7 +5424,7 @@ button.list-group-item-danger.active:focus { } .panel { margin-bottom: 21px; - background-color: #ffffff; + background-color: #fff; border: 1px solid transparent; border-radius: 4px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); @@ -5458,7 +5458,7 @@ button.list-group-item-danger.active:focus { .panel-footer { padding: 10px 15px; background-color: #f5f5f5; - border-top: 1px solid #dddddd; + border-top: 1px solid #ddd; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; } @@ -5572,7 +5572,7 @@ button.list-group-item-danger.active:focus { .panel > .panel-body + .table-responsive, .panel > .table + .panel-body, .panel > .table-responsive + .panel-body { - border-top: 1px solid #dddddd; + border-top: 1px solid #ddd; } .panel > .table > tbody:first-child > tr:first-child th, .panel > .table > tbody:first-child > tr:first-child td { @@ -5649,37 +5649,37 @@ button.list-group-item-danger.active:focus { } .panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid #dddddd; + border-top: 1px solid #ddd; } .panel-group .panel-footer { border-top: 0; } .panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #dddddd; + border-bottom: 1px solid #ddd; } .panel-default { - border-color: #dddddd; + border-color: #ddd; } .panel-default > .panel-heading { - color: #6b6d70; + color: #6B6D70; background-color: #f5f5f5; - border-color: #dddddd; + border-color: #ddd; } .panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #dddddd; + border-top-color: #ddd; } .panel-default > .panel-heading .badge { color: #f5f5f5; - background-color: #6b6d70; + background-color: #6B6D70; } .panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #dddddd; + border-bottom-color: #ddd; } .panel-primary { border-color: #21b799; } .panel-primary > .panel-heading { - color: #ffffff; + color: #fff; background-color: #21b799; border-color: #21b799; } @@ -5688,7 +5688,7 @@ button.list-group-item-danger.active:focus { } .panel-primary > .panel-heading .badge { color: #21b799; - background-color: #ffffff; + background-color: #fff; } .panel-primary > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #21b799; @@ -5818,14 +5818,14 @@ button.list-group-item-danger.active:focus { font-size: 22.5px; font-weight: bold; line-height: 1; - color: #000000; - text-shadow: 0 1px 0 #ffffff; + color: #000; + text-shadow: 0 1px 0 #fff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover, .close:focus { - color: #000000; + color: #000; text-decoration: none; cursor: pointer; opacity: 0.5; @@ -5880,8 +5880,8 @@ button.close { } .modal-content { position: relative; - background-color: #ffffff; - border: 1px solid #999999; + background-color: #fff; + border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); @@ -5896,7 +5896,7 @@ button.close { bottom: 0; left: 0; z-index: 1040; - background-color: #000000; + background-color: #000; } .modal-backdrop.fade { opacity: 0; @@ -6007,9 +6007,9 @@ button.close { .tooltip-inner { max-width: 200px; padding: 3px 8px; - color: #ffffff; + color: #fff; text-align: center; - background-color: #000000; + background-color: #000; border-radius: 4px; } .tooltip-arrow { @@ -6024,56 +6024,56 @@ button.close { left: 50%; margin-left: -5px; border-width: 5px 5px 0; - border-top-color: #000000; + border-top-color: #000; } .tooltip.top-left .tooltip-arrow { bottom: 0; right: 5px; margin-bottom: -5px; border-width: 5px 5px 0; - border-top-color: #000000; + border-top-color: #000; } .tooltip.top-right .tooltip-arrow { bottom: 0; left: 5px; margin-bottom: -5px; border-width: 5px 5px 0; - border-top-color: #000000; + border-top-color: #000; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-width: 5px 5px 5px 0; - border-right-color: #000000; + border-right-color: #000; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-width: 5px 0 5px 5px; - border-left-color: #000000; + border-left-color: #000; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-width: 0 5px 5px; - border-bottom-color: #000000; + border-bottom-color: #000; } .tooltip.bottom-left .tooltip-arrow { top: 0; right: 5px; margin-top: -5px; border-width: 0 5px 5px; - border-bottom-color: #000000; + border-bottom-color: #000; } .tooltip.bottom-right .tooltip-arrow { top: 0; left: 5px; margin-top: -5px; border-width: 0 5px 5px; - border-bottom-color: #000000; + border-bottom-color: #000; } .popover { position: absolute; @@ -6099,9 +6099,9 @@ button.close { word-spacing: normal; word-wrap: normal; font-size: 15px; - background-color: #ffffff; + background-color: #fff; background-clip: padding-box; - border: 1px solid #cccccc; + border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); @@ -6159,7 +6159,7 @@ button.close { bottom: 1px; margin-left: -10px; border-bottom-width: 0; - border-top-color: #ffffff; + border-top-color: #fff; } .popover.right > .arrow { top: 50%; @@ -6174,7 +6174,7 @@ button.close { left: 1px; bottom: -10px; border-left-width: 0; - border-right-color: #ffffff; + border-right-color: #fff; } .popover.bottom > .arrow { left: 50%; @@ -6189,7 +6189,7 @@ button.close { top: 1px; margin-left: -10px; border-top-width: 0; - border-bottom-color: #ffffff; + border-bottom-color: #fff; } .popover.left > .arrow { top: 50%; @@ -6203,7 +6203,7 @@ button.close { content: " "; right: 1px; border-right-width: 0; - border-left-color: #ffffff; + border-left-color: #fff; bottom: -10px; } .carousel { @@ -6297,7 +6297,7 @@ button.close { opacity: 0.5; filter: alpha(opacity=50); font-size: 20px; - color: #ffffff; + color: #fff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0); @@ -6321,7 +6321,7 @@ button.close { .carousel-control:hover, .carousel-control:focus { outline: 0; - color: #ffffff; + color: #fff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); @@ -6376,7 +6376,7 @@ button.close { height: 10px; margin: 1px; text-indent: -999px; - border: 1px solid #ffffff; + border: 1px solid #fff; border-radius: 10px; cursor: pointer; background-color: #000 \9; @@ -6386,7 +6386,7 @@ button.close { margin: 0; width: 12px; height: 12px; - background-color: #ffffff; + background-color: #fff; } .carousel-caption { position: absolute; @@ -6396,7 +6396,7 @@ button.close { z-index: 10; padding-top: 20px; padding-bottom: 20px; - color: #ffffff; + color: #fff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); } @@ -9203,7 +9203,7 @@ main.has_code_col:after, } @media screen and (min-width: 768px) { .o-doc-dropdown.open { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o-doc-dropdown.open .dropdown-toggle { @@ -9218,7 +9218,7 @@ main.has_code_col:after, border-radius: 0; text-align: left; min-width: 100%; - background-color: #fcfcfc; + background-color: #FCFCFC; padding-bottom: 12.5px; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } @@ -9253,7 +9253,7 @@ main.has_code_col:after, } @media screen and (min-width: 768px) { .o-doc-dropdown.open .dropdown-menu { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o-doc-dropdown.o_dropdown_mobile_nav { @@ -9569,7 +9569,7 @@ header { position: relative; } #wrap > .container.index { - background-color: #f9f9f9; + background-color: #F9F9F9; width: 100%; position: relative; } @@ -9651,8 +9651,8 @@ main aside { } } main article.doc-body { - background: #ffffff; - border-left: 1px solid #f2f2f2; + background: #fff; + border-left: 1px solid #F2F2F2; padding: 15px 30px; } @media (min-width: 992px) { @@ -9931,8 +9931,8 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header > .o_main_header_main > .o_primary_nav.o_sub_opened:before { visibility: visible; - background: #fcfcfc; - box-shadow: 0 1px 0 #f2f2f2; + background: #FCFCFC; + box-shadow: 0 1px 0 #F2F2F2; -webkit-transition: background 500ms cubic-bezier(0.55, 0, 0.1, 1) 0ms, visibility 0ms linear 0s, box-shadow 500ms linear 0ms; -o-transition: background 500ms cubic-bezier(0.55, 0, 0.1, 1) 0ms, visibility 0ms linear 0s, box-shadow 500ms linear 0ms; transition: background 500ms cubic-bezier(0.55, 0, 0.1, 1) 0ms, visibility 0ms linear 0s, box-shadow 500ms linear 0ms; @@ -9983,12 +9983,12 @@ article.doc-toc .toctree-wrapper > ul > li > span { transform: rotate(-45deg); } .o_main_header > .o_main_header_main > .o_primary_nav .dropdown.open > a { - color: #9e588b !important; + color: #9E588B !important; font-weight: 600; } .o_main_header > .o_main_header_main > .o_primary_nav .dropdown.open > a::before, .o_main_header > .o_main_header_main > .o_primary_nav .dropdown.open > a::after { - background-color: #9e588b !important; + background-color: #9E588B !important; box-shadow: 0 1px 1px rgba(158, 88, 139, 0.1); right: 3.53553391px; } @@ -10104,7 +10104,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { padding-top: 10px; } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div + div { - border-left: 1px solid #f2f2f2; + border-left: 1px solid #F2F2F2; } } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div ul { @@ -10221,12 +10221,12 @@ article.doc-toc .toctree-wrapper > ul > li > span { .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_website_apps a:hover, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_website_apps a:focus, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_website_apps .o_nav_app_family { - color: #5b899e; + color: #5B899E; } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_sale_apps a:hover, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_sale_apps a:focus, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_sale_apps .o_nav_app_family { - color: #e46f78; + color: #E46F78; } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_sale_apps .o_nav_app_family > span { background-position: -60px 50%; @@ -10234,7 +10234,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_operation_apps a:hover, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_operation_apps a:focus, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_operation_apps .o_nav_app_family { - color: #5c5b80; + color: #5C5B80; } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_operation_apps .o_nav_app_family > span { background-position: -120px 50%; @@ -10242,7 +10242,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_productivity_apps a:hover, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_productivity_apps a:focus, .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_productivity_apps .o_nav_app_family { - color: #d5653e; + color: #D5653E; } .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav > .container > .row > div.o_productivity_apps .o_nav_app_family > span { background-position: -181px 50%; @@ -10258,7 +10258,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { display: block; height: 50px; line-height: 50px; - border-top: 1px solid #f2f2f2; + border-top: 1px solid #F2F2F2; text-align: center; font-size: 12px; font-weight: 600; @@ -10266,7 +10266,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { @media (min-width: 768px) { .o_main_header > .o_main_header_main > .o_primary_nav .o_secondary_nav { display: block; - background-color: #fcfcfc; + background-color: #FCFCFC; visibility: hidden; z-index: -2; -webkit-transform: translate(0, -115%); @@ -10530,11 +10530,11 @@ article.doc-toc .toctree-wrapper > ul > li > span { box-shadow: 0 1px 1px rgba(255, 255, 255, 0.1); } .o_main_header > .o_main_header_main > .o_header_buttons .dropdown.open { - background-color: #fcfcfc; + background-color: #FCFCFC; color: #5a5f68; } .o_main_header > .o_main_header_main > .o_header_buttons .dropdown.open .dropdown-menu { - background-color: #fcfcfc; + background-color: #FCFCFC; margin-top: 0; border: none; border-radius: 0; @@ -10560,7 +10560,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header.o_scrolled:not(.o_transparent_blocked), .o_main_header.o_sub_opened { - background-color: #fcfcfc; + background-color: #FCFCFC; color: #5a5f68; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } @@ -10584,7 +10584,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { box-shadow: 0 1px 1px rgba(90, 95, 104, 0.1); } .o_main_header.o_scrolled .o_sub_nav { - background: #fcfcfc; + background: #FCFCFC; } .o_main_header.o_scrolled .o_sub_nav > .container .navbar-header > span { -webkit-transform: translate(0, 0); @@ -10603,7 +10603,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { position: relative; height: auto; min-height: 50px; - background-color: #fcfcfc; + background-color: #FCFCFC; color: #5a5f68; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } @@ -10648,7 +10648,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_header_buttons { float: none; - background-color: #25252d; + background-color: #25252D; padding: 0 15px; box-sizing: content-box; margin: 50px -15px 0; @@ -10659,7 +10659,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_header_buttons > * { overflow: visible!important; - color: #fcfcfc; + color: #FCFCFC; float: none; display: inline; } @@ -10667,7 +10667,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { display: initial!important; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_header_buttons > * .dropdown-toggle { - color: #fcfcfc !important; + color: #FCFCFC !important; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_header_buttons > * .dropdown-menu { position: relative; @@ -10683,7 +10683,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { display: block; margin-bottom: 5px; padding: 10px; - color: #fcfcfc !important; + color: #FCFCFC !important; font-size: 0.8em; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_header_buttons > * .dropdown-menu > li > a:hover { @@ -10691,7 +10691,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav { display: block; - background-color: #25252d; + background-color: #25252D; color: white; margin: 0 -15px 0; padding: 0; @@ -10704,7 +10704,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { color: white; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav li { - border: 0 solid #33343d; + border: 0 solid #33343D; border-width: 1px 5px 0; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav > li { @@ -10750,7 +10750,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav > li.dropdown > .o_secondary_nav > .container > .row > div > .o_nav_app_family { height: 50px; line-height: 50px; - background-color: #33343d; + background-color: #33343D; } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav > li.dropdown > .o_secondary_nav > .container > .row > div > .o_nav_app_family > * { display: none; @@ -10760,7 +10760,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { } .o_main_header.o_mobile_menu_opened > .o_main_header_main > .o_primary_nav > li.dropdown > .o_secondary_nav > .o_store_link { position: relative; - border: 0 solid #33343d; + border: 0 solid #33343D; border-width: 14px 0 0; padding-top: 14px; line-height: 1.5; @@ -10772,7 +10772,7 @@ article.doc-toc .toctree-wrapper > ul > li > span { width: 100%; height: 20px; margin-bottom: -5px; - background-color: #33343d; + background-color: #33343D; } } body > footer { @@ -10781,7 +10781,7 @@ body > footer { width: 100%; height: auto; min-height: 300px; - background-color: #282f33; + background-color: #282F33; color: #888888; z-index: 1; } @@ -10809,14 +10809,14 @@ body > footer a:focus { color: white; } body > footer .dropdown-menu a { - color: #6b6d70; + color: #6B6D70; } body > footer .dropdown-menu a:hover, body > footer .dropdown-menu a:focus { color: #5f6063; } body > footer .dropdown-menu a:active { - color: #ffffff; + color: #fff; } body > footer .divider { margin: 10px 0; @@ -11011,7 +11011,7 @@ body > footer .o_footer_bottom .social-links .fa { } .navbar-aside ul ul { max-height: 0; - background-color: #f2f2f2; + background-color: #F2F2F2; padding-left: 15px; overflow: hidden; -webkit-transition: max-height 0.3s cubic-bezier(0.55, 0, 0.1, 1); @@ -11021,7 +11021,7 @@ body > footer .o_footer_bottom .social-links .fa { .navbar-aside li.active, .navbar-aside li.active:hover, .navbar-aside li.active:focus { - border-color: #f2f2f2; + border-color: #F2F2F2; background: transparent; } .navbar-aside li.active > a, @@ -11033,7 +11033,7 @@ body > footer .o_footer_bottom .social-links .fa { max-height: 1000px; } .navbar-aside > ul > li { - border-bottom: 1px solid #f2f2f2; + border-bottom: 1px solid #F2F2F2; background: white; } .navbar-aside > ul > li > a { @@ -11263,8 +11263,8 @@ body > footer .o_footer_bottom .social-links .fa { } } .o_main_header.o_mobile_menu_opened .mdi-navigation-menu { - background-color: #282f33; - color: #f2f2f2; + background-color: #282F33; + color: #F2F2F2; } @media screen and (min-width: 768px) { .o_main_header > .o_sub_nav #o_sub-menu .o_breadcrumb { @@ -11361,13 +11361,13 @@ body > footer .o_footer_bottom .social-links .fa { padding: 0 15px; margin: 0; height: 38px; - background-color: #f2f2f2; + background-color: #F2F2F2; } .o_main_header > .o_sub_nav .navbar-toggle span { line-height: 38px; } .o_main_header > .o_sub_nav .navbar-toggle.collapsed { - background-color: #fcfcfc; + background-color: #FCFCFC; } .o_main_header > .o_sub_nav .collapse .nav { margin-right: 0; @@ -11413,7 +11413,7 @@ body > footer .o_footer_bottom .social-links .fa { } @media screen and (min-width: 768px) { .o_main_header > .o_sub_nav .collapse .nav > li.dropdown.open { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o_main_header > .o_sub_nav .collapse .nav > li.dropdown.open .dropdown-toggle { @@ -11428,7 +11428,7 @@ body > footer .o_footer_bottom .social-links .fa { border-radius: 0; text-align: left; min-width: 100%; - background-color: #fcfcfc; + background-color: #FCFCFC; padding-bottom: 12.5px; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } @@ -11463,7 +11463,7 @@ body > footer .o_footer_bottom .social-links .fa { } @media screen and (min-width: 768px) { .o_main_header > .o_sub_nav .collapse .nav > li.dropdown.open .dropdown-menu { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o_main_header > .o_sub_nav .collapse .nav > li.dropdown.o_dropdown_mobile_nav { @@ -11526,7 +11526,7 @@ body > footer .o_footer_bottom .social-links .fa { } @media screen and (min-width: 768px) { .o_main_header > .o_sub_nav li.dropdown.open { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o_main_header > .o_sub_nav li.dropdown.open .dropdown-toggle { @@ -11541,7 +11541,7 @@ body > footer .o_footer_bottom .social-links .fa { border-radius: 0; text-align: left; min-width: 100%; - background-color: #fcfcfc; + background-color: #FCFCFC; padding-bottom: 12.5px; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } @@ -11576,7 +11576,7 @@ body > footer .o_footer_bottom .social-links .fa { } @media screen and (min-width: 768px) { .o_main_header > .o_sub_nav li.dropdown.open .dropdown-menu { - background-color: #fcfcfc; + background-color: #FCFCFC; } } .o_main_header > .o_sub_nav li.dropdown.o_dropdown_mobile_nav { @@ -11660,7 +11660,7 @@ body > footer .o_footer_bottom .social-links .fa { #wrap { z-index: 1; position: relative; - background: #f9f9f9; + background: #F9F9F9; padding-bottom: 40px; } main { @@ -11669,7 +11669,7 @@ main { margin: -10px auto 0; display: block; border-radius: 2px; - background-color: #ffffff; + background-color: #fff; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17); } main.deep_hover:hover { @@ -11700,7 +11700,7 @@ main.index .card { overflow: hidden; margin-bottom: 20px; min-height: 200px; - background-color: #ffffff; + background-color: #fff; will-change: transform; box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.1), 0 2px 2px 0 rgba(0, 0, 0, 0.05); -webkit-transform: scale3d(0, 0, 0) translate3d(50px, 0, 0); @@ -11808,11 +11808,11 @@ main.index.animating .card { } .card-img { background: #75526b; - background: -webkit-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -moz-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -ms-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -o-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: linear-gradient(99deg, #875a7b 10%, #62495b 90%); + background: -webkit-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -moz-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -ms-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -o-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: linear-gradient(99deg, #875A7B 10%, #62495B 90%); position: absolute; top: 0; left: auto; @@ -11832,11 +11832,11 @@ main.index.animating .card { overflow: hidden; margin: 0; background: #75526b; - background: -webkit-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -moz-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -ms-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: -o-linear-gradient(99deg, #875a7b 10%, #62495b 90%); - background: linear-gradient(99deg, #875a7b 10%, #62495b 90%); + background: -webkit-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -moz-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -ms-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: -o-linear-gradient(99deg, #875A7B 10%, #62495B 90%); + background: linear-gradient(99deg, #875A7B 10%, #62495B 90%); -webkit-animation: fadeIn 1s; -o-animation: fadeIn 1s; animation: fadeIn 1s; @@ -11974,7 +11974,7 @@ main.index.animating .card { } } .card.top.has_banner { - background: #282f33; + background: #282F33; } .card.top.has_banner:before { display: none; @@ -12047,7 +12047,7 @@ main .alert > ul { } main .alert > .alert-title, main .alert > h3 { - color: #4b9eb6; + color: #4B9EB6; } main .alert > .alert-title:before, main .alert > h3:before { @@ -12095,7 +12095,7 @@ main .alert.alert-success { } main .alert.alert-success > .alert-title, main .alert.alert-success > h3 { - color: #50af51; + color: #50AF51; } main .alert.alert-success > .alert-title:before, main .alert.alert-success > h3:before { @@ -12111,7 +12111,7 @@ main .alert.alert-info > .alert-title, main .alert.tip > .alert-title, main .alert.alert-info > h3, main .alert.tip > h3 { - color: #4b9eb6; + color: #4B9EB6; } main .alert.alert-info > .alert-title:before, main .alert.tip > .alert-title:before, @@ -12129,7 +12129,7 @@ main .alert.alert-warning > .alert-title, main .alert.warning > .alert-title, main .alert.alert-warning > h3, main .alert.warning > h3 { - color: #f0ad4e; + color: #F0AD4E; } main .alert.alert-warning > .alert-title:before, main .alert.warning > .alert-title:before, @@ -12144,7 +12144,7 @@ main .alert.alert-danger { } main .alert.alert-danger > .alert-title, main .alert.alert-danger > h3 { - color: #d9534f; + color: #D9534F; } main .alert.alert-danger > .alert-title:before, main .alert.alert-danger > h3:before { @@ -12157,7 +12157,7 @@ main .alert.alert-exercise { } main .alert.alert-exercise > .alert-title, main .alert.alert-exercise > h3 { - color: #938e94; + color: #938E94; } main .alert.alert-exercise > .alert-title:before, main .alert.alert-exercise > h3:before { @@ -12179,7 +12179,7 @@ main .alert.alert-go_to a { } main .alert.alert-go_to > .alert-title, main .alert.alert-go_to > h3 { - color: #4b9eb6; + color: #4B9EB6; } main .alert.alert-go_to > .alert-title:before, main .alert.alert-go_to > h3:before { @@ -12214,6 +12214,7 @@ span.menuselection { } dt { margin: .5em 0 .3em; + font-weight: normal; } blockquote { font-family: Georgia, "Times New Roman", Times, serif; @@ -12283,6 +12284,8 @@ table, .table { font-size: 0.9em; } +.code-namespace, +.code-module, .code-class, .code-staticmethod, .code-classmethod, @@ -12293,6 +12296,8 @@ table, padding-left: 20px; margin-bottom: 2em; } +.code-namespace > h6, +.code-module > h6, .code-class > h6, .code-staticmethod > h6, .code-classmethod > h6, @@ -12303,6 +12308,8 @@ table, margin-left: -20px; margin-bottom: 0.3em; } +.code-namespace > h6 .viewcode-link, +.code-module > h6 .viewcode-link, .code-class > h6 .viewcode-link, .code-staticmethod > h6 .viewcode-link, .code-classmethod > h6 .viewcode-link, @@ -12313,6 +12320,8 @@ table, display: none; float: right; } +.code-namespace > h6:hover .viewcode-link, +.code-module > h6:hover .viewcode-link, .code-class > h6:hover .viewcode-link, .code-staticmethod > h6:hover .viewcode-link, .code-classmethod > h6:hover .viewcode-link, @@ -12322,6 +12331,8 @@ table, .code-data > h6:hover .viewcode-link { display: inline; } +.code-namespace p, +.code-module p, .code-class p, .code-staticmethod p, .code-classmethod p, @@ -12340,7 +12351,7 @@ table, } } article.doc-body { - background: #ffffff; + background: #fff; } article.doc-body section.doc-content:first-of-type > p:first-child { margin-bottom: 21px; diff --git a/doc/_extensions/odoo_ext/static/style.less b/doc/_extensions/odoo_ext/static/style.less index 5fd9fe17804..89d287d487e 100644 --- a/doc/_extensions/odoo_ext/static/style.less +++ b/doc/_extensions/odoo_ext/static/style.less @@ -621,7 +621,7 @@ span.menuselection{ background:transparent; } -dt { margin: .5em 0 .3em;} +dt { margin: .5em 0 .3em; font-weight: normal; } blockquote { font-family: @font-family-serif; @@ -700,7 +700,7 @@ table, .table { font-size: 0.9em; } -.code-class, +.code-namespace, .code-module, .code-class, .code-staticmethod, .code-classmethod, .code-method, .code-function, .code-attribute, .code-data { // indents *all* content diff --git a/doc/_extensions/pyjsparser/LICENSE b/doc/_extensions/pyjsparser/LICENSE new file mode 100644 index 00000000000..5f5aff9f636 --- /dev/null +++ b/doc/_extensions/pyjsparser/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Piotr Dabkowski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/doc/_extensions/pyjsparser/README b/doc/_extensions/pyjsparser/README new file mode 100644 index 00000000000..574593bbf2e --- /dev/null +++ b/doc/_extensions/pyjsparser/README @@ -0,0 +1,4 @@ +Vendoring of pyjsparser to add comments support as we need them for autojsdoc. + +Alternative: use https://github.com/Kronuz/esprima-python instead, seems to +support comments though may be attaching them differently. diff --git a/doc/_extensions/pyjsparser/__init__.py b/doc/_extensions/pyjsparser/__init__.py new file mode 100644 index 00000000000..19036bddbf1 --- /dev/null +++ b/doc/_extensions/pyjsparser/__init__.py @@ -0,0 +1,4 @@ +s__all__ = ['PyJsParser', 'parse', 'JsSyntaxError'] +__author__ = 'Piotr Dabkowski' +__version__ = '2.2.0' +from .parser import PyJsParser, parse, JsSyntaxError diff --git a/doc/_extensions/pyjsparser/parser.py b/doc/_extensions/pyjsparser/parser.py new file mode 100644 index 00000000000..78ebe14e6ec --- /dev/null +++ b/doc/_extensions/pyjsparser/parser.py @@ -0,0 +1,2928 @@ +# The MIT License +# +# Copyright 2014, 2015 Piotr Dabkowski +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the 'Software'), +# to deal in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +from __future__ import unicode_literals +from .pyjsparserdata import * +from .std_nodes import * +from pprint import pprint +import sys + +__all__ = ['PyJsParser', 'parse', 'ENABLE_JS2PY_ERRORS', 'ENABLE_PYIMPORT', 'JsSyntaxError'] +REGEXP_SPECIAL_SINGLE = ('\\', '^', '$', '*', '+', '?', '.', '[', ']', '(', ')', '{', '{', '|', '-') +ENABLE_PYIMPORT = False +ENABLE_JS2PY_ERRORS = False + +PY3 = sys.version_info >= (3,0) + +if PY3: + basestring = str + long = int + xrange = range + unicode = str + +ESPRIMA_VERSION = '2.2.0' +DEBUG = False +# Small naming convention changes +# len -> leng +# id -> d +# type -> typ +# str -> st +true = True +false = False +null = None + + +class PyJsParser: + """ Usage: + parser = PyJsParser() + parser.parse('var JavaScriptCode = 5.1') + """ + + def __init__(self): + self.clean() + + def test(self, code): + pprint(self.parse(code)) + + def clean(self): + self.strict = None + self.sourceType = None + self.index = 0 + self.lineNumber = 1 + self.lineStart = 0 + self.hasLineTerminator = None + self.lastIndex = None + self.lastLineNumber = None + self.lastLineStart = None + self.startIndex = None + self.startLineNumber = None + self.startLineStart = None + self.scanning = None + self.lookahead = None + self.state = None + self.extra = None + self.isBindingElement = None + self.isAssignmentTarget = None + self.firstCoverInitializedNameError = None + + # 7.4 Comments + + def skipSingleLineComment(self, offset): + start = self.index - offset; + while self.index < self.length: + ch = self.source[self.index]; + self.index += 1 + if isLineTerminator(ch): + if (ord(ch) == 13 and ord(self.source[self.index]) == 10): + self.index += 1 + self.lineNumber += 1 + self.hasLineTerminator = True + self.lineStart = self.index + return { + 'type': 'Line', + 'value': self.source[start + offset:self.index-2], + 'leading': True, + 'trailing': False, + 'loc': None, + } + + def skipMultiLineComment(self): + start = self.index + while self.index < self.length: + ch = ord(self.source[self.index]) + if isLineTerminator(ch): + if (ch == 0x0D and ord(self.source[self.index + 1]) == 0x0A): + self.index += 1 + self.lineNumber += 1 + self.index += 1 + self.hasLineTerminator = True + self.lineStart = self.index + elif ch == 0x2A: + # Block comment ends with '*/'. + if ord(self.source[self.index + 1]) == 0x2F: + self.index += 2 + return { + 'type': 'Block', + 'value': self.source[start:self.index-2], + 'leading': True, + 'trailing': False, + 'loc': None, + } + self.index += 1 + else: + self.index += 1 + self.tolerateUnexpectedToken() + + def skipComment(self): + self.hasLineTerminator = False + startIndex = self.index + start = (self.index == 0) + comments = [] + while self.index < self.length: + ch = ord(self.source[self.index]) + if isWhiteSpace(ch): + self.index += 1 + elif isLineTerminator(ch): + self.hasLineTerminator = True + self.index += 1 + if (ch == 0x0D and ord(self.source[self.index]) == 0x0A): + self.index += 1 + self.lineNumber += 1 + self.lineStart = self.index + start = True + elif (ch == 0x2F): # U+002F is '/' + ch = ord(self.source[self.index + 1]) + if (ch == 0x2F): + self.index += 2 + comments.append(self.skipSingleLineComment(2)) + start = True + elif (ch == 0x2A): # U+002A is '*' + self.index += 2 + comments.append(self.skipMultiLineComment()) + else: + break + elif (start and ch == 0x2D): # U+002D is '-' + # U+003E is '>' + if (ord(self.source[self.index + 1]) == 0x2D) and (ord(self.source[self.index + 2]) == 0x3E): + # '-->' is a single-line comment + self.index += 3 + self.skipSingleLineComment(3) + else: + break + elif (ch == 0x3C): # U+003C is '<' + if self.source[self.index + 1: self.index + 4] == '!--': + # - - - -

-
-
-
- -:: - - // test/demo.js - test('templates', {templates: true}, function (instance) { - var s = instance.web.qweb.render('DemoTemplate'); - var texts = $(s).find('p').map(function () { - return $(this).text(); - }).get(); - - deepEqual(texts, ['0', '1', '2', '3', '4']); - }); - -Asynchronous cases ------------------- - -The test case examples so far are all synchronous, they execute from -the first to the last line and once the last line has executed the -test is done. But the web client is full of :ref:`asynchronous code -`, and thus test cases need to be async-aware. - -This is done by returning a :class:`deferred ` from the -case callback:: - - // test/demo.js - test('asynchronous', { - asserts: 1 - }, function () { - var d = $.Deferred(); - setTimeout(function () { - ok(true); - d.resolve(); - }, 100); - return d; - }); - -This example also uses the :class:`options parameter ` -to specify the number of assertions the case should expect, if less or -more assertions are specified the case will count as failed. - -Asynchronous test cases *must* specify the number of assertions they -will run. This allows more easily catching situations where e.g. the -test architecture was not warned about asynchronous operations. - -.. note:: - - Asynchronous test cases also have a 2 seconds timeout: if the test - does not finish within 2 seconds, it will be considered - failed. This pretty much always means the test will not - resolve. This timeout *only* applies to the test itself, not to - the setup and teardown processes. - -.. note:: - - If the returned deferred is rejected, the test will be failed - unless :attr:`~TestOptions.fail_on_rejection` is set to - ``false``. - -RPC ---- - -An important subset of asynchronous test cases is test cases which -need to perform (and chain, to an extent) RPC calls. - -.. note:: - - Because they are a subset of asynchronous cases, RPC cases must - also provide a valid :attr:`assertions count - `. - -To enable mock RPC, set the :attr:`rpc option ` to -``mock``. This will add a third parameter to the test case callback: - -.. function:: mock(rpc_spec, handler) - - Can be used in two different ways depending on the shape of the - first parameter: - - * If it matches the pattern ``model:method`` (if it contains a - colon, essentially) the call will set up the mocking of an RPC - call straight to the Odoo server (through XMLRPC) as - performed via e.g. :func:`odoo.web.Model.call`. - - In that case, ``handler`` should be a function taking two - arguments ``args`` and ``kwargs``, matching the corresponding - arguments on the server side and should simply return the value - as if it were returned by the Python XMLRPC handler:: - - test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { - // set up mocking - mock('people.famous:name_search', function (args, kwargs) { - strictEqual(kwargs.name, 'bob'); - return [ - [1, "Microsoft Bob"], - [2, "Bob the Builder"], - [3, "Silent Bob"] - ]; - }); - - // actual test code - return new instance.web.Model('people.famous') - .call('name_search', {name: 'bob'}).then(function (result) { - strictEqual(result.length, 3, "shoud return 3 people"); - strictEqual(result[0][1], "Microsoft Bob", - "the most famous bob should be Microsoft Bob"); - }); - }); - - * Otherwise, if it matches an absolute path (e.g. ``/a/b/c``) it - will mock a JSON-RPC call to a web client controller, such as - ``/web/webclient/translations``. In that case, the handler takes - a single ``params`` argument holding all of the parameters - provided over JSON-RPC. - - As previously, the handler should simply return the result value - as if returned by the original JSON-RPC handler:: - - test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) { - var fetched_dbs = false, fetched_langs = false; - mock('/web/database/get_list', function () { - fetched_dbs = true; - return ['foo', 'bar', 'baz']; - }); - mock('/web/session/get_lang_list', function () { - fetched_langs = true; - return [['vo_IS', 'Hopelandic / Vonlenska']]; - }); - - // widget needs that or it blows up - instance.webclient = {toggle_bars: odoo.testing.noop}; - var dbm = new instance.web.DatabaseManager({}); - return dbm.appendTo($s).then(function () { - ok(fetched_dbs, "should have fetched databases"); - ok(fetched_langs, "should have fetched languages"); - deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); - }); - }); - -.. note:: - - Mock handlers can contain assertions, these assertions should be - part of the assertions count (and if multiple calls are made to a - handler containing assertions, it multiplies the effective number - of assertions). - -Testing API ------------ - -.. function:: odoo.testing.section(name[, options], body) - - A test section, serves as shared namespace for related tests (for - constants or values to only set up once). The ``body`` function - should contain the tests themselves. - - Note that the order in which tests are run is essentially - undefined, do *not* rely on it. - - :param String name: - :param TestOptions options: - :param body: - :type body: Function<:func:`~odoo.testing.case`, void> - -.. function:: odoo.testing.case(name[, options], callback) - - Registers a test case callback in the test runner, the callback - will only be run once the runner is started (or maybe not at all, - if the test is filtered out). - - :param String name: - :param TestOptions options: - :param callback: - :type callback: Function> - -.. class:: TestOptions - - the various options which can be passed to - :func:`~odoo.testing.section` or - :func:`~odoo.testing.case`. Except for - :attr:`~TestOptions.setup` and - :attr:`~TestOptions.teardown`, an option on - :func:`~odoo.testing.case` will overwrite the corresponding - option on :func:`~odoo.testing.section` so - e.g. :attr:`~TestOptions.rpc` can be set for a - :func:`~odoo.testing.section` and then differently set for - some :func:`~odoo.testing.case` of that - :func:`~odoo.testing.section` - - .. attribute:: TestOptions.asserts - - An integer, the number of assertions which should run during a - normal execution of the test. Mandatory for asynchronous tests. - - .. attribute:: TestOptions.setup - - Test case setup, run right before each test case. A section's - :func:`~TestOptions.setup` is run before the case's own, if - both are specified. - - .. attribute:: TestOptions.teardown - - Test case teardown, a case's :func:`~TestOptions.teardown` - is run before the corresponding section if both are present. - - .. attribute:: TestOptions.fail_on_rejection - - If the test is asynchronous and its resulting promise is - rejected, fail the test. Defaults to ``true``, set to - ``false`` to not fail the test in case of rejection:: - - // test/demo.js - test('unfail rejection', { - asserts: 1, - fail_on_rejection: false - }, function () { - var d = $.Deferred(); - setTimeout(function () { - ok(true); - d.reject(); - }, 100); - return d; - }); - - .. attribute:: TestOptions.rpc - - RPC method to use during tests, one of ``"mock"`` or - ``"rpc"``. Any other value will disable RPC for the test (if - they were enabled by the suite for instance). - - .. attribute:: TestOptions.templates - - Whether the current module (and its dependencies)'s templates - should be loaded into QWeb before starting the test. A - boolean, ``false`` by default. - -The test runner can also use two global configuration values set -directly on the ``window`` object: - -* ``oe_all_dependencies`` is an ``Array`` of all modules with a web - component, ordered by dependency (for a module ``A`` with - dependencies ``A'``, any module of ``A'`` must come before ``A`` in - the array) - -Running through Python ----------------------- - -The web client includes the means to run these tests on the -command-line (or in a CI system), but while actually running it is -pretty simple the setup of the pre-requisite parts has some -complexities. - -#. Install PhantomJS_. It is a headless - browser which allows automating running and testing web - pages. QUnitSuite_ uses it to actually run the qunit_ test suite. - - The PhantomJS_ website provides pre-built binaries for some - platforms, and your OS's package management probably provides it as - well. - - If you're building PhantomJS_ from source, I recommend preparing - for some knitting time as it's not exactly fast (it needs to - compile both `Qt `_ and `Webkit - `_, both being pretty big projects). - - .. note:: - - Because PhantomJS_ is webkit-based, it will not be able to test - if Firefox, Opera or Internet Explorer can correctly run the - test suite (and it is only an approximation for Safari and - Chrome). It is therefore recommended to *also* run the test - suites in actual browsers once in a while. - - .. note:: - - The version of PhantomJS_ this was build through is 1.7, - previous versions *should* work but are not actually supported - (and tend to just segfault when something goes wrong in - PhantomJS_ itself so they're a pain to debug). - -#. Install a new database with all relevant modules (all modules with - a web component at least), then restart the server - - .. note:: - - For some tests, a source database needs to be duplicated. This - operation requires that there be no connection to the database - being duplicated, but Odoo doesn't currently break - existing/outstanding connections, so restarting the server is - the simplest way to ensure everything is in the right state. - -#. Launch ``oe run-tests -d $DATABASE -mweb`` with the correct - addons-path specified (and replacing ``$DATABASE`` by the source - database you created above) - - .. note:: - - If you leave out ``-mweb``, the runner will attempt to run all - the tests in all the modules, which may or may not work. - -If everything went correctly, you should now see a list of tests with -(hopefully) ``ok`` next to their names, closing with a report of the -number of tests run and the time it took: - -.. literalinclude:: test-report.txt - :language: text - -Congratulation, you have just performed a successful "offline" run of -the OpenERP Web test suite. - -.. note:: - - Note that this runs all the Python tests for the ``web`` module, - but all the web tests for all of Odoo. This can be surprising. - -.. _qunit: http://qunitjs.com/ - -.. _qunit assertions: http://api.qunitjs.com/category/assert/ - -.. _QUnitSuite: http://pypi.python.org/pypi/QUnitSuite/ - -.. _PhantomJS: http://phantomjs.org/ - -.. [#eventsdelegation] not all DOM events are compatible with events delegation - -.. [#terminal] - with a small twist: :py:meth:`sqlalchemy.orm.query.Query.group_by` is not - terminal, it returns a query which can still be altered. - +.. automodule:: * + :members: diff --git a/doc/requirements.txt b/doc/requirements.txt index e3059c049c9..6c2a5df88c2 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,4 @@ -sphinx==1.2.3 +sphinx>=1.2 mercurial==3.2.2 sphinx-patchqueue==0.4.0 +PyJSDoc==0.9.1 diff --git a/odoo/api.py b/odoo/api.py index 506c344da30..143f51bc31c 100644 --- a/odoo/api.py +++ b/odoo/api.py @@ -692,9 +692,9 @@ def call_kw(model, name, args, kwargs): class Environment(Mapping): """ An environment wraps data for ORM records: - - :attr:`cr`, the current database cursor; - - :attr:`uid`, the current user id; - - :attr:`context`, the current context dictionary. + - :attr:`cr`, the current database cursor; + - :attr:`uid`, the current user id; + - :attr:`context`, the current context dictionary. It provides access to the registry by implementing a mapping from model names to new api models. It also holds a cache for records, and a data From f1a85ba70a2412fb0d7bf789a758d8f2d2e86a02 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 18 Sep 2017 10:03:51 +0200 Subject: [PATCH 10/40] [FIX] *: fix a bunch of incorrectly documented docstring Fix a bunch of ill-documented/incomplete/incorrect method docs Without this, the automatic doc generation does not work. --- .../src/js/account_dashboard_setup_bar.js | 4 +- .../js/reconciliation/reconciliation_model.js | 62 +++++++++-------- .../barcodes/static/src/js/barcode_events.js | 7 +- addons/bus/static/src/js/bus.js | 13 ++-- addons/mail/static/src/js/activity.js | 2 +- addons/mail/static/src/js/chatter_composer.js | 6 +- addons/mail/static/src/js/document_viewer.js | 2 +- addons/mail/static/src/js/thread.js | 10 +-- addons/point_of_sale/static/src/js/models.js | 1 - addons/point_of_sale/static/src/js/popups.js | 30 ++++---- addons/portal/static/src/js/portal_chatter.js | 2 +- .../static/src/js/timesheet_plan.js | 2 +- addons/web/static/src/js/_deprecated/data.js | 1 + .../src/js/chrome/abstract_web_client.js | 11 +-- .../static/src/js/chrome/action_manager.js | 14 ++-- .../static/src/js/chrome/search_filters.js | 44 ++++++------ .../web/static/src/js/chrome/search_view.js | 6 +- .../web/static/src/js/chrome/view_manager.js | 5 +- addons/web/static/src/js/core/ajax.js | 2 +- addons/web/static/src/js/core/bus.js | 2 + addons/web/static/src/js/core/class.js | 57 ++++++++-------- addons/web/static/src/js/core/concurrency.js | 15 ++-- addons/web/static/src/js/core/dialog.js | 14 ++-- addons/web/static/src/js/core/dom.js | 8 ++- addons/web/static/src/js/core/mixins.js | 64 ++++++++++------- addons/web/static/src/js/core/pyeval.js | 10 +-- addons/web/static/src/js/core/session.js | 4 +- addons/web/static/src/js/core/translation.js | 10 +++ addons/web/static/src/js/core/utils.js | 12 ++-- addons/web/static/src/js/core/widget.js | 68 +++++++++---------- .../static/src/js/fields/abstract_field.js | 4 +- .../web/static/src/js/fields/basic_fields.js | 7 +- .../web/static/src/js/fields/field_utils.js | 8 +-- .../static/src/js/fields/special_fields.js | 8 +-- .../static/src/js/fields/upgrade_fields.js | 2 +- addons/web/static/src/js/services/config.js | 8 +++ addons/web/static/src/js/services/core.js | 10 ++- .../static/src/js/services/crash_manager.js | 16 ++--- .../static/src/js/services/data_manager.js | 8 ++- .../static/src/js/views/abstract_renderer.js | 3 + .../src/js/views/basic/basic_controller.js | 4 +- .../static/src/js/views/basic/basic_model.js | 27 ++++---- .../static/src/js/views/form/form_renderer.js | 2 +- .../src/js/views/kanban/kanban_record.js | 4 +- .../views/standalone_field_manager_mixin.js | 12 +++- .../web/static/src/js/widgets/date_picker.js | 8 +-- .../static/src/js/widgets/domain_selector.js | 12 ++-- .../src/js/widgets/domain_selector_dialog.js | 3 + .../static/src/js/widgets/iframe_widget.js | 3 +- .../static/src/js/editor/snippets.editor.js | 5 +- .../web_editor/static/src/js/widgets/ace.js | 4 +- .../static/src/js/widgets/widgets.js | 6 +- .../static/src/js/kanban_gauge.js | 13 ++-- addons/web_tour/static/src/js/tip.js | 5 +- addons/web_tour/static/src/js/tour_service.js | 10 +++ .../static/src/js/backend/dashboard.js | 3 + .../static/src/js/website_mail.js | 17 +++-- .../static/src/js/website_sale_rating.js | 26 ------- 58 files changed, 396 insertions(+), 330 deletions(-) delete mode 100644 addons/website_sale/static/src/js/website_sale_rating.js diff --git a/addons/account/static/src/js/account_dashboard_setup_bar.js b/addons/account/static/src/js/account_dashboard_setup_bar.js index acbc188ccd3..1af9416008f 100644 --- a/addons/account/static/src/js/account_dashboard_setup_bar.js +++ b/addons/account/static/src/js/account_dashboard_setup_bar.js @@ -124,7 +124,7 @@ var AccountSetupBarModel = KanbanModel.extend({ /** * @abstract - * @returns {Deferred -> Object} resolves to the required dashboard data + * @returns {Deferred} resolves to the required dashboard data */ _fetchDashboardData: function () { return $.when(this._rpc({ @@ -136,7 +136,7 @@ var AccountSetupBarModel = KanbanModel.extend({ /** * @private * @param {Deferred} super_def a deferred that resolves with a dataPoint id - * @returns {Deferred -> string} resolves to the dataPoint id + * @returns {Deferred} resolves to the dataPoint id */ _loadDashboard: function (super_def) { var self = this; diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index b136af9a4ed..8019a42688e 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -12,7 +12,7 @@ var _t = core._t; * Model use to fetch, format and update 'account.bank.statement' and * 'account.bank.statement.line' datas allowing reconciliation * - * The statement internal structure: + * The statement internal structure:: * * { * valuenow: integer @@ -25,7 +25,7 @@ var _t = core._t; * accounts: {id: code} * } * - * The internal structure of each line is: + * The internal structure of each line is:: * * { * balance: { @@ -114,7 +114,7 @@ var StatementModel = BasicModel.extend({ * account type * * @param {string} handle - * @param {number} mv_lines id + * @param {number} mv_line_id * @returns {Deferred} */ addProposition: function (handle, mv_line_id) { @@ -167,13 +167,15 @@ var StatementModel = BasicModel.extend({ * change the mode line ('inactive', 'match', 'create'), and fetch the new * matched lines or prepare to create a new line * - * 'match': display the matched lines, the user can select the lines to - * apply there as proposition - * 'create': display fields and quick create button to create a new - * proposition for the reconciliation + * ``match`` + * display the matched lines, the user can select the lines to apply + * there as proposition + * ``create`` + * display fields and quick create button to create a new proposition + * for the reconciliation * * @param {string} handle - * @param {string} mode + * @param {'inactive' | 'match' | 'create'} mode * @returns {Deferred} */ changeMode: function (handle, mode) { @@ -316,7 +318,7 @@ var StatementModel = BasicModel.extend({ /** * get the line data for this handle * - * @param {OdooEvent} event + * @param {Object} handle * @returns {Object} */ getLine: function (handle) { @@ -324,6 +326,7 @@ var StatementModel = BasicModel.extend({ }, /** * load data from + * * - 'account.bank.statement' fetch the line id and bank_statement_id info * - 'account.reconcile.model' fetch all reconcile model (for quick add) * - 'account.account' fetch all account code @@ -430,7 +433,7 @@ var StatementModel = BasicModel.extend({ * 'amount_type' * * @param {string} handle - * @param {integer} reconcile model id + * @param {integer} reconcileModelId * @returns {Deferred} */ quickCreateProposition: function (handle, reconcileModelId) { @@ -460,7 +463,7 @@ var StatementModel = BasicModel.extend({ * Remove a proposition and switch to an active mode ('create' or 'match') * * @param {string} handle - * @param {number} proposition id (move line id) + * @param {number} id (move line id) * @returns {Deferred} */ removeProposition: function (handle, id) { @@ -519,7 +522,7 @@ var StatementModel = BasicModel.extend({ * Then the total is recomputed to have 100%. * * @param {string} handle - * @param {number[]} context.statement_ids + * @param {*} values * @returns {Deferred} */ updateProposition: function (handle, values) { @@ -636,7 +639,7 @@ var StatementModel = BasicModel.extend({ * stop the editable proposition line and remove it if it's invalid then * compute the line * - * @see '_computeLine' + * See :func:`_computeLine` * * @private * @param {string} handle @@ -679,7 +682,7 @@ var StatementModel = BasicModel.extend({ * Check the taxes server side for each updated propositions with tax_id * * @private - * @param {Object} + * @param {Object} line * @returns {Deferred} */ _computeLine: function (line) { @@ -771,7 +774,7 @@ var StatementModel = BasicModel.extend({ * * @private * @param {string} handle - * @param {integer} reconcile model id + * @param {integer} reconcileModelId */ _computeReconcileModels: function (handle, reconcileModelId) { var line = this.getLine(handle); @@ -788,8 +791,7 @@ var StatementModel = BasicModel.extend({ * format a name_get into an object {id, display_name}, idempotent * * @private - * @param {Object|Array} data or name_get - * @param {Object|false} {id, display_name} + * @param {Object|Array} [value] data or name_get */ _formatNameGet: function (value) { return value ? (value.id ? value : {'id': value[0], 'display_name': value[1]}) : false; @@ -798,8 +800,8 @@ var StatementModel = BasicModel.extend({ * Format each propositions (amount, label, account_id) * * @private - * @param {Object} - * @param {Object[]} + * @param {Object} line + * @param {Object[]} props */ _formatLineProposition: function (line, props) { var self = this; @@ -818,7 +820,7 @@ var StatementModel = BasicModel.extend({ * @see '_computeLine' * * @private - * @param {Object[]} + * @param {Object[]} lines * @returns {Deferred} */ _formatLine: function (lines) { @@ -845,7 +847,7 @@ var StatementModel = BasicModel.extend({ * * @private * @param {string} handle - * @param {Object[]} + * @param {Object[]} mv_lines * @returns {Deferred} */ _formatMoveLine: function (handle, mv_lines) { @@ -869,8 +871,8 @@ var StatementModel = BasicModel.extend({ * base_amount with the decimal number from the currency * * @private - * @param {Object} - * @param {Object} + * @param {Object} line + * @param {Object} values * @returns {Object} */ _formatQuickCreate: function (line, values) { @@ -980,7 +982,7 @@ var StatementModel = BasicModel.extend({ * * @private * @param {object} line - * @param {object} proposition + * @param {object} prop * @returns {object} */ _formatToProcessReconciliation: function (line, prop) { @@ -1216,7 +1218,7 @@ var ManualModel = StatementModel.extend({ * * @override * @private - * @param {Object} + * @param {Object} line * @returns {Deferred} */ _computeLine: function (line) { @@ -1237,8 +1239,8 @@ var ManualModel = StatementModel.extend({ * @see '_computeLine' * * @private - * @param {string} 'customers', 'suppliers' or 'accounts' - * @param {Object} + * @param {'customers' | 'suppliers' | 'accounts'} type + * @param {Object} data * @returns {Deferred} */ _formatLine: function (type, data) { @@ -1264,8 +1266,8 @@ var ManualModel = StatementModel.extend({ * * @override * @private - * @param {Object} - * @param {Object} + * @param {Object} line + * @param {Object} props */ _formatLineProposition: function (line, props) { var self = this; @@ -1330,4 +1332,4 @@ return { StatementModel: StatementModel, ManualModel: ManualModel, }; -}); \ No newline at end of file +}); diff --git a/addons/barcodes/static/src/js/barcode_events.js b/addons/barcodes/static/src/js/barcode_events.js index 0f13c59fe66..f26748ac7b3 100644 --- a/addons/barcodes/static/src/js/barcode_events.js +++ b/addons/barcodes/static/src/js/barcode_events.js @@ -182,9 +182,12 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { }); return { - // Singleton that emits barcode_scanned events on core.bus + /** Singleton that emits barcode_scanned events on core.bus */ BarcodeEvents: new BarcodeEvents(), - // List of barcode prefixes that are reserved for internal purposes + /** + * List of barcode prefixes that are reserved for internal purposes + * @type Array + */ ReservedBarcodePrefixes: ['O-CMD'], }; diff --git a/addons/bus/static/src/js/bus.js b/addons/bus/static/src/js/bus.js index a79c7500669..25a8b86903f 100644 --- a/addons/bus/static/src/js/bus.js +++ b/addons/bus/static/src/js/bus.js @@ -136,12 +136,13 @@ bus.Bus = Widget.extend({ * one in the list of open tabs. This one start polling for the other. When a notification is recieved from the poll, it * is signaling through the localStorage too. * - * localStorage used keys are : - * - bus.channels : shared public channel list to listen during the poll - * - bus.options : shared options - * - bus.notification : the received notifications from the last poll - * - bus.tab_list : list of opened tab ids - * - bus.tab_master : generated id of the master tab + * localStorage used keys are: + * + * - bus.channels : shared public channel list to listen during the poll + * - bus.options : shared options + * - bus.notification : the received notifications from the last poll + * - bus.tab_list : list of opened tab ids + * - bus.tab_master : generated id of the master tab */ var CrossTabBus = bus.Bus.extend({ init: function(){ diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js index 716f1ceed70..a2ae24dff91 100644 --- a/addons/mail/static/src/js/activity.js +++ b/addons/mail/static/src/js/activity.js @@ -13,7 +13,7 @@ var _t = core._t; /** * Set the 'label_delay' entry in activity data according to the deadline date - * @param {Array} list of activity Object + * @param {Array} activities list of activity Object * @return {Array} : list of modified activity Object */ var setDelayLabel = function(activities){ diff --git a/addons/mail/static/src/js/chatter_composer.js b/addons/mail/static/src/js/chatter_composer.js index 77c8834252f..908dfd8b1c5 100644 --- a/addons/mail/static/src/js/chatter_composer.js +++ b/addons/mail/static/src/js/chatter_composer.js @@ -89,7 +89,7 @@ var ChatterComposer = composer.BasicComposer.extend({ /** * Get the list of selected suggested partners - * @returns Array() : list of 'recipient' selected partners (may not be created in db) + * @returns {Array} list of 'recipient' selected partners (may not be created in db) **/ get_checked_suggested_partners: function () { var self = this; @@ -106,8 +106,8 @@ var ChatterComposer = composer.BasicComposer.extend({ /** * Check the additional partners (not necessary registered partners), and open a popup form view * for the ones who informations is missing. - * @param Array : list of 'recipient' partners to complete informations or validate - * @returns Deferred resolved with the list of checked suggested partners (real partner) + * @param {Array} checked_suggested_partners list of 'recipient' partners to complete informations or validate + * @returns {Deferred} resolved with the list of checked suggested partners (real partner) **/ check_suggested_partners: function (checked_suggested_partners) { var self = this; diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js index b3ea0e18bfc..2fa34b613ba 100644 --- a/addons/mail/static/src/js/document_viewer.js +++ b/addons/mail/static/src/js/document_viewer.js @@ -34,7 +34,7 @@ var DocumentViewer = Widget.extend({ * Documents that are not of type image or video are filtered out. * * @override - * @param {Array[Object]} attachments list of attachments + * @param {Array} attachments list of attachments * @param {integer} activeAttachmentID */ init: function (parent, attachments, activeAttachmentID) { diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 80d4c4c8a4c..ec5ffdda1a9 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -130,11 +130,11 @@ var Thread = Widget.extend({ }, /** - * Modifies $element to add the 'read more/read less' functionality - * All element nodes with "data-o-mail-quote" attribute are concerned. - * All text nodes after a ""#stopSpelling" element are concerned. - * Those text nodes need to be wrapped in a span (toggle functionality). - * All consecutive elements are joined in one 'read more/read less'. + * Modifies $element to add the 'read more/read less' functionality + * All element nodes with "data-o-mail-quote" attribute are concerned. + * All text nodes after a ``#stopSpelling`` element are concerned. + * Those text nodes need to be wrapped in a span (toggle functionality). + * All consecutive elements are joined in one 'read more/read less'. */ insert_read_more: function ($element) { var self = this; diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index a956ac62501..db75edbe558 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -18,7 +18,6 @@ var _t = core._t; var Mutex = concurrency.Mutex; var round_di = utils.round_decimals; var round_pr = utils.round_precision; -var Backbone = window.Backbone; var exports = {}; diff --git a/addons/point_of_sale/static/src/js/popups.js b/addons/point_of_sale/static/src/js/popups.js index 274c54c61a8..e27ffc75dd6 100644 --- a/addons/point_of_sale/static/src/js/popups.js +++ b/addons/point_of_sale/static/src/js/popups.js @@ -135,21 +135,23 @@ var ConfirmPopupWidget = PopupWidget.extend({ gui.define_popup({name:'confirm', widget: ConfirmPopupWidget}); /** - * A popup that allows the user to select one item from a list. + * A popup that allows the user to select one item from a list. * - * show_popup('selection',{ - * title: "Popup Title", - * list: [ - * { label: 'foobar', item: 45 }, - * { label: 'bar foo', item: 'stuff' }, - * ], - * confirm: function(item) { - * // get the item selected by the user. - * }, - * cancel: function(){ - * // user chose nothing - * } - * }); + * Example:: + * + * show_popup('selection',{ + * title: "Popup Title", + * list: [ + * { label: 'foobar', item: 45 }, + * { label: 'bar foo', item: 'stuff' }, + * ], + * confirm: function(item) { + * // get the item selected by the user. + * }, + * cancel: function(){ + * // user chose nothing + * } + * }); */ var SelectionPopupWidget = PopupWidget.extend({ diff --git a/addons/portal/static/src/js/portal_chatter.js b/addons/portal/static/src/js/portal_chatter.js index 5aeab9bcf31..8e9868ad825 100644 --- a/addons/portal/static/src/js/portal_chatter.js +++ b/addons/portal/static/src/js/portal_chatter.js @@ -76,7 +76,7 @@ var PortalChatter = Widget.extend({ * Fetch the messages and the message count from the server for the * current page and current domain. * - * @param {Array} + * @param {Array} domain * @returns {Deferred} */ messageFetch: function(domain){ diff --git a/addons/sale_timesheet/static/src/js/timesheet_plan.js b/addons/sale_timesheet/static/src/js/timesheet_plan.js index e146fc4b365..2aa8dd7b631 100644 --- a/addons/sale_timesheet/static/src/js/timesheet_plan.js +++ b/addons/sale_timesheet/static/src/js/timesheet_plan.js @@ -101,7 +101,7 @@ var PlanAction = Widget.extend(ControlPanelMixin, { //-------------------------------------------------------------------------- /** * Refresh the DOM html - * @param {string|html} + * @param {string|html} dom * @private */ _refreshPlan: function(dom){ diff --git a/addons/web/static/src/js/_deprecated/data.js b/addons/web/static/src/js/_deprecated/data.js index 14b3daeb2c6..be5496c55c7 100644 --- a/addons/web/static/src/js/_deprecated/data.js +++ b/addons/web/static/src/js/_deprecated/data.js @@ -733,6 +733,7 @@ var data = { DataSet: DataSet, DataSetStatic: DataSetStatic, DataSetSearch: DataSetSearch, + /** @type String */ noDisplayContent: "" + _t("Unnamed") + "", }; diff --git a/addons/web/static/src/js/chrome/abstract_web_client.js b/addons/web/static/src/js/chrome/abstract_web_client.js index 2a5bb5310ce..8492adc33f6 100644 --- a/addons/web/static/src/js/chrome/abstract_web_client.js +++ b/addons/web/static/src/js/chrome/abstract_web_client.js @@ -206,16 +206,17 @@ var AbstractWebClient = Widget.extend(mixins.ServiceProvider, { // Window title handling // -------------------------------------------------------------- /** - Sets the first part of the title of the window, dedicated to the current action. + * Sets the first part of the title of the window, dedicated to the current action. */ set_title: function (title) { this.set_title_part("action", title); }, /** - Sets an arbitrary part of the title of the window. Title parts are identified by strings. Each time - a title part is changed, all parts are gathered, ordered by alphabetical order and displayed in the - title of the window separated by '-'. - */ + * Sets an arbitrary part of the title of the window. Title parts are + * identified by strings. Each time a title part is changed, all parts + * are gathered, ordered by alphabetical order and displayed in the title + * of the window separated by ``-``. + */ set_title_part: function (part, title) { var tmp = _.clone(this.get("title_part")); tmp[part] = title; diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index 131a31ad776..e18a3d60734 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -67,7 +67,7 @@ var Action = core.Class.extend({ }, /** * Stores the DOM fragment of the action - * @param {jQuery} [fragment] the DOM fragment + * @param {jQuery} [$fragment] the DOM fragment */ set_fragment: function($fragment) { this.$fragment = $fragment; @@ -300,11 +300,11 @@ var ActionManager = Widget.extend({ /** * Add a new action to the action manager * - * widget: typically, widgets added are openerp.web.ViewManager. The action manager - * uses the stack of actions to handle the breadcrumbs. - * action_descr: new action description - * options.on_reverse_breadcrumb: will be called when breadcrumb is clicked on - * options.clear_breadcrumbs: boolean, if true, action stack is destroyed + * @param {Widget} widget typically, widgets added are openerp.web.ViewManager. The action manager uses the stack of actions to handle the breadcrumbs. + * @param {Object} action_descr new action description + * @param {Object} options + * @param options.on_reverse_breadcrumb will be called when breadcrumb is clicked on + * @param options.clear_breadcrumbs: boolean, if true, action stack is destroyed */ push_action: function(widget, action_descr, options) { var self = this; @@ -613,7 +613,7 @@ var ActionManager = Widget.extend({ /** * Execute an OpenERP action * - * @param {Number|String|String|Object} Can be either an action id, an action XML id, a client action tag or an action descriptor. + * @param {Number|String|String|Object} action Can be either an action id, an action XML id, a client action tag or an action descriptor. * @param {Object} [options] * @param {Boolean} [options.clear_breadcrumbs=false] Clear the breadcrumbs history list * @param {Boolean} [options.replace_breadcrumb=false] Replace the current breadcrumb with the action diff --git a/addons/web/static/src/js/chrome/search_filters.js b/addons/web/static/src/js/chrome/search_filters.js index a0e3c1c077f..b9cf1b0fce9 100644 --- a/addons/web/static/src/js/chrome/search_filters.js +++ b/addons/web/static/src/js/chrome/search_filters.js @@ -96,7 +96,7 @@ var ExtendedSearchProposition = Widget.extend(/** @lends instance.web.search.Ext }, }); -ExtendedSearchProposition.Field = Widget.extend({ +var Field = Widget.extend({ init: function (parent, field) { this._super(parent); this.field = field; @@ -153,7 +153,7 @@ ExtendedSearchProposition.Field = Widget.extend({ } }); -ExtendedSearchProposition.Char = ExtendedSearchProposition.Field.extend({ +var Char = Field.extend({ tagName: 'input', className: 'o_input', attributes: { @@ -172,7 +172,7 @@ ExtendedSearchProposition.Char = ExtendedSearchProposition.Field.extend({ } }); -ExtendedSearchProposition.DateTime = ExtendedSearchProposition.Field.extend({ +var DateTime = Field.extend({ tagName: 'span', attributes: { type: 'datetime' @@ -241,7 +241,7 @@ ExtendedSearchProposition.DateTime = ExtendedSearchProposition.Field.extend({ }, }); -ExtendedSearchProposition.Date = ExtendedSearchProposition.DateTime.extend({ +var Date = DateTime.extend({ attributes: { type: 'date' }, @@ -250,7 +250,7 @@ ExtendedSearchProposition.Date = ExtendedSearchProposition.DateTime.extend({ }, }); -ExtendedSearchProposition.Integer = ExtendedSearchProposition.Field.extend({ +var Integer = Field.extend({ tagName: 'input', className: 'o_input', attributes: { @@ -280,11 +280,11 @@ ExtendedSearchProposition.Integer = ExtendedSearchProposition.Field.extend({ } }); -ExtendedSearchProposition.Id = ExtendedSearchProposition.Integer.extend({ +var Id = Integer.extend({ operators: [{value: "=", text: _lt("is")}] }); -ExtendedSearchProposition.Float = ExtendedSearchProposition.Field.extend({ +var Float = Field.extend({ template: 'SearchView.extended_search.proposition.float', operators: [ {value: "=", text: _lt("is equal to")}, @@ -313,7 +313,7 @@ ExtendedSearchProposition.Float = ExtendedSearchProposition.Field.extend({ } }); -ExtendedSearchProposition.Selection = ExtendedSearchProposition.Field.extend({ +var Selection = Field.extend({ template: 'SearchView.extended_search.proposition.selection', operators: [ {value: "=", text: _lt("is")}, @@ -331,7 +331,7 @@ ExtendedSearchProposition.Selection = ExtendedSearchProposition.Field.extend({ } }); -ExtendedSearchProposition.Boolean = ExtendedSearchProposition.Field.extend({ +var Boolean = Field.extend({ tagName: 'span', operators: [ {value: "=", text: _lt("is true")}, @@ -347,19 +347,19 @@ ExtendedSearchProposition.Boolean = ExtendedSearchProposition.Field.extend({ }); core.search_filters_registry - .add('char', ExtendedSearchProposition.Char) - .add('text', ExtendedSearchProposition.Char) - .add('one2many', ExtendedSearchProposition.Char) - .add('many2one', ExtendedSearchProposition.Char) - .add('many2many', ExtendedSearchProposition.Char) - .add('datetime', ExtendedSearchProposition.DateTime) - .add('date', ExtendedSearchProposition.Date) - .add('integer', ExtendedSearchProposition.Integer) - .add('float', ExtendedSearchProposition.Float) - .add('monetary', ExtendedSearchProposition.Float) - .add('boolean', ExtendedSearchProposition.Boolean) - .add('selection', ExtendedSearchProposition.Selection) - .add('id', ExtendedSearchProposition.Id); + .add('char', Char) + .add('text', Char) + .add('one2many', Char) + .add('many2one', Char) + .add('many2many', Char) + .add('datetime', DateTime) + .add('date', Date) + .add('integer', Integer) + .add('float', Float) + .add('monetary', Float) + .add('boolean', Boolean) + .add('selection', Selection) + .add('id', Id); return { ExtendedSearchProposition: ExtendedSearchProposition diff --git a/addons/web/static/src/js/chrome/search_view.js b/addons/web/static/src/js/chrome/search_view.js index 630183d89ff..d8d02ac9a41 100644 --- a/addons/web/static/src/js/chrome/search_view.js +++ b/addons/web/static/src/js/chrome/search_view.js @@ -265,7 +265,7 @@ var SearchView = Widget.extend({ * * @param parent * @param dataset - * @param fields_view + * @param fvg * @param {Object} [options] * @param {Boolean} [options.hidden=false] hide the search view * @param {Boolean} [options.disable_custom_filters=false] do not load custom filters from ir.filters @@ -499,8 +499,8 @@ var SearchView = Widget.extend({ .$el.focus(); }, /** - * @param {openerp.web.search.SearchQuery | undefined} Undefined if event is change - * @param {openerp.web.search.Facet} + * @param {openerp.web.search.SearchQuery | undefined} collection Undefined if event is change + * @param {openerp.web.search.Facet} model * @param {Object} [options] */ renderFacets: function (collection, model, options) { diff --git a/addons/web/static/src/js/chrome/view_manager.js b/addons/web/static/src/js/chrome/view_manager.js index 8f62ff101f7..03eb2da27d8 100644 --- a/addons/web/static/src/js/chrome/view_manager.js +++ b/addons/web/static/src/js/chrome/view_manager.js @@ -232,8 +232,9 @@ var ViewManager = Widget.extend(ControlPanelMixin, { }, /** * Returns the default view with the following fallbacks: - * - use the default_view defined in the flags, if any - * - use the first view in the view_order + * + * - use the default_view defined in the flags, if any + * - use the first view in the view_order * * @returns {Object} the default view */ diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js index 5bab96a0c1e..d69574d2e10 100644 --- a/addons/web/static/src/js/core/ajax.js +++ b/addons/web/static/src/js/core/ajax.js @@ -211,7 +211,7 @@ var loadJS = (function () { * @param {HTMLFormElement} [options.form] the form to submit in order to fetch the file * @param {Function} [options.success] callback in case of download success * @param {Function} [options.error] callback in case of request error, provided with the error body - * @param {Function} [options.complete] called after both ``success`` and ``error` callbacks have executed + * @param {Function} [options.complete] called after both ``success`` and ``error`` callbacks have executed */ function get_file(options) { // need to detect when the file is done downloading (not used diff --git a/addons/web/static/src/js/core/bus.js b/addons/web/static/src/js/core/bus.js index bf33c1fe01e..1f715da4df1 100644 --- a/addons/web/static/src/js/core/bus.js +++ b/addons/web/static/src/js/core/bus.js @@ -6,6 +6,8 @@ var mixins = require('web.mixins'); /** * Event Bus used to bind events scoped in the current instance + * + * @class Bus */ return Class.extend(mixins.EventDispatcherMixin, { init: function() { diff --git a/addons/web/static/src/js/core/class.js b/addons/web/static/src/js/core/class.js index 8e53f0ba06d..4d1e6baaa8e 100644 --- a/addons/web/static/src/js/core/class.js +++ b/addons/web/static/src/js/core/class.js @@ -12,46 +12,47 @@ odoo.define('web.Class', function () { * Defines The Class object. That object can be used to define and inherit classes using * the extend() method. * - * Example: + * Example:: * - * var Person = Class.extend({ - * init: function(isDancing){ - * this.dancing = isDancing; - * }, - * dance: function(){ - * return this.dancing; - * } - * }); + * var Person = Class.extend({ + * init: function(isDancing){ + * this.dancing = isDancing; + * }, + * dance: function(){ + * return this.dancing; + * } + * }); * - * The init() method act as a constructor. This class can be instancied this way: + * The init() method act as a constructor. This class can be instanced this way:: * - * var person = new Person(true); - * person.dance(); + * var person = new Person(true); + * person.dance(); * - * The Person class can also be extended again: + * The Person class can also be extended again: * - * var Ninja = Person.extend({ - * init: function(){ - * this._super( false ); - * }, - * dance: function(){ - * // Call the inherited version of dance() - * return this._super(); - * }, - * swingSword: function(){ - * return true; - * } - * }); + * var Ninja = Person.extend({ + * init: function(){ + * this._super( false ); + * }, + * dance: function(){ + * // Call the inherited version of dance() + * return this._super(); + * }, + * swingSword: function(){ + * return true; + * } + * }); * * When extending a class, each re-defined method can use this._super() to call the previous * implementation of that method. + * + * @class Class */ +function OdooClass(){} + var initializing = false; var fnTest = /xyz/.test(function(){xyz();}) ? /\b_super\b/ : /.*/; -// The web Class implementation (does nothing) -function OdooClass(){}; - /** * Subclass an existing class * diff --git a/addons/web/static/src/js/core/concurrency.js b/addons/web/static/src/js/core/concurrency.js index cab9df6529e..aeef29809d9 100644 --- a/addons/web/static/src/js/core/concurrency.js +++ b/addons/web/static/src/js/core/concurrency.js @@ -122,7 +122,7 @@ return { * the last operation. * * For example, let us say that we have a _fetch method on a widget which - * fetches data. We want to rerender the widget after. We could do this: + * fetches data. We want to rerender the widget after. We could do this:: * * this._fetch().then(function (result) { * self.state = result; @@ -130,17 +130,18 @@ return { * }); * * Now, we have at least two problems: + * * - if this code is called twice and the second _fetch completes before the * first, the end state will be the result of the first _fetch, which is * not what we expect * - in any cases, the user interface will rerender twice, which is bad. * - * Now, if we have a DropPrevious: + * Now, if we have a DropPrevious:: * * this.dropPrevious = new DropPrevious(); * * Then we can wrap the _fetch in a DropPrevious and have the expected - * result: + * result:: * * this.dropPrevious * .add(this._fetch()) @@ -153,7 +154,7 @@ return { /** * Registers a new deferred and rejects the previous one * - * @param {Deferred} the new deferred + * @param {Deferred} deferred the new deferred * @returns {Promise} */ add: function (deferred) { @@ -171,7 +172,7 @@ return { * * Imagine that we have a function to fetch some data _load(), which returns * a deferred which resolves to something useful. Now, we have some code - * looking like this: + * looking like this:: * * return this._load().then(function (result) { * this.state = result; @@ -179,11 +180,11 @@ return { * * If this code is run twice, but the second execution ends before the * first, then the final state will be the result of the first call to - * _load. However, if we have a mutex: + * _load. However, if we have a mutex:: * * this.mutex = new Mutex(); * - * and if we wrap the calls to _load in a mutex: + * and if we wrap the calls to _load in a mutex:: * * return this.mutex.exec(function() { * return this._load().then(function (result) { diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js index 88bfae2b545..8c75db392fb 100644 --- a/addons/web/static/src/js/core/dialog.js +++ b/addons/web/static/src/js/core/dialog.js @@ -9,17 +9,17 @@ var QWeb = core.qweb; var _t = core._t; /** - A useful class to handle dialogs. - - Attributes: - - $footer: A jQuery element targeting a dom part where buttons can be added. It always exists - during the lifecycle of the dialog. -*/ + * A useful class to handle dialogs. + * Attributes: + * + * ``$footer`` + * A jQuery element targeting a dom part where buttons can be added. It + * always exists during the lifecycle of the dialog. + **/ var Dialog = Widget.extend({ xmlDependencies: ['/web/static/src/xml/dialog.xml'], /** - * @constructor * @param {Widget} parent * @param {Object} [options] * @param {string} [options.title=Odoo] diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js index 7bae1bc29a5..6ca13f18e4e 100644 --- a/addons/web/static/src/js/core/dom.js +++ b/addons/web/static/src/js/core/dom.js @@ -115,10 +115,14 @@ return { } }, /** - * jQuery find function behavior is: + * jQuery find function behavior is:: + * * $('A').find('A B') <=> $('A A B') - * The searches behavior to find options' DOM needs to be + * + * The searches behavior to find options' DOM needs to be:: + * * $('A').find('A B') <=> $('A B') + * * This is what this function does. * * @param {jQuery} $from - the jQuery element(s) from which to search diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js index cc99cc1aaa4..79de054bf10 100644 --- a/addons/web/static/src/js/core/mixins.js +++ b/addons/web/static/src/js/core/mixins.js @@ -10,6 +10,9 @@ var AbstractService = require('web.AbstractService'); * relationship. Each object can a have a parent and multiple children. * When an object is destroyed, all its children are destroyed too releasing * any resource they could have reserved before. + * + * @name ParentedMixin + * @mixin */ var ParentedMixin = { __parentedMixin : true, @@ -57,21 +60,21 @@ var ParentedMixin = { return this.__parentedDestroyed; }, /** - Utility method to only execute asynchronous actions if the current - object has not been destroyed. - - @param {$.Deferred} promise The promise representing the asynchronous - action. - @param {bool} [reject=false] If true, the returned promise will be - rejected with no arguments if the current - object is destroyed. If false, the - returned promise will never be resolved - or rejected. - @returns {$.Deferred} A promise that will mirror the given promise if - everything goes fine but will either be rejected - with no arguments or never resolved if the - current object is destroyed. - */ + * Utility method to only execute asynchronous actions if the current + * object has not been destroyed. + * + * @param {$.Deferred} promise The promise representing the asynchronous + * action. + * @param {bool} [reject=false] If true, the returned promise will be + * rejected with no arguments if the current + * object is destroyed. If false, the + * returned promise will never be resolved + * or rejected. + * @returns {$.Deferred} A promise that will mirror the given promise if + * everything goes fine but will either be rejected + * with no arguments or never resolved if the + * current object is destroyed. + */ alive: function (promise, reject) { var self = this; return $.Deferred(function (def) { @@ -228,13 +231,16 @@ var Events = Class.extend({ }); /** - Mixin containing an event system. Events are also registered by specifying the target object - (the object which will receive the event when it is raised). Both the event-emitting object - and the target object store or reference to each other. This is used to correctly remove all - reference to the event handler when any of the object is destroyed (when the destroy() method - from ParentedMixin is called). Removing those references is necessary to avoid memory leak - and phantom events (events which are raised and sent to a previously destroyed object). -*/ + * Mixin containing an event system. Events are also registered by specifying the target object + * (the object which will receive the event when it is raised). Both the event-emitting object + * and the target object store or reference to each other. This is used to correctly remove all + * reference to the event handler when any of the object is destroyed (when the destroy() method + * from ParentedMixin is called). Removing those references is necessary to avoid memory leak + * and phantom events (events which are raised and sent to a previously destroyed object). + * + * @name EventDispatcherMixin + * @mixin + */ var EventDispatcherMixin = _.extend({}, ParentedMixin, { __eventDispatcherMixin: true, custom_events: {}, @@ -349,6 +355,10 @@ var EventDispatcherMixin = _.extend({}, ParentedMixin, { } }); +/** + * @name PropertiesMixin + * @mixin + */ var PropertiesMixin = _.extend({}, EventDispatcherMixin, { init: function () { EventDispatcherMixin.init.call(this); @@ -432,6 +442,10 @@ odoo.define('web.ServicesMixin', function (require) { var rpc = require('web.rpc'); +/** + * @mixin + * @name ServicesMixin + */ var ServicesMixin = { call: function (service, method) { var args = Array.prototype.slice.call(arguments, 2); @@ -450,9 +464,9 @@ var ServicesMixin = { * Builds and executes RPC query. Returns a deferred's promise resolved with * the RPC result. * - * @param {string} arg1 either a route or a model - * @param {string} method if a model is given, this argument is a method - * @returns {Deferred's Promise} + * @param {string} params either a route or a model + * @param {string} options if a model is given, this argument is a method + * @returns {Promise} */ _rpc: function (params, options) { var query = rpc.buildQuery(params); diff --git a/addons/web/static/src/js/core/pyeval.js b/addons/web/static/src/js/core/pyeval.js index 502c6a4ce90..ee4ac697fd9 100644 --- a/addons/web/static/src/js/core/pyeval.js +++ b/addons/web/static/src/js/core/pyeval.js @@ -530,11 +530,11 @@ datetime.date = py.type('date', null, { }), }); /** - Returns the current local date, which means the date on the client (which can be different - compared to the date of the server). - - @return {datetime.date} -*/ + * Returns the current local date, which means the date on the client (which can be different + * compared to the date of the server). + * + * @return {datetime.date} + */ function context_today() { var d = new Date(); return py.PY_call( diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js index fc45e669407..0ecea92fb71 100644 --- a/addons/web/static/src/js/core/session.js +++ b/addons/web/static/src/js/core/session.js @@ -321,8 +321,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, { * @param {String} url RPC endpoint * @param {Object} params call parameters * @param {Object} options additional options for rpc call - * @param {Function} success_callback function to execute on RPC call success - * @param {Function} error_callback function to execute on RPC call failure * @returns {jQuery.Deferred} jquery-provided ajax deferred */ rpc: function (url, params, options) { @@ -413,7 +411,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, { * (host system settings) to UTC, for a given date. The offset is positive * if the local timezone is behind UTC, and negative if it is ahead. * - * @param {string || moment} date a valid string date or moment instance + * @param {string | moment} date a valid string date or moment instance * @returns {integer} */ getTZOffset: function (date) { diff --git a/addons/web/static/src/js/core/translation.js b/addons/web/static/src/js/core/translation.js index fae44774a07..76493fdb432 100644 --- a/addons/web/static/src/js/core/translation.js +++ b/addons/web/static/src/js/core/translation.js @@ -71,6 +71,16 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase# } }); +/** + * Eager translation function, performs translation immediately at call + * site. Beware using this outside of method bodies (before the + * translation database is loaded), you probably want :func:`_lt` + * instead. + * + * @function _t + * @param {String} source string to translate + * @returns {String} source translated into the current locale + */ var _t = new TranslationDataBase().build_translation_function(); /** * Lazy translation function, only performs the translation when actually diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 585be4d37b8..9eefc12944c 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -107,7 +107,7 @@ var utils = { /** * Returns a human readable size * - * @param {Number} number of bytes + * @param {Number} size number of bytes */ human_size: function (size) { var units = _t("Bytes,Kb,Mb,Gb,Tb,Pb,Eb,Zb,Yb").split(','); @@ -271,8 +271,8 @@ var utils = { /** * performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision * See the corresponding float_round() in server/tools/float_utils.py for more info - * @param {Number} the value to be rounded - * @param {Number} the number of decimals. eg: round_decimals(3.141592,2) -> 3.14 + * @param {Number} value the value to be rounded + * @param {Number} decimals the number of decimals. eg: round_decimals(3.141592,2) -> 3.14 */ round_decimals: function (value, decimals) { return utils.round_precision(value, Math.pow(10,-decimals)); @@ -319,9 +319,9 @@ var utils = { }, /** * Create a cookie - * @param {String} name : the name of the cookie - * @param {String} value : the value stored in the cookie - * @param {Integer} ttl : time to live of the cookie in millis. -1 to erase the cookie. + * @param {String} name the name of the cookie + * @param {String} value the value stored in the cookie + * @param {Integer} ttl time to live of the cookie in millis. -1 to erase the cookie. */ set_cookie: function (name, value, ttl) { ttl = ttl || 24*60*60*365; diff --git a/addons/web/static/src/js/core/widget.js b/addons/web/static/src/js/core/widget.js index 8ef141a6020..c47deff7330 100644 --- a/addons/web/static/src/js/core/widget.js +++ b/addons/web/static/src/js/core/widget.js @@ -7,50 +7,51 @@ var mixins = require('web.mixins'); var ServicesMixin = require('web.ServicesMixin'); /** - * Base class for all visual components. Provides a lot of functionalities helpful + * Base class for all visual components. Provides a lot of functions helpful * for the management of a part of the DOM. * * Widget handles: + * * - Rendering with QWeb. - * - Life-cycle management and parenting (when a parent is destroyed, all its children are - * destroyed too). + * - Life-cycle management and parenting (when a parent is destroyed, all its + * children are destroyed too). * - Insertion in DOM. * - * Guide to create implementations of the Widget class: - * ============================================== + * **Guide to create implementations of the Widget class** * - * Here is a sample child class: + * Here is a sample child class:: * - * MyWidget = openerp.base.Widget.extend({ - * // the name of the QWeb template to use for rendering - * template: "MyQWebTemplate", + * var MyWidget = openerp.base.Widget.extend({ + * // the name of the QWeb template to use for rendering + * template: "MyQWebTemplate", * - * init: function(parent) { - * this._super(parent); - * // stuff that you want to init before the rendering - * }, - * start: function() { - * // stuff you want to make after the rendering, `this.$el` holds a correct value - * this.$(".my_button").click(/* an example of event binding * /); + * init: function(parent) { + * this._super(parent); + * // stuff that you want to init before the rendering + * }, + * start: function() { + * // stuff you want to make after the rendering, `this.$el` holds a correct value + * this.$(".my_button").click(/* an example of event binding * /); * - * // if you have some asynchronous operations, it's a good idea to return - * // a promise in start() - * var promise = this._rpc(...); - * return promise; - * } - * }); + * // if you have some asynchronous operations, it's a good idea to return + * // a promise in start() + * var promise = this._rpc(...); + * return promise; + * } + * }); * - * Now this class can simply be used with the following syntax: + * Now this class can simply be used with the following syntax:: * - * var my_widget = new MyWidget(this); - * my_widget.appendTo($(".some-div")); + * var my_widget = new MyWidget(this); + * my_widget.appendTo($(".some-div")); * - * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the - * DOM inside the ".some-div" div and its events were binded. + * With these two lines, the MyWidget instance was initialized, rendered, + * inserted into the DOM inside the ``.some-div`` div and its events were + * bound. * - * And of course, when you don't need that widget anymore, just do: + * And of course, when you don't need that widget anymore, just do:: * - * my_widget.destroy(); + * my_widget.destroy(); * * That will kill the widget in a clean way and erase its content from the dom. */ @@ -67,7 +68,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { * The name of the QWeb template that will be used for rendering. Must be * redefined in subclasses or the default render() method can not be used. * - * @type string + * @type {String} */ template: null, /** @@ -82,8 +83,6 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { /** * Constructs the widget and sets its parent if a parent is given. * - * @constructs openerp.Widget - * * @param {openerp.Widget} parent Binds the current instance to the given Widget instance. * When that widget is destroyed by calling destroy(), the current instance will be * destroyed too. Can be null. @@ -238,7 +237,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { * (if any) by the new one in the DOM. * * @param {HTMLElement | jQuery} $el - * @returns {*} this + * @returns {Widget} this */ replaceElement: function ($el) { var $oldel = this.$el; @@ -257,13 +256,14 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { * Re-sets the widget's root element (el/$el/$el). * * Includes: + * * * re-delegating events * * re-binding sub-elements * * if the widget already had a root element, replacing the pre-existing * element in the DOM * * @param {HTMLElement | jQuery} element new root element for the widget - * @return {*} this + * @return {Widget} this */ setElement: function (element) { // NB: completely useless, as WidgetMixin#init creates a $el diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index bdb745298b2..894ee57c813 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -59,6 +59,8 @@ var AbstractField = Widget.extend({ specialData: false, /** * to override to indicate which field types are supported by the widget + * + * @type Array */ supportedFieldTypes: [], @@ -196,7 +198,7 @@ var AbstractField = Widget.extend({ * will have the cursor at the very end. * * @param {Object} [options] - * @param {boolean} [noselect=false] if false and the input + * @param {boolean} [options.noselect=false] if false and the input * is of type text or textarea, the content will also be selected * @param {Event} [options.event] the event which fired this activation * @returns {boolean} true if the widget was activated, false if the diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index da7def82dd2..5681be3262a 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1741,10 +1741,9 @@ var FieldPercentPie = AbstractField.extend({ }); /** - * FieldProgressBar - * parameters - * - title: title of the bar, displayed on top of the bar - * options + * Node options: + * + * - title: title of the bar, displayed on top of the bar options * - editable: boolean if value is editable * - current_value: get the current_value from the field that must be present in the view * - max_value: get the max_value from the field that must be present in the view diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index cbb2a856337..369dda9f037 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -80,7 +80,7 @@ function formatChar(value, field, options) { * Returns a string representing a date. If the value is false, then we return * an empty string. Note that this is dependant on the localization settings * - * @param {Moment|false} + * @param {Moment|false} value * @param {Object} [field] * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options @@ -258,7 +258,7 @@ function formatX2Many(value) { * @param {Object} [options] * additional options to override the values in the python description of * the field. - * @param {Object} [options.currency] - the description of the currency to use + * @param {Object} [options.currency] the description of the currency to use * @param {integer} [options.currency_id] * the id of the 'res.currency' to use (ignored if options.currency) * @param {string} [options.currency_field] @@ -336,7 +336,7 @@ function formatSelection(value, field, options) { * Create an Date object * The method toJSON return the formated value to send value server side * - * @param {string} + * @param {string} value * @param {Object} [field] * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options @@ -375,7 +375,7 @@ function parseDate(value, field, options) { * Create an Date object * The method toJSON return the formated value to send value server side * - * @param {string} + * @param {string} value * @param {Object} [field] * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options diff --git a/addons/web/static/src/js/fields/special_fields.js b/addons/web/static/src/js/fields/special_fields.js index 7a0bb9ed092..19db97fe985 100644 --- a/addons/web/static/src/js/fields/special_fields.js +++ b/addons/web/static/src/js/fields/special_fields.js @@ -10,10 +10,10 @@ var _t = core._t; /** - * This widget is intended to display a warning near a label of a 'timezone' field - * indicating if the browser timezone is identical (or not) to the selected timezone. - * This widget depends on a field given with the param 'tz_offset_field', which contains - * the time difference between UTC time and local time, in minutes. + * This widget is intended to display a warning near a label of a 'timezone' field + * indicating if the browser timezone is identical (or not) to the selected timezone. + * This widget depends on a field given with the param 'tz_offset_field', which contains + * the time difference between UTC time and local time, in minutes. */ var FieldTimezoneMismatch = FieldSelection.extend({ /** diff --git a/addons/web/static/src/js/fields/upgrade_fields.js b/addons/web/static/src/js/fields/upgrade_fields.js index 9d61036ab8b..119a64881e3 100644 --- a/addons/web/static/src/js/fields/upgrade_fields.js +++ b/addons/web/static/src/js/fields/upgrade_fields.js @@ -112,7 +112,7 @@ var AbstractFieldUpgrade = { /** * @private - * @param {MouseEvent} + * @param {MouseEvent} event */ _onInputClicked: function (event) { if ($(event.currentTarget).prop("checked")) { diff --git a/addons/web/static/src/js/services/config.js b/addons/web/static/src/js/services/config.js index 9b8d6c03e2f..f892801a593 100644 --- a/addons/web/static/src/js/services/config.js +++ b/addons/web/static/src/js/services/config.js @@ -16,23 +16,31 @@ var config = { /** * debug is a boolean flag. It is only considered true if the flag is set * in the url + * + * @type Boolean */ debug: ($.deparam($.param.querystring()).debug !== undefined), device: { /** * touch is a boolean, true if the device supports touch interaction + * + * @type Boolean */ touch: 'ontouchstart' in window || 'onmsgesturechange' in window, /** * size_class is an integer: 0, 1, 2 or 3, depending on the (current) * size of the device. This is a dynamic property, updated whenever the * browser is resized + * + * @type Number */ size_class: null, /** * A frequent use case is to have a different render in 'mobile' mode, * meaning when the screen is small. This flag (boolean) is true when * the size is not 3. It is also updated dynamically. + * + * @type Boolean */ isMobile: null, /** diff --git a/addons/web/static/src/js/services/core.js b/addons/web/static/src/js/services/core.js index 0a52da1c521..86937c0e2c5 100644 --- a/addons/web/static/src/js/services/core.js +++ b/addons/web/static/src/js/services/core.js @@ -7,6 +7,11 @@ var QWeb = require('web.QWeb'); var Registry = require('web.Registry'); var translation = require('web.translation'); +/** + * Whether the client is currently in "debug" mode + * + * @type Boolean + */ var debug = $.deparam($.param.querystring()).debug !== undefined; var bus = new Bus (); @@ -43,8 +48,11 @@ return { one2many_view_registry: new Registry(), search_filters_registry: new Registry(), search_widgets_registry: new Registry(), - + /** + * @type {String} + */ csrf_token: odoo.csrf_token, + a_thing: 42, }; }); diff --git a/addons/web/static/src/js/services/crash_manager.js b/addons/web/static/src/js/services/crash_manager.js index 533cac6f3ad..3ce280c3aa8 100644 --- a/addons/web/static/src/js/services/crash_manager.js +++ b/addons/web/static/src/js/services/crash_manager.js @@ -161,19 +161,19 @@ var CrashManager = core.Class.extend({ }); /** - An interface to implement to handle exceptions. Register implementation in instance.web.crash_manager_registry. + * An interface to implement to handle exceptions. Register implementation in instance.web.crash_manager_registry. */ var ExceptionHandler = { /** - @param parent The parent. - @param error The error object as returned by the JSON-RPC implementation. - */ + * @param parent The parent. + * @param error The error object as returned by the JSON-RPC implementation. + */ init: function(parent, error) {}, /** - Called to inform to display the widget, if necessary. A typical way would be to implement - this interface in a class extending instance.web.Dialog and simply display the dialog in this - method. - */ + * Called to inform to display the widget, if necessary. A typical way would be to implement + * this interface in a class extending instance.web.Dialog and simply display the dialog in this + * method. + */ display: function() {}, }; diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 4bf1748fbab..22c7e86ba7d 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -64,9 +64,11 @@ return core.Class.extend({ * Loads various information concerning views: fields_view for each view, * the fields of the corresponding model, and optionally the filters. * - * @param {Object} [dataset] the dataset for which the views are loaded - * @param {Array} [views_descr] array of [view_id, view_type] - * @param {Object} [options] dictionnary of various options: + * @param {Object} params + * @param {String} params.model + * @param {Object} params.context + * @param {Array} params.views_descr array of [view_id, view_type] + * @param {Object} [options] dictionary of various options: * - options.load_filters: whether or not to load the filters, * - options.action_id: the action_id (required to load filters), * - options.toolbar: whether or not a toolbar will be displayed, diff --git a/addons/web/static/src/js/views/abstract_renderer.js b/addons/web/static/src/js/views/abstract_renderer.js index d7eb5002f2d..935fcc6643e 100644 --- a/addons/web/static/src/js/views/abstract_renderer.js +++ b/addons/web/static/src/js/views/abstract_renderer.js @@ -9,6 +9,9 @@ odoo.define('web.AbstractRenderer', function (require) { var Widget = require('web.Widget'); +/** + * @class AbstractRenderer + */ return Widget.extend({ /** * @constructor diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index 67de3ec8ad9..46359188577 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -114,7 +114,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { /** * Method that will be overriden by the views with the ability to have selected ids * - * @returns [] + * @returns {Array} */ getSelectedIds: function () { return []; @@ -517,7 +517,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { * in readonly (e.g. Priority). * * @private - * @param {OdooEvent} + * @param {OdooEvent} ev */ _onFieldChanged: function (ev) { if (this.mode === 'readonly') { diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index bcccefbb984..5b6eb35b4ac 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -200,7 +200,7 @@ var BasicModel = AbstractModel.extend({ * * @param {string} id local resource id of a record * @param {string} viewType the current viewType - * @returns {Deferred -> string} resolves to the id of the record + * @returns {Deferred} resolves to the id of the record */ applyRawChanges: function (recordID, viewType) { var record = this.localData[recordID]; @@ -277,7 +277,7 @@ var BasicModel = AbstractModel.extend({ * Duplicate a record (by calling the 'copy' route) * * @param {string} recordID id for a local resource - * @returns {Deferred -> string} resolves to the id of duplicate record + * @returns {Deferred} resolves to the id of duplicate record */ duplicateRecord: function (recordID) { var self = this; @@ -544,7 +544,7 @@ var BasicModel = AbstractModel.extend({ * @param {Object} params.fields contains the description of each field * @param {string} [params.type] 'record' or 'list' * @param {string} [params.recordID] an ID for an existing resource. - * @returns {Deferred -> string} resolves to a local id, or handle + * @returns {Deferred} resolves to a local id, or handle */ load: function (params) { params.type = params.type || (params.res_id !== undefined ? 'record' : 'list'); @@ -694,7 +694,7 @@ var BasicModel = AbstractModel.extend({ * @param {Object} [options] * @param {boolean} [options.keepChanges=false] if true, doesn't discard the * changes on the record before reloading it - * @returns {Deferred -> string} resolves to the id of the resource + * @returns {Deferred} resolves to the id of the resource */ reload: function (id, options) { options = options || {}; @@ -784,7 +784,7 @@ var BasicModel = AbstractModel.extend({ * Resequences records. * * @param {string} modelName the resIDs model - * @param {Array[integer]} resIDs the new sequence of ids + * @param {Array} resIDs the new sequence of ids * @param {string} parentID the localID of the parent * @param {object} [options] * @param {integer} [options.offset] @@ -834,8 +834,7 @@ var BasicModel = AbstractModel.extend({ * - it needs to check all changes, * - generate commands for x2many fields, * - call the /create or /write method according to the record status - * - After that, it has to reload all data, in case something changed, - * server side. + * - After that, it has to reload all data, in case something changed, server side. * * @param {string} record_id local resource * @param {Object} [options] @@ -1006,7 +1005,7 @@ var BasicModel = AbstractModel.extend({ * data * * @param {string} groupId - * @returns {Deferred -> string} resolves to the group id + * @returns {Deferred} resolves to the group id */ toggleGroup: function (groupId) { var self = this; @@ -1048,7 +1047,7 @@ var BasicModel = AbstractModel.extend({ * @param {Object} [options] * @param {string} [options.position=top] if the new record should be added * on top or on bottom of the list - * @returns {Deferred -> string} resolves to the new record id + * @returns {Deferred} resolves to the new record id */ _addX2ManyDefaultRecord: function (list, options) { var self = this; @@ -1760,7 +1759,7 @@ var BasicModel = AbstractModel.extend({ * @param {string} [optinos.viewType] the type of view for which the record * is fetched (usefull to load the adequate fields), by defaults, uses * record.viewType - * @returns {Deferred -> Object} resolves to the record or is rejected in + * @returns {Deferred} resolves to the record or is rejected in * case no id given were valid ids */ _fetchRecord: function (record, options) { @@ -2221,7 +2220,7 @@ var BasicModel = AbstractModel.extend({ * Fetch all data in a ungrouped list * * @param {Object} list a valid resource object - * @returns {Deferred -> Object} resolves to the fecthed list + * @returns {Deferred} resolves to the fecthed list */ _fetchUngroupedList: function (list) { var self = this; @@ -3029,7 +3028,7 @@ var BasicModel = AbstractModel.extend({ * @param {Object} params.fields contains the description of each field * @param {Object} params.context the context for the new record * @param {string} params.viewType the key in fieldsInfo of the fields to load - * @returns {Deferred -> string} resolves to the id for the created resource + * @returns {Deferred} resolves to the id for the created resource */ _makeDefaultRecord: function (modelName, params) { var self = this; @@ -3318,7 +3317,7 @@ var BasicModel = AbstractModel.extend({ * * @param {Object} record * @param {Object} record - * @returns {Deferred -> Object} resolves to the finished resource + * @returns {Deferred} resolves to the finished resource */ _postprocess: function (record, options) { var self = this; @@ -3455,7 +3454,7 @@ var BasicModel = AbstractModel.extend({ * instead of a /search_read. * * @param {Object} list a valid resource object - * @returns {Deferred -> Object} resolves to the fetched list object + * @returns {Deferred} resolves to the fetched list object */ _readUngroupedList: function (list) { var self = this; diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 8f1724c3e64..9c71c9eb2a3 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -79,7 +79,7 @@ var FormRenderer = BasicRenderer.extend({ * Show a warning message if the user modified a translated field. For each * field, the notification provides a link to edit the field's translations. * - * @param {Object[]} alertFields: field list + * @param {Object[]} alertFields field list */ displayTranslationAlert: function (alertFields) { this.$('.o_notification_box').remove(); diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index 52597e6ac71..495f98b28ee 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -99,7 +99,7 @@ var KanbanRecord = Widget.extend({ * Generates the color classname from a given variable * * @private - * @param {number || string} variable + * @param {number | string} variable * @return {string} the classname */ _getColorClassname: function (variable) { @@ -110,7 +110,7 @@ var KanbanRecord = Widget.extend({ * Computes a color id between 0 and 10 from a given value * * @private - * @param {number || string} variable + * @param {number | string} variable * @returns {integer} the color id */ _getColorID: function (variable) { diff --git a/addons/web/static/src/js/views/standalone_field_manager_mixin.js b/addons/web/static/src/js/views/standalone_field_manager_mixin.js index 2c01dc25622..da3cc19350d 100644 --- a/addons/web/static/src/js/views/standalone_field_manager_mixin.js +++ b/addons/web/static/src/js/views/standalone_field_manager_mixin.js @@ -1,13 +1,19 @@ odoo.define('web.StandaloneFieldManagerMixin', function (require) { "use strict"; + +var FieldManagerMixin = require('web.FieldManagerMixin'); + /** * The StandaloneFieldManagerMixin is a mixin, designed to be used by a widget * that instanciates its own field widgets. + * + * @mixin + * @name StandaloneFieldManagerMixin + * @mixes FieldManagerMixin + * @property {Function} _confirmChange + * @property {Function} _registerWidget */ - -var FieldManagerMixin = require('web.FieldManagerMixin'); - var StandaloneFieldManagerMixin = _.extend({}, FieldManagerMixin, { /** diff --git a/addons/web/static/src/js/widgets/date_picker.js b/addons/web/static/src/js/widgets/date_picker.js index 655e94f9f43..26b73c27ac5 100644 --- a/addons/web/static/src/js/widgets/date_picker.js +++ b/addons/web/static/src/js/widgets/date_picker.js @@ -104,7 +104,7 @@ var DateWidget = Widget.extend({ } }, /** - * @param {Moment|false} + * @param {Moment|false} value */ setValue: function (value) { this.set({'value': value}); @@ -121,7 +121,7 @@ var DateWidget = Widget.extend({ /** * @private - * @param {Moment} + * @param {Moment} v * @returns {string} */ _formatClient: function (v) { @@ -129,7 +129,7 @@ var DateWidget = Widget.extend({ }, /** * @private - * @param {string|false} + * @param {string|false} v * @returns {Moment} */ _parseClient: function (v) { @@ -137,7 +137,7 @@ var DateWidget = Widget.extend({ }, /** * @private - * @param {boolean} + * @param {boolean} readonly */ _setReadonly: function (readonly) { this.readonly = readonly; diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js index 74572e81b39..8b273ed5aac 100644 --- a/addons/web/static/src/js/widgets/domain_selector.js +++ b/addons/web/static/src/js/widgets/domain_selector.js @@ -51,7 +51,6 @@ var DomainNode = Widget.extend({ "mouseleave button": "_onButtonLeft", }, /** - * @constructor * A DomainNode needs a model and domain to work. It can also receive a set * of options. * @@ -427,11 +426,12 @@ var DomainTree = DomainNode.extend({ * DomainTree specialization to use to have a fully working widget. * * Known limitations: - * - Some operators like "child_of", "parent_of", "like", "not like", - * "=like", "=ilike" will come only if you use them from demo data or - * debug input. - * - Some kind of domain can not be build right now - * e.g ("country_id", "in", [1,2,3]) but you can insert from debug input. + * + * - Some operators like "child_of", "parent_of", "like", "not like", + * "=like", "=ilike" will come only if you use them from demo data or + * debug input. + * - Some kind of domain can not be build right now + * e.g ("country_id", "in", [1,2,3]) but you can insert from debug input. */ var DomainSelector = DomainTree.extend({ template: "DomainSelector", diff --git a/addons/web/static/src/js/widgets/domain_selector_dialog.js b/addons/web/static/src/js/widgets/domain_selector_dialog.js index c8f48d0ddc8..5f41973951d 100644 --- a/addons/web/static/src/js/widgets/domain_selector_dialog.js +++ b/addons/web/static/src/js/widgets/domain_selector_dialog.js @@ -7,6 +7,9 @@ var DomainSelector = require("web.DomainSelector"); var _t = core._t; +/** + * @class DomainSelectorDialog + */ return Dialog.extend({ init: function (parent, model, domain, options) { this.model = model; diff --git a/addons/web/static/src/js/widgets/iframe_widget.js b/addons/web/static/src/js/widgets/iframe_widget.js index cf5bc15c950..77d27fac5b4 100644 --- a/addons/web/static/src/js/widgets/iframe_widget.js +++ b/addons/web/static/src/js/widgets/iframe_widget.js @@ -6,7 +6,8 @@ var Widget = require('web.Widget'); /** * Generic widget to create an iframe that listens for clicks * - * It should be extended by overwritting the methods: + * It should be extended by overwriting the methods:: + * * init: function(parent) { * this._super(parent, ); * }, diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index c0299fc2969..c08fd39f0db 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -33,7 +33,8 @@ var SnippetEditor = Widget.extend({ /** * @constructor * @param {Widget} parent - * @param {DOMElement} target + * @param {Element} target + * @param templateOptions */ init: function (parent, target, templateOptions) { this._super.apply(this, arguments); @@ -640,7 +641,7 @@ var SnippetsMenu = Widget.extend({ * @private * @param {jQuery} [$selectorSiblings] * elements which must have siblings drop zones - * @param {jQuery} [$selectorSiblings] + * @param {jQuery} [$selectorChildren] * elements which must have child drop zones between each of existing * child */ diff --git a/addons/web_editor/static/src/js/widgets/ace.js b/addons/web_editor/static/src/js/widgets/ace.js index 3ba6d29b2b8..8053b7b12c8 100644 --- a/addons/web_editor/static/src/js/widgets/ace.js +++ b/addons/web_editor/static/src/js/widgets/ace.js @@ -790,7 +790,7 @@ var ViewEditor = Widget.extend({ * is toggled -> reloads the resources accordingly. * * @private - * @param {Event} + * @param {Event} ev */ _onIncludeAllLessChange: function (ev) { this.options.includeAllLess = $(ev.target).prop('checked'); @@ -801,7 +801,7 @@ var ViewEditor = Widget.extend({ * included is toggled -> reloads the resources accordingly. * * @private - * @param {Event} + * @param {Event} ev */ _onIncludeBundlesChange: function (ev) { this.options.includeBundles = $(ev.target).prop('checked'); diff --git a/addons/web_editor/static/src/js/widgets/widgets.js b/addons/web_editor/static/src/js/widgets/widgets.js index d25f1c631e2..1c2f542c6cd 100644 --- a/addons/web_editor/static/src/js/widgets/widgets.js +++ b/addons/web_editor/static/src/js/widgets/widgets.js @@ -391,11 +391,15 @@ var ImageDialog = Widget.extend({ }, }); -/* list of font icons to load by editor. The icons are displayed in the media editor and +/** + * list of font icons to load by editor. The icons are displayed in the media editor and * identified like font and image (can be colored, spinned, resized with fa classes). * To add font, push a new object {base, parser} + * * - base: class who appear on all fonts (eg: fa fa-refresh) * - parser: regular expression used to select all font in css style sheets + * + * @type Array */ var fontIcons = [{'base': 'fa', 'parser': /(?=^|\s)(\.fa-[0-9a-z_-]+::?before)/i}]; diff --git a/addons/web_kanban_gauge/static/src/js/kanban_gauge.js b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js index b36ec8cb654..1b6362068ea 100644 --- a/addons/web_kanban_gauge/static/src/js/kanban_gauge.js +++ b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js @@ -6,21 +6,20 @@ var field_registry = require('web.field_registry'); var utils = require('web.utils'); /** - * Field widget: GaugeWidget * options + * * - max_value: maximum value of the gauge [default: 100] * - max_field: get the max_value from the field that must be present in the - * view; takes over max_value + * view; takes over max_value * - gauge_value_field: if set, the value displayed below the gauge is taken - from this field instead of the base field used for - the gauge. This allows to display a number different - from the gauge. + * from this field instead of the base field used for + * the gauge. This allows to display a number different + * from the gauge. * - label: lable of the gauge, displayed below the gauge value * - label_field: get the label from the field that must be present in the - view; takes over label + * view; takes over label * - title: title of the gauge, displayed on top of the gauge * - style: custom style - * */ var GaugeWidget = AbstractField.extend({ diff --git a/addons/web_tour/static/src/js/tip.js b/addons/web_tour/static/src/js/tip.js index 48b1e67b21e..8fb5fe49ffd 100644 --- a/addons/web_tour/static/src/js/tip.js +++ b/addons/web_tour/static/src/js/tip.js @@ -11,7 +11,8 @@ var Tip = Widget.extend({ mouseleave: "_to_bubble_mode", }, /** - * @param {info} [Object] description of the tip, containing the following keys: + * @param {Widget} parent + * @param {Object} [info] description of the tip, containing the following keys: * - content [String] the html content of the tip * - event_handlers [Object] description of optional event handlers to bind to the tip: * - event [String] the event name @@ -40,7 +41,7 @@ var Tip = Widget.extend({ }; }, /** - * @param {$anchor} [JQuery] the node on which the tip should be placed + * @param {jQuery} $anchor the node on which the tip should be placed */ attach_to: function ($anchor) { this.$anchor = $anchor; diff --git a/addons/web_tour/static/src/js/tour_service.js b/addons/web_tour/static/src/js/tour_service.js index 23bafde1c4d..09b4e6896b9 100644 --- a/addons/web_tour/static/src/js/tour_service.js +++ b/addons/web_tour/static/src/js/tour_service.js @@ -23,6 +23,16 @@ var CallService = Class.extend(mixins.EventDispatcherMixin, mixins.ServiceProvid }, }); +/** + * @namespace + * @property {Object} active_tooltips + * @property {Object} tours + * @property {Array} consumed_tours + * @property {String} running_tour + * @property {Number} running_step_delay + * @property {'community' | 'enterprise'} edition + * @property {Array} _log + */ return session.is_bound.then(function () { var defs = []; // Load the list of consumed tours and the tip template only if we are admin, in the frontend, diff --git a/addons/website/static/src/js/backend/dashboard.js b/addons/website/static/src/js/backend/dashboard.js index 966c37b49f9..c48da63e59d 100644 --- a/addons/website/static/src/js/backend/dashboard.js +++ b/addons/website/static/src/js/backend/dashboard.js @@ -61,6 +61,9 @@ var Dashboard = Widget.extend(ControlPanelMixin, { }); }, + /** + * Fetches dashboard data + */ fetch_data: function() { var self = this; return this._rpc({ diff --git a/addons/website_rating/static/src/js/website_mail.js b/addons/website_rating/static/src/js/website_mail.js index d672af6788d..4f22fe60eea 100644 --- a/addons/website_rating/static/src/js/website_mail.js +++ b/addons/website_rating/static/src/js/website_mail.js @@ -87,7 +87,7 @@ odoo.define('website_rating.thread', function(require) { /** * Update the messages format * - * @param {Array} + * @param {Array} messages * @returns {Array} */ preprocessMessages: function(messages){ @@ -102,17 +102,20 @@ odoo.define('website_rating.thread', function(require) { }, /** * Round the given value with a precision of 0.5. - * Example : 1.2 --> 1.0 - * 1.7 --> 1.5 - * 1.9 --> 2.0 - * @param Float - * @returns Float + * + * Examples: + * - 1.2 --> 1.0 + * - 1.7 --> 1.5 + * - 1.9 --> 2.0 + * + * @param {Number} value + * @returns Number **/ round_to_half: function(value) { var converted = parseFloat(value); // Make sure we have a number var decimal = (converted - parseInt(converted, 10)); decimal = Math.round(decimal * 10); - if(decimal == 5){ + if(decimal === 5){ return (parseInt(converted, 10)+0.5); } if((decimal < 3) || (decimal > 7)){ diff --git a/addons/website_sale/static/src/js/website_sale_rating.js b/addons/website_sale/static/src/js/website_sale_rating.js deleted file mode 100644 index 921645215bc..00000000000 --- a/addons/website_sale/static/src/js/website_sale_rating.js +++ /dev/null @@ -1,26 +0,0 @@ -odoo.define('website_sale.rating', function (require) { - "use strict"; - - var core = require('web.core'); - var ajax = require('web.ajax'); - var rating = require('rating.rating'); - var WebsiteMailThread = require('website_mail.thread'); - - var qweb = core.qweb; - - ajax.loadXML('/rating/static/src/xml/rating_common.xml', qweb); - - WebsiteMailThread.include({ - prepend_message: function(message_data){ - var $elem = this._super.call(this, message_data); - if(message_data['rating_default_value']){ - var rating_star = new rating.RatingStarWidget(this, { - 'rating_default_value': message_data['rating_default_value'], - 'rating_disabled': message_data['rating_disabled'], - }); - rating_star.appendTo($elem.find('h5')); - this.$('.stars i').mouseout(); - } - }, - }); -}); From a62480ad0f6d0958fb65ebb517ba8536b5bab6ba Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Mon, 18 Sep 2017 11:34:06 +0200 Subject: [PATCH 11/40] [FIX] payment_sips: make it configurable for other sips provider. Atos is not the only sips provider, clean fix for hack 265f9ab5090e68ca4dc1e4147a262aaec1897a29 --- addons/payment_sips/models/payment.py | 19 +++++++------------ addons/payment_sips/views/payment_views.xml | 5 ++++- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index a6c9b390eae..53bd6bd2455 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -40,16 +40,11 @@ class AcquirerSips(models.Model): _inherit = 'payment.acquirer' provider = fields.Selection(selection_add=[('sips', 'Sips')]) - sips_merchant_id = fields.Char('SIPS API User Password', required_if_provider='sips', groups='base.group_user') - sips_secret = fields.Char('SIPS Secret', size=64, required_if_provider='sips', groups='base.group_user') - - def _get_sips_urls(self, environment): - """ Worldline SIPS URLS """ - url = { - 'prod': 'https://payment-webinit.sips-atos.com/paymentInit', - 'test': 'https://payment-webinit.simu.sips-atos.com/paymentInit', } - - return {'sips_form_url': url.get(environment, url['test']), } + sips_merchant_id = fields.Char('Merchant ID', help="Used for production only", required_if_provider='sips', groups='base.group_user') + sips_secret = fields.Char('Secret Key', size=64, required_if_provider='sips', groups='base.group_user') + sips_test_url = fields.Char("Test's url", required_if_provider='sips', groups='base.group_no_one', default='https://payment-webinit.sips-atos.com/paymentInit') + sips_prod_url = fields.Char("Prod's url", required_if_provider='sips', groups='base.group_no_one', default='https://payment-webinit.simu.sips-atos.com/paymentInit') + sips_version = fields.Char("Interface Version", required_if_provider='sips', groups='base.group_no_one', default='HP_2.3') def _sips_generate_shasign(self, values): """ Generate the shasign for incoming or outgoing communications. @@ -97,7 +92,7 @@ class AcquirerSips(models.Model): u'transactionReference=%s|' % values['reference'] + u'statementReference=%s|' % values['reference'] + u'keyVersion=%s' % key_version, - 'InterfaceVersion': 'HP_2.3', + 'InterfaceVersion': self.sips_version, }) return_context = {} @@ -113,7 +108,7 @@ class AcquirerSips(models.Model): @api.multi def sips_get_form_action_url(self): self.ensure_one() - return self._get_sips_urls(self.environment)['sips_form_url'] + return self.environment == 'prod' and self.sips_prod_url or self.sips_test_url class TxSips(models.Model): diff --git a/addons/payment_sips/views/payment_views.xml b/addons/payment_sips/views/payment_views.xml index 4e5585af458..aa3b20bd92e 100644 --- a/addons/payment_sips/views/payment_views.xml +++ b/addons/payment_sips/views/payment_views.xml @@ -9,8 +9,11 @@ - + + + + From af8936037f57b2a56537dba428a2ea7b372e717a Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Mon, 18 Sep 2017 13:03:04 +0200 Subject: [PATCH 12/40] [FIX] web: fix several kanban design issues - Load more was invisible; now also add a little bit of styling - Small column records were not centered in their column - Add a column padding bottom to allow seeing reaching the scrollend - Column create was misaligned since some padding changes --- .../src/less/kanban_column_progressbar.less | 4 ++++ addons/web/static/src/less/kanban_view.less | 21 +++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/addons/web/static/src/less/kanban_column_progressbar.less b/addons/web/static/src/less/kanban_column_progressbar.less index c1cf86adc81..47fe96a57f2 100644 --- a/addons/web/static/src/less/kanban_column_progressbar.less +++ b/addons/web/static/src/less/kanban_column_progressbar.less @@ -21,6 +21,10 @@ ~ .oe_kanban_card_@{class} { margin-top: -@o-kanban-inside-vgutter*0.5 - 1px; } + + ~ .o_kanban_load_more { + margin-top: -@o-kanban-inside-vgutter*0.5; + } } .o_kanban_load_more { diff --git a/addons/web/static/src/less/kanban_view.less b/addons/web/static/src/less/kanban_view.less index cedc5193e6d..ee510f75e29 100644 --- a/addons/web/static/src/less/kanban_view.less +++ b/addons/web/static/src/less/kanban_view.less @@ -446,20 +446,15 @@ margin-right: 0; } - &.o_kanban_small_column .o_kanban_group { - &:not(.o_column_folded) { - width: @o-kanban-small-record-width + 2*@o-kanban-group-padding; - .o_kanban_record, .o_kanban_quick_create { - width: @o-kanban-small-record-width; - } - } + &.o_kanban_small_column .o_kanban_group:not(.o_column_folded) { + width: @o-kanban-small-record-width + 2*@o-kanban-group-padding; } } // Kanban Grouped Layout - Column default .o_kanban_group { .o-flex(0, 0, auto); - padding: 0 @o-kanban-group-padding; + padding: 0 @o-kanban-group-padding @o-kanban-group-padding; border: 1px solid @gray-lighter-dark; background-color: @gray-lighter; border-width: 0 1px; @@ -500,11 +495,9 @@ } .o_kanban_load_more { + padding: @o-kanban-record-margin 0; + box-shadow: inset 0 10px 13px -13px black; text-align: center; - a { - color: white; - font-weight: 300; - } } &.ui-sortable-helper { @@ -577,9 +570,11 @@ } .o_kanban_quick_create { - .o-position-absolute(-1px, 0, 0, (-@o-kanban-group-padding - 1px)); display: none; width: @o-kanban-default-record-width; + height: 100%; + margin: 0 (-@o-kanban-group-padding/2); + border: none; box-shadow: 0 0 20px -10px; background-color: @gray-lighter; From b3aa323919ef6e504dce818a5391c8d9db90e700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 18 Sep 2017 11:49:39 +0200 Subject: [PATCH 13/40] [FIX] web: prevent crash sometimes when sorting one2many Before this commit, there was a crash when sorting a one2many in a form view. This is due to the fact that the event from the one2many bubbled up to the main form view, which basically assumed that it was supposed to sort some sub one2many. It could be seen for example when editing a 'attribute' in a product form view (need to activate variants), then sorting the 'attribute values' sub one2many. With this commit, we simply stop the event propagation at the correct level. --- .../src/js/views/form/form_controller.js | 1 + addons/web/static/tests/views/form_tests.js | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 611847ac3f4..df5ce2cc2c1 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -514,6 +514,7 @@ var FormController = BasicController.extend({ * @param {OdooEvent} event */ _onToggleColumnOrder: function (event) { + event.stopPropagation(); this.model.setSort(event.data.id, event.data.name); var field = event.data.field; var state = this.model.get(this.handle); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index f47b12d6096..7bc6734c5ac 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -5842,5 +5842,45 @@ QUnit.module('Views', { "there should be only one column"); form.destroy(); }); + + QUnit.test('can toggle column in x2many in sub form view', function (assert) { + assert.expect(2); + + this.data.partner.records[2].p = [1,2]; + this.data.partner.fields.foo.sortable = true; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '', + res_id: 1, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/get_formview_id') { + return $.when(false); + } + return this._super.apply(this, arguments); + }, + archs: { + 'partner,false,form': '
' + + '' + + '' + + '' + + '' + + '' + + '
', + }, + viewOptions: {mode: 'edit'}, + }); + form.$('.o_external_button').click(); + assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip", + "table has some initial order"); + + $('.modal-body .o_form_view .o_list_view th').click(); + assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop", + "table is now sorted"); + form.destroy(); + }); }); }); From 8f02b16c27d75a420bbb1c6345d205312a1eb2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 18 Sep 2017 12:28:29 +0200 Subject: [PATCH 14/40] [FIX] web: tests: mockserver should crash instead of log When the mockserver handles an unimplemented route, it just log an error. This is annoying because it does not break the QUnit suite, so if the developer does not look at the console, it will look like the test suite pass. However, the runbot will see that as an error. With this commit, we throw an error to force the test suite to fail in that case. --- addons/web/static/tests/helpers/mock_server.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 9523f8b0c0f..4f73e15f9ae 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -910,8 +910,7 @@ var MockServer = Class.extend({ return $.when(this.data[args.model][args.method](args.args, args.kwargs)); } - console.error("Unimplemented route", route, args); - return $.when(); + throw new Error("Unimplemented route: " + route); }, /** * helper function: traverse a tree and apply the function f to each of its From ccea0b788d74bb7fc93205547b1752251e064932 Mon Sep 17 00:00:00 2001 From: amoyaux Date: Tue, 12 Sep 2017 10:32:44 +0200 Subject: [PATCH 15/40] [REF] stock: move compute_state logic to stock move file Before when comuting state picking there was a computation among all moves in order to guess the picking state. However this code could be reuse in other scenario for example in merge moves. In order to avoid code duplication this commit move the part responsible for the state computation among moves in a specific method inside stock move file. --- addons/stock/models/stock_move.py | 32 ++++++++++++++++++++++++++++ addons/stock/models/stock_picking.py | 30 +------------------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index a6b1af3664b..09e582f3604 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -462,6 +462,38 @@ class StockMove(models.Model): if rules and (not move.origin_returned_move_id or move.origin_returned_move_id.location_dest_id.id != rules.location_dest_id.id): rules._apply(move) + def _get_relevant_state_among_moves(self): + # We sort our moves by importance of state: + # ------------- 0 + # | Assigned | + # ------------- + # | Waiting | + # ------------- + # | Partial | + # ------------- + # | Confirm | + # ------------- len-1 + sort_map = { + 'assigned': 4, + 'waiting': 3, + 'partially_available': 2, + 'confirmed': 1, + } + moves_todo = self\ + .filtered(lambda move: move.state not in ['cancel', 'done'])\ + .sorted(key=lambda move: sort_map.get(move.state, 0)) + # The picking should be the same for all moves. + if moves_todo[0].picking_id.move_type == 'one': + if moves_todo[0].state in ('partially_available', 'confirmed'): + return 'confirmed' + else: + return moves_todo[0].state or 'draft' + elif moves_todo[0].state != 'assigned' and any(move.state in ['assigned', 'partially_available'] for move in moves_todo): + return 'partially_available' + else: + # take the less important state among all move_lines. + return moves_todo[-1].state or 'draft' + @api.onchange('product_id', 'product_qty') def onchange_quantity(self): if not self.product_id or self.product_qty < 0.0: diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index afb80b4c44d..675c9a76009 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -305,35 +305,7 @@ class Picking(models.Model): elif all(move.state in ['cancel', 'done'] for move in self.move_lines): self.state = 'done' else: - # We sort our moves by importance of state: - # ------------- 0 - # | Confirmed | - # ------------- - # | Partial | - # ------------- - # | Waiting | - # ------------- - # | Assigned | - # ------------- len - 1 - sort_map = { - 'assigned': 4, - 'waiting': 3, - 'partially_available': 2, - 'confirmed': 1, - } - moves_todo = self.move_lines\ - .filtered(lambda move: move.state not in ['cancel', 'done'])\ - .sorted(key=lambda move: sort_map.get(move.state, 0)) - if self.move_type == 'one': - if moves_todo[0].state in ('partially_available', 'confirmed'): - self.state = 'confirmed' - else: - self.state = moves_todo[0].state or 'draft' - elif moves_todo[0].state != 'assigned' and any(x.state in ['assigned', 'partially_available'] for x in moves_todo): - self.state = 'partially_available' - else: - # take the less important state among all move_lines. - self.state = moves_todo[-1].state or 'draft' + self.state = self.move_lines._get_relevant_state_among_moves() @api.one @api.depends('move_lines.priority') From 5d7e6dfad5a6e21a68c0c306073004eefa503458 Mon Sep 17 00:00:00 2001 From: amoyaux Date: Tue, 12 Sep 2017 14:10:59 +0200 Subject: [PATCH 16/40] [IMP] stock: merge moves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rationale for the need of a merge move mechanism is that, with the new default view, having multiple stock move for the same products is confusing. The idea is that if a move is confirmed in a picking already having a move with the same characteristics, we update the existing move and unlink the new one. That’s why it’s done at the end of `_action_confirm`. In some cases, merging moves is unwanted (backordered moves for examples). Therefore, we chose to add a kwarg to `_action_confirm` in order do control the mechanism. --- addons/mrp/models/stock_move.py | 4 +- addons/purchase/tests/test_create_picking.py | 2 +- addons/stock/models/stock_move.py | 85 ++++++-- addons/stock/tests/test_move2.py | 201 +++++++++++++++---- addons/stock/tests/test_stock_flow.py | 36 ++-- 5 files changed, 244 insertions(+), 84 deletions(-) diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index 933307e5aed..2e4b03e0a10 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -124,12 +124,12 @@ class StockMove(models.Model): } return result - def _action_confirm(self): + def _action_confirm(self, merge=True): moves = self for move in self.filtered(lambda m: m.production_id): moves |= move.action_explode() # we go further with the list of ids potentially changed by action_explode - return super(StockMove, moves)._action_confirm() + return super(StockMove, moves)._action_confirm(merge=merge) def action_explode(self): """ Explodes pickings """ diff --git a/addons/purchase/tests/test_create_picking.py b/addons/purchase/tests/test_create_picking.py index ce66f74ea0c..c276c1f2264 100644 --- a/addons/purchase/tests/test_create_picking.py +++ b/addons/purchase/tests/test_create_picking.py @@ -49,7 +49,7 @@ class TestCreatePicking(common.TestProductCommon): self.assertEqual(len(self.po.order_line.move_ids), 1, 'One move should be created') # Change purchase order line product quantity self.po.order_line.write({'product_qty': 7.0}) - self.assertEqual(len(self.po.order_line.move_ids), 2, 'Two move should be created') + self.assertEqual(len(self.po.order_line.move_ids), 1, 'The two moves should be merged in one') # Validate first shipment self.picking = self.po.picking_ids[0] diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 09e582f3604..c85a47aeb57 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -462,6 +462,59 @@ class StockMove(models.Model): if rules and (not move.origin_returned_move_id or move.origin_returned_move_id.location_dest_id.id != rules.location_dest_id.id): rules._apply(move) + def _merge_moves_fields(self): + """ This method will return a dict of stock move’s values that represent the values of all moves in `self` merged. """ + state = self._get_relevant_state_among_moves() + origin = '/'.join(set(self.filtered(lambda m: m.origin).mapped('origin'))) + return { + 'product_uom_qty': sum(self.mapped('product_uom_qty')), + 'date': min(self.mapped('date')), + 'date_expected': min(self.mapped('date_expected')) if self.mapped('picking_id').move_type == 'direct' else max(self.mapped('date_expected')), + 'move_dest_ids': [(4, m.id) for m in self.mapped('move_dest_ids')], + 'move_orig_ids': [(4, m.id) for m in self.mapped('move_orig_ids')], + 'state': state, + 'origin': origin, + } + + def _merge_moves(self): + """ This method will, for each move in `self`, go up in their linked picking and try to + find in their existing moves a candidate into which we can merge the move. + :return: Recordset of moves passed to this method. If some of the passed moves were merged + into another existing one, return this one and not the (now unlinked) original. + """ + distinct_fields = ['price_unit', 'product_id', 'product_packaging', + 'product_uom', 'restrict_partner_id', 'scrapped', 'origin_returned_move_id'] + + def _keys_sorted(move): + return tuple([getattr(move, attr) for attr in distinct_fields]) + + # Move removed after merge + moves_to_unlink = self.env['stock.move'] + moves_to_merge = [] + for picking in self.mapped('picking_id'): + # First step find move to merge. + for k, g in groupby(sorted(picking.move_lines, key=_keys_sorted), key=itemgetter(*distinct_fields)): + moves = self.env['stock.move'].concat(*g).filtered(lambda m: m.state not in ('done', 'cancel', 'draft')) + # If we have multiple records we will merge then in a single one. + if len(moves) > 1: + moves_to_merge.append(moves) + + # second step merge its move lines, initial demand, ... + for moves in moves_to_merge: + # link all move lines to record 0 (the one we will keep). + moves.mapped('move_line_ids').write({'move_id': moves[0].id}) + # merge move data + moves[0].write(moves._merge_moves_fields()) + # update merged moves dicts + moves_to_unlink |= moves[1:] + + if moves_to_unlink: + # We are using propagate to False in order to not cancel destination moves merged in moves[0] + moves_to_unlink.write({'propagate': False}) + moves_to_unlink._action_cancel() + moves_to_unlink.unlink() + return (self | self.env['stock.move'].concat(*moves_to_merge)) - moves_to_unlink + def _get_relevant_state_among_moves(self): # We sort our moves by importance of state: # ------------- 0 @@ -570,8 +623,11 @@ class StockMove(models.Model): 'location_dest_id': self.location_dest_id.id, } - def _action_confirm(self): - """ Confirms stock move or put it in waiting if it's linked to another move. """ + def _action_confirm(self, merge=True): + """ Confirms stock move or put it in waiting if it's linked to another move. + :param: merge: According to this boolean, a newly confirmed move will be merged + in another move of the same picking sharing its characteristics. + """ move_create_proc = self.env['stock.move'] move_to_confirm = self.env['stock.move'] move_waiting = self.env['stock.move'] @@ -606,6 +662,8 @@ class StockMove(models.Model): for moves in to_assign.values(): moves._assign_picking() self._push_apply() + if merge: + return self._merge_moves() return self def _prepare_procurement_values(self): @@ -694,7 +752,7 @@ class StockMove(models.Model): return taken_quantity def _action_assign(self): - """ Reserve stock moves by creating their stock move lines. A stock move is + """ Reserve stock moves by creating their stock move lines. A stock move is considered reserved once the sum of `product_qty` for all its move lines is equal to its `product_qty`. If it is less, the stock move is considered partially available. @@ -838,24 +896,6 @@ class StockMove(models.Model): rounding_method ='UP') extra_move_vals = self._prepare_extra_move_vals(extra_move_quantity) extra_move = self.copy(default=extra_move_vals)._action_confirm() - - # link it to some move lines - for move_line in self.move_line_ids.filtered(lambda ml: ml.qty_done): - if float_compare(move_line.qty_done, extra_move_quantity, precision_rounding=rounding) <= 0: - # move this move line to our extra move - move_line.move_id = extra_move.id - extra_move_quantity -= move_line.qty_done - else: - # split this move line and assign the new part to our extra move - quantity_split = float_round( - move_line.qty_done - extra_move_quantity, - precision_rounding=self.product_uom.rounding, - rounding_method='UP') - move_line.qty_done = quantity_split - move_line.copy(default={'move_id': extra_move.id, 'qty_done': extra_move_quantity, 'product_uom_qty': 0}) - extra_move_quantity -= extra_move_quantity - if extra_move_quantity == 0.0: - break return extra_move def _action_done(self): @@ -969,7 +1009,8 @@ class StockMove(models.Model): # new_move.write({'move_dest_id': new_move_prop}) # returning the first element of list returned by action_confirm is ok because we checked it wouldn't be exploded (and # thus the result of action_confirm should always be a list of 1 element length) - new_move._action_confirm() + # In this case we don't merge move since the new move with 0 quantity done will be used for the backorder. + new_move = new_move._action_confirm(merge=False) # TDE FIXME: due to action confirm change return new_move.id diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index 62c76166c52..cea81e5a663 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -625,23 +625,13 @@ class TestSinglePicking(TestStockCommon): self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location, allow_negative=True), -1.0) - extra_move = delivery_order.move_lines - move1 - extra_move_line = extra_move.move_line_ids[0] - - # self.assertEqual(move1.product_qty, 1.0) - # self.assertEqual(move1.quantity_done, 1.0) + self.assertEqual(move1.product_qty, 2.0) + self.assertEqual(move1.quantity_done, 2.0) self.assertEqual(move1.reserved_availability, 0.0) self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move - self.assertEqual(move1.move_line_ids.qty_done, 1.0) + self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 2.0) self.assertEqual(move1.state, 'done') - self.assertEqual(extra_move.product_qty, 1.0) - self.assertEqual(extra_move.quantity_done, 1.0) - self.assertEqual(extra_move.reserved_availability, 0.0) - self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve - self.assertEqual(extra_move_line.qty_done, 1.0) - self.assertEqual(extra_move.state, 'done') - def test_extra_move_2(self): """ Check the good behavior of creating an extra move in a delivery order. This usecase simulates the delivery of 3 item while the initial stock move had to move 1 and there's @@ -681,23 +671,13 @@ class TestSinglePicking(TestStockCommon): self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location, allow_negative=True), -2.0) - extra_move = delivery_order.move_lines - move1 - extra_move_line = extra_move.move_line_ids[0] - - self.assertEqual(move1.product_qty, 1.0) - self.assertEqual(move1.quantity_done, 1.0) + self.assertEqual(move1.product_qty, 3.0) + self.assertEqual(move1.quantity_done, 3.0) self.assertEqual(move1.reserved_availability, 0.0) self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move - self.assertEqual(move1.move_line_ids.qty_done, 1.0) + self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 3.0) self.assertEqual(move1.state, 'done') - self.assertEqual(extra_move.product_qty, 2.0) - self.assertEqual(extra_move.quantity_done, 2.0) - self.assertEqual(extra_move.reserved_availability, 0.0) - self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve - self.assertEqual(extra_move_line.qty_done, 2.0) - self.assertEqual(extra_move.state, 'done') - def test_extra_move_3(self): """ Check the good behavior of creating an extra move in a receipt. This usecase simulates the receipt of 2 item while the initial stock move had to move 1. @@ -729,23 +709,13 @@ class TestSinglePicking(TestStockCommon): receipt.with_context(debug=True).do_transfer() self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, stock_location), 2.0) - extra_move = receipt.move_lines - move1 - extra_move_line = extra_move.move_line_ids[0] - - self.assertEqual(move1.product_qty, 1.0) - self.assertEqual(move1.quantity_done, 1.0) + self.assertEqual(move1.product_qty, 2.0) + self.assertEqual(move1.quantity_done, 2.0) self.assertEqual(move1.reserved_availability, 0.0) self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move - self.assertEqual(move1.move_line_ids.qty_done, 1.0) + self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 2.0) self.assertEqual(move1.state, 'done') - self.assertEqual(extra_move.product_qty, 1.0) - self.assertEqual(extra_move.quantity_done, 1.0) - self.assertEqual(extra_move.reserved_availability, 0.0) - self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve - self.assertEqual(extra_move_line.qty_done, 1.0) - self.assertEqual(extra_move.state, 'done') - def test_recheck_availability_1(self): """ Check the good behavior of check availability. I create a DO for 2 unit with only one in stock. After the first check availability, I should have 1 reserved @@ -1208,6 +1178,159 @@ class TestSinglePicking(TestStockCommon): move_line.lot_id = lot1 delivery_order.action_done() + def test_merge_moves_1(self): + receipt = self.env['stock.picking'].create({ + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'partner_id': self.partner_delta_id, + 'picking_type_id': self.picking_type_in, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 3, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 5, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 1, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + }) + self.MoveObj.create({ + 'name': self.productB.name, + 'product_id': self.productB.id, + 'product_uom_qty': 5, + 'product_uom': self.productB.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + }) + receipt.action_confirm() + self.assertEqual(len(receipt.move_lines), 2, 'Moves were not merged') + self.assertEqual(receipt.move_lines.filtered(lambda m: m.product_id == self.productA).product_uom_qty, 9, 'Merged quantity is not correct') + self.assertEqual(receipt.move_lines.filtered(lambda m: m.product_id == self.productB).product_uom_qty, 5, 'Merge should not impact product B reserved quantity') + + def test_merge_moves_2(self): + receipt = self.env['stock.picking'].create({ + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'partner_id': self.partner_delta_id, + 'picking_type_id': self.picking_type_in, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 3, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'origin': 'MPS' + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 5, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'origin': 'PO0001' + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 3, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'origin': 'MPS' + }) + receipt.action_confirm() + self.assertEqual(len(receipt.move_lines), 1, 'Moves were not merged') + self.assertEqual(receipt.move_lines.origin.count('MPS'), 1, 'Origin not merged together or duplicated') + self.assertEqual(receipt.move_lines.origin.count('PO0001'), 1, 'Origin not merged together or duplicated') + + def test_merge_chained_moves(self): + """ Imagine multiple step delivery. Two different receipt picking for the same product should only generate + 1 picking from input to QC and another from QC to stock. The link at the end should follow this scheme. + Move receipt 1 \ + Move Input-> QC - Move QC -> Stock + Move receipt 2 / + """ + warehouse = self.env['stock.warehouse'].create({ + 'name': 'TEST WAREHOUSE', + 'code': 'TEST1', + 'reception_steps': 'three_steps', + }) + receipt1 = self.env['stock.picking'].create({ + 'location_id': self.supplier_location, + 'location_dest_id': warehouse.wh_input_stock_loc_id.id, + 'partner_id': self.partner_delta_id, + 'picking_type_id': warehouse.in_type_id.id, + }) + move_receipt_1 = self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 5, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt1.id, + 'location_id': self.supplier_location, + 'location_dest_id': warehouse.wh_input_stock_loc_id.id, + }) + receipt2 = self.env['stock.picking'].create({ + 'location_id': self.supplier_location, + 'location_dest_id': warehouse.wh_input_stock_loc_id.id, + 'partner_id': self.partner_delta_id, + 'picking_type_id': warehouse.in_type_id.id, + }) + move_receipt_2 = self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 3, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt2.id, + 'location_id': self.supplier_location, + 'location_dest_id': warehouse.wh_input_stock_loc_id.id, + }) + receipt1.action_confirm() + receipt2.action_confirm() + + # Check following move has been created and grouped in one picking. + self.assertTrue(move_receipt_1.move_dest_ids, 'No move created from push rules') + self.assertTrue(move_receipt_2.move_dest_ids, 'No move created from push rules') + self.assertEqual(move_receipt_1.move_dest_ids.picking_id, move_receipt_2.move_dest_ids.picking_id, 'Destination moves should be in the same picking') + + # Check link for input move are correct. + input_move = move_receipt_2.move_dest_ids + self.assertEqual(len(input_move.move_dest_ids), 1) + self.assertEqual(set(input_move.move_orig_ids.ids), set((move_receipt_2 | move_receipt_1).ids), + 'Move from input to QC should be merged and have the two receipt moves as origin.') + self.assertEqual(move_receipt_1.move_dest_ids, input_move) + self.assertEqual(move_receipt_2.move_dest_ids, input_move) + + # Check link for quality check move are also correct. + qc_move = input_move.move_dest_ids + self.assertEqual(len(qc_move), 1) + self.assertTrue(qc_move.move_orig_ids == input_move, 'Move between QC and stock should only have the input move as origin') + class TestStockUOM(TestStockCommon): diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index 83e8391f954..adf4fedabf2 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -141,7 +141,7 @@ class TestStockFlow(TestStockCommon): back_order_in = self.PickingObj.search([('backorder_id', '=', picking_in.id)]) self.assertEqual(len(back_order_in), 1, 'Back order should be created.') # Check total move lines of back order. - self.assertEqual(len(back_order_in.move_lines), 3, 'Wrong number of move lines.') + self.assertEqual(len(back_order_in.move_lines), 2, 'Wrong number of move lines.') # Check back order should be created with 3 quantity of product C. moves = self.MoveObj.search([('product_id', '=', self.productC.id), ('picking_id', '=', back_order_in.id)]) product_c_qty = [move.product_uom_qty for move in moves] @@ -320,13 +320,9 @@ class TestStockFlow(TestStockCommon): # ---------------------------------------------------------------------- packD = self.StockPackObj.search([('product_id', '=', self.productD.id), ('picking_id', '=', back_order_in.id)], order='product_qty') - self.assertEqual(len(packD), 2, 'Wrong number of pack operation.') + self.assertEqual(len(packD), 1, 'Wrong number of pack operation.') packD[0].write({ - 'qty_done': 3, - 'lot_id': lot1_productD.id, - }) - packD[1].write({ - 'qty_done': 5, + 'qty_done': 8, 'lot_id': lot1_productD.id, }) packCs = self.StockPackObj.search([('product_id', '=', self.productC.id), ('picking_id', '=', back_order_in.id)], limit=1) @@ -376,7 +372,7 @@ class TestStockFlow(TestStockCommon): # ---------------------------------------------------------------------- # Check total no of move lines. - self.assertEqual(len(back_order_in.move_lines), 5, 'Wrong number of move lines') + self.assertEqual(len(back_order_in.move_lines), 4, 'Wrong number of move lines') # Check incoming shipment state must be 'Done'. self.assertEqual(back_order_in.state, 'done', 'Wrong state of picking.') # Check incoming shipment move lines state must be 'Done'. @@ -392,7 +388,7 @@ class TestStockFlow(TestStockCommon): # Check product D done quantity must be 5.0 and 3.0 movesD = self.MoveObj.search([('product_id', '=', self.productD.id), ('picking_id', '=', back_order_in.id)]) d_done_qty = [move.product_uom_qty for move in movesD] - self.assertEqual(set(d_done_qty), set([3.0, 5.0]), 'Wrong quantity of moves product D.') + self.assertEqual(set(d_done_qty), set([8.0]), 'Wrong quantity of moves product D.') # Check no back order is created. self.assertFalse(self.PickingObj.search([('backorder_id', '=', back_order_in.id)]), "Should not create any back order.") @@ -662,7 +658,7 @@ class TestStockFlow(TestStockCommon): for move in picking_in_B.move_lines: self.assertEqual(move.state, 'done', 'Wrong state of move line.') # Check total done move lines for incoming shipment. - self.assertEqual(len(picking_in_B.move_lines), 6, 'Wrong number of move lines') + self.assertEqual(len(picking_in_B.move_lines), 5, 'Wrong number of move lines') # Check product DozA done quantity. moves_DozA = self.MoveObj.search([('product_id', '=', self.DozA.id), ('picking_id', '=', picking_in_B.id)], limit=1) self.assertEqual(moves_DozA.product_uom_qty, 96, 'Wrong move quantity (%s found instead of 96)' % (moves_DozA.product_uom_qty)) @@ -681,7 +677,7 @@ class TestStockFlow(TestStockCommon): self.assertEqual(moves_kgB.product_uom.id, self.uom_gm.id, 'Wrong uom in move for product kgB.') # Check two moves created for product gB with quantity (0.525 kg and 0.3 g) moves_gB_kg = self.MoveObj.search([('product_id', '=', self.gB.id), ('picking_id', '=', picking_in_B.id), ('product_uom', '=', self.uom_kg.id)], limit=1) - self.assertEqual(moves_gB_kg.product_uom_qty, 0.525, 'Wrong move quantity (%s found instead of 0.525)' % (moves_gB_kg.product_uom_qty)) + self.assertEqual(moves_gB_kg.product_uom_qty, 0.526, 'Wrong move quantity (%s found instead of 0.526)' % (moves_gB_kg.product_uom_qty)) self.assertEqual(moves_gB_kg.product_uom.id, self.uom_kg.id, 'Wrong uom in move for product gB.') # TODO Test extra move once the uom is editable in the move_lines @@ -1769,27 +1765,27 @@ class TestStockFlow(TestStockCommon): 'location_dest_id': self.customer_location, 'procure_method': 'make_to_order'}) move_with_ancestors = self.MoveObj.create({ - 'name': self.productA.name, - 'product_id': self.productA.id, + 'name': self.productB.name, + 'product_id': self.productB.id, 'product_uom_qty': 2, - 'product_uom': self.productA.uom_id.id, + 'product_uom': self.productB.uom_id.id, 'picking_id': picking_out.id, 'location_id': self.stock_location, 'location_dest_id': self.customer_location}) self.MoveObj.create({ - 'name': self.productA.name, - 'product_id': self.productA.id, + 'name': self.productB.name, + 'product_id': self.productB.id, 'product_uom_qty': 2, - 'product_uom': self.productA.uom_id.id, + 'product_uom': self.productB.uom_id.id, 'picking_id': picking_out.id, 'location_id': self.stock_location, 'location_dest_id': self.customer_location, 'move_dest_ids': [(4, move_with_ancestors.id, 0)]}) other_move = self.MoveObj.create({ - 'name': self.productA.name, - 'product_id': self.productA.id, + 'name': self.productC.name, + 'product_id': self.productC.id, 'product_uom_qty': 2, - 'product_uom': self.productA.uom_id.id, + 'product_uom': self.productC.uom_id.id, 'picking_id': picking_out.id, 'location_id': self.stock_location, 'location_dest_id': self.customer_location}) From 48671620b70e64e3b8b01666a230a99f27480d7a Mon Sep 17 00:00:00 2001 From: amoyaux Date: Wed, 13 Sep 2017 14:36:05 +0200 Subject: [PATCH 17/40] [FIX] stock: orderpoint should not have been remove on product Orderpoint has been removed by this commit 0e4f3bb95991261c04c08e72b28430acfabdecd1 However it was still used in the overide of product write in order to avoid archive a product that still have active orderpoint. This commit readd the field orderpoint_ids --- addons/stock/models/product.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 12c957855ad..577e5aefc7b 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -71,6 +71,7 @@ class Product(models.Model): "Otherwise, this includes goods leaving any Stock " "Location with 'internal' type.") + orderpoint_ids = fields.One2many('stock.warehouse.orderpoint', 'product_id', 'Minimum Stock Rules') nbr_reordering_rules = fields.Integer('Reordering Rules', compute='_compute_nbr_reordering_rules') reordering_min_qty = fields.Float(compute='_compute_nbr_reordering_rules') reordering_max_qty = fields.Float(compute='_compute_nbr_reordering_rules') From 57c4dd8b626358a17e08b464c7bb1de8eb991734 Mon Sep 17 00:00:00 2001 From: amoyaux Date: Fri, 15 Sep 2017 16:19:16 +0200 Subject: [PATCH 18/40] [FIX] stock: priority on new move compare bool and str Since python3 compare boolean and string is not possible anymore. Priority field on stock move line is not required and thus it happens that we compare a set priority with an unset one. In order to correct it this commit only compares move line that have priority and if tey are not use the default priority 1. --- addons/stock/models/stock_picking.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 675c9a76009..cd739b5bb42 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -310,7 +310,11 @@ class Picking(models.Model): @api.one @api.depends('move_lines.priority') def _compute_priority(self): - self.priority = self.mapped('move_lines') and max(self.mapped('move_lines').mapped('priority')) or '1' + if self.mapped('move_lines'): + priorities = [priority for priority in self.mapped('move_lines.priority') if priority] or ['1'] + self.priority = max(priorities) + else: + self.priority = '1' @api.one def _set_priority(self): From cebbee89291b130e2657130d4b56eea574ab66e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 18 Sep 2017 15:11:19 +0200 Subject: [PATCH 19/40] [FIX] mail: prevent pos tour from sometimes failing Here is what could (sometimes) happen in community: - the point of sale tour is started by the runbot - it loads the '/web' url - this instantiate the mail client action (init) - the tour sees that the POS link is in the dom and clicks on it - the action manager destroys the discuss client action (before its start method is called) - the destroy method from the client action is called, this.$buttons is not set, the destroy method causes a traceback --- addons/mail/static/src/js/client_action.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index 52e67c60f68..9f43a9f08df 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -660,7 +660,9 @@ var ChatAction = Widget.extend(ControlPanelMixin, { }); }, destroy: function() { - this.$buttons.off().destroy(); + if (this.$buttons) { + this.$buttons.off().destroy(); + } this._super.apply(this, arguments); }, From 596e88f05d928d443732e9895b5e8a446b2a42b4 Mon Sep 17 00:00:00 2001 From: Dhawal Limbuwala Date: Wed, 6 Sep 2017 12:53:34 +0530 Subject: [PATCH 20/40] [FIX] mail: restore background color of notes in chatter It had been removed by the new design of v11, but it is necessary to easily make the distinction between internal notes and messages. --- addons/mail/static/src/less/thread.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/mail/static/src/less/thread.less b/addons/mail/static/src/less/thread.less index 03bb984599a..f18643dde41 100644 --- a/addons/mail/static/src/less/thread.less +++ b/addons/mail/static/src/less/thread.less @@ -104,6 +104,10 @@ max-width: 100%; word-wrap: break-word; + &.o_mail_note { + background-color: @odoo-color-silver-dark; + } + .o_mail_subject { font-style: italic; } From 8bf06adc8d78c1bff8dc80ce53d6646e3ad22fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Sun, 17 Sep 2017 16:44:02 +0200 Subject: [PATCH 21/40] [FIX] namespace packages: move from pkg_resources-style to pkg_util Deprecates the previous pkg_resources-style packages. Our use was not entirely spec compliant, and it broke with setuptools 31. More information in https://github.com/odoo/odoo/pull/15718 Instead, use the pkgutil-style namespace packages. This is spec compliant as long as all other distributions providing odoo.addons use PEP 420 namespace packages (i.e. no __init__.py). So this mechanism fully works on Python 3 only, but does not break anything on Python 2. See also: https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages Closes #19517 Fixes #15718 --- odoo-bin | 1 - odoo/__init__.py | 6 ++++++ odoo/addons/__init__.py | 5 ++++- setup/odoo | 1 - 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/odoo-bin b/odoo-bin index 535ea47f60f..fae9bf233b6 100755 --- a/odoo-bin +++ b/odoo-bin @@ -2,7 +2,6 @@ # set server timezone in UTC before time module imported __import__('os').environ['TZ'] = 'UTC' -__import__('pkg_resources').declare_namespace('odoo.addons') import odoo if __name__ == "__main__": diff --git a/odoo/__init__.py b/odoo/__init__.py index 3c3b14fdadc..2814706b57a 100644 --- a/odoo/__init__.py +++ b/odoo/__init__.py @@ -3,6 +3,12 @@ """ OpenERP core library.""" +#---------------------------------------------------------- +# odoo must be a namespace package for odoo.addons to become one too +# https://packaging.python.org/guides/packaging-namespace-packages/ +#---------------------------------------------------------- +__path__ = __import__('pkgutil').extend_path(__path__, __name__) + #---------------------------------------------------------- # Running mode flags (gevent, prefork) #---------------------------------------------------------- diff --git a/odoo/addons/__init__.py b/odoo/addons/__init__.py index d3a3e7e9ba2..c0058937588 100644 --- a/odoo/addons/__init__.py +++ b/odoo/addons/__init__.py @@ -14,4 +14,7 @@ This module also conveniently reexports some symbols from odoo.modules. Importing them from here is deprecated. """ -__import__('pkg_resources').declare_namespace(__name__) +# make odoo.addons a namespace package, while keeping this __init__.py +# present, for python 2 compatibility +# https://packaging.python.org/guides/packaging-namespace-packages/ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/setup/odoo b/setup/odoo index 535ea47f60f..fae9bf233b6 100644 --- a/setup/odoo +++ b/setup/odoo @@ -2,7 +2,6 @@ # set server timezone in UTC before time module imported __import__('os').environ['TZ'] = 'UTC' -__import__('pkg_resources').declare_namespace('odoo.addons') import odoo if __name__ == "__main__": From 245f2595614f1f014f03e8f65db5d0f5b51a400f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Maes?= Date: Mon, 18 Sep 2017 13:41:42 +0200 Subject: [PATCH 22/40] [FIX] hr_recruitement: avoid crash when no res_model_id is given --- addons/hr_recruitment/models/calendar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_recruitment/models/calendar.py b/addons/hr_recruitment/models/calendar.py index 5da3ed28f51..976b5019b73 100644 --- a/addons/hr_recruitment/models/calendar.py +++ b/addons/hr_recruitment/models/calendar.py @@ -20,7 +20,7 @@ class CalendarEvent(models.Model): # sync res_model / res_id to opportunity id (aka creating meeting from lead chatter) if 'applicant_id' not in defaults and defaults.get('res_id') and (defaults.get('res_model') or defaults.get('res_model_id')): - if (defaults.get('res_model') and defaults['res_model'] == 'hr.applicant') or self.env['ir.model'].sudo().browse(defaults['res_model_id']).model == 'hr.applicant': + if (defaults.get('res_model') and defaults['res_model'] == 'hr.applicant') or (defaults.get('res_model_id') and self.env['ir.model'].sudo().browse(defaults['res_model_id']).model == 'hr.applicant'): defaults['applicant_id'] = defaults['res_id'] return defaults From 97138a1eaeca76ebf297490604268dadbfa43f97 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Mon, 18 Sep 2017 14:39:53 +0200 Subject: [PATCH 23/40] [FIX] website_theme_install: fix several design issues - Useless horizontal scrollbar - Misalignments - Broken mobile layout --- .../static/src/less/website_theme_install.less | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/website_theme_install/static/src/less/website_theme_install.less b/addons/website_theme_install/static/src/less/website_theme_install.less index f72d98eb4f0..775b5761dea 100644 --- a/addons/website_theme_install/static/src/less/website_theme_install.less +++ b/addons/website_theme_install/static/src/less/website_theme_install.less @@ -6,9 +6,11 @@ /// Un-grouped Layout (default) &.o_kanban_ungrouped { .o-justify-content(space-between); + margin: 0 0 0 (@o-kanban-record-margin - 2 * @grid-gutter-width); - @media (min-width: @screen-md-min) { - margin: 0 -@grid-gutter-width; + @media (max-width: @screen-xs-max) { + padding-left: @odoo-horizontal-padding - @o-kanban-record-margin; + padding-right: @odoo-horizontal-padding; } .o_kanban_record { @@ -17,8 +19,7 @@ } .o_kanban_record { - margin-left: @grid-gutter-width; - margin-right: @grid-gutter-width; + margin-left: @grid-gutter-width * 2; padding: 0; box-shadow: none; background: none; From ae2a64ab6396dda9a2d04acd23943977718aff77 Mon Sep 17 00:00:00 2001 From: Jaykishan Solanki Date: Tue, 12 Sep 2017 18:50:08 +0530 Subject: [PATCH 24/40] [FIX] hr_attendance: use getSession() to retrieve `user_has_group` property --- addons/hr_attendance/static/src/js/greeting_message.js | 2 +- addons/hr_attendance/static/src/js/kiosk_confirm.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hr_attendance/static/src/js/greeting_message.js b/addons/hr_attendance/static/src/js/greeting_message.js index 08c6879e077..ac6e3f86c73 100644 --- a/addons/hr_attendance/static/src/js/greeting_message.js +++ b/addons/hr_attendance/static/src/js/greeting_message.js @@ -23,7 +23,7 @@ var GreetingMessage = Widget.extend({ // to the (likely) appropriate menu, according to the user access rights if(!action.attendance) { this.activeBarcode = false; - this.session.user_has_group('hr_attendance.group_hr_attendance_user').then(function(has_group) { + this.getSession().user_has_group('hr_attendance.group_hr_attendance_user').then(function(has_group) { if(has_group) { self.next_action = 'hr_attendance.hr_attendance_action_kiosk_mode'; } else { diff --git a/addons/hr_attendance/static/src/js/kiosk_confirm.js b/addons/hr_attendance/static/src/js/kiosk_confirm.js index b489102fe68..9ee035dc493 100644 --- a/addons/hr_attendance/static/src/js/kiosk_confirm.js +++ b/addons/hr_attendance/static/src/js/kiosk_confirm.js @@ -67,7 +67,7 @@ var KioskConfirm = Widget.extend({ start: function () { var self = this; - self.session.user_has_group('hr_attendance.group_hr_attendance_use_pin').then(function(has_group){ + self.getSession().user_has_group('hr_attendance.group_hr_attendance_use_pin').then(function(has_group){ self.use_pin = has_group; self.$el.html(QWeb.render("HrAttendanceKioskConfirm", {widget: self})); self.start_clock(); From a8f1adc29a575ebf63b8418409846bea603e53d9 Mon Sep 17 00:00:00 2001 From: Hardik Patel Date: Tue, 29 Aug 2017 18:45:39 +0530 Subject: [PATCH 25/40] [FIX] rating: correctly encode base64 image Fixed a typo from commit 3824b5dcc13678d3985ad45ac21dcf9ac9202c20 --- addons/rating/models/rating.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py index 5825c284ca1..67360ffd3d3 100644 --- a/addons/rating/models/rating.py +++ b/addons/rating/models/rating.py @@ -69,7 +69,7 @@ class Rating(models.Model): for rating in self: try: image_path = get_resource_path('rating', 'static/src/img', 'rating_%s.png' % (int(rating.rating),)) - rating.rating_image = base64.b64decode(open(image_path, 'rb').read()) + rating.rating_image = base64.b64encode(open(image_path, 'rb').read()) except (IOError, OSError): rating.rating_image = False From 860ed1c7f98c75f3d74911c7ee0e5e6da909bc64 Mon Sep 17 00:00:00 2001 From: Hetashree Chauhan Date: Fri, 18 Aug 2017 15:16:11 +0530 Subject: [PATCH 26/40] [IMP] rating: typo on stat button --- addons/rating/views/rating_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rating/views/rating_view.xml b/addons/rating/views/rating_view.xml index d2ae638e3b6..a3f18c899fd 100644 --- a/addons/rating/views/rating_view.xml +++ b/addons/rating/views/rating_view.xml @@ -26,7 +26,7 @@
From 09e44c02f2b5531b816783a964fcbbcf069a49db Mon Sep 17 00:00:00 2001 From: Monish Soni Date: Wed, 13 Sep 2017 16:58:04 +0530 Subject: [PATCH 27/40] [FIX] mail: Fix typo in mail chatter --- addons/mail/static/src/xml/chatter.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/static/src/xml/chatter.xml b/addons/mail/static/src/xml/chatter.xml index ef8bf100419..1d268471af2 100644 --- a/addons/mail/static/src/xml/chatter.xml +++ b/addons/mail/static/src/xml/chatter.xml @@ -53,7 +53,7 @@ - From b3d1a7f7cfa1c302d5afb1dd3f32c56151ec82d5 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 18 Sep 2017 19:00:54 +0200 Subject: [PATCH 28/40] [FIX] point_of_sale: format date correctly Oversight of previous forward-port --- addons/point_of_sale/static/src/js/models.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index c560230064c..03121f74b70 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -2074,8 +2074,7 @@ exports.Order = Backbone.Model.extend({ initialize_validation_date: function () { this.validation_date = new Date(); - this.formatted_validation_date = formats.format_value( - this.validation_date, {type: 'datetime'}); + this.formatted_validation_date = field_utils.format.datetime(this.validation_date); }, set_tip: function(tip) { From ec96c0b3c252244066bea264e88867983969d6ee Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Mon, 18 Sep 2017 21:57:48 +0200 Subject: [PATCH 29/40] [IMP] base: add vat_label on res.country That allows to display the 'vat' field under the right label in reports. --- addons/account/views/report_invoice.xml | 2 +- .../mrp_repair_templates_repair_order.xml | 4 +-- .../static/src/xml/printbill.xml | 2 +- .../report/purchase_order_templates.xml | 2 +- .../report/purchase_quotation_templates.xml | 2 +- .../sale/report/invoice_report_templates.xml | 2 +- addons/sale/report/sale_report_templates.xml | 2 +- .../report/report_stockpicking_operations.xml | 2 +- addons/web/views/report_templates.xml | 8 +++--- odoo/addons/base/res/res_country.py | 1 + odoo/addons/base/res/res_country_data.xml | 28 +++++++++++++++++++ odoo/addons/base/res/res_country_view.xml | 1 + 12 files changed, 43 insertions(+), 13 deletions(-) diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml index bec3e095229..cca8934e060 100644 --- a/addons/account/views/report_invoice.xml +++ b/addons/account/views/report_invoice.xml @@ -9,7 +9,7 @@
-
VAT:
+
:
diff --git a/addons/mrp_repair/report/mrp_repair_templates_repair_order.xml b/addons/mrp_repair/report/mrp_repair_templates_repair_order.xml index 54dca87b277..4c54eaf7d21 100644 --- a/addons/mrp_repair/report/mrp_repair_templates_repair_order.xml +++ b/addons/mrp_repair/report/mrp_repair_templates_repair_order.xml @@ -15,13 +15,13 @@ Invoice address:
-

VAT:

+

:

Shipping address :
-

VAT:

+

:

diff --git a/addons/pos_restaurant/static/src/xml/printbill.xml b/addons/pos_restaurant/static/src/xml/printbill.xml index 79c82ea95b2..2771409e5e1 100644 --- a/addons/pos_restaurant/static/src/xml/printbill.xml +++ b/addons/pos_restaurant/static/src/xml/printbill.xml @@ -54,7 +54,7 @@
Tel:
-
VAT:
+
:
diff --git a/addons/purchase/report/purchase_order_templates.xml b/addons/purchase/report/purchase_order_templates.xml index 7ca0c433b33..c91660ba147 100644 --- a/addons/purchase/report/purchase_order_templates.xml +++ b/addons/purchase/report/purchase_order_templates.xml @@ -22,7 +22,7 @@
-

VAT:

+

:

diff --git a/addons/purchase/report/purchase_quotation_templates.xml b/addons/purchase/report/purchase_quotation_templates.xml index c14f3229b72..79a1d82ab75 100644 --- a/addons/purchase/report/purchase_quotation_templates.xml +++ b/addons/purchase/report/purchase_quotation_templates.xml @@ -22,7 +22,7 @@
-

VAT:

+

:

diff --git a/addons/sale/report/invoice_report_templates.xml b/addons/sale/report/invoice_report_templates.xml index 865ec8a58d0..bf806ebce3b 100644 --- a/addons/sale/report/invoice_report_templates.xml +++ b/addons/sale/report/invoice_report_templates.xml @@ -100,7 +100,7 @@
-
VAT:
+
:
diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml index c5a912625c8..1c8ef5e3497 100644 --- a/addons/sale/report/sale_report_templates.xml +++ b/addons/sale/report/sale_report_templates.xml @@ -24,7 +24,7 @@
-

VAT:

+

:

diff --git a/addons/stock/report/report_stockpicking_operations.xml b/addons/stock/report/report_stockpicking_operations.xml index 1169a9772d1..443e18c8a71 100644 --- a/addons/stock/report/report_stockpicking_operations.xml +++ b/addons/stock/report/report_stockpicking_operations.xml @@ -33,7 +33,7 @@
-

VAT:

+

:

diff --git a/addons/web/views/report_templates.xml b/addons/web/views/report_templates.xml index bb5a11bc684..8a2b3be34c2 100644 --- a/addons/web/views/report_templates.xml +++ b/addons/web/views/report_templates.xml @@ -157,7 +157,7 @@
  • -
  • VAT:
  • +
  • :
  • @@ -196,7 +196,7 @@
  • Tel:
  • Mail:
  • Web:
  • -
  • VAT:
  • +
  • :
  • @@ -215,7 +215,7 @@
    • -
    • VAT:
    • +
    • :
    • Tel:
    • @@ -281,7 +281,7 @@
    • Phone:
    • Email:
    • Web:
    • -
    • VAT:
    • +
    • :
    diff --git a/odoo/addons/base/res/res_country.py b/odoo/addons/base/res/res_country.py index 36e539f8e23..a3984155b4e 100644 --- a/odoo/addons/base/res/res_country.py +++ b/odoo/addons/base/res/res_country.py @@ -64,6 +64,7 @@ class Country(models.Model): ('after', 'After Address'), ], string="Customer Name Position", default="before", help="Determines where the customer/company name should be placed, i.e. after or before the address.") + vat_label = fields.Char(string='Vat Label', translate=True, help="Use this field if you want to change vat label.") _sql_constraints = [ ('name_uniq', 'unique (name)', diff --git a/odoo/addons/base/res/res_country_data.xml b/odoo/addons/base/res/res_country_data.xml index 95b83a5fa52..abe8291d7c0 100644 --- a/odoo/addons/base/res/res_country_data.xml +++ b/odoo/addons/base/res/res_country_data.xml @@ -84,6 +84,7 @@ + VAT Australia @@ -142,6 +143,7 @@ + VAT Burkina Faso @@ -156,6 +158,7 @@ + VAT Bahrain @@ -391,6 +394,7 @@ + VAT Czech Republic @@ -398,6 +402,7 @@ + VAT Germany @@ -406,6 +411,7 @@ + VAT Djibouti @@ -420,6 +426,7 @@ + VAT Dominica @@ -455,6 +462,7 @@ + VAT Egypt @@ -483,6 +491,7 @@ + VAT Ethiopia @@ -498,6 +507,7 @@ + VAT Fiji @@ -534,6 +544,7 @@ + VAT Gabon @@ -623,6 +634,7 @@ + VAT South Georgia and the South Sandwich Islands @@ -685,6 +697,7 @@ + VAT Haiti @@ -699,6 +712,7 @@ + VAT Indonesia @@ -713,6 +727,7 @@ + VAT Israel @@ -770,6 +785,7 @@ + VAT Jersey @@ -934,6 +950,7 @@ + VAT Luxembourg @@ -941,6 +958,7 @@ + VAT Latvia @@ -948,6 +966,7 @@ + VAT Libya @@ -1073,6 +1092,7 @@ + VAT Mauritius @@ -1165,6 +1185,7 @@ + VAT Norway @@ -1257,6 +1278,7 @@ + VAT Saint Pierre and Miquelon @@ -1291,6 +1313,7 @@ + VAT Palau @@ -1325,6 +1348,7 @@ + VAT Serbia @@ -1381,6 +1405,7 @@ + VAT Singapore @@ -1402,6 +1427,7 @@ + VAT Svalbard and Jan Mayen @@ -1415,6 +1441,7 @@ + VAT Sierra Leone @@ -1626,6 +1653,7 @@ + VAT USA Minor Outlying Islands diff --git a/odoo/addons/base/res/res_country_view.xml b/odoo/addons/base/res/res_country_view.xml index 5b883b993e3..aede3731c9d 100644 --- a/odoo/addons/base/res/res_country_view.xml +++ b/odoo/addons/base/res/res_country_view.xml @@ -31,6 +31,7 @@ + From 194c38f09d2a76aaec6a514f86484eb8e9b6e08c Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Mon, 18 Sep 2017 22:00:37 +0200 Subject: [PATCH 30/40] [REF] account, sale: some minor refactoring that would allow to easily overwrite the printed report name and invoice/sale reports --- addons/account/models/account_invoice.py | 12 +++++++++++ addons/account/views/account_report.xml | 20 ++----------------- addons/account/views/report_invoice.xml | 2 +- .../sale/report/invoice_report_templates.xml | 2 +- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 1e76dbc4b63..5f9b93f0d85 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -431,6 +431,18 @@ class AccountInvoice(models.Model): sequence = journal_sequence._get_current_sequence() sequence.number_next = int(result.group(2)) + @api.multi + def _get_printed_report_name(self): + self.ensure_one() + return self.type == 'out_invoice' and self.state == 'draft' and _('Draft Invoice') or \ + self.type == 'out_invoice' and self.state in ('open','paid') and _('Invoice - %s') % (self.number) or \ + self.type == 'out_refund' and self.state == 'draft' and _('Credit Note') or \ + self.type == 'out_refund' and _('Credit Note - %s') % (self.number) or \ + self.type == 'in_invoice' and self.state == 'draft' and _('Vendor Bill') or \ + self.type == 'in_invoice' and self.state in ('open','paid') and _('Vendor Bill - %s') % (self.number) or \ + self.type == 'in_refund' and self.state == 'draft' and _('Vendor Credit Note') or \ + self.type == 'in_refund' and _('Vendor Credit Note - %s') % (self.number) + @api.model def create(self, vals): onchanges = { diff --git a/addons/account/views/account_report.xml b/addons/account/views/account_report.xml index c6f3ba536ff..6328d865c2c 100644 --- a/addons/account/views/account_report.xml +++ b/addons/account/views/account_report.xml @@ -10,15 +10,7 @@ name="account.report_invoice_with_payments" file="account.report_invoice_with_payments" attachment="(object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')" - print_report_name="( - object.type == 'out_invoice' and object.state == 'draft' and 'Draft Invoice' or - object.type == 'out_invoice' and object.state in ('open','paid') and 'Invoice - %s' % (object.number) or - object.type == 'out_refund' and object.state == 'draft' and 'Credit Note' or - object.type == 'out_refund' and 'Credit Note - %s' % (object.number) or - object.type == 'in_invoice' and object.state == 'draft' and 'Vendor Bill' or - object.type == 'in_invoice' and object.state in ('open','paid') and 'Vendor Bill - %s' % (object.number) or - object.type == 'in_refund' and object.state == 'draft' and 'Vendor Credit Note' or - object.type == 'in_refund' and 'Vendor Credit Note - %s' % (object.number))" + print_report_name="(object._get_printed_report_name())" /> - +
    diff --git a/addons/sale/report/invoice_report_templates.xml b/addons/sale/report/invoice_report_templates.xml index bf806ebce3b..672fc817422 100644 --- a/addons/sale/report/invoice_report_templates.xml +++ b/addons/sale/report/invoice_report_templates.xml @@ -13,7 +13,7 @@ !sale.group_sale_layout - +
    Description
    From 2b3c8e6ca9777f6264ecb3d1510dd292ed30ab9f Mon Sep 17 00:00:00 2001 From: Foram Katharotiya Date: Mon, 18 Sep 2017 22:17:43 +0200 Subject: [PATCH 31/40] [IMP] l10n_in: GST introduced as new legal requirements. aka 'Indian localization out of the box'. Details: GST introduced, module refactored. Update GST chart of account, tags and SGST, CGST & IGST taxes. Replace vat label with GSTIN in reports & views. Added HSN Code field and display it on invoice form view & report. Added pin number field in res_country_state. Show the total amount in words based on Indian numbering system on form view of customer/supplier invoice/refund. Arrange address format of India country. l10n_in_schedule6: Introduce new GST taxes, chart of accounts & account tags. l10n_in_sale, l10n_in_purchase, l10n_in_stock: added modules to add hsn code and replace vat with gstin in sale, purchase & stock reports Was task: 33241. Was PR #18952 --- addons/l10n_in/__init__.py | 2 + addons/l10n_in/__manifest__.py | 9 +- addons/l10n_in/data/account_data.xml | 25 +- .../data/account_fiscal_position_data.xml | 140 ++ .../data/account_tax_template_data.xml | 1241 +++++++------- addons/l10n_in/data/l10n_in_chart_data.xml | 94 +- .../l10n_in/data/res_country_state_data.xml | 113 ++ addons/l10n_in/models/__init__.py | 7 + addons/l10n_in/models/account_invoice.py | 43 + addons/l10n_in/models/chart_template.py | 23 + addons/l10n_in/models/product_template.py | 10 + addons/l10n_in/models/res_country_state.py | 10 + .../l10n_in/views/product_template_view.xml | 15 + addons/l10n_in/views/report_invoice.xml | 130 ++ addons/l10n_in/views/res_company_view.xml | 16 + .../l10n_in/views/res_country_state_view.xml | 15 + addons/l10n_in/views/res_partner_views.xml | 14 + addons/l10n_in_purchase/__init__.py | 2 + addons/l10n_in_purchase/__manifest__.py | 19 + .../views/report_purchase_order.xml | 17 + addons/l10n_in_sale/__init__.py | 2 + addons/l10n_in_sale/__manifest__.py | 20 + .../views/report_invoice_view.xml | 114 ++ .../l10n_in_sale/views/report_sale_order.xml | 10 + addons/l10n_in_schedule6/__manifest__.py | 2 +- addons/l10n_in_schedule6/account_data.xml | 40 +- .../l10n_in_schedule6_chart.xml | 108 +- .../l10n_in_schedule6_tax_template.xml | 1463 +++++++---------- addons/l10n_in_stock/__init__.py | 2 + addons/l10n_in_stock/__manifest__.py | 19 + .../views/report_stockpicking_operations.xml | 10 + odoo/addons/base/res/res_country_data.xml | 3 +- 32 files changed, 2116 insertions(+), 1622 deletions(-) create mode 100644 addons/l10n_in/data/account_fiscal_position_data.xml create mode 100644 addons/l10n_in/data/res_country_state_data.xml create mode 100644 addons/l10n_in/models/__init__.py create mode 100644 addons/l10n_in/models/account_invoice.py create mode 100644 addons/l10n_in/models/chart_template.py create mode 100644 addons/l10n_in/models/product_template.py create mode 100644 addons/l10n_in/models/res_country_state.py create mode 100644 addons/l10n_in/views/product_template_view.xml create mode 100644 addons/l10n_in/views/report_invoice.xml create mode 100644 addons/l10n_in/views/res_company_view.xml create mode 100644 addons/l10n_in/views/res_country_state_view.xml create mode 100644 addons/l10n_in/views/res_partner_views.xml create mode 100644 addons/l10n_in_purchase/__init__.py create mode 100644 addons/l10n_in_purchase/__manifest__.py create mode 100644 addons/l10n_in_purchase/views/report_purchase_order.xml create mode 100644 addons/l10n_in_sale/__init__.py create mode 100644 addons/l10n_in_sale/__manifest__.py create mode 100644 addons/l10n_in_sale/views/report_invoice_view.xml create mode 100644 addons/l10n_in_sale/views/report_sale_order.xml create mode 100644 addons/l10n_in_stock/__init__.py create mode 100644 addons/l10n_in_stock/__manifest__.py create mode 100644 addons/l10n_in_stock/views/report_stockpicking_operations.xml diff --git a/addons/l10n_in/__init__.py b/addons/l10n_in/__init__.py index 67dee8c60db..dc5e6b693d1 100644 --- a/addons/l10n_in/__init__.py +++ b/addons/l10n_in/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/addons/l10n_in/__manifest__.py b/addons/l10n_in/__manifest__.py index 476a3b5460d..2dd8452e84f 100644 --- a/addons/l10n_in/__manifest__.py +++ b/addons/l10n_in/__manifest__.py @@ -18,12 +18,19 @@ Sheet, now only Vertical format has been permitted Which is Supported By Odoo. """, 'category': 'Localization', 'depends': [ - 'account', + 'account_tax_python', ], 'data': [ 'data/account_data.xml', 'data/l10n_in_chart_data.xml', 'data/account_tax_template_data.xml', + 'data/account_fiscal_position_data.xml', + 'data/res_country_state_data.xml', 'data/account_chart_template_data.yml', + 'views/product_template_view.xml', + 'views/report_invoice.xml', + 'views/res_company_view.xml', + 'views/res_country_state_view.xml', + 'views/res_partner_views.xml', ], } diff --git a/addons/l10n_in/data/account_data.xml b/addons/l10n_in/data/account_data.xml index cd46677af1b..724b3e3e876 100644 --- a/addons/l10n_in/data/account_data.xml +++ b/addons/l10n_in/data/account_data.xml @@ -3,26 +3,17 @@ - - VAT 1% + + SGST - - VAT 2.5% + + CGST - - VAT 4% + + IGST - - VAT 12% - - - VAT 12.5% - - - VAT 14% - - - VAT 15% + + Cess diff --git a/addons/l10n_in/data/account_fiscal_position_data.xml b/addons/l10n_in/data/account_fiscal_position_data.xml new file mode 100644 index 00000000000..d36e31fc1d0 --- /dev/null +++ b/addons/l10n_in/data/account_fiscal_position_data.xml @@ -0,0 +1,140 @@ + + + + + + + Inter State + + + + + Export + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/l10n_in/data/account_tax_template_data.xml b/addons/l10n_in/data/account_tax_template_data.xml index e564bba381f..0261b910602 100644 --- a/addons/l10n_in/data/account_tax_template_data.xml +++ b/addons/l10n_in/data/account_tax_template_data.xml @@ -1,659 +1,718 @@ - - - Tax to Pay - taxes - - - - Excise Duty - taxes - - - - Excise Duty 12.5% - taxes - - - - Excise Duty Collected on Sales - taxes - - - - Excise Duty Paid on Purchase - taxes - - - - Sales Tax - taxes - - - - Sales Tax 4% - taxes - - - - Sales Tax 4% Collected on Sale - taxes - - - - Sales Tax 4% Paid on Purchase - taxes - - - - Sales Tax 12% - taxes - - - - Sales Tax 12% Collected on Sale - taxes - - - - Sales Tax 12% Paid on Purchase - taxes - - - - Sales Tax 15% - taxes - - - - Sales Tax 15% Collected on Sale - taxes - - - - Sales Tax 15% Paid on Purchase - taxes - - - - Service Tax - taxes - - - - Service Tax 14% - taxes - - - - Service Tax Collected on Sales of Services - taxes - - - - Swachh Bharat Cess 0.5% Service Tax Collected on Sales of Services - taxes - - - - Krishi Kalayan Cess 0.5% Service Tax Collected on Sales of Services - taxes - - - - Service Tax Paid on Purchase of Services - taxes - - - - Swachh Bharat Cess 0.5% Service Tax Paid on Purchase of Services - taxes - - - - Krishi Kalayan Cess 0.5% Service Tax Paid on Purchase of Services - taxes - - - - VAT - taxes - - - - VAT 4% - taxes - - - - VAT 4% Collected on Sale - taxes - - - - VAT 4% Paid on Purchase - taxes - - - - VAT 12.5% - taxes - - - - VAT 12.5% Collected on Sale - taxes - - - - VAT 12.5% Paid on Purchase - taxes - - - - Additional VAT 1% - taxes - - - - Additional VAT 1% Collected on Sale - taxes - - - - Additional VAT 1% Paid on Purchase - taxes - - - - Additional VAT 2.5% - taxes - - - - Additional VAT 2.5% Collected on Sale - taxes - - - - Additional VAT 2.5% Paid on Purchase - taxes - - - - Tax Bases - taxes - - - - Base Excise Duty - taxes - - - - Base Excise Duty 12.5% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax - taxes - - - - Base Sales Tax 4% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax 12% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax 15% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Service Tax - taxes - - - - Base Service Tax 15% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT - taxes - - - - Base VAT 4% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT 12.5% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - Base Additional VAT 1% + + SGST taxes - - - Base of Sale + + CGST taxes - - - Base of Purchase + + IGST taxes - - - Base Additional VAT 2.5% + + CESS taxes - - Base of Sale - taxes - + - - Base of Purchase - taxes - - + - - (standard)Input Sales Tax @ 15% - (standard)Input Sales Tax @ 15% - sale + + CESS Sale 5% + CESS 5% + none percent - 15 - 10 - - + 5 + - - + - - (standard)Input Sales Tax @ 12% - (standard)Input Sales Tax @ 12% + + + CESS Sale 1591 Per Thousand + 1591 PER THOUSAND + none + fixed + 1.591 + + + + + + + CESS 5% + RS.1591/THOUSAND + CESS 5% + RS.1591/THOUSAND sale - percent - 12 - 10 - - + group + 0 - - + + - - (standard)Input Sales Tax @ 4% - (standard)Input Sales Tax @ 4% + + + CESS 21% or RS.4170/THOUSAND + CESS 21% or RS.4170/THOUSAND sale - percent - 4 - 10 - - + code + 0 + result=base_amount * 0.21 +tax=quantity * 4.17 +if tax > result:result=tax + - - + - - (standard)Additional Input VAT @ 1% - (standard)Additional Input VAT @ 1% + + + + + IGST 1% + IGST 1% sale percent 1 - 15 - + - - - - - (standard)Input VAT @ 12.5% - (standard)Input VAT @ 12.5% - sale - percent - 12.5 - 10 - - - - - - - - (standard)Additional Input VAT @ 2.5% - (standard)Additional Input VAT @ 2.5% - sale - percent - 2.5 - 15 - - - - - - - - (standard)Input Excise Duty @ 12.5% - (standard)Input Excise Duty @ 12.5% - sale - percent - 12.5 - 1 - - - - - - - - (standard)Input Service Tax 14% - (standard)Input Service Tax 14% - none - percent - 14 - 13 - - - - - - - - (standard)Swachh Bharat Cess @ 0.5% On Input Service - (standard)Swacha Bharat Cess @ 0.5% - none - percent - 0.5 - 14 - - - - - - - (standard)Krishi Kalyan Cess @ 0.5% On Input Service - (standard)Input Higher Education Cess @ 0.5% On Service Tax - none - percent - 0.5 - 15 - - - - - - - (standard)Input Service Tax @ 15% - (standard)Input Service Tax @ 15% - sale - group - 14 - True - 8 - - - - - - - - - (standard)Input VAT @ 4% - (standard)Input VAT @ 4% - sale - percent - 4 - 10 - - - - - + + - - - (standard)Output Purchase Tax @ 15% - (standard)Output Purchase Tax @ 15% - purchase + + IGST 2% + IGST 2% + sale percent - 15 - 10 - - + 2 + + - - + + - - (standard)Output Purchase Tax @ 12% - (standard)Output Purchase Tax @ 12% - purchase + + + IGST 28% + IGST 28% + sale + percent + 28 + + + + + + + + + IGST 18% + IGST 18% + sale + percent + 18 + + + + + + + + + IGST 12% + IGST 12% + sale percent 12 - 10 - - + + - - + + - - (standard)Output Purchase Tax @ 4% - (standard)Output Purchase Tax @ 4% - purchase + + + IGST 5% + IGST 5% + sale percent - 4 - 10 - - + 5 + + - - + + - - (standard)Additional Output VAT @ 1% - (standard)Additional Output VAT @ 1% + + + + + SGST Sale 0.5% + SGST 0.5% + none + percent + 0.5 + + + + + + + + + CGST Sale 0.5% + CGST 0.5% + none + percent + 0.5 + + + + + + + + + GST 1% + GST 1% + sale + group + 0 + + + + + + SGST Sale 1% + SGST 1% + none + percent + 1 + + + + + + + + + CGST Sale 1% + CGST 1% + none + percent + 1 + + + + + + + + + GST 2% + GST 2% + sale + group + 0 + + + + + + SGST Sale 14% + SGST 14% + none + percent + 14 + + + + + + + + + CGST Sale 14% + CGST 14% + none + percent + 14 + + + + + + + + + GST 28% + GST 28% + sale + group + 0 + + + + + + SGST Sale 9% + SGST 9% + none + percent + 9 + + + + + + + + + CGST Sale 9% + CGST 9% + none + percent + 9 + + + + + + + + + GST 18% + GST 18% + sale + group + 0 + + + + + + SGST Sale 6% + SGST 6% + none + percent + 6 + + + + + + + + + CGST Sale 6% + CGST 6% + none + percent + 6 + + + + + + + + + GST 12% + GST 12% + sale + group + 0 + + + + + + SGST Sale 2.5% + SGST 2.5% + none + percent + 2.5 + + + + + + + + + CGST Sale 2.5% + CGST 2.5% + none + percent + 2.5 + + + + + + + + + GST 5% + GST 5% + sale + group + 0 + + + + + + + + + + CESS Purchase 5% + CESS 5% + none + percent + 5 + + + + + + + CESS Purchase 1591 Per Thousand + 1591 PER THOUSAND + none + fixed + 1.591 + + + + + + + CESS 5% + RS.1591/THOUSAND + CESS 5% + RS.1591/THOUSAND + purchase + group + 0 + + + + + + CESS 21% or RS.4170/THOUSAND + CESS 21% or RS.4170/THOUSAND + purchase + code + 0 + result=base_amount * 0.21 +tax=quantity * 4.17 +if tax > result:result=tax + + + + + + + + + IGST 1% + IGST 1% purchase percent 1 - 15 - + - - + + - - (standard)Output VAT @ 12.5% - (standard)Output VAT @ 12.5% + + + IGST 2% + IGST 2% purchase percent - 12.5 - 10 + 2 + + + + + + + + + IGST 28% + IGST 28% + purchase + percent + 28 + + + + + + + + + IGST 18% + IGST 18% + purchase + percent + 18 + + + + + + + + + IGST 12% + IGST 12% + purchase + percent + 12 + + + + + + + + + IGST 5% + IGST 5% + purchase + percent + 5 + + + + + + + + + + + SGST Purchase 0.5% + SGST 0.5% + none + percent + 0.5 - - + + - - (standard)Additional Output VAT @ 2.5% - (standard)Additional Output VAT @ 2.5% + + + CGST Purchase 0.5% + CGST 0.5% + none + percent + 0.5 + + + + + + + + + GST 1% + GST 1% purchase + group + 0 + + + + + + SGST Purchase 1% + SGST 1% + none + percent + 1 + + + + + + + + + CGST Purchase 1% + CGST 1% + none + percent + 1 + + + + + + + + + GST 2% + GST 2% + purchase + group + 0 + + + + + + SGST Purchase 14% + SGST 14% + none + percent + 14 + + + + + + + + + CGST Purchase 14% + CGST 14% + none + percent + 14 + + + + + + + + + GST 28% + GST 28% + purchase + group + 0 + + + + + + SGST Purchase 9% + SGST 9% + none + percent + 9 + + + + + + + + + CGST Purchase 9% + CGST 9% + none + percent + 9 + + + + + + + + + GST 18% + GST 18% + purchase + group + 0 + + + + + + SGST Purchase 6% + SGST 6% + none + percent + 6 + + + + + + + + + CGST Purchase 6% + CGST 6% + none + percent + 6 + + + + + + + + + GST 12% + GST 12% + purchase + group + 0 + + + + + + SGST Purchase 2.5% + SGST 2.5% + none percent 2.5 - 15 - - + + - - (standard)Output Excise Duty @ 12.5% - (standard)Output Excise Duty @ 12.5% - purchase + + + CGST Purchase 2.5% + CGST 2.5% + none percent - 12.5 - 1 - + 2.5 + - - + + - - (standard)Output Serivce Tax 14% - (standard)Output Serivce Tax 14% - none - percent - 14 - 9 - - - - - - - - (standard)Swachh Bharat Cess @ 0.5% On Output Service - (standard)Swachh Bharat Cess @ 0.5% - none - percent - 0.5 - 10 - - - - - - - (standard)Krishi Kalyan Cess @ 0.5% On Output Service - (standard)Krishi Kalyan Cess @ 0.5% - none - percent - 0.5 - 11 - - - - - - - (standard)Output Service Tax @ 15% - (standard)Output Service Tax @ 15% + + + GST 5% + GST 5% purchase - True group - 14 - 8 - - - + 0 - - - - - (standard)Output VAT @ 4% - (standard)Output VAT @ 4% - purchase - percent - 4 - 10 - - - - - + + diff --git a/addons/l10n_in/data/l10n_in_chart_data.xml b/addons/l10n_in/data/l10n_in_chart_data.xml index fefaf6bb309..bb6665970ac 100644 --- a/addons/l10n_in/data/l10n_in_chart_data.xml +++ b/addons/l10n_in/data/l10n_in_chart_data.xml @@ -20,6 +20,19 @@ + + SGST + accounts + + + CGST + accounts + + + IGST + accounts + + Inventories 10031 @@ -34,47 +47,31 @@ - - Sales Tax Receivable - 10050 - - - - - VAT Receivable + SGST Receivable 10051 + - - Excise Duty Receivable - 100521 + + + CGST Receivable + 10052 + - - Service Tax Receivable - 100531 - - - - - - Swachh Bharat Cess Receivable On Service - 100532 - - - - - - Krishi Kalyan Cess Receivable On Service - 100533 + + + IGST Receivable + 10053 + TDS Receivable @@ -207,46 +204,30 @@ - VAT Payable + SGST Payable 11232 + - - Excise Duty Payable - 112331 + + + CGST Payable + 11233 + - - Service Tax Payable - 112341 - - - - - - Swachh Bharat Cess Payable On Service - 112342 - - - - - - Krishi Kalyan Cess Payable On Service - 112343 - - - - - - Sales Tax Payable - 11235 + + + IGST Payable + 11234 + Wages Payable @@ -528,4 +509,5 @@ + diff --git a/addons/l10n_in/data/res_country_state_data.xml b/addons/l10n_in/data/res_country_state_data.xml new file mode 100644 index 00000000000..c580d80eac8 --- /dev/null +++ b/addons/l10n_in/data/res_country_state_data.xml @@ -0,0 +1,113 @@ + + + + + 35 + + + 28 + + + 12 + + + 18 + + + 10 + + + 04 + + + 22 + + + 26 + + + 25 + + + 07 + + + 30 + + + 24 + + + 06 + + + 02 + + + 01 + + + 20 + + + 29 + + + 32 + + + 31 + + + 23 + + + 27 + + + 14 + + + 17 + + + 15 + + + 13 + + + 21 + + + 34 + + + 03 + + + 08 + + + 11 + + + 33 + + + 36 + + + 16 + + + 09 + + + 05 + + + 19 + + + diff --git a/addons/l10n_in/models/__init__.py b/addons/l10n_in/models/__init__.py new file mode 100644 index 00000000000..a4c946eba25 --- /dev/null +++ b/addons/l10n_in/models/__init__.py @@ -0,0 +1,7 @@ +# -*- coding:utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import account_invoice +from . import chart_template +from . import product_template +from . import res_country_state diff --git a/addons/l10n_in/models/account_invoice.py b/addons/l10n_in/models/account_invoice.py new file mode 100644 index 00000000000..d6c55b95e9c --- /dev/null +++ b/addons/l10n_in/models/account_invoice.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ + + +class AccountInvoice(models.Model): + + _inherit = "account.invoice" + + @api.depends('amount_total') + def _compute_amount_total_words(self): + for invoice in self: + invoice.amount_total_words = invoice.currency_id.amount_to_text(invoice.amount_total) + + amount_total_words = fields.Char("Total (In Words)", compute="_compute_amount_total_words") + + def _get_printed_report_name(self): + self.ensure_one() + if self.company_id.country_id.code != 'IN': + return super(AccountInvoice, self)._get_printed_report_name() + return self.type == 'out_invoice' and self.state == 'draft' and _('Draft %s') % (self.journal_id.name) or \ + self.type == 'out_invoice' and self.state in ('open','paid') and '%s - %s' % (self.journal_id.name, self.number) or \ + self.type == 'out_refund' and self.state == 'draft' and _('Credit Note') or \ + self.type == 'out_refund' and _('Credit Note - %s') % (self.number) or \ + self.type == 'in_invoice' and self.state == 'draft' and _('Vendor Bill') or \ + self.type == 'in_invoice' and self.state in ('open','paid') and _('Vendor Bill - %s') % (self.number) or \ + self.type == 'in_refund' and self.state == 'draft' and _('Vendor Credit Note') or \ + self.type == 'in_refund' and _('Vendor Credit Note - %s') % (self.number) + + @api.multi + def _invoice_line_tax_values(self): + self.ensure_one() + tax_datas = {} + TAX = self.env['account.tax'] + + for line in self.mapped('invoice_line_ids'): + price_unit = line.price_unit * (1 - (line.discount or 0.0) / 100.0) + tax_lines = line.invoice_line_tax_ids.compute_all(price_unit, line.invoice_id.currency_id, line.quantity, line.product_id, line.invoice_id.partner_id)['taxes'] + for tax_line in tax_lines: + tax_line['tag_ids'] = TAX.browse(tax_line['id']).tag_ids.ids + tax_datas[line.id] = tax_lines + return tax_datas diff --git a/addons/l10n_in/models/chart_template.py b/addons/l10n_in/models/chart_template.py new file mode 100644 index 00000000000..275087c7dbc --- /dev/null +++ b/addons/l10n_in/models/chart_template.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models, _ + + +class AccountChartTemplate(models.Model): + _inherit = 'account.chart.template' + + + @api.multi + def _prepare_all_journals(self, acc_template_ref, company, journals_dict=None): + res = super(AccountChartTemplate, self)._prepare_all_journals( + acc_template_ref, company, journals_dict=journals_dict) + if not self == self.env.ref('l10n_in.indian_chart_template_standard'): + return res + for journal in res: + if journal['code'] == 'INV': + journal['name'] = _('Tax Invoices') + + res += [{'type': 'sale', 'name': _('Retail Invoices'), 'code': 'RETINV', 'company_id': company.id, 'show_on_dashboard': True,}, + {'type': 'sale', 'name': _('Export Invoices'), 'code': 'EXPINV', 'company_id': company.id, 'show_on_dashboard': True,},] + return res diff --git a/addons/l10n_in/models/product_template.py b/addons/l10n_in/models/product_template.py new file mode 100644 index 00000000000..0a8b47196e9 --- /dev/null +++ b/addons/l10n_in/models/product_template.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + l10n_in_hsn_code = fields.Char(string="HSN/SAC Code", help="Harmonized System Nomenclature/Services Accounting Code") diff --git a/addons/l10n_in/models/res_country_state.py b/addons/l10n_in/models/res_country_state.py new file mode 100644 index 00000000000..6cb495a7365 --- /dev/null +++ b/addons/l10n_in/models/res_country_state.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class CountryState(models.Model): + _inherit = 'res.country.state' + + l10n_in_tin = fields.Char('TIN Number', size=2, help="TIN number-first two digits") diff --git a/addons/l10n_in/views/product_template_view.xml b/addons/l10n_in/views/product_template_view.xml new file mode 100644 index 00000000000..fdf0a1200a9 --- /dev/null +++ b/addons/l10n_in/views/product_template_view.xml @@ -0,0 +1,15 @@ + + + + + l10n_in.product.template.form.hs_code + product.template + + + + + + + + + diff --git a/addons/l10n_in/views/report_invoice.xml b/addons/l10n_in/views/report_invoice.xml new file mode 100644 index 00000000000..f5cae06634c --- /dev/null +++ b/addons/l10n_in/views/report_invoice.xml @@ -0,0 +1,130 @@ + + + + + + diff --git a/addons/l10n_in/views/res_company_view.xml b/addons/l10n_in/views/res_company_view.xml new file mode 100644 index 00000000000..0e3ba268898 --- /dev/null +++ b/addons/l10n_in/views/res_company_view.xml @@ -0,0 +1,16 @@ + + + + + l10n.in.view.company.form + res.company + + + + + GSTIN + + + + + diff --git a/addons/l10n_in/views/res_country_state_view.xml b/addons/l10n_in/views/res_country_state_view.xml new file mode 100644 index 00000000000..bdac8ff6241 --- /dev/null +++ b/addons/l10n_in/views/res_country_state_view.xml @@ -0,0 +1,15 @@ + + + + + l10n.in.res.country.state.form.inhert + res.country.state + + + + + + + + + diff --git a/addons/l10n_in/views/res_partner_views.xml b/addons/l10n_in/views/res_partner_views.xml new file mode 100644 index 00000000000..de4c589d21c --- /dev/null +++ b/addons/l10n_in/views/res_partner_views.xml @@ -0,0 +1,14 @@ + + + + l10n.in.res.partner.vat.inherit + res.partner + + + + + GSTIN + + + + diff --git a/addons/l10n_in_purchase/__init__.py b/addons/l10n_in_purchase/__init__.py new file mode 100644 index 00000000000..67dee8c60db --- /dev/null +++ b/addons/l10n_in_purchase/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. diff --git a/addons/l10n_in_purchase/__manifest__.py b/addons/l10n_in_purchase/__manifest__.py new file mode 100644 index 00000000000..a37f00026d3 --- /dev/null +++ b/addons/l10n_in_purchase/__manifest__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Indian - Purchase Report(GST)', + 'version': '1.0', + 'description': """GST Purchase Report""", + 'category': 'Localization', + 'depends': [ + 'l10n_in', + 'purchase', + ], + 'data': [ + 'views/report_purchase_order.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': True, +} diff --git a/addons/l10n_in_purchase/views/report_purchase_order.xml b/addons/l10n_in_purchase/views/report_purchase_order.xml new file mode 100644 index 00000000000..398e9fcf068 --- /dev/null +++ b/addons/l10n_in_purchase/views/report_purchase_order.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/addons/l10n_in_sale/__init__.py b/addons/l10n_in_sale/__init__.py new file mode 100644 index 00000000000..67dee8c60db --- /dev/null +++ b/addons/l10n_in_sale/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. diff --git a/addons/l10n_in_sale/__manifest__.py b/addons/l10n_in_sale/__manifest__.py new file mode 100644 index 00000000000..6547ae0aa9d --- /dev/null +++ b/addons/l10n_in_sale/__manifest__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Indian - Sale Report(GST)', + 'version': '1.0', + 'description': """GST Sale Report""", + 'category': 'Localization', + 'depends': [ + 'l10n_in', + 'sale', + ], + 'data': [ + 'views/report_sale_order.xml', + 'views/report_invoice_view.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': True, +} diff --git a/addons/l10n_in_sale/views/report_invoice_view.xml b/addons/l10n_in_sale/views/report_invoice_view.xml new file mode 100644 index 00000000000..f3be1383da1 --- /dev/null +++ b/addons/l10n_in_sale/views/report_invoice_view.xml @@ -0,0 +1,114 @@ + + + + + + diff --git a/addons/l10n_in_sale/views/report_sale_order.xml b/addons/l10n_in_sale/views/report_sale_order.xml new file mode 100644 index 00000000000..c9d241cb043 --- /dev/null +++ b/addons/l10n_in_sale/views/report_sale_order.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/addons/l10n_in_schedule6/__manifest__.py b/addons/l10n_in_schedule6/__manifest__.py index 90c92f0bdc5..ce04fdd376f 100644 --- a/addons/l10n_in_schedule6/__manifest__.py +++ b/addons/l10n_in_schedule6/__manifest__.py @@ -18,7 +18,7 @@ Sheet, now only Vertical format has been permitted Which is Supported By OpenERP """, 'category': 'Localization', 'depends': [ - 'account', + 'account_tax_python', ], 'demo': [], 'data': [ diff --git a/addons/l10n_in_schedule6/account_data.xml b/addons/l10n_in_schedule6/account_data.xml index f60c009f56d..1cadb77ec14 100644 --- a/addons/l10n_in_schedule6/account_data.xml +++ b/addons/l10n_in_schedule6/account_data.xml @@ -3,41 +3,17 @@ - - VAT 0.24% + + SGST - - VAT 0.1224% + + CGST - - VAT 1% + + IGST - - VAT 2% - - - VAT 2.5% - - - VAT 4% - - - VAT 8% - - - VAT 10% - - - VAT 12% - - - VAT 12.5% - - - VAT 12.36% - - - VAT 15% + + Cess diff --git a/addons/l10n_in_schedule6/l10n_in_schedule6_chart.xml b/addons/l10n_in_schedule6/l10n_in_schedule6_chart.xml index 5552803bd7a..1b3ce822d00 100644 --- a/addons/l10n_in_schedule6/l10n_in_schedule6_chart.xml +++ b/addons/l10n_in_schedule6/l10n_in_schedule6_chart.xml @@ -1,6 +1,5 @@ - - + 1206 @@ -190,44 +189,23 @@ - - Excise Duty Payable - 1142111 + + (schedule6)SGST Payable + 114210 - - Education Cess Payable On Excise Duty - 1142112 + + (schedule6)CGST Payable + 114211 - - Higher Education Cess Payable On Excise Duty - 1142113 - - - - - - Service Tax Payable - 1142121 - - - - - - Education Cess Payable On Service Tax - 1142122 - - - - - - Higher Education Cess Payable On Service Tax - 1142123 + + (schedule6)IGST Payable + 114212 @@ -239,20 +217,6 @@ - - Central Sales Tax Payable - 114214 - - - - - - VAT Payable - 114215 - - - - Out Standing Cheques for Clearance 11422 @@ -810,58 +774,23 @@ - - Sales Tax Receivable - 121610 - - - - - VAT Receivable + (schedule6)SGST Receivable 121611 - - Excise Duty Receivable - 1216121 + + (schedule6)CGST Receivable + 121612 - - Education Cess Receivable On Excise Duty - 1216122 - - - - - - Higher Education Cess Receivable On Excise Duty - 1216123 - - - - - - Service Tax Receivable - 1216131 - - - - - - Education Cess Receivable On Service Tax - 1216132 - - - - - - Higher Education Cess Receivable On Service Tax - 1216133 + + (schedule6)IGST Receivable + 121613 @@ -1429,5 +1358,4 @@ - - \ No newline at end of file + diff --git a/addons/l10n_in_schedule6/l10n_in_schedule6_tax_template.xml b/addons/l10n_in_schedule6/l10n_in_schedule6_tax_template.xml index 3b6548acb39..d1400e7ac07 100644 --- a/addons/l10n_in_schedule6/l10n_in_schedule6_tax_template.xml +++ b/addons/l10n_in_schedule6/l10n_in_schedule6_tax_template.xml @@ -1,876 +1,673 @@ - - + - - - Tax to Pay + + SGST taxes - - - C Forms - taxes - - - - C Forms Tax Collected on Sale - taxes - - - - C Forms Tax Paid on Purchase - taxes - - - - Excise Duty - taxes - - - - Excise Duty 12.36% - taxes - - - - Excise Duty Collected on Sales - taxes - - - - Education Cess 2% Excise Duty Collected on Sales - taxes - - - - Higher Education Cess 1% Excise Duty Collected on Sales - taxes - - - - Excise Duty Paid on Purchase - taxes - - - - Education Cess 2% Excise Duty Paid on Purchase - taxes - - - - Higher Education Cess 1% Excise Duty Paid on Purchase - taxes - - - - Sales Tax - taxes - - - - Sales Tax 4% - taxes - - - - Sales Tax 4% Collected on Sale - taxes - - - - Sales Tax 4% Paid on Purchase - taxes - - - - Sales Tax 12% - taxes - - - - Sales Tax 12% Collected on Sale - taxes - - - - Sales Tax 12% Paid on Purchase - taxes - - - - Sales Tax 15% - taxes - - - - Sales Tax 15% Collected on Sale - taxes - - - - Sales Tax 15% Paid on Purchase - taxes - - - - Service Tax - taxes - - - - Service Tax 12.36% - taxes - - - - Service Tax Collected on Sales of Services - taxes - - - - Education Cess 2% Service Tax Collected on Sales of Services - taxes - - - - Higher Education Cess 1% Service Tax Collected on Sales of Services - taxes - - - - Service Tax Paid on Purchase of Services - taxes - - - - Education Cess 2% Service Tax Paid on Purchase of Services - taxes - - - - Higher Education Cess 1% Service Tax Paid on Purchase of Services - taxes - - - - VAT - taxes - - - - VAT 4% - taxes - - - - VAT 4% Collected on Sale - taxes - - - - VAT 4% Paid on Purchase - taxes - - - - VAT 8% - taxes - - - - VAT 8% Collected on Sale - taxes - - - - VAT 8% Paid on Purchase - taxes - - - - VAT 10% - taxes - - - - VAT 10% Collected on Sale - taxes - - - - VAT 10% Paid on Purchase - taxes - - - - VAT 12.5% - taxes - - - - VAT 12.5% Collected on Sale - taxes - - - - VAT 12.5% Paid on Purchase - taxes - - - - Additional VAT 1% - taxes - - - - Additional VAT 1% Collected on Sale + + CGST taxes - - - Additional VAT 1% Paid on Purchase - taxes - - - - Additional VAT 2.5% - taxes - - - - Additional VAT 2.5% Collected on Sale - taxes - - - - Additional VAT 2.5% Paid on Purchase - taxes - - - - Tax Bases - taxes - - - - Base C Forms - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Excise Duty - taxes - - - - Base Excise Duty 12.36% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax - taxes - - - - Base Sales Tax 4% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax 12% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Sales Tax 15% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Service Tax - taxes - - - - Base Service Tax 12.36% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT - taxes - - - - Base VAT 4% + + IGST taxes - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT 8% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT 10% + + CESS taxes - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base VAT 12.5% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Additional VAT 1% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - - Base Additional VAT 2.5% - taxes - - - - Base of Sale - taxes - - - - Base of Purchase - taxes - - - (schedule6)Input Sales Tax @ 15% - (schedule6)Input Sales Tax @ 15% - sale - percent - 15 - 10 - - - - - - - (schedule6)Input Sales Tax @ 12% - (schedule6)Input Sales Tax @ 12% - sale - percent - 12 - 10 - - - - - - - (schedule6)Input Sales Tax @ 4% - (schedule6)Input Sales Tax @ 4% - sale - percent - 4 - 10 - - - - - - - (schedule6)Additional Input VAT @ 1% - (schedule6)Additional Input VAT @ 1% - sale - percent - 1 - 15 - - - - - - - (schedule6)Input VAT @ 12.5% - (schedule6)Input VAT @ 12.5% - sale - percent - 12.5 - 10 - - - - - - - (schedule6)Additional Input VAT @ 2.5% - (schedule6)Additional Input VAT @ 2.5% - sale - percent - 2.5 - 15 - - - - - - - (schedule6)Input VAT @ 8% - (schedule6)Input VAT @ 8% - sale - percent - 8 - 10 - - - - - - - (schedule6)Input VAT @ 10% - (schedule6)Input VAT @ 10% - sale - percent - 10 - 10 - - - - - - - (schedule6)Input Tax 12% - (schedule6)Input Tax 12% + + + + (schedule6)SGST Sale 0.5% + SGST 0.5% none percent - 12 - 1 - + 0.5 + - - + + + - - (schedule6)Input Education Cess @ 2% On Excise Duty - (schedule6)Input Education Cess @ 2% On Excise Duty + + + (schedule6)CGST Sale 0.5% + CGST 0.5% none percent - 0.24 - 2 - + 0.5 + - - + + - - (schedule6)Input Higher Education Cess @ 1% On Excise Duty - (schedule6)Input Higher Education Cess @ 1% On Excise Duty - none - percent - 0.1224 - 3 - - - - - - - (schedule6)Input Excise Duty @ 12.36% - (schedule6)Input Excise Duty @ 12.36% + + + (schedule6)GST 1% + GST 1% sale group 0 - 1 - - - - - - - (schedule6)Input Service Tax 12% - (schedule6)Input Service Tax 12% - none - percent - 12 - 13 - - - - - - - (schedule6)Input Education Cess @ 2% On Service Tax - (schedule6)Input Education Cess @ 2% On Service Tax - none - percent - 0.24 - 14 - - - - - - - (schedule6)Input Higher Education Cess @ 1% On Service Tax - (schedule6)Input Higher Education Cess @ 1% On Service Tax - none - percent - 0.1224 - 15 - - - - - - - (schedule6)Input Service Tax @ 12.36% - (schedule6)Input Service Tax @ 12.36% - sale - group - 12 - True - 8 - - - - - - - - (schedule6)Input VAT @ 4% - (schedule6)Input VAT @ 4% - sale - percent - 4 - 10 - - - - + - - - (schedule6)Output Purchase Tax @ 15% - (schedule6)Output Purchase Tax @ 15% - purchase + + (schedule6)SGST Sale 1% + SGST 1% + none percent - 15 - 10 - + 1 + - - + + - - (schedule6)Output Purchase Tax @ 12% - (schedule6)Output Purchase Tax @ 12% - purchase + + + (schedule6)CGST Sale 1% + CGST 1% + none + percent + 1 + + + + + + + + (schedule6)GST 2% + GST 2% + sale + group + 0 + + + + + + (schedule6)SGST Sale 2.5% + SGST 2.5% + none + percent + 2.5 + + + + + + + + (schedule6)CGST Sale 2.5% + CGST 2.5% + none + percent + 2.5 + + + + + + + + (schedule6)GST 5% + GST 5% + sale + group + 0 + + + + + + (schedule6)SGST Sale 6% + SGST 6% + none + percent + 6 + + + + + + + + (schedule6)CGST Sale 6% + CGST 6% + none + percent + 6 + + + + + + + + (schedule6)GST 12% + GST 12% + sale + group + 0 + + + + + + (schedule6)SGST Sale 9% + SGST 9% + none + percent + 9 + + + + + + + + (schedule6)CGST Sale 9% + CGST 9% + none + percent + 9 + + + + + + + + (schedule6)GST 18% + GST 18% + sale + group + 0 + + + + + + (schedule6)SGST Sale 14% + SGST 14% + none + percent + 14 + + + + + + + + (schedule6)CGST Sale 14% + CGST 14% + none + percent + 14 + + + + + + + + (schedule6)GST 28% + GST 28% + sale + group + 0 + + + + + + (schedule6)IGST 1% + IGST 1% + sale + percent + 1 + + + + + + + + (schedule6)IGST 2% + IGST 2% + sale + percent + 2 + + + + + + + + (schedule6)IGST 5% + IGST 5% + sale + percent + 5 + + + + + + + + (schedule6)IGST 12% + IGST 12% + sale percent 12 - 10 - + - - + + - - (schedule6)Output Purchase Tax @ 4% - (schedule6)Output Purchase Tax @ 4% - purchase + + + (schedule6)IGST 18% + IGST 18% + sale percent - 4 - 10 - + 18 + - - + + - - (schedule6)Additional Output VAT @ 1% - (schedule6)Additional Output VAT @ 1% + + + (schedule6)IGST 28% + IGST 28% + sale + percent + 28 + + + + + + + + (schedule6)CESS Sale 5% + CESS 5% + none + percent + 5 + + + + + + + (schedule6)CESS Sale 1591 Per Thousand + 1591 PER THOUSAND + none + fixed + 1.591 + + + + + + + (schedule6)CESS 5% + RS.1591/THOUSAND + CESS 5% + RS.1591/THOUSAND + sale + group + 0 + + + + + + + (schedule6)CESS 21% or RS.4170/THOUSAND + CESS 21% or RS.4170/THOUSAND + sale + code + 0 + result=base_amount * 0.21 +tax=quantity * 4.17 +if tax > result:result=tax + + + + + + + + + (schedule6)SGST Purchase 0.5% + SGST 0.5% + none + percent + 0.5 + + + + + + + + (schedule6)CGST Purchase 0.5% + CGST 0.5% + none + percent + 0.5 + + + + + + + + (schedule6)GST 1% + GST 1% + purchase + group + 0 + + + + + + (schedule6)SGST Purchase 1% + SGST 1% + none + percent + 1 + + + + + + + + (schedule6)CGST Purchase 1% + CGST 1% + none + percent + 1 + + + + + + + + (schedule6)GST 2% + GST 2% + purchase + group + 0 + + + + + + (schedule6)SGST Purchase 2.5% + SGST 2.5% + none + percent + 2.5 + + + + + + + + (schedule6)CGST Purchase 2.5% + CGST 2.5% + none + percent + 2.5 + + + + + + + + (schedule6)GST 5% + GST 5% + purchase + group + 0 + + + + + + (schedule6)SGST Purchase 6% + SGST 6% + none + percent + 6 + + + + + + + + (schedule6)CGST Purchase 6% + CGST 6% + none + percent + 6 + + + + + + + + (schedule6)GST 12% + GST 12% + purchase + group + 0 + + + + + + (schedule6)SGST Purchase 9% + SGST 9% + none + percent + 9 + + + + + + + + (schedule6)CGST Purchase 9% + CGST 9% + none + percent + 9 + + + + + + + + (schedule6)GST 18% + GST 18% + purchase + group + 0 + + + + + + (schedule6)SGST Purchase 14% + SGST 14% + none + percent + 14 + + + + + + + + (schedule6)CGST Purchase 14% + CGST 14% + none + percent + 14 + + + + + + + + (schedule6)GST 28% + GST 28% + purchase + group + 0 + + + + + + (schedule6)IGST 1% + IGST 1% purchase percent 1 - 15 - + - - - - - (schedule6)Output VAT @ 12.5% - (schedule6)Output VAT @ 12.5% - purchase - percent - 12.5 - 10 - - - - - - - (schedule6)Additional Output VAT @ 2.5% - (schedule6)Additional Output VAT @ 2.5% - purchase - percent - 2.5 - 15 - - - - - - - (schedule6)Output VAT @ 8% - (schedule6)Output VAT @ 8% - purchase - percent - 8 - 10 - - - - - - - (schedule6)Output VAT @ 10% - (schedule6)Output VAT @ 10% - purchase - percent - 10 - 10 - - - - - - - (schedule6)Output Tax 12% - (schedule6)Output Tax 12% - none - percent - 12 - 2 - - - - - - - (schedule6)Output Education Cess @ 2% Excise Duty - (schedule6)Output Education Cess @ 2% Excise Duty - none - percent - 0.24 - 3 - - - - - - - (schedule6)Output Higher Education Cess @ 1% Excise Duty - (schedule6)Output Higher Education Cess @ 1% Excise Duty - none - percent - 0.1224 - 4 - - - - - - - (schedule6)Output Excise Duty @ 12.36% - (schedule6)Output Excise Duty @ 12.36% - purchase - group - 12 - True - 1 - - - - - - - - (schedule6)Output Service Tax 12% - (schedule6)Output Service Tax 12% - none - percent - 12 - 9 - - - - - - - (schedule6)Output Education Cess @ 2% On Service Tax - (schedule6)Output Education Cess @ 2% On Service Tax - none - percent - 0.24 - 10 - - - - - - - (schedule6)Output Higher Education Cess @ 1% On Service Tax - (schedule6)Output Higher Education Cess @ 1% On Service Tax - none - percent - 0.1224 - 11 - - - - - - - (schedule6)Output Service Tax @ 12.36% - (schedule6)Output Service Tax @ 12.36% - purchase - True - group - 12 - 8 - - - - - - - - (schedule6)Output VAT @ 4% - (schedule6)Output VAT @ 4% - purchase - percent - 4 - 10 - - - - + + - - + + (schedule6)IGST 2% + IGST 2% + purchase + percent + 2 + + + + + + + + (schedule6)IGST 5% + IGST 5% + purchase + percent + 5 + + + + + + + + (schedule6)IGST 12% + IGST 12% + purchase + percent + 12 + + + + + + + + (schedule6)IGST 18% + IGST 18% + purchase + percent + 18 + + + + + + + + (schedule6)IGST 28% + IGST 28% + purchase + percent + 28 + + + + + + + + (schedule6)CESS Purchase 5% + CESS 5% + none + percent + 5 + + + + + + + (schedule6)CESS Purchase 1591 Per Thousand + 1591 PER THOUSAND + none + fixed + 1.591 + + + + + + + (schedule6)CESS 5% + RS.1591/THOUSAND + CESS 5% + RS.1591/THOUSAND + purchase + group + 0 + + + + + + (schedule6)CESS 21% or RS.4170/THOUSAND + CESS 21% or RS.4170/THOUSAND + purchase + code + 0 + result=base_amount * 0.21 +tax=quantity * 4.17 +if tax > result:result=tax + + + + + + diff --git a/addons/l10n_in_stock/__init__.py b/addons/l10n_in_stock/__init__.py new file mode 100644 index 00000000000..67dee8c60db --- /dev/null +++ b/addons/l10n_in_stock/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. diff --git a/addons/l10n_in_stock/__manifest__.py b/addons/l10n_in_stock/__manifest__.py new file mode 100644 index 00000000000..96761b0ee36 --- /dev/null +++ b/addons/l10n_in_stock/__manifest__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Indian - Stock Report(GST)', + 'version': '1.0', + 'description': """GST Stock Report""", + 'category': 'Localization', + 'depends': [ + 'l10n_in', + 'stock', + ], + 'data': [ + 'views/report_stockpicking_operations.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': True, +} diff --git a/addons/l10n_in_stock/views/report_stockpicking_operations.xml b/addons/l10n_in_stock/views/report_stockpicking_operations.xml new file mode 100644 index 00000000000..334fc0a017e --- /dev/null +++ b/addons/l10n_in_stock/views/report_stockpicking_operations.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/odoo/addons/base/res/res_country_data.xml b/odoo/addons/base/res/res_country_data.xml index abe8291d7c0..ff2a5c71242 100644 --- a/odoo/addons/base/res/res_country_data.xml +++ b/odoo/addons/base/res/res_country_data.xml @@ -747,9 +747,10 @@ India in - + + GSTIN British Indian Ocean Territory From a8d20e6804fe0e3dde174483a7de5ccd7c814396 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 18 Sep 2017 23:06:58 +0200 Subject: [PATCH 32/40] [FIX] point_of_sale: correctly format date --- addons/point_of_sale/static/src/js/models.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 03121f74b70..beddc51219a 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -2074,7 +2074,8 @@ exports.Order = Backbone.Model.extend({ initialize_validation_date: function () { this.validation_date = new Date(); - this.formatted_validation_date = field_utils.format.datetime(this.validation_date); + this.formatted_validation_date = field_utils.format.datetime( + moment(this.validation_date), {}, {timezone: false}); }, set_tip: function(tip) { From 43e412ccabef7a04c9513d74da5436a57d7ff2ca Mon Sep 17 00:00:00 2001 From: fwi-odoo Date: Fri, 15 Sep 2017 13:01:48 +0200 Subject: [PATCH 33/40] [FIX] mail: fix due to the changes for the app switcher whitelist The app switcher in the enterprise branch introduces a new way to whitelist the element in the app switcher. This commit apply this mechanism to the mail windows. --- addons/mail/static/src/xml/chat_window.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/xml/chat_window.xml b/addons/mail/static/src/xml/chat_window.xml index 525898dabd8..f21fe09991b 100644 --- a/addons/mail/static/src/xml/chat_window.xml +++ b/addons/mail/static/src/xml/chat_window.xml @@ -2,7 +2,7 @@ -
    +
    @@ -19,7 +19,7 @@ -
    +
    From 8ba10a3b9ad8348ae867334adab80725543bd1b5 Mon Sep 17 00:00:00 2001 From: Darshan Kalola Date: Tue, 25 Jul 2017 12:08:11 +0530 Subject: [PATCH 34/40] [FIX] web: FormView: invisible='True' on x2many fields Before this rev., it crashed if an x2many field had the attr invisible set to 'True' in a form view. --- addons/web/static/src/js/views/abstract_view.js | 2 +- addons/web/static/tests/views/form_tests.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js index fc3c3cb63c3..8eedc4d2c2a 100644 --- a/addons/web/static/src/js/views/abstract_view.js +++ b/addons/web/static/src/js/views/abstract_view.js @@ -255,7 +255,7 @@ var AbstractView = Class.extend({ attrs.limit = attrs.mode === "tree" ? 80 : 40; - if (attrs.Widget.prototype.useSubview && !(attrs.invisible && JSON.parse(attrs.invisible)) && !attrs.views[attrs.mode]) { + if (attrs.Widget.prototype.useSubview && !attrs.__no_fetch && !attrs.views[attrs.mode]) { var context = {}; var regex = /'([a-z]*_view_ref)' *: *'(.*?)'/g; var matches; diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 7bc6734c5ac..4dcdede75d1 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -209,7 +209,7 @@ QUnit.module('Views', { }); QUnit.test('invisible fields are properly hidden', function (assert) { - assert.expect(3); + assert.expect(4); var form = createView({ View: FormView, @@ -222,6 +222,10 @@ QUnit.module('Views', { '' + '' + '' + + // x2many field without inline view: as it is always invisible, the view + // should not be fetched. we don't specify any view in this test, so if it + // ever tries to fetch it, it will crash, indicating that this is wrong. + '' + '' + '', res_id: 1, @@ -233,6 +237,8 @@ QUnit.module('Views', { "should not contain span with field value"); assert.strictEqual(form.$('.o_field_widget.o_invisible_modifier:contains(0.4)').length, 1, "field qux should be invisible"); + assert.ok(form.$('.o_field_widget[name=p]').hasClass('o_invisible_modifier'), + "field p should be invisible"); form.destroy(); }); From 116aa22685c8aa3babd87c8d1091a53fbf4ff35b Mon Sep 17 00:00:00 2001 From: Hardik Patel Date: Mon, 4 Sep 2017 11:41:10 +0530 Subject: [PATCH 35/40] [FIX] web: reset offset to 0 when searching for records Scenario: Go to any list or kanban view: go to next page and set a filter that matches less that 'limit' record (e.g. less than 40), but at least one. No record will be displayed, because the offset is kept for the search_read. This rev. ensures to reset the offset to 0 when a search is done using the searchview. --- addons/web/static/src/js/chrome/view_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/chrome/view_manager.js b/addons/web/static/src/js/chrome/view_manager.js index 2e92ce004a9..c76c7aecc4a 100644 --- a/addons/web/static/src/js/chrome/view_manager.js +++ b/addons/web/static/src/js/chrome/view_manager.js @@ -26,7 +26,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, { search: function(event) { var d = event.data; _.extend(this.env, this._process_search_data(d.domains, d.contexts, d.groupbys)); - this.active_view.controller.reload(_.extend({}, this.env)); + this.active_view.controller.reload(_.extend({offset: 0}, this.env)); }, switch_view: function(event) { if ('res_id' in event.data) { From de48daf53adc922da6b2ff4ef794e37b0b7cd835 Mon Sep 17 00:00:00 2001 From: Pratima Gupta Date: Thu, 17 Aug 2017 12:29:21 +0530 Subject: [PATCH 36/40] [FIX] web: FieldDomain: don't open record from selection The FieldDomain allows to open a list in a dialog to display the records matching the current domain. In this dialog, clicking on a record should do nothing (this was the behavior before the new views). Before this rev., it actually tried to open the record and it produced a crash. --- .../web/static/src/js/fields/basic_fields.js | 14 ++++++- .../static/tests/fields/basic_fields_tests.js | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index d9482156745..2a465c4dc1b 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1994,8 +1994,9 @@ var FieldDomain = AbstractField.extend({ "click .o_field_domain_dialog_button": "_onDialogEditButtonClick", }), custom_events: _.extend({}, AbstractField.prototype.custom_events, { - "domain_changed": "_onDomainSelectorValueChange", - "domain_selected": "_onDomainSelectorDialogValueChange", + domain_changed: "_onDomainSelectorValueChange", + domain_selected: "_onDomainSelectorDialogValueChange", + open_record: "_onOpenRecord", }), /** * @constructor @@ -2176,6 +2177,15 @@ var FieldDomain = AbstractField.extend({ _onDomainSelectorDialogValueChange: function (e) { this._setValue(Domain.prototype.arrayToString(e.data.domain)); }, + /** + * Stops the propagation of the 'open_record' event, as we don't want the + * user to be able to open records from the list opened in a dialog. + * + * @param {OdooEvent} event + */ + _onOpenRecord: function (event) { + event.stopPropagation(); + }, }); /** diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index c33cb8a4151..90f2b14cb01 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -3795,6 +3795,46 @@ QUnit.module('basic_fields', { form.destroy(); }); + + QUnit.test('basic domain field: show the selection', function (assert) { + assert.expect(2); + + this.data.partner.records[0].foo = "[]"; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: + '
    ' + + '' + + '' + + '' + + '' + + '' + + '', + archs: { + 'partner_type,false,list': '', + 'partner_type,false,search': '', + }, + res_id: 1, + }); + + assert.equal(form.$(".o_domain_show_selection_button").text().trim().substr(0, 2), "2 ", + "selection should contain 2 records"); + + // open the selection + form.$(".o_domain_show_selection_button").click(); + assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2, + "should have open a list view with 2 records in a dialog"); + + // click on a record -> should not open the record + // we don't actually check that it doesn't open the record because even + // if it tries to, it will crash as we don't define an arch in this test + $('.modal .o_list_view .o_data_row:first .o_data_cell').click(); + + form.destroy(); + }); }); }); }); From c3a48da767b333d21ceff2cb829ffba102d6ff3d Mon Sep 17 00:00:00 2001 From: Hardik Patel Date: Fri, 8 Sep 2017 14:07:50 +0530 Subject: [PATCH 37/40] [FIX] web: FormView button box: position of More dropdown Before this rev., the dropdown was positioned in the bottom left corner of the form view. --- addons/web/static/src/less/form_view_extra.less | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/addons/web/static/src/less/form_view_extra.less b/addons/web/static/src/less/form_view_extra.less index 6e48c173c6e..cc153825d1c 100644 --- a/addons/web/static/src/less/form_view_extra.less +++ b/addons/web/static/src/less/form_view_extra.less @@ -115,6 +115,18 @@ vertical-align: middle; } } + + &.o_full { + position: relative; + .o_button_more { + padding: 0 10px; + } + .o_dropdown_more { + .o-position-absolute(@top: 100%, @right: 0); + min-width: 0; + padding: 0px; + } + } } // Avatar From 4afdc57c88cc94b4c8b6ab95c146632a7fca7264 Mon Sep 17 00:00:00 2001 From: Prakash Prajapati Date: Tue, 12 Sep 2017 12:51:47 +0530 Subject: [PATCH 38/40] [FIX] mail: Open simple partner form when email is requested on actions Purpose ======= When you want to send an email to a contact without an email address set, you get a wizard to enter the contact email. In master, you get the full contact form You should get the simplified form view (like in 10.0) --- addons/account/models/account_invoice.py | 3 ++- addons/mail/static/src/js/many2many_tags_email.js | 1 + addons/purchase/models/purchase.py | 3 ++- addons/sale/models/sale.py | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 5f9b93f0d85..f3af53af8fc 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -563,7 +563,8 @@ class AccountInvoice(models.Model): default_template_id=template and template.id or False, default_composition_mode='comment', mark_invoice_as_sent=True, - custom_layout="account.mail_template_data_notification_email_account_invoice" + custom_layout="account.mail_template_data_notification_email_account_invoice", + force_email=True ) return { 'name': _('Compose Email'), diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index c566d2a4706..96688a06dbc 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -80,6 +80,7 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({ var pop = new form_common.FormViewDialog(self, { res_model: self.field.relation, res_id: resID, + context: self.record.context, title: _t("Please complete partner's informations and Email"), on_saved: function (record) { if (record.data.email) { diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index d048cfefc02..422c0bd30f6 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -306,7 +306,8 @@ class PurchaseOrder(models.Model): 'default_use_template': bool(template_id), 'default_template_id': template_id, 'default_composition_mode': 'comment', - 'custom_layout': "purchase.mail_template_data_notification_email_purchase_order" + 'custom_layout': "purchase.mail_template_data_notification_email_purchase_order", + 'force_email': True }) return { 'name': _('Compose Email'), diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 9b354af7ab6..160264707a8 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -477,7 +477,8 @@ class SaleOrder(models.Model): 'default_composition_mode': 'comment', 'mark_so_as_sent': True, 'custom_layout': "sale.mail_template_data_notification_email_sale_order", - 'proforma': self.env.context.get('proforma', False) + 'proforma': self.env.context.get('proforma', False), + 'force_email': True } return { 'type': 'ir.actions.act_window', From 70ea155a9689af82736b9b42cb43a256db33daa3 Mon Sep 17 00:00:00 2001 From: Yannick Tivisse Date: Tue, 19 Sep 2017 11:04:57 +0200 Subject: [PATCH 39/40] [FIX] stock: Define correctly the filter --- addons/stock/views/stock_move_line_views.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/views/stock_move_line_views.xml b/addons/stock/views/stock_move_line_views.xml index f8793760889..43a983c8a88 100644 --- a/addons/stock/views/stock_move_line_views.xml +++ b/addons/stock/views/stock_move_line_views.xml @@ -61,7 +61,7 @@ - + From 63ebdd086985c29479f30681339e44757888d6ab Mon Sep 17 00:00:00 2001 From: Kirti Choudhary Date: Thu, 29 Jun 2017 10:55:41 +0530 Subject: [PATCH 40/40] [FIX] web: Display 'Favorites' filters list with a scrollbar when too long --- addons/web/static/src/less/search_view.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/web/static/src/less/search_view.less b/addons/web/static/src/less/search_view.less index a34905cb929..a9d6d28e9e4 100644 --- a/addons/web/static/src/less/search_view.less +++ b/addons/web/static/src/less/search_view.less @@ -185,6 +185,8 @@ // Favorites .o_favorites_menu { + max-height: 75vh; + overflow-y: auto; .o-selected-li; .divider {display: none;} // hide the divider by default (no favorite)