From caacd95a8787b2874a129753b7e5439d0c0c02e8 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Thu, 24 Jan 2019 10:48:56 +0000 Subject: [PATCH 1/7] [FIX] web: allow to open community website menu on iOS Before this commit, the menu to go into the backend from the website was not possible to open on iOS without opening the right menu first. This was because position: fixed is not able to counter overflow: hidden in iOS. This is the fix for stable versions, the proper solution will be done in master. Closes https://github.com/odoo/odoo/issues/29390 task-1923151 closes odoo/odoo#30507 --- addons/web/static/src/less/navbar.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/less/navbar.less b/addons/web/static/src/less/navbar.less index 5f3aff0b98f..7b31ec11089 100644 --- a/addons/web/static/src/less/navbar.less +++ b/addons/web/static/src/less/navbar.less @@ -94,7 +94,6 @@ position: relative; height: @odoo-navbar-height; - overflow: hidden; > ul { > li { @@ -110,6 +109,7 @@ &.o_menu_sections { width: 100%; + display: none; > li.open .dropdown-menu { position: static; @@ -158,6 +158,10 @@ .o_main_navbar { height: 100%; overflow: auto; + + .o_menu_sections { + display: block; + } } } } From f63569beef1f900225732adb8e51714d10938d43 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 23 Jan 2019 16:37:03 +0000 Subject: [PATCH 2/7] [I18N] base: export source terms Fixes odoo/odoo#30483 closes odoo/odoo#30488 --- odoo/addons/base/i18n/base.pot | 222 ++++++++++++++++++++++++++++----- 1 file changed, 194 insertions(+), 28 deletions(-) diff --git a/odoo/addons/base/i18n/base.pot b/odoo/addons/base/i18n/base.pot index 957d4990175..73e48f39c48 100644 --- a/odoo/addons/base/i18n/base.pot +++ b/odoo/addons/base/i18n/base.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-10-20 07:12+0000\n" -"PO-Revision-Date: 2017-10-20 07:12+0000\n" +"POT-Creation-Date: 2019-01-23 16:30+0000\n" +"PO-Revision-Date: 2019-01-23 16:30+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -552,6 +552,17 @@ msgid "\n" " " msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_account_lock +msgid "\n" +" Make the lock date irreversible:\n" +"\n" +" * You cannot define stricter conditions on advisors than on users. Then, the lock date on advisor must be set before the lock date for users.\n" +" * You cannot lock a period that is not finished yet. Then, the lock date for advisors must be set before the last day of the previous month.\n" +" * The new lock date for advisors must be set after the previous lock date.\n" +" " +msgstr "" + #. module: base #: model:ir.module.module,description:base.module_hr_timesheet_attendance msgid "\n" @@ -858,6 +869,13 @@ msgid "\n" " " msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_l10n_be_intrastat_2019 +msgid "\n" +"Adds the possibility to specify the origin country of goods and the partner VAT in the Intrastat XML report.\n" +" " +msgstr "" + #. module: base #: model:ir.module.module,description:base.module_pos_mercury msgid "\n" @@ -2283,6 +2301,13 @@ msgid "\n" "" msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_account_cash_basis_base_account +msgid "\n" +"Move the cash basis lines to another account.\n" +" " +msgstr "" + #. module: base #: model:ir.module.module,description:base.module_l10n_nz msgid "\n" @@ -3116,6 +3141,44 @@ msgid "\n" "" msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_l10n_fr_pos_cert +msgid "\n" +"This add-on brings the technical requirements of the French regulation CGI art. 286, I. 3° bis that stipulates certain criteria concerning the inalterability, security, storage and archiving of data related to sales to private individuals (B2C).\n" +"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" +"\n" +"Install it if you use the Point of Sale app to sell to individuals.\n" +"\n" +"The module adds following features:\n" +"\n" +" Inalterability: deactivation of all the ways to cancel or modify key data of POS orders, invoices and journal entries\n" +"\n" +" Security: chaining algorithm to verify the inalterability\n" +"\n" +" Storage: automatic sales closings with computation of both period and cumulative totals (daily, monthly, annually)\n" +"\n" +" Access to download the mandatory Certificate of Conformity delivered by Odoo SA (only for Odoo Enterprise users)\n" +"" +msgstr "" + +#. module: base +#: model:ir.module.module,description:base.module_l10n_fr_certification +msgid "\n" +"This add-on brings the technical requirements of the French regulation CGI art. 286, I. 3° bis that stipulates certain criteria concerning the inalterability, security, storage and archiving of data related to sales to private individuals (B2C).\n" +"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" +"\n" +"The module adds following features:\n" +"\n" +" Inalterability: deactivation of all the ways to cancel or modify key data, invoices and journal entries\n" +"\n" +" Security: chaining algorithm to verify the inalterability\n" +"\n" +" Storage: automatic sales closings with computation of both period and cumulative totals (daily, monthly, annually)\n" +"\n" +" Access to download the mandatory Certificate of Conformity delivered by Odoo SA (only for Odoo Enterprise users)\n" +"" +msgstr "" + #. module: base #: model:ir.module.module,description:base.module_pos_cache msgid "\n" @@ -3521,6 +3584,19 @@ msgid "\n" " " msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_l10n_fr_sale_closing +msgid "\n" +"This module adds support for automatic sales closings with computation of both period and cumulative totals (daily, monthly, annually)\n" +"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" +"\n" +"The module adds following features:\n" +"\n" +" Storage: automatic sales closings with computation of both period and cumulative totals (daily, monthly, annually)\n" +"\n" +"" +msgstr "" + #. module: base #: model:ir.module.module,description:base.module_barcodes msgid "\n" @@ -3873,7 +3949,7 @@ msgstr "" #: model:ir.module.module,description:base.module_purchase_mrp msgid "\n" "This module provides facility to the user to install mrp and purchase modules at a time.\n" -"====================================================================================\n" +"========================================================================================\n" "\n" "It is basically used when we want to keep track of production orders generated\n" "from purchase order.\n" @@ -4824,6 +4900,11 @@ msgstr "" msgid "Access Rules" msgstr "" +#. module: base +#: model:res.groups,name:base.group_private_addresses +msgid "Access to Private Addresses" +msgstr "" + #. module: base #: model:ir.module.module,shortdesc:base.module_account_analytic_default msgid "Account Analytic Defaults" @@ -5121,6 +5202,11 @@ msgstr "" msgid "Add RML Header" msgstr "" +#. module: base +#: model:ir.module.module,summary:base.module_account_cash_basis_base_account +msgid "Add a custom account to handle base amount lines" +msgstr "" + #. module: base #: model:ir.module.module,summary:base.module_stock_barcode msgid "Add barcode scanning facilities to Warehouse Management." @@ -5162,6 +5248,7 @@ msgid "Add your sales document in the frontend portal (sales order, quotations, msgstr "" #. module: base +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_partner_address_form #: model:ir.ui.view,arch_db:base.view_partner_form @@ -5784,6 +5871,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_res_partner_bank_account_form #: model:ir.model,name:base.model_res_partner_bank #: model:ir.model.fields,field_description:base.field_res_company_bank_ids +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_partner_bank_search #: model:ir.ui.view,arch_db:base.view_partner_bank_tree msgid "Bank Accounts" @@ -5939,6 +6027,11 @@ msgstr "" msgid "Belgian Intrastat Declaration" msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_l10n_be_intrastat_2019 +msgid "Belgian Intrastat Declaration - Complement for 2019" +msgstr "" + #. module: base #: model:ir.module.module,shortdesc:base.module_pos_blackbox_be msgid "Belgian Registered Cash Register" @@ -6521,6 +6614,7 @@ msgstr "" #: model:ir.model.fields,field_description:base.field_res_company_city #: model:ir.model.fields,field_description:base.field_res_partner_city #: model:ir.model.fields,field_description:base.field_res_users_city +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_partner_address_form #: model:ir.ui.view,arch_db:base.view_partner_form @@ -6807,6 +6901,11 @@ msgstr "" msgid "Compute" msgstr "" +#. module: base +#: model:ir.module.module,summary:base.module_website_sale_taxcloud_delivery +msgid "Compute taxes with TaxCloud after online delivery computation." +msgstr "" + #. module: base #: model:ir.ui.view,arch_db:base.view_model_form msgid "Computed fields are defined with the fields\n" @@ -7064,6 +7163,7 @@ msgstr "" #: model:ir.model.fields,field_description:base.field_res_country_state_country_id #: model:ir.model.fields,field_description:base.field_res_partner_country_id #: model:ir.model.fields,field_description:base.field_res_users_country_id +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_country_tree #: model:ir.ui.view,arch_db:base.view_partner_address_form @@ -9004,11 +9104,6 @@ msgstr "" msgid "France - Accounting" msgstr "" -#. module: base -#: model:ir.module.module,shortdesc:base.module_l10n_fr_certification -msgid "France - Accounting - Certified CGI 286 I-3 bis" -msgstr "" - #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_fr_reports msgid "France - Accounting Reports" @@ -9019,6 +9114,21 @@ msgstr "" msgid "France - FEC" msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_l10n_fr_certification +msgid "France - VAT Anti-Fraud Certification (CGI 286 I-3 bis)" +msgstr "" + +#. module: base +#: model:ir.module.module,shortdesc:base.module_l10n_fr_sale_closing +msgid "France - VAT Anti-Fraud Certification (CGI 286 I-3 bis) - Sale Closings" +msgstr "" + +#. module: base +#: model:ir.module.module,shortdesc:base.module_l10n_fr_pos_cert +msgid "France - VAT Anti-Fraud Certification for Point of Sale (CGI 286 I-3 bis)" +msgstr "" + #. module: base #: model:res.country,name:base.gf msgid "French Guyana" @@ -10414,6 +10524,11 @@ msgstr "" msgid "Ireland" msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_account_lock +msgid "Irreversible Lock Date" +msgstr "" + #. module: base #: model:ir.model.fields,field_description:base.field_res_partner_is_company #: model:ir.model.fields,field_description:base.field_res_users_is_company @@ -10592,6 +10707,11 @@ msgstr "" msgid "Kontni načrt za gospodarske družbe" msgstr "" +#. module: base +#: model:res.country,name:base.xk +msgid "Kosovo" +msgstr "" + #. module: base #: model:res.country,name:base.kw msgid "Kuwait" @@ -11466,18 +11586,6 @@ msgstr "" msgid "Memos pad" msgstr "" -#. module: base -#: code:addons/base/ir/ir_model.py:382 -#, python-format -msgid "Model %s does not exist" -msgstr "" - -#. module: base -#: code:addons/base/ir/ir_model.py:383 -#, python-format -msgid "Please specify a valid model for the object relation" -msgstr "" - #. module: base #: model:ir.model.fields,field_description:base.field_ir_ui_menu_name #: model:ir.ui.view,arch_db:base.edit_menu @@ -11648,13 +11756,19 @@ msgid "Model" msgstr "" #. module: base -#: code:addons/base/ir/ir_model.py:487 +#: code:addons/base/ir/ir_model.py:404 +#, python-format +msgid "Model %s does not exist" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:550 #, python-format msgid "Model %s does not exist!" msgstr "" #. module: base -#: code:addons/base/ir/ir_model.py:132 +#: code:addons/base/ir/ir_model.py:138 #, python-format msgid "Model '%s' contains module data and cannot be removed!" msgstr "" @@ -12494,8 +12608,9 @@ msgid "Original View" msgstr "" #. module: base -#: code:addons/base/res/res_users.py:728 -#: code:addons/base/res/res_users.py:888 +#: code:addons/base/res/res_users.py:785 +#: code:addons/base/res/res_users.py:951 +#: model:ir.ui.view,arch_db:base.user_groups_view #, python-format msgid "Other" msgstr "" @@ -12944,13 +13059,19 @@ msgid "Please set the Base Model of the action to enable the dynamic expression msgstr "" #. module: base -#: code:addons/base/ir/ir_actions.py:787 +#: code:addons/base/ir/ir_model.py:405 +#, python-format +msgid "Please specify a valid model for the object relation" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:799 #, python-format msgid "Please specify an action to launch!" msgstr "" #. module: base -#: code:addons/base/res/res_users.py:248 +#: code:addons/base/res/res_users.py:250 #, python-format msgid "Please use the change password wizard (in User Preferences or User menu) to change your own password." msgstr "" @@ -13145,6 +13266,16 @@ msgstr "" msgid "Priority" msgstr "" +#. module: base +#: selection:res.partner,type:0 +msgid "Private Address" +msgstr "" + +#. module: base +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private +msgid "Private Address Form" +msgstr "" + #. module: base #: code:addons/models.py:107 #, python-format @@ -14750,6 +14881,7 @@ msgstr "" #: model:ir.model.fields,field_description:base.field_base_language_export_state #: model:ir.model.fields,field_description:base.field_res_partner_state_id #: model:ir.model.fields,field_description:base.field_res_users_state_id +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_country_state_form #: model:ir.ui.view,arch_db:base.view_country_state_tree @@ -14848,6 +14980,7 @@ msgid "Street" msgstr "" #. module: base +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_partner_address_form #: model:ir.ui.view,arch_db:base.view_partner_form @@ -14856,6 +14989,7 @@ msgid "Street 2..." msgstr "" #. module: base +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_partner_address_form #: model:ir.ui.view,arch_db:base.view_partner_form @@ -15153,6 +15287,11 @@ msgstr "" msgid "Target Window" msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_account_cash_basis_base_account +msgid "Tax Cash Basis Edit Base Account" +msgstr "" + #. module: base #: model:ir.model.fields,field_description:base.field_res_company_vat msgid "Tax ID" @@ -15165,6 +15304,11 @@ msgstr "" msgid "Tax Identification Number. Fill it if the company is subjected to taxes. Used by the some of the legal statements." msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_website_sale_taxcloud_delivery +msgid "TaxCloud and Delivery - Ecommerce" +msgstr "" + #. module: base #: model:ir.module.module,summary:base.module_account_taxcloud msgid "TaxCloud make it easy for business to comply with sales tax law" @@ -15199,12 +15343,12 @@ msgstr "" #. module: base #: model:ir.module.category,name:base.module_category_hidden -#: model:ir.ui.view,arch_db:base.user_groups_view +#: model:ir.module.category,name:base.module_category_technical_settings msgid "Technical Settings" msgstr "" #. module: base -#: code:addons/base/ir/ir_translation.py:746 +#: code:addons/base/ir/ir_translation.py:792 #, python-format msgid "Technical Translations" msgstr "" @@ -15696,6 +15840,12 @@ msgstr "" msgid "This module adds support for barcodes scanning to the manufacturing system." msgstr "" +#. module: base +#: model:ir.module.module,description:base.module_website_sale_taxcloud_delivery +msgid "This module ensures that when delivery price is computed online, and taxes are computed with TaxCloud, the tax computation is done correctly on both the order and delivery.\n" +" " +msgstr "" + #. module: base #: model:ir.ui.view,arch_db:base.view_base_module_upgrade msgid "This module will trigger the uninstallation of below modules." @@ -17375,6 +17525,7 @@ msgid "Yugoslavia" msgstr "" #. module: base +#: model:ir.ui.view,arch_db:base.res_partner_view_form_private #: model:ir.ui.view,arch_db:base.view_company_form #: model:ir.ui.view,arch_db:base.view_partner_address_form #: model:ir.ui.view,arch_db:base.view_partner_form @@ -17426,6 +17577,16 @@ msgstr "" msgid "a new currency before creating a new company." msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_account_online_sync +msgid "account_online_sync" +msgstr "" + +#. module: base +#: model:ir.module.module,shortdesc:base.module_account_plaid +msgid "account_plaid" +msgstr "" + #. module: base #: model:ir.ui.view,arch_db:base.res_partner_kanban_view msgid "at" @@ -17581,6 +17742,11 @@ msgstr "" msgid "here" msgstr "" +#. module: base +#: model:ir.module.module,shortdesc:base.module_hr_timesheet_sheet_timesheet_grid +msgid "hr_timesheet_sheet_timesheet_grid" +msgstr "" + #. module: base #: selection:base.language.install,state:0 #: selection:base.module.update,state:0 From 5a6c523cc77180c79c220f42420fe3772939765b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Mon, 21 Jan 2019 07:02:58 +0000 Subject: [PATCH 3/7] [FIX] website_slides: prevent slide download for public users Task #1930691 Purpose ======= If the download security is set to 'Authenticated users', the route should prevent public users from downloading the slides. closes #30281 closes odoo/odoo#30399 --- addons/website_slides/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index e6ce5bbdaba..63b5780b9b7 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -216,7 +216,7 @@ class WebsiteSlides(http.Controller): @http.route('''/slides/slide//download''', type='http', auth="public", website=True) def slide_download(self, slide): - if slide.download_security == 'public' or (slide.download_security == 'user' and request.session.uid): + if slide.download_security == 'public' or (slide.download_security == 'user' and request.env.user and request.env.user != request.website.user_id): filecontent = base64.b64decode(slide.datas) disposition = 'attachment; filename=%s.pdf' % werkzeug.urls.url_quote(slide.name) return request.make_response( From 93a767a678dc74b426d3416aeade4e231258c128 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Thu, 22 Feb 2018 09:02:21 +0000 Subject: [PATCH 4/7] [FIX] pos_discount: error if misconfigured product In case the discount product is misconfigured and therefore not loaded by the POS, a traceback appears when applying a discount. Add a comprehensive error message instead. Closes #30574 opw-817527 closes odoo/odoo#30582 --- addons/pos_discount/i18n/pos_discount.pot | 14 ++++++++++++++ addons/pos_discount/static/src/js/discount.js | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/addons/pos_discount/i18n/pos_discount.pot b/addons/pos_discount/i18n/pos_discount.pot index bf6956ca4ef..71ad94728b1 100644 --- a/addons/pos_discount/i18n/pos_discount.pot +++ b/addons/pos_discount/i18n/pos_discount.pot @@ -45,6 +45,13 @@ msgstr "" msgid "Discounts" msgstr "" +#. module: pos_discount +#. openerp-web +#: code:addons/pos_discount/static/src/js/discount.js:28 +#, python-format +msgid "No discount product found" +msgstr "" + #. module: pos_discount #: model:ir.model.fields,field_description:pos_discount.field_pos_config_iface_discount msgid "Order Discounts" @@ -55,6 +62,13 @@ msgstr "" msgid "The default discount percentage" msgstr "" +#. module: pos_discount +#. openerp-web +#: code:addons/pos_discount/static/src/js/discount.js:29 +#, python-format +msgid "The discount product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'." +msgstr "" + #. module: pos_discount #: model:ir.model.fields,help:pos_discount.field_pos_config_discount_product_id msgid "The product used to model the discount" diff --git a/addons/pos_discount/static/src/js/discount.js b/addons/pos_discount/static/src/js/discount.js index 7ef38d6ffdb..f29cf796845 100644 --- a/addons/pos_discount/static/src/js/discount.js +++ b/addons/pos_discount/static/src/js/discount.js @@ -23,6 +23,13 @@ var DiscountButton = screens.ActionButtonWidget.extend({ var order = this.pos.get_order(); var lines = order.get_orderlines(); var product = this.pos.db.get_product_by_id(this.pos.config.discount_product_id[0]); + if (product === undefined) { + this.gui.show_popup('error', { + title : _t("No discount product found"), + body : _t("The discount product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'."), + }); + return; + } // Remove existing discounts var i = 0; From 7ab26999bebccb302c57b5c8778682bb2b5bcc88 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 17 Jan 2019 15:40:27 +0000 Subject: [PATCH 5/7] [FIX] account: tax in right refund account Have a tax that has a different account for refunds make an invoice and its refund Before this commit, the refund's tax is still in the old account After this commit, the refund's tax is in the account for refund defined on the tax OPW 1907950 closes odoo/odoo#30325 --- addons/account/models/account_invoice.py | 22 +++++++- .../tests/test_account_customer_invoice.py | 56 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index aff495072ce..008c52777ad 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -998,6 +998,21 @@ class AccountInvoice(models.Model): result.append((0, 0, values)) return result + @api.model + def _refund_tax_lines_account_change(self, lines, taxes_to_change): + # Let's change the account on tax lines when + # @param {list} lines: a list of orm commands + # @param {dict} taxes_to_change + # key: tax ID, value: refund account + + if not taxes_to_change: + return lines + + for line in lines: + if isinstance(line[2], dict) and line[2]['tax_id'] in taxes_to_change: + line[2]['account_id'] = taxes_to_change[line[2]['tax_id']] + return lines + def _get_refund_common_fields(self): return ['partner_id', 'payment_term_id', 'account_id', 'currency_id', 'journal_id'] @@ -1039,7 +1054,12 @@ class AccountInvoice(models.Model): values['invoice_line_ids'] = self._refund_cleanup_lines(invoice.invoice_line_ids) tax_lines = invoice.tax_line_ids - values['tax_line_ids'] = self._refund_cleanup_lines(tax_lines) + taxes_to_change = { + line.tax_id.id: line.tax_id.refund_account_id.id + for line in tax_lines.filtered(lambda l: l.tax_id.refund_account_id != l.tax_id.account_id) + } + cleaned_tax_lines = self._refund_cleanup_lines(tax_lines) + values['tax_line_ids'] = self._refund_tax_lines_account_change(cleaned_tax_lines, taxes_to_change) if journal_id: journal = self.env['account.journal'].browse(journal_id) diff --git a/addons/account/tests/test_account_customer_invoice.py b/addons/account/tests/test_account_customer_invoice.py index 12a164cd3cb..6c6c6a253fa 100644 --- a/addons/account/tests/test_account_customer_invoice.py +++ b/addons/account/tests/test_account_customer_invoice.py @@ -170,3 +170,59 @@ class TestAccountCustomerInvoice(AccountTestUsers): )) self.assertEquals(invoice.amount_untaxed, sum([x.base for x in invoice.tax_line_ids])) + + def test_customer_invoice_tax_refund(self): + company = self.env.user.company_id + tax_account = self.env['account.account'].create({ + 'name': 'TAX', + 'code': 'TAX', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + 'company_id': company.id, + }) + + tax_refund_account = self.env['account.account'].create({ + 'name': 'TAX_REFUND', + 'code': 'TAX_R', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + 'company_id': company.id, + }) + + journalrec = self.env['account.journal'].search([('type', '=', 'sale')])[0] + partner3 = self.env.ref('base.res_partner_3') + account_id = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id + + tax = self.env['account.tax'].create({ + 'name': 'Tax 15.0', + 'amount': 15.0, + 'amount_type': 'percent', + 'type_tax_use': 'sale', + 'account_id': tax_account.id, + 'refund_account_id': tax_refund_account.id + }) + + invoice_line_data = [ + (0, 0, + { + 'product_id': self.env.ref('product.product_product_1').id, + 'quantity': 40.0, + 'account_id': account_id, + 'name': 'product test 1', + 'discount': 10.00, + 'price_unit': 2.27, + 'invoice_line_tax_ids': [(6, 0, [tax.id])], + } + )] + + invoice = self.env['account.invoice'].create(dict( + name="Test Customer Invoice", + reference_type="none", + journal_id=journalrec.id, + partner_id=partner3.id, + invoice_line_ids=invoice_line_data + )) + + invoice.action_invoice_open() + + refund = invoice.refund() + self.assertEqual(invoice.tax_line_ids.mapped('account_id'), tax_account) + self.assertEqual(refund.tax_line_ids.mapped('account_id'), tax_refund_account) From dc751f20a2da5017644794f68af3cb0f161f77b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Fri, 11 Jan 2019 10:21:49 +0000 Subject: [PATCH 6/7] [FIX] web: add exponential backoff strategy for lost connection Before this commit, the web client had a naive strategy to handle lost connections: it tried to poll the server every 2 seconds until a rpc succeeds. This works quite well from the perspective of the user, but may be a problem from the perspective of the server. If a server is down for a longish period, then each users active tabs will then perform a request every 2 seconds. This means that the server will be progressively hammered by many requests, which will clutter the logs, and make it more difficult to gracefully recover. With this commit, we simply exponentially increase the delay each time, and add a little jitter to give a better distribution. Cherry-pick of 4a3f04bcc580c514c61e3bd608fa2b85065434cc closes odoo/odoo#30136 closes odoo/odoo#30596 --- .../static/src/js/framework/crash_manager.js | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/addons/web/static/src/js/framework/crash_manager.js b/addons/web/static/src/js/framework/crash_manager.js index 831f762b78c..f36a04eb103 100644 --- a/addons/web/static/src/js/framework/crash_manager.js +++ b/addons/web/static/src/js/framework/crash_manager.js @@ -22,6 +22,7 @@ var map_title ={ var CrashManager = core.Class.extend({ init: function() { this.active = true; + this.isConnected = true; }, enable: function () { this.active = true; @@ -29,8 +30,29 @@ var CrashManager = core.Class.extend({ disable: function () { this.active = false; }, - rpc_error: function(error) { + handleLostConnection: function () { var self = this; + if (!this.isConnected) { + // already handled, nothing to do. This can happen when several + // rpcs are done in parallel and fail because of a lost connection. + return; + } + this.isConnected = false; + var delay = 2000; + core.bus.trigger('connection_lost'); + + setTimeout(function checkConnection() { + ajax.jsonRpc('/web/webclient/version_info', 'call', {}, {shadow:true}).then(function () { + core.bus.trigger('connection_restored'); + self.isConnected = true; + }).fail(function () { + // exponential backoff, with some jitter + delay = (delay * 1.5) + 500*Math.random(); + setTimeout(checkConnection, delay); + }); + }, delay); + }, + rpc_error: function(error) { if (!this.active) { return; } @@ -38,15 +60,7 @@ var CrashManager = core.Class.extend({ return; } if (error.code == -32098) { - core.bus.trigger('connection_lost'); - this.connection_lost = true; - var timeinterval = setInterval(function() { - ajax.jsonRpc('/web/webclient/version_info').then(function() { - clearInterval(timeinterval); - core.bus.trigger('connection_restored'); - self.connection_lost = false; - }); - }, 2000); + this.handleLostConnection(); return; } var handler = core.crash_registry.get(error.data.name, true); From 4a5862a492fff66a474b7069cb5ba45836249a0e Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 24 Jan 2019 09:56:33 +0000 Subject: [PATCH 7/7] [FIX] point_of_sale: offline invoicing => backend printing In a pos session: OFFLINE make an order with invoicing , try to validate The order stays there because it needs to be validated by the server make another non invoiced order, validate ONLINE make another order At validation, all orders will be pushed to the server Before this commit, when trying to validate the invoiced order the report download couldn't find the order id, and crashed This was because the order in question was already pushed but treated as a non invoiced order After this commit, an "warning" message is displayed to the customer saying he/she has to print the invoice from the backend. In most cases it is enough and acceptable, since a customer would actually leave the premises and come back later for the invoice It is also safer in terms of data consistency to keep pushing all orders once the connection is back OPW 1918044 closes odoo/odoo#30485 --- addons/point_of_sale/i18n/point_of_sale.pot | 14 +++++++++++++ addons/point_of_sale/static/src/js/models.js | 20 +++++++++++++------ addons/point_of_sale/static/src/js/screens.js | 11 ++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/addons/point_of_sale/i18n/point_of_sale.pot b/addons/point_of_sale/i18n/point_of_sale.pot index 2067c6a928c..dbf186e92ce 100644 --- a/addons/point_of_sale/i18n/point_of_sale.pot +++ b/addons/point_of_sale/i18n/point_of_sale.pot @@ -2157,6 +2157,13 @@ msgstr "" msgid "Please define income account for this product: \"%s\" (id:%d)." msgstr "" +#. module: point_of_sale +#. openerp-web +#: code:addons/point_of_sale/static/src/js/screens.js:2017 +#, python-format +msgid "Please print the invoice from the backend" +msgstr "" + #. module: point_of_sale #: code:addons/point_of_sale/models/pos_order.py:446 #, python-format @@ -3051,6 +3058,13 @@ msgstr "" msgid "The order could not be sent to the server due to an unknown error" msgstr "" +#. module: point_of_sale +#. openerp-web +#: code:addons/point_of_sale/static/src/js/screens.js:2018 +#, python-format +msgid "The order has been synchronized earlier. Please make the invoice from the backend for the order: " +msgstr "" + #. module: point_of_sale #: model:ir.model.fields,help:point_of_sale.field_pos_config_iface_precompute_cash msgid "The payment input will behave similarily to bank payment input, and will be prefilled with the exact due amount" diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index fa6215ee0e8..2fe1efe8bfa 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -741,12 +741,20 @@ exports.PosModel = Backbone.Model.extend({ transfer.pipe(function(order_server_id){ // generate the pdf and download it - self.chrome.do_action('point_of_sale.pos_invoice_report',{additional_context:{ - active_ids:order_server_id, - }}).done(function () { - invoiced.resolve(); - done.resolve(); - }); + if (order_server_id.length) { + self.chrome.do_action('point_of_sale.pos_invoice_report',{additional_context:{ + active_ids:order_server_id, + }}).done(function () { + invoiced.resolve(); + done.resolve(); + }); + } else { + // The order has been pushed separately in batch when + // the connection came back. + // The user has to go to the backend to print the invoice + invoiced.reject({code:401, message:'Backend Invoice', data:{order: order}}); + done.reject(); + } }); return done; diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 82e6fa0e7b2..2b397e10a2e 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -2012,6 +2012,17 @@ var PaymentScreenWidget = ScreenWidget.extend({ self.gui.show_screen('clientlist'); }, }); + } else if (error.message === 'Backend Invoice') { + self.gui.show_popup('confirm',{ + 'title': _t('Please print the invoice from the backend'), + 'body': _t('The order has been synchronized earlier. Please make the invoice from the backend for the order: ') + error.data.order.name, + confirm: function () { + this.gui.show_screen('receipt'); + }, + cancel: function () { + this.gui.show_screen('receipt'); + }, + }); } else if (error.code < 0) { // XmlHttpRequest Errors self.gui.show_popup('error',{ 'title': _t('The order could not be sent'),