diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot index 43deedf6f9d..1ea910942bf 100644 --- a/addons/account/i18n/account.pot +++ b/addons/account/i18n/account.pot @@ -3855,6 +3855,12 @@ msgid "" "balance." msgstr "" +#. module: account +#: code:addons/account/models/account_move.py:408 +#, python-format +msgid "Difference debit - credit: " +msgstr "" + #. module: account #: model:ir.model,name:account.model_digest_digest msgid "Digest" diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 8a6de4e1ccf..b0f559a283b 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1224,10 +1224,15 @@ class AccountMove(models.Model): lang_env = move.with_context(lang=move.partner_id.lang).env tax_lines = move.line_ids.filtered(lambda line: line.tax_line_id) res = {} + # There are as many tax line as there are repartition lines + done_taxes = set() for line in tax_lines: res.setdefault(line.tax_line_id.tax_group_id, {'base': 0.0, 'amount': 0.0}) res[line.tax_line_id.tax_group_id]['amount'] += line.price_subtotal - res[line.tax_line_id.tax_group_id]['base'] += line.tax_base_amount + if line.tax_line_id.id not in done_taxes: + # The base should be added ONCE + res[line.tax_line_id.tax_group_id]['base'] += line.tax_base_amount + done_taxes.add(line.tax_line_id.id) res = sorted(res.items(), key=lambda l: l[0].sequence) move.amount_by_group = [( group.name, amounts['amount'], @@ -1304,7 +1309,7 @@ class AccountMove(models.Model): # are already done. Then, this query MUST NOT depend of computed stored fields (e.g. balance). # It happens as the ORM makes the create with the 'no_recompute' statement. self._cr.execute(''' - SELECT line.move_id + SELECT line.move_id, ROUND(SUM(debit - credit), currency.decimal_places) FROM account_move_line line JOIN account_move move ON move.id = line.move_id JOIN account_journal journal ON journal.id = move.journal_id @@ -1318,7 +1323,8 @@ class AccountMove(models.Model): query_res = self._cr.fetchall() if query_res: ids = [res[0] for res in query_res] - raise UserError(_("Cannot create unbalanced journal entry. Ids: %s") % str(ids)) + sums = [res[1] for res in query_res] + raise UserError(_("Cannot create unbalanced journal entry. Ids: %s\nDifferences debit - credit: %s") % (ids, sums)) @api.multi def _check_fiscalyear_lock_date(self): diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 6c7b28d89c7..43651c74bcd 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -229,6 +229,7 @@ class AccountReconcileModel(models.Model): 'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)], 'debit': line_balance > 0 and line_balance or 0, 'credit': line_balance < 0 and -line_balance or 0, + 'reconcile_model_id': self.id, } new_aml_dicts.append(writeoff_line) @@ -243,7 +244,11 @@ class AccountReconcileModel(models.Model): # Second write-off line. if self.has_second_line and self.second_account_id: - line_balance = balance - sum(aml['debit'] - aml['credit'] for aml in new_aml_dicts) + remaining_balance = balance - sum(aml['debit'] - aml['credit'] for aml in new_aml_dicts) + if self.second_amount_type == 'percentage': + line_balance = remaining_balance * (self.second_amount / 100.0) + else: + line_balance = self.second_amount * (1 if remaining_balance > 0.0 else -1) second_writeoff_line = { 'name': self.second_label or st_line.name, 'account_id': self.second_account_id.id, @@ -251,6 +256,7 @@ class AccountReconcileModel(models.Model): 'analytic_tag_ids': [(6, 0, self.second_analytic_tag_ids.ids)], 'debit': line_balance > 0 and line_balance or 0, 'credit': line_balance < 0 and -line_balance or 0, + 'reconcile_model_id': self.id, } new_aml_dicts.append(second_writeoff_line) diff --git a/addons/account/models/reconciliation_widget.py b/addons/account/models/reconciliation_widget.py index 85a755c2920..0544a413acd 100644 --- a/addons/account/models/reconciliation_widget.py +++ b/addons/account/models/reconciliation_widget.py @@ -522,22 +522,16 @@ class AccountReconciliation(models.AbstractModel): ]) domain = expression.OR([domain_reconciliation, domain_matching]) - partner_domain = [] if partner_id: - partner_domain = [('partner_id', '=', partner_id)] - domain = expression.AND([domain, partner_domain]) + domain = expression.AND([domain, [('partner_id', '=', partner_id)]]) # Domain factorized for all reconciliation use cases if search_str: str_domain = self._domain_move_lines(search_str=search_str) - if not partner_id: - partner_domain = [('partner_id.name', 'ilike', search_str)] - str_domain = expression.OR([ str_domain, - partner_domain, + [('partner_id.name', 'ilike', search_str)] ]) - domain = expression.AND([ domain, str_domain @@ -553,7 +547,6 @@ class AccountReconciliation(models.AbstractModel): if st_line.company_id.account_bank_reconciliation_start: domain = expression.AND([domain, [('date', '>=', st_line.company_id.account_bank_reconciliation_start)]]) - return domain @api.model diff --git a/addons/account/models/res_users.py b/addons/account/models/res_users.py index 013acde54ff..cc423c2d3a5 100644 --- a/addons/account/models/res_users.py +++ b/addons/account/models/res_users.py @@ -13,8 +13,12 @@ class Users(models.Model): def _check_one_user_type(self): super(Users, self)._check_one_user_type() - g1 = self.env.ref('account.group_show_line_subtotals_tax_included') - g2 = self.env.ref('account.group_show_line_subtotals_tax_excluded') + g1 = self.env.ref('account.group_show_line_subtotals_tax_included', False) + g2 = self.env.ref('account.group_show_line_subtotals_tax_excluded', False) + + if not g1 or not g2: + # A user cannot be in a non-existant group + return if self._has_multiple_groups([g1.id, g2.id]): raise ValidationError(_("A user cannot have both Tax B2B and Tax B2C.\n" diff --git a/addons/account/tests/test_reconciliation_widget.py b/addons/account/tests/test_reconciliation_widget.py index a588fccd42c..ebd23ddd434 100644 --- a/addons/account/tests/test_reconciliation_widget.py +++ b/addons/account/tests/test_reconciliation_widget.py @@ -57,6 +57,7 @@ class TestReconciliationWidget(TestReconciliation): def test_filter_partner1(self): inv1 = self.create_invoice(currency_id=self.currency_euro_id) inv2 = self.create_invoice(currency_id=self.currency_euro_id) + partner = inv1.partner_id receivable1 = inv1.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable') receivable2 = inv2.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable') @@ -75,7 +76,31 @@ class TestReconciliationWidget(TestReconciliation): 'date': time.strftime('%Y-07-15'), }) - # This is like opening the widget, and type "deco" in the filter + # This is like input a partner in the widget + mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line( + bank_stmt_line.id, + partner_id=partner.id, + excluded_ids=[], + search_str=False + ) + mv_lines_ids = [l['id'] for l in mv_lines_rec] + + self.assertTrue(receivable1.id in mv_lines_ids) + self.assertTrue(receivable2.id in mv_lines_ids) + + # With a partner set, type the invoice reference in the filter + mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line( + bank_stmt_line.id, + partner_id=partner.id, + excluded_ids=[], + search_str=inv1.invoice_payment_ref, + ) + mv_lines_ids = [l['id'] for l in mv_lines_rec] + + self.assertTrue(receivable1.id in mv_lines_ids) + self.assertFalse(receivable2.id in mv_lines_ids) + + # Without a partner set, type "deco" in the filter mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line( bank_stmt_line.id, partner_id=False, @@ -87,8 +112,7 @@ class TestReconciliationWidget(TestReconciliation): self.assertTrue(receivable1.id in mv_lines_ids) self.assertTrue(receivable2.id in mv_lines_ids) - # This is like clicking on the first receivable - partner = inv1.partner_id + # With a partner set, type "deco" in the filter and click on the first receivable mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line( bank_stmt_line.id, partner_id=partner.id, diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index c70b70e7dc9..c709897ca69 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -1128,7 +1128,7 @@ action = model.setting_init_bank_account_action() - + diff --git a/addons/auth_signup/models/res_partner.py b/addons/auth_signup/models/res_partner.py index c041ffd3ccf..6f484117fa0 100644 --- a/addons/auth_signup/models/res_partner.py +++ b/addons/auth_signup/models/res_partner.py @@ -113,7 +113,7 @@ class ResPartner(models.Model): allow_signup = self.env['res.users']._get_signup_invitation_scope() == 'b2c' for partner in self: - if allow_signup and not partner.user_ids: + if allow_signup and not partner.sudo().user_ids: partner = partner.sudo() partner.signup_prepare() res[partner.id]['auth_signup_token'] = partner.signup_token diff --git a/addons/digest/data/res_config_settings_data.xml b/addons/digest/data/res_config_settings_data.xml index cbd93e4fef0..cacc318daf0 100644 --- a/addons/digest/data/res_config_settings_data.xml +++ b/addons/digest/data/res_config_settings_data.xml @@ -1,10 +1,10 @@ - - + + digest.default_digest_emails True - + digest.default_digest_id diff --git a/addons/event/controllers/main.py b/addons/event/controllers/main.py index f844e6a5d51..723d30aaa51 100644 --- a/addons/event/controllers/main.py +++ b/addons/event/controllers/main.py @@ -10,8 +10,6 @@ class EventController(Controller): @route(['''/event//ics'''], type='http', auth="public") def event_ics_file(self, event, **kwargs): - if not event or not event.registration_ids: - return request.not_found() files = event._get_ics_file() if not event.id in files: return NotFound() diff --git a/addons/l10n_fr/data/account_fiscal_position_template_data.xml b/addons/l10n_fr/data/account_fiscal_position_template_data.xml index c1b3663520f..c82d89442e7 100644 --- a/addons/l10n_fr/data/account_fiscal_position_template_data.xml +++ b/addons/l10n_fr/data/account_fiscal_position_template_data.xml @@ -54,6 +54,11 @@ + + + + + @@ -64,6 +69,11 @@ + + + + + @@ -146,11 +156,31 @@ + + + + + + + + + + + + + + + + + + + + @@ -168,22 +198,42 @@ + + + + + + + + + + + + + + + + + + + + @@ -203,11 +253,21 @@ + + + + + + + + + + @@ -280,6 +340,11 @@ + + + + + @@ -291,12 +356,27 @@ + + + + + + + + + + + + + + + diff --git a/addons/l10n_fr/data/account_tax_data.xml b/addons/l10n_fr/data/account_tax_data.xml index 3f72c43b63e..41fc79e15a1 100644 --- a/addons/l10n_fr/data/account_tax_data.xml +++ b/addons/l10n_fr/data/account_tax_data.xml @@ -46,6 +46,47 @@ ]"/> + + + TVA à l'encaissement (vente) 10,0% + TVA 10% + + percent + on_payment + + + sale + + + + + TVA à l'encaissement (vente) 20,0% @@ -367,6 +408,48 @@ ]"/> + + + TVA à l'encaissement (vente) 10,0% TTC + TVA 10% TTC + + + percent + on_payment + + + sale + + + + + TVA à l'encaissement (vente) 20,0% TTC @@ -693,6 +776,88 @@ ]"/> + + + TVA à l'encaissement (achat) 20,0% + TVA 20% + + percent + on_payment + + + purchase + + + + + + + + TVA à l'encaissement (achat) 10,0% + TVA 10% + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 8,5% @@ -810,6 +975,47 @@ ]"/> + + + TVA à l'encaissement (achat) 5,5% + TVA 5,5% + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 2,1% @@ -851,6 +1057,47 @@ + + + TVA à l'encaissement (achat) 2,1% + TVA 2,1% + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 20,0% TTC @@ -891,6 +1138,48 @@ ]"/> + + + TVA à l'encaissement (achat) 20,0% TTC + TVA 20% TTC + + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 8,5% TTC @@ -931,6 +1220,48 @@ ]"/> + + + TVA à l'encaissement (achat) 10,0% TTC + TVA 10% TTC + + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 10,0% TTC @@ -1011,6 +1342,48 @@ ]"/> + + + TVA à l'encaissement (achat) 5,5% TTC + TVA 5,5% TTC + + + percent + on_payment + + + purchase + + + + + TVA déductible (achat) 2,1% TTC @@ -1051,6 +1424,48 @@ ]"/> + + + TVA à l'encaissement (achat) 2,1% TTC + TVA 2,1% TTC + + + percent + on_payment + + + purchase + + + + + diff --git a/addons/l10n_in/data/account_data.xml b/addons/l10n_in/data/account_data.xml index c1fb9299c1e..c20cfa8839f 100644 --- a/addons/l10n_in/data/account_data.xml +++ b/addons/l10n_in/data/account_data.xml @@ -3,6 +3,12 @@ + + SGST + + + CGST + IGST diff --git a/addons/l10n_in/data/account_tax_template_data.xml b/addons/l10n_in/data/account_tax_template_data.xml index 6c0d3b8892e..374628bb05d 100644 --- a/addons/l10n_in/data/account_tax_template_data.xml +++ b/addons/l10n_in/data/account_tax_template_data.xml @@ -459,14 +459,14 @@ if tax > result:result=tax - - GST 1% - GST 1% - sale + + SGST Sale 0.5% + SGST 0.5% + none percent - 1.0 + 0.5 - + + + + + CGST Sale 0.5% + CGST 0.5% + none + percent + 0.5 + + + + + + + + GST 1% + GST 1% + sale + group + 1.0 + + + + + + + SGST Sale 1% + SGST 1% + none + percent + 1 + + + + + + + + CGST Sale 1% + CGST 1% + none + percent + 1 + + + + @@ -511,10 +614,21 @@ if tax > result:result=tax GST 2% GST 2% sale - percent + group 2.0 + + + + + SGST Sale 14% + SGST 14% + none + percent + 14 + + + + + + CGST Sale 14% + CGST 14% + none + percent + 14 + + + + @@ -559,10 +695,21 @@ if tax > result:result=tax GST 28% GST 28% sale - percent + group 28.0 + + + + + SGST Sale 9% + SGST 9% + none + percent + 9 + + + + + + CGST Sale 9% + CGST 9% + none + percent + 9 + + + + @@ -607,43 +776,74 @@ if tax > result:result=tax GST 18% GST 18% sale - percent + group 18.0 + + + + + SGST Sale 6% + SGST 6% + none + percent + 6 + + + + + + CGST Sale 6% + CGST 6% + none + percent + 6 + + + + GST 12% GST 12% sale - percent + group 12.0 + + + + + SGST Sale 2.5% + SGST 2.5% + none + percent + 2.5 + + + + + + CGST Sale 2.5% + CGST 2.5% + none + percent + 2.5 + + + + @@ -703,49 +936,12 @@ if tax > result:result=tax GST 5% GST 5% sale - percent + group 5.0 0 - - + @@ -1166,31 +1362,25 @@ if tax > result:result=tax - - GST 1% - GST 1% - purchase + + SGST Purchase 0.5% + SGST 0.5% + none percent - 1.0 + 0.5 - + + + + + CGST Purchase 0.5% + CGST 0.5% + none + percent + 0.5 + + + + + + GST 1% + GST 1% + purchase + group + 1.0 + + + + + + + SGST Purchase 1% + SGST 1% + none + percent + 1 + + + + + + + + CGST Purchase 1% + CGST 1% + none + percent + 1 + + + + + + + GST 2% GST 2% purchase - percent + group 2.0 + + + + + SGST Purchase 14% + SGST 14% + none + percent + 14 + + + + + + CGST Purchase 14% + CGST 14% + none + percent + 14 + + + + @@ -1264,10 +1595,21 @@ if tax > result:result=tax GST 28% GST 28% purchase - percent + group 28.0 + + + + + SGST Purchase 9% + SGST 9% + none + percent + 9 + + + + + + CGST Purchase 9% + CGST 9% + none + percent + 9 + + + + @@ -1312,10 +1676,21 @@ if tax > result:result=tax GST 18% GST 18% purchase - percent + group 18.0 + + + + + SGST Purchase 6% + SGST 6% + none + percent + 6 + + + + + + + CGST Purchase 6% + CGST 6% + none + percent + 6 + + + @@ -1360,10 +1757,21 @@ if tax > result:result=tax GST 12% GST 12% purchase - percent + group 12.0 + + + + + SGST Purchase 2.5% + SGST 2.5% + none + percent + 2.5 + + + + + + CGST Purchase 2.5% + CGST 2.5% + none + percent + 2.5 + + + + @@ -1408,49 +1838,12 @@ if tax > result:result=tax GST 5% GST 5% purchase - percent + group 5.0 0 - - + diff --git a/addons/l10n_it_edi/models/account_invoice.py b/addons/l10n_it_edi/models/account_invoice.py index 3a8d8361b95..77185ea4e3d 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -110,7 +110,7 @@ class AccountMove(models.Model): raise UserError(_("%s must have a country.") % (seller.display_name)) # <1.4.1> - if not buyer.vat and not buyer.l10n_it_codice_fiscale and buyer.country_id.code != 'IT': + if not buyer.vat and not buyer.l10n_it_codice_fiscale and buyer.country_id.code == 'IT': raise UserError(_("The buyer, %s, or his company must have either a VAT number either a tax code (Codice Fiscale).") % (buyer.display_name)) # <1.4.2> @@ -273,11 +273,12 @@ class AccountMove(models.Model): 'body': _('Sending file: %s to ES: %s') % (self.l10n_it_einvoice_id.name, self.env.company.l10n_it_address_recipient_fatturapa), 'author_id': self.env.user.partner_id.id, 'email_from': self.env.company.l10n_it_address_send_fatturapa, + 'reply_to': self.env.company.l10n_it_address_send_fatturapa, 'mail_server_id': self.env.company.l10n_it_mail_pec_server_id.id, 'attachment_ids': [(6, 0, self.l10n_it_einvoice_id.ids)], }) - mail_fattura = self.env['mail.mail'].create({ + mail_fattura = self.env['mail.mail'].with_context(wo_return_path=True).create({ 'mail_message_id': message.id, 'email_to': self.env.company.l10n_it_address_recipient_fatturapa, }) diff --git a/addons/l10n_it_edi/models/ir_mail_server.py b/addons/l10n_it_edi/models/ir_mail_server.py index 581274ac404..18c4a66af3c 100644 --- a/addons/l10n_it_edi/models/ir_mail_server.py +++ b/addons/l10n_it_edi/models/ir_mail_server.py @@ -355,3 +355,17 @@ class FetchmailServer(models.Model): if descrizione: output_str += "
  • Errore %s: %s
  • " % (element[0].text, descrizione) return output_str + "" + +class IrMailServer(models.Model): + _name = "ir.mail_server" + _inherit = "ir.mail_server" + + def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, + attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None, + body_alternative=None, subtype_alternative='plain'): + + if self.env.context.get('wo_return_path') and headers: + headers.pop('Return-Path', False) + return super(IrMailServer, self).build_email(email_from, email_to, subject, body, email_cc=email_cc, email_bcc=email_bcc, reply_to=reply_to, + attachments=attachments, message_id=message_id, references=references, object_id=object_id, subtype=subtype, headers=headers, + body_alternative=body_alternative, subtype_alternative=subtype_alternative) diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js index 6eeeaecf7c3..de5ce88b742 100644 --- a/addons/mail/static/src/js/discuss.js +++ b/addons/mail/static/src/js/discuss.js @@ -280,6 +280,8 @@ var Discuss = AbstractAction.extend({ this.options.channelQuickSearchThreshold = 20; } + this._isMessagingReady = this.call('mail_service', 'isReady'); + this._isStarted = false; this._threadsScrolltop = {}; this._composerStates = {}; this._defaultThreadID = this.options.active_id || @@ -291,68 +293,20 @@ var Discuss = AbstractAction.extend({ this._updateThreads.bind(this), 100, { leading: false }); this.controlPanelParams.modelName = 'mail.message'; - }, - /** - * @override - */ - willStart: function () { - return Promise.all([this._super(), this.call('mail_service', 'isReady')]); + this.call('mail_service', 'getMailBus').on('messaging_ready', this, this._onMessagingReady); }, /** * @override */ start: function () { var self = this; - - this._basicComposer = new BasicComposer(this, { - mentionPartnersRestricted: true, - showTyping: true, + this._isStarted = true; + return this._super.apply(this, arguments).then(function () { + if (!self._isMessagingReady) { + return; + } + return self._initRender(); }); - this._extendedComposer = new ExtendedComposer(this, { - mentionPartnersRestricted: true, - showTyping: true, - }); - this._basicComposer - .on('post_message', this, this._onPostMessage) - .on('input_focused', this, this._onComposerFocused); - this._extendedComposer - .on('post_message', this, this._onPostMessage) - .on('input_focused', this, this._onComposerFocused); - this._renderButtons(); - - var defs = []; - defs.push( - this._renderThread() - ); - defs.push( - this._basicComposer.appendTo(this.$('.o_mail_discuss_content'))); - defs.push( - this._extendedComposer.appendTo(this.$('.o_mail_discuss_content'))); - defs.push(this._super.apply(this, arguments)); - - return Promise.all(defs) - .then(function () { - return self._setThread(self._defaultThreadID); - }) - .then(function () { - self._initThreads(); - self._startListening(); - self._threadWidget.$el.on('scroll', null, _.debounce(function () { - if ( - self._threadWidget.getScrolltop() < 20 && - !self._threadWidget.$('.o_mail_no_content').length && - !self._thread.isAllHistoryLoaded(self.domain) - ) { - self._loadMoreMessages(); - } - if ( - self._threadWidget.isAtBottom() && - self._thread.getType() !== 'mailbox' - ) { - self._thread.markAsRead(); - } - }, 100)); - }); }, /** * @override @@ -381,8 +335,8 @@ var Discuss = AbstractAction.extend({ this.call('mail_service', 'getMailBus').trigger('discuss_open', true); if (this._thread) { this._threadWidget.scrollToPosition(this._threadsScrolltop[this._thread.getID()]); + this._loadEnoughMessages(); } - this._loadEnoughMessages(); }, /** * @override @@ -546,6 +500,60 @@ var Discuss = AbstractAction.extend({ } } }, + /** + * @private + */ + _initRender: function () { + var self = this; + this._basicComposer = new BasicComposer(this, { + mentionPartnersRestricted: true, + showTyping: true, + }); + this._extendedComposer = new ExtendedComposer(this, { + mentionPartnersRestricted: true, + showTyping: true, + }); + this._basicComposer + .on('post_message', this, this._onPostMessage) + .on('input_focused', this, this._onComposerFocused); + this._extendedComposer + .on('post_message', this, this._onPostMessage) + .on('input_focused', this, this._onComposerFocused); + this._renderButtons(); + + var defs = []; + defs.push( + this._renderThread() + ); + defs.push( + this._basicComposer.appendTo(this.$('.o_mail_discuss_content'))); + defs.push( + this._extendedComposer.appendTo(this.$('.o_mail_discuss_content'))); + + return Promise.all(defs) + .then(function () { + return self._setThread(self._defaultThreadID); + }) + .then(function () { + self._initThreads(); + self._startListening(); + self._threadWidget.$el.on('scroll', null, _.debounce(function () { + if ( + self._threadWidget.getScrolltop() < 20 && + !self._threadWidget.$('.o_mail_no_content').length && + !self._thread.isAllHistoryLoaded(self.domain) + ) { + self._loadMoreMessages(); + } + if ( + self._threadWidget.isAtBottom() && + self._thread.getType() !== 'mailbox' + ) { + self._thread.markAsRead(); + } + }, 100)); + }); + }, /** * Renders the mainside bar with current threads * @@ -1400,6 +1408,20 @@ var Discuss = AbstractAction.extend({ this._fetchAndRenderThread(); } }, + /** + * @private + */ + _onMessagingReady: function () { + if (this._isMessagingReady) { + return; + } + this._isMessagingReady = true; + if (!this._isStarted) { + return; + } + this.$('.o_mail_discuss_loading').remove(); + this._initRender(); + }, /** * @private * @param {MouseEvent} ev diff --git a/addons/mail/static/src/js/services/mail_document_thread_manager.js b/addons/mail/static/src/js/services/mail_document_thread_manager.js index 6bb66b1b439..652567baf14 100644 --- a/addons/mail/static/src/js/services/mail_document_thread_manager.js +++ b/addons/mail/static/src/js/services/mail_document_thread_manager.js @@ -34,7 +34,7 @@ MailManager.include({ this.call('local_storage', 'getItem', key); } } - this.isReady().then(this._updateDocumentThreadWindows.bind(this, this._documentThreadWindowStates)); + this._mailBus.on('messaging_ready', this, this._updateDocumentThreadWindows.bind(this, this._documentThreadWindowStates)); // listen to localStorage changes to synchronize DocumentThread's // windows between tabs this.call('local_storage', 'onStorage', this, this._onStorage); diff --git a/addons/mail/static/src/js/services/mail_manager.js b/addons/mail/static/src/js/services/mail_manager.js index 3ed4031abeb..950ac8c5cd6 100644 --- a/addons/mail/static/src/js/services/mail_manager.js +++ b/addons/mail/static/src/js/services/mail_manager.js @@ -46,6 +46,7 @@ var PREVIEW_MSG_MAX_SIZE = 350; // optimal for native english speakers var MailManager = AbstractService.extend({ dependencies: ['ajax', 'bus_service', 'local_storage'], + _isReady: false, _ODOOBOT_ID: ["ODOOBOT", "ODOOBOT"], // authorID for transient messages /** @@ -294,7 +295,7 @@ var MailManager = AbstractService.extend({ * This is the case when it has fetched the initial state from the server, * by means of the route 'mail/init_messaging' * - * @returns {Promise} + * @returns {boolean} */ isReady: function () { return this._isReady; @@ -636,7 +637,7 @@ var MailManager = AbstractService.extend({ */ _fetchMailStateFromServer: function () { var self = this; - this._isReady = session.is_bound.then(function () { + session.is_bound.then(function () { var context = _.extend( { isMobile: config.device.isMobile }, session.user_context @@ -648,6 +649,8 @@ var MailManager = AbstractService.extend({ }).then(function (result) { self._updateInternalStateFromServer(result); self.call('bus_service', 'startPolling'); + self._isReady = true; + self._mailBus.trigger('messaging_ready'); }); }, /** diff --git a/addons/mail/static/src/js/systray/systray_activity_menu.js b/addons/mail/static/src/js/systray/systray_activity_menu.js index 641ff4be1bc..8afa88d7e20 100644 --- a/addons/mail/static/src/js/systray/systray_activity_menu.js +++ b/addons/mail/static/src/js/systray/systray_activity_menu.js @@ -19,9 +19,6 @@ var ActivityMenu = Widget.extend({ 'click .o_mail_preview': '_onActivityFilterClick', 'show.bs.dropdown': '_onActivityMenuShow', }, - willStart: function () { - return Promise.resolve(this.call('mail_service', 'isReady')); - }, start: function () { this._$activitiesPreview = this.$('.o_mail_systray_dropdown_items'); this.call('mail_service', 'getMailBus').on('activity_updated', this, this._updateCounter); diff --git a/addons/mail/static/src/js/systray/systray_messaging_menu.js b/addons/mail/static/src/js/systray/systray_messaging_menu.js index f4c4eb48f39..1093a22d27a 100644 --- a/addons/mail/static/src/js/systray/systray_messaging_menu.js +++ b/addons/mail/static/src/js/systray/systray_messaging_menu.js @@ -27,12 +27,6 @@ var MessagingMenu = Widget.extend({ 'click .o_thread_window_expand': '_onClickExpand', 'show.bs.dropdown': '_onShowDropdown', }, - /** - * @override - */ - willStart: function () { - return Promise.all([this._super.apply(this, arguments), this.call('mail_service', 'isReady')]); - }, /** * @override */ @@ -40,8 +34,10 @@ var MessagingMenu = Widget.extend({ this._$filterButtons = this.$('.o_filter_button'); this._$previews = this.$('.o_mail_systray_dropdown_items'); this._filter = false; + this._isMessagingReady = this.call('mail_service', 'isReady'); this._updateCounter(); var mailBus = this.call('mail_service', 'getMailBus'); + mailBus.on('messaging_ready', this, this._onMessagingReady); mailBus.on('update_needaction', this, this._updateCounter); mailBus.on('new_channel', this, this._updateCounter); mailBus.on('update_thread_unread_counter', this, this._updateCounter); @@ -207,6 +203,9 @@ var MessagingMenu = Widget.extend({ _updatePreviews: function () { // Display spinner while waiting for conversations preview this._$previews.html(QWeb.render('Spinner')); + if (!this._isMessagingReady) { + return; + } this._getPreviews() .then(this._renderPreviews.bind(this)); }, @@ -229,7 +228,11 @@ var MessagingMenu = Widget.extend({ * @private */ _updateCounter: function () { + if (!this._isMessagingReady) { + return; + } var counter = this._computeCounter(); + this.$('.o_mail_messaging_menu_icon').removeClass('fa-spinner fa-spin'); this.$('.o_notification_counter').text(counter); this.$el.toggleClass('o_no_notification', !counter); if (this._isShown()) { @@ -338,6 +341,16 @@ var MessagingMenu = Widget.extend({ } } }, + /** + * @private + */ + _onMessagingReady: function () { + if (this._isMessagingReady) { + return; + } + this._isMessagingReady = true; + this._updateCounter(); + }, }); // Systray menu items display order matches order in the list diff --git a/addons/mail/static/src/js/thread_field.js b/addons/mail/static/src/js/thread_field.js index ab8023b06ad..c8a59850016 100644 --- a/addons/mail/static/src/js/thread_field.js +++ b/addons/mail/static/src/js/thread_field.js @@ -20,23 +20,21 @@ var ThreadField = AbstractField.extend({ */ init: function () { this._super.apply(this, arguments); + this._isMessagingReady = this.call('mail_service', 'isReady'); + this._isStarted = false; + this.call('mail_service', 'getMailBus').on('messaging_ready', this, this._onMessagingReady); // Used to automatically mark document thread as read at the moment we // access the document and render the thread. this._markAsReadOnNextRender = false; this._setDocumentThread(); }, - /** - * @override - */ - willStart: function () { - return this.alive(this.call('mail_service', 'isReady')); - }, /** * @override */ start: function () { var self = this; + this._isStarted = true; this.dp = new concurrency.DropPrevious(); this._threadWidget = new ThreadWidget(this, { @@ -159,6 +157,9 @@ var ThreadField = AbstractField.extend({ * If it is a new document in create mode, unset the document thread. */ _setDocumentThread: function () { + if (!this._isMessagingReady) { + return; + } var params = { messageIDs: this.value.res_ids, name: this.recordData.display_name, @@ -185,6 +186,19 @@ var ThreadField = AbstractField.extend({ _onLoadMoreMessages: function () { this._fetchAndRenderThread({ forceFetch: true }); }, + /** + * @private + */ + _onMessagingReady: function () { + if (this._isMessagingReady) { + return; + } + this._isMessagingReady = true; + if (!this._isStarted) { + return; + } + this._setDocumentThread(); + }, /** * @private * @param {mail.model.Message} diff --git a/addons/mail/static/src/scss/discuss.scss b/addons/mail/static/src/scss/discuss.scss index 8284fdc70b5..4cb902e4539 100644 --- a/addons/mail/static/src/scss/discuss.scss +++ b/addons/mail/static/src/scss/discuss.scss @@ -7,6 +7,18 @@ height: 100%; overflow: hidden; + .o_mail_discuss_loading { + display: flex; + flex: 1 1 auto; + align-items: center; + justify-content: center; + min-height: 100%; + + > i { + margin-right: 5px; + } + } + .o_mail_discuss_sidebar { width: $o-mail-chat-sidebar-width; height: 100%; diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml index afee3a84da2..781a03c016d 100644 --- a/addons/mail/static/src/xml/discuss.xml +++ b/addons/mail/static/src/xml/discuss.xml @@ -8,8 +8,15 @@ -->
    -
    +
    +
    + Please wait... +
    +
    +
    + Please wait... +
    diff --git a/addons/mail/static/src/xml/systray.xml b/addons/mail/static/src/xml/systray.xml index 7bcda0fb273..204af3700e4 100644 --- a/addons/mail/static/src/xml/systray.xml +++ b/addons/mail/static/src/xml/systray.xml @@ -7,7 +7,7 @@