diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index e0fbfbc1873..131ca0f3a53 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1220,10 +1220,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'], @@ -1315,7 +1320,7 @@ class AccountMove(models.Model): self.env['account.move.line'].flush(['debit', 'credit', 'move_id']) self.env['account.move'].flush(['journal_id']) 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 @@ -1329,7 +1334,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)) def _check_fiscalyear_lock_date(self): for move in self: @@ -2060,7 +2066,6 @@ class AccountMove(models.Model): """ if any(not move.is_invoice(include_receipts=True) for move in self): raise UserError(_("Only invoices could be printed.")) - self._check_tax_lock_date() self.filtered(lambda inv: not inv.invoice_sent).write({'invoice_sent': True}) if self.user_has_groups('account.group_account_invoice'): @@ -2309,7 +2314,7 @@ class AccountMoveLine(models.Model): ), ( 'check_accountable_required_fields', - "CHECK(display_type IN ('line_section', 'line_note') OR account_id IS NOT NULL)", + "CHECK(COALESCE(display_type IN ('line_section', 'line_note'), 'f') OR account_id IS NOT NULL)", "Missing required account on accountable invoice line." ), ( @@ -2794,7 +2799,7 @@ class AccountMoveLine(models.Model): currency = record.company_id.currency_id audit_str = '' for tag in record.tag_ids: - tag_amount = (tag.tax_negate and -1 or 1) * (record.move_id.is_outbound() and -1 or 1) * record.balance + tag_amount = (tag.tax_negate and -1 or 1) * (record.move_id.is_inbound() and -1 or 1) * record.balance if tag.tax_report_line_ids: #Then, the tag comes from a report line, and hence has a + or - sign (also in its name) diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 56a8fc81a4e..147c8334a67 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -265,6 +265,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) @@ -298,6 +299,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 a52aa1ee3b3..d17d1e21ef4 100644 --- a/addons/account/models/reconciliation_widget.py +++ b/addons/account/models/reconciliation_widget.py @@ -556,10 +556,8 @@ 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)]]) if mode == 'rp': domain = expression.AND([domain, [('account_id.internal_type', 'in', ['receivable', 'payable', 'liquidity'])] @@ -572,14 +570,10 @@ class AccountReconciliation(models.AbstractModel): # 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 @@ -596,7 +590,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 6b379668fa3..d564746dfd6 100644 --- a/addons/account/models/res_users.py +++ b/addons/account/models/res_users.py @@ -12,8 +12,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/account_test_no_chart.py b/addons/account/tests/account_test_no_chart.py index fbd895fdb46..61cbe3e47a6 100644 --- a/addons/account/tests/account_test_no_chart.py +++ b/addons/account/tests/account_test_no_chart.py @@ -83,12 +83,16 @@ class TestAccountNoChartCommon(SavepointCase): 'code': 'AJ-PURC', 'type': 'purchase', 'company_id': cls.env.user.company_id.id, + 'default_debit_account_id': cls.account_expense.id, + 'default_credit_account_id': cls.account_expense.id, }) cls.journal_sale = cls.env['account.journal'].create({ 'name': 'Sale Journal - Test', 'code': 'AJ-SALE', 'type': 'sale', 'company_id': cls.env.user.company_id.id, + 'default_debit_account_id': cls.account_income.id, + 'default_credit_account_id': cls.account_income.id, }) cls.journal_general = cls.env['account.journal'].create({ 'name': 'General Journal - Test', diff --git a/addons/account/tests/test_account_move_entry.py b/addons/account/tests/test_account_move_entry.py index 587dfc48deb..d3c3503ff5a 100644 --- a/addons/account/tests/test_account_move_entry.py +++ b/addons/account/tests/test_account_move_entry.py @@ -60,6 +60,7 @@ class TestAccountMove(InvoiceTestCommon): self.env['account.move'].create(self.test_move.copy_data()) def test_misc_tax_lock_date_1(self): + self.test_move.post() # Set the tax lock date after the journal entry date. self.test_move.company_id.tax_lock_date = fields.Date.from_string('2017-01-01') diff --git a/addons/account/tests/test_account_move_partner_count.py b/addons/account/tests/test_account_move_partner_count.py index 7ec2b6cc410..68527cf7572 100644 --- a/addons/account/tests/test_account_move_partner_count.py +++ b/addons/account/tests/test_account_move_partner_count.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.tests import tagged from odoo.tests.common import TransactionCase +@tagged('post_install', '-at_install') class TestAccountMovePartnerCount(TransactionCase): def setUp(self): @@ -14,6 +16,13 @@ class TestAccountMovePartnerCount(TransactionCase): with self.registry.cursor() as cr: env = self.env(cr=cr) self.partner = self.env['res.partner'].with_env(env).create({'name': 'Lucien'}) + user_type_income = env.ref('account.data_account_type_direct_costs') + self.account_income = self.env['account.account'].with_env(env).create({ + 'code': 'TESTCOUNT42', + 'name': 'Sale - Test Account', + 'user_type_id': user_type_income.id + }) + self.journal = self.env['account.journal'].with_env(env).create({ 'name': 'Journal', 'code': '7775', @@ -28,6 +37,7 @@ class TestAccountMovePartnerCount(TransactionCase): self.line = self.env['account.move.line'].with_env(env).create({ 'move_id': self.move.id, 'name': 'account move line test', + 'account_id': self.account_income.id, }) def tearDown(self): @@ -38,6 +48,7 @@ class TestAccountMovePartnerCount(TransactionCase): move.state = 'draft' move.unlink() self.journal.with_env(env).unlink() + self.account_income.with_env(env).unlink() self.partner.with_env(env).unlink() def test_account_move_count(self): diff --git a/addons/account/tests/test_reconciliation_widget.py b/addons/account/tests/test_reconciliation_widget.py index 99769bc2f2e..0baa2c23f8b 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,33 @@ 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, + mode="rp", + ) + mv_lines_ids = [l['id'] for l in mv_lines_rec] + + self.assertIn(receivable1.id, mv_lines_ids) + self.assertIn(receivable2.id, 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, + mode="rp", + ) + mv_lines_ids = [l['id'] for l in mv_lines_rec] + + self.assertIn(receivable1.id, mv_lines_ids) + self.assertNotIn(receivable2.id, 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, @@ -88,8 +115,7 @@ class TestReconciliationWidget(TestReconciliation): self.assertIn(receivable1.id, mv_lines_ids) self.assertIn(receivable2.id, 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 a488cc09ed0..07e733d0b42 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -1265,7 +1265,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 b92e5dc55f5..259a5838b30 100644 --- a/addons/auth_signup/models/res_partner.py +++ b/addons/auth_signup/models/res_partner.py @@ -109,7 +109,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/hr_org_chart/controllers/hr_org_chart.py b/addons/hr_org_chart/controllers/hr_org_chart.py index 8df4c81ae40..f9160767995 100644 --- a/addons/hr_org_chart/controllers/hr_org_chart.py +++ b/addons/hr_org_chart/controllers/hr_org_chart.py @@ -14,8 +14,8 @@ class HrOrgChartController(http.Controller): return None employee_id = int(employee_id) - if ('context' in kw and 'allowed_company_ids' in kw['context']): - cids = kw['context']['allowed_company_ids'] + if 'allowed_company_ids' in request.env.context: + cids = request.env.context['allowed_company_ids'] else: cids = [request.env.company.id] 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 2938c6630ff..062e7f184a2 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -109,7 +109,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> @@ -270,11 +270,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 51e4a0a23a3..2d2f33540a1 100644 --- a/addons/l10n_it_edi/models/ir_mail_server.py +++ b/addons/l10n_it_edi/models/ir_mail_server.py @@ -360,3 +360,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 27208f0edfc..015ebfa01a3 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 7dcd1ca058f..fce3247e15b 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 9a9b21fe953..4a27ed0713f 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); @@ -235,6 +231,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)); }, @@ -257,7 +256,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()) { @@ -346,6 +349,16 @@ var MessagingMenu = Widget.extend({ var $preview = $(ev.currentTarget).closest('.o_mail_preview'); this._markAsRead($preview); }, + /** + * @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 ea64d1fc9e3..218a4b552ec 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, { @@ -160,6 +158,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, @@ -186,6 +187,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 21ff765dfdb..d7a01bdf26f 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 71138ae1f24..3b21d7f230a 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 dfa1d02b76c..dc275079e28 100644 --- a/addons/mail/static/src/xml/systray.xml +++ b/addons/mail/static/src/xml/systray.xml @@ -7,7 +7,7 @@