diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-04-01 16:20:00 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-04-01 16:20:00 +0200 |
| commit | 7ac5ec628cb9fe8ff3f6b54a1466f246a24ff01c (patch) | |
| tree | e9297c876e0f9886c1b0abbb7e5cd389a7ab708c /addons | |
| parent | 8de362fac65867687a3eb0557012db75faeab850 (diff) | |
| parent | 18c735361a6861a294a9dc254395a084eb42f505 (diff) | |
[MERGE] forward port branch saas-12.2 up to 18c735361a6
Diffstat (limited to 'addons')
45 files changed, 536 insertions, 222 deletions
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 9c203190b0e..3c71e6c625a 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from collections import OrderedDict import json import re import uuid @@ -539,10 +540,7 @@ class AccountInvoice(models.Model): if not vals.get('journal_id') and vals.get('type'): vals['journal_id'] = self.with_context(type=vals.get('type'))._default_journal().id - onchanges = { - '_onchange_partner_id': ['account_id', 'payment_term_id', 'fiscal_position_id', 'partner_bank_id'], - '_onchange_journal_id': ['currency_id'], - } + onchanges = self._get_onchange_create() for onchange_method, changed_fields in onchanges.items(): if any(f not in vals for f in changed_fields): invoice = self.new(vals) @@ -696,7 +694,7 @@ class AccountInvoice(models.Model): """ # Split `From` and `CC` email address from received email to look for related partners to subscribe on the invoice subscribed_emails = email_split((msg_dict.get('from') or '') + ',' + (msg_dict.get('cc') or '')) - subscribed_partner_ids = [pid for pid in self._find_partner_from_emails(subscribed_emails) if pid] + seen_partner_ids = [pid for pid in self._find_partner_from_emails(subscribed_emails) if pid] # Detection of the partner_id of the invoice: # 1) check if the email_from correspond to a supplier @@ -720,7 +718,7 @@ class AccountInvoice(models.Model): # If the partner_id can be found, subscribe it to the bill, otherwise it's left empty to be manually filled if partner_id: - subscribed_partner_ids.append(partner_id) + seen_partner_ids.append(partner_id) # Find the right purchase journal based on the "TO" email address destination_emails = email_split((msg_dict.get('to') or '') + ',' + (msg_dict.get('cc') or '')) @@ -736,9 +734,13 @@ class AccountInvoice(models.Model): # Passing `type` in context so that _default_journal(...) can correctly set journal for new vendor bill invoice = super(AccountInvoice, self.with_context(type=values.get('type'))).message_new(msg_dict, values) - # Subscribe people on the newly created bill - if subscribed_partner_ids: - invoice.message_subscribe(subscribed_partner_ids) + # Subscribe internal users on the newly created bill + partners = self.env['res.partner'].browse(seen_partner_ids) + is_internal = lambda p: (p.user_ids and + all(p.user_ids.mapped(lambda u: u.user_has_groups('base.group_user')))) + partners_to_subscribe = partners.filtered(is_internal) + if partners_to_subscribe: + invoice.message_subscribe([p.id for p in partners_to_subscribe]) return invoice @api.model @@ -1657,6 +1659,13 @@ class AccountInvoice(models.Model): def _get_intrastat_country_id(self): return self.partner_id.country_id.id + def _get_onchange_create(self): + return OrderedDict([ + ('_onchange_partner_id', ['account_id', 'payment_term_id', 'fiscal_position_id', 'partner_bank_id']), + ('_onchange_journal_id', ['currency_id']), + ]) + + class AccountInvoiceLine(models.Model): _name = "account.invoice.line" _description = "Invoice Line" diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index be8416f3502..11306b4a5a6 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -391,10 +391,10 @@ class account_journal(models.Model): action_name = 'action_view_bank_statement_tree' elif self.type == 'sale': action_name = 'action_invoice_tree1' - self = self.with_context(use_domain=[('type', 'in', ['out_invoice', 'out_refund'])]) + self = self.with_context(use_domain=[('journal_id', '=', self.id)]) elif self.type == 'purchase': action_name = 'action_vendor_bill_template' - self = self.with_context(use_domain=[('type', 'in', ['in_invoice', 'in_refund'])]) + self = self.with_context(use_domain=[('journal_id', '=', self.id)]) else: action_name = 'action_move_journal_line' diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 58daa1227a8..cf90802f58f 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1086,7 +1086,7 @@ class AccountMoveLine(models.Model): writeoff_moves += writeoff_move # writeoff_move.post() - line_to_reconcile += writeoff_move.line_ids.filtered(lambda r: r.account_id == self[0].account_id) + line_to_reconcile += writeoff_move.line_ids.filtered(lambda r: r.account_id == self[0].account_id).sorted(key='id')[-1:] if writeoff_moves: writeoff_moves.post() # Return the writeoff move.line which is to be reconciled diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index 46f6a91bb8b..dfc2b605790 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -665,9 +665,7 @@ class account_payment(models.Model): if any(len(record.invoice_ids) != 1 for record in self): # For multiple invoices, there is account.register.payments wizard raise UserError(_("This method should only be called to process a single invoice's payment.")) - res = self.post() - self.mapped('payment_transaction_id').filtered(lambda x: x.state == 'done' and not x.is_processed)._post_process_after_done() - return res + return self.post() def _create_payment_entry(self, amount): """ Create a journal entry corresponding to a payment, if the payment references invoice(s) they are reconciled. diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index e33f18260a1..5ab6865831a 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -418,6 +418,9 @@ class AccountReconcileModel(models.Model): aml.date_maturity AS aml_date_maturity, aml.amount_residual AS aml_amount_residual, aml.amount_residual_currency AS aml_amount_residual_currency, + aml.balance AS aml_balance, + aml.amount_currency AS aml_amount_currency, + account.internal_type AS account_internal_type, -- Determine a matching or not with the statement line communication using the move.name or move.ref. regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+') @@ -565,9 +568,12 @@ class AccountReconcileModel(models.Model): return True # Match total residual amount. - total_residual = sum( - aml['aml_currency_id'] and aml['aml_amount_residual_currency'] or aml['aml_amount_residual'] for aml in - candidates) + total_residual = 0.0 + for aml in candidates: + if aml['account_internal_type'] == 'liquidity': + total_residual += aml['aml_currency_id'] and aml['aml_amount_currency'] or aml['aml_balance'] + else: + total_residual += aml['aml_currency_id'] and aml['aml_amount_residual_currency'] or aml['aml_amount_residual'] line_residual = statement_line.currency_id and statement_line.amount_currency or statement_line.amount line_currency = statement_line.currency_id or statement_line.journal_id.currency_id or statement_line.company_id.currency_id diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index ca35292af5a..49a9be865e2 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -471,6 +471,67 @@ class TestReconciliation(AccountingTestCase): self.assertEquals(aml.amount_residual, 0, 'The journal item should be totally reconciled') self.assertEquals(aml.amount_residual_currency, 0, 'The journal item should be totally reconciled') + def test_manual_reconcile_wizard_same_account(self): + move_ids = self.env['account.move'] + debit_line_vals = { + 'name': '1', + 'debit': 728.35, + 'credit': 0.0, + 'account_id': self.account_rcv.id, + 'amount_currency': 795.05, + 'currency_id': self.currency_swiss_id, + } + credit_line_vals = { + 'name': '1', + 'debit': 0.0, + 'credit': 728.35, + 'account_id': self.account_rsa.id, + 'amount_currency': -795.05, + 'currency_id': self.currency_swiss_id, + } + vals = { + 'journal_id': self.bank_journal_euro.id, + 'date': time.strftime('%Y') + '-02-15', + 'line_ids': [(0,0, debit_line_vals), (0, 0, credit_line_vals)] + } + move_ids += self.env['account.move'].create(vals) + debit_line_vals = { + 'name': '2', + 'debit': 0.0, + 'credit': 737.10, + 'account_id': self.account_rcv.id, + 'amount_currency': -811.25, + 'currency_id': self.currency_swiss_id, + } + credit_line_vals = { + 'name': '2', + 'debit': 737.10, + 'credit': 0.0, + 'account_id': self.account_rsa.id, + 'amount_currency': 811.25, + 'currency_id': self.currency_swiss_id, + } + vals = { + 'journal_id': self.bank_journal_euro.id, + 'date': time.strftime('%Y') + '-07-15', + 'line_ids': [(0,0, debit_line_vals), (0, 0, credit_line_vals)] + } + move_ids += self.env['account.move'].create(vals) + + account_move_line = move_ids.mapped('line_ids').filtered(lambda l: l.account_id == self.account_rcv) + writeoff_vals = [{ + 'account_id': self.account_rcv.id, + 'journal_id': self.bank_journal_euro.id, + 'date': time.strftime('%Y') + '-04-15', + 'debit': 8.75, + 'credit': 0.0 + }] + writeoff_line = account_move_line._create_writeoff(writeoff_vals) + (account_move_line + writeoff_line).reconcile() + self.assertEquals(len(writeoff_line), 1, "The writeoff_line (balance_line) should have only one moves line") + self.assertTrue(all(l.reconciled for l in writeoff_line), 'The balance lines should be totally reconciled') + self.assertTrue(all(l.reconciled for l in account_move_line), 'The move lines should be totally reconciled') + def test_reconcile_bank_statement_with_payment_and_writeoff(self): # Use case: # Company is in EUR, create a bill for 80 USD and register payment of 80 USD. diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index f50173296b5..cb10bee162e 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -24,8 +24,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): lines = invoice.move_id.line_ids return lines.filtered(lambda l: l.account_id == invoice.account_id) - def _check_statement_matching(self, rules, expected_values): - statement_lines = (self.bank_st + self.cash_st).mapped('line_ids') + def _check_statement_matching(self, rules, expected_values, statements=None): + if statements is None: + statements = self.bank_st + self.cash_st + statement_lines = statements.mapped('line_ids') matching_values = rules._apply_rules(statement_lines) for st_line_id, values in matching_values.items(): values.pop('reconciled_lines', None) @@ -34,6 +36,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): def setUp(self): super(AccountingTestCase, self).setUp() + self.account_pay = self.env['account.account'].search([('internal_type', '=', 'payable')], limit=1) + self.account_liq = self.env['account.account'].search([('internal_type', '=', 'liquidity')], limit=1) + self.account_rcv = self.env['account.account'].search([('internal_type', '=', 'receivable')], limit=1) + self.partner_1 = self.env['res.partner'].create({'name': 'partner_1'}) self.partner_2 = self.env['res.partner'].create({'name': 'partner_2'}) @@ -45,7 +51,8 @@ class TestReconciliationMatchingRules(AccountingTestCase): current_assets_account = self.env['account.account'].search( [('user_type_id', '=', self.env.ref('account.data_account_type_current_assets').id)], limit=1) - self.rule_1 = self.env.ref('account.reconciliation_model_default_rule') + self.rule_0 = self.env.ref('account.reconciliation_model_default_rule') + self.rule_1 = self.rule_0.copy() self.rule_1.account_id = current_assets_account self.rule_1.match_partner = True self.rule_1.match_partner_ids |= self.partner_1 + self.partner_2 @@ -59,10 +66,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): invoice_number = self.invoice_line_1.move_id.name - bank_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1) + self.bank_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1) self.bank_st = self.env['account.bank.statement'].create({ - 'name': 'test bank journal', 'journal_id': bank_journal.id, + 'name': 'test bank journal', 'journal_id': self.bank_journal.id, }) self.bank_line_1 = self.env['account.bank.statement.line'].create({ 'statement_id': self.bank_st.id, @@ -296,3 +303,47 @@ class TestReconciliationMatchingRules(AccountingTestCase): {'partner_id': self.partner_2.id, 'debit': 0.0, 'credit': 1000.0}, {'partner_id': self.partner_2.id, 'debit': 1000.0, 'credit': 0.0}, ]) + + def test_reverted_move_matching(self): + AccountMove = self.env['account.move'] + move = AccountMove.create({ + 'name': 'To Revert', + 'journal_id': self.bank_journal.id, + }) + + partner = self.env['res.partner'].create({'name': 'Eugene'}) + AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False) + payment_payable_line = AccountMoveLine.create({ + 'account_id': self.account_pay.id, + 'move_id': move.id, + 'partner_id': partner.id, + 'name': 'One of these days', + 'debit': 10, + }) + payment_bnk_line = AccountMoveLine.create({ + 'account_id': self.account_liq.id, + 'move_id': move.id, + 'partner_id': partner.id, + 'name': 'I\'m gonna cut you into little pieces', + 'credit': 10, + }) + + move.post() + move_reversed = AccountMove.browse(move.reverse_moves()) + self.assertTrue(move_reversed.exists()) + + bank_st = self.env['account.bank.statement'].create({ + 'name': 'test bank journal', 'journal_id': self.bank_journal.id, + }) + bank_line_1 = self.env['account.bank.statement.line'].create({ + 'statement_id': bank_st.id, + 'name': '8', + 'partner_id': partner.id, + 'amount': -10, + 'sequence': 1, + }) + + expected_values = { + bank_line_1.id: {'aml_ids': [payment_bnk_line.id], 'model': self.rule_0} + } + self._check_statement_matching(self.rule_0, expected_values, statements=bank_st) diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml index c32413a4f1d..1c57b6892c9 100644 --- a/addons/account/views/report_invoice.xml +++ b/addons/account/views/report_invoice.xml @@ -51,29 +51,26 @@ <table class="table table-sm o_main_table" name="invoice_line_table"> <thead> <tr> - <t t-set="colspan" t-value="6"/> <th class="text-left"><span>Description</span></th> <th class="d-none text-left"><span>Source Document</span></th> <th class="text-right"><span>Quantity</span></th> <th t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Unit Price</span></th> <th t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"> <span>Disc.(%)</span> - <t t-set="colspan" t-value="colspan+1"/> </th> <th t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Taxes</span></th> - <th class="text-right"> - <span groups="account.group_show_line_subtotals_tax_excluded">Amount</span> - <span groups="account.group_show_line_subtotals_tax_included">Total Price</span> - </th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_excluded">Amount</th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_included">Total Price</th> </tr> </thead> <tbody class="invoice_tbody"> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> <t t-foreach="o.invoice_line_ids" t-as="line"> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <t t-set="current_subtotal_tax_excluded" t-value="current_subtotal_tax_excluded + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> + <t t-set="current_subtotal_tax_included" t-value="current_subtotal_tax_included + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> <tr t-att-class="'bg-200 font-weight-bold o_line_section' if line.display_type == 'line_section' else 'font-italic o_line_note' if line.display_type == 'line_note' else ''"> <t t-if="not line.display_type" name="account_invoice_line_accountable"> @@ -92,20 +89,23 @@ <td t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"> <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.invoice_line_tax_ids))"/> </td> - <td class="text-right o_price_total"> - <span t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <span t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_excluded"> + <span t-field="line.price_subtotal"/> + </td> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_included"> + <span t-field="line.price_total"/> </td> </t> <t t-if="line.display_type == 'line_section'"> - <td t-att-colspan="colspan"> + <td colspan="99"> <span t-field="line.name"/> </td> <t t-set="current_section" t-value="line"/> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> </t> <t t-if="line.display_type == 'line_note'"> - <td t-att-colspan="colspan"> + <td colspan="99"> <span t-field="line.name"/> </td> </t> @@ -113,12 +113,17 @@ <t t-if="current_section and (line_last or o.invoice_line_ids[line_index+1].display_type == 'line_section')"> <tr class="is-subtotal text-right"> - <td t-att-colspan="colspan"> + <td colspan="99"> <strong class="mr16">Subtotal</strong> <span - t-esc="current_subtotal" + groups="account.group_show_line_subtotals_tax_excluded" + t-esc="current_subtotal_tax_excluded" t-options='{"widget": "monetary", "display_currency": o.currency_id}' /> + <span groups="account.group_show_line_subtotals_tax_included"> | <span + t-esc="current_subtotal_tax_included" + t-options='{"widget": "monetary", "display_currency": o.currency_id}' + /></span> </td> </tr> </t> diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py index e52a7cbe278..d2fd855ab07 100644 --- a/addons/account_check_printing/models/account_payment.py +++ b/addons/account_check_printing/models/account_payment.py @@ -28,7 +28,7 @@ class AccountRegisterPayments(models.TransientModel): def _onchange_amount(self): if hasattr(super(AccountRegisterPayments, self), '_onchange_amount'): super(AccountRegisterPayments, self)._onchange_amount() - self.check_amount_in_words = self.currency_id.amount_to_text(self.amount) + self.check_amount_in_words = self.currency_id.amount_to_text(self.amount) if self.currency_id else False def _prepare_payment_vals(self, invoices): res = super(AccountRegisterPayments, self)._prepare_payment_vals(invoices) diff --git a/addons/bus/models/bus.py b/addons/bus/models/bus.py index 8187e2d43e6..7e0831fe9b7 100644 --- a/addons/bus/models/bus.py +++ b/addons/bus/models/bus.py @@ -131,7 +131,7 @@ class ImDispatch(object): event = self.Event() for channel in channels: - self.channels.setdefault(hashable(channel), []).append(event) + self.channels.setdefault(hashable(channel), set()).add(event) try: event.wait(timeout=timeout) with registry.cursor() as cr: @@ -140,6 +140,12 @@ class ImDispatch(object): except Exception: # timeout pass + finally: + # gc pointers to event + for channel in channels: + channel_events = self.channels.get(hashable(channel)) + if channel_events and event in channel_events: + channel_events.remove(event) return notifications def loop(self): @@ -160,7 +166,7 @@ class ImDispatch(object): # dispatch to local threads/greenlets events = set() for channel in channels: - events.update(self.channels.pop(hashable(channel), [])) + events.update(self.channels.pop(hashable(channel), set())) for event in events: event.set() diff --git a/addons/hr_holidays/models/hr.py b/addons/hr_holidays/models/hr.py index fa35359c089..6a0dae5d5a2 100644 --- a/addons/hr_holidays/models/hr.py +++ b/addons/hr_holidays/models/hr.py @@ -93,6 +93,9 @@ class Employee(models.Model): show_leaves = fields.Boolean('Able to see Remaining Time Off', compute='_compute_show_leaves') is_absent = fields.Boolean('Absent Today', compute='_compute_leave_status', search='_search_absent_employee') + def _get_date_start_work(self): + return self.create_date + def _get_remaining_leaves(self): """ Helper to compute the remaining leaves for the current employees :returns dict where the key is the employee id, and the value is the remain leaves diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index c942829c3a2..abfb441a0c9 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -167,16 +167,15 @@ class HolidaysAllocation(models.Model): # We have to check when the employee has been created # in order to not allocate him/her too much leaves - creation_date = fields.Datetime.from_string(holiday.employee_id.create_date) - + start_date = holiday.employee_id._get_date_start_work() # If employee is created after the period, we cancel the computation - if period_end <= creation_date: + if period_end <= start_date: holiday.write(values) continue # If employee created during the period, taking the date at which he has been created - if period_start <= creation_date: - period_start = creation_date + if period_start <= start_date: + period_start = start_date worked = holiday.employee_id._get_work_days_data(period_start, period_end, domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')])['days'] left = holiday.employee_id._get_leave_days_data(period_start, period_end, domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')])['days'] diff --git a/addons/hw_escpos/escpos/constants.py b/addons/hw_escpos/escpos/constants.py index 238e8bdbf0f..0000109a964 100644 --- a/addons/hw_escpos/escpos/constants.py +++ b/addons/hw_escpos/escpos/constants.py @@ -2,6 +2,9 @@ """ ESC/POS Commands (Constants) """ +# Control characters +ESC = '\x1b' + # Feed control sequences CTL_LF = '\x0a' # Print and line feed CTL_FF = '\x0c' # Form feed @@ -19,9 +22,10 @@ DLE_EOT_PAPER = '\x10\x04\x04' HW_INIT = '\x1b\x40' # Clear data in buffer and reset modes HW_SELECT = '\x1b\x3d\x01' # Printer select HW_RESET = '\x1b\x3f\x0a\x00' # Reset printer hardware -# Cash Drawer -CD_KICK_2 = '\x1b\x70\x00' # Sends a pulse to pin 2 [] -CD_KICK_5 = '\x1b\x70\x01' # Sends a pulse to pin 5 [] +# Cash Drawer (ESC p <pin> <on time: 2*ms> <off time: 2*ms>) +_CASH_DRAWER = lambda m, t1='', t2='': ESC + 'p' + m + chr(t1) + chr(t2) +CD_KICK_2 = _CASH_DRAWER('\x00', 50, 50) # Sends a pulse to pin 2 [] +CD_KICK_5 = _CASH_DRAWER('\x01', 50, 50) # Sends a pulse to pin 5 [] # Paper PAPER_FULL_CUT = '\x1d\x56\x00' # Full cut paper PAPER_PART_CUT = '\x1d\x56\x01' # Partial cut paper diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py index 8b81501db20..cb3f57f689c 100644 --- a/addons/im_livechat/models/mail_channel.py +++ b/addons/im_livechat/models/mail_channel.py @@ -30,7 +30,6 @@ class MailChannel(models.Model): _name = 'mail.channel' _inherit = ['mail.channel', 'rating.mixin'] - _description = 'Discussion channel' anonymous_name = fields.Char('Anonymous Name') channel_type = fields.Selection(selection_add=[('livechat', 'Livechat Conversation')]) diff --git a/addons/l10n_fr/data/account_tax_data.xml b/addons/l10n_fr/data/account_tax_data.xml index afd9efc4037..b7bdcf79e32 100644 --- a/addons/l10n_fr/data/account_tax_data.xml +++ b/addons/l10n_fr/data/account_tax_data.xml @@ -1024,7 +1024,7 @@ <field name="account_id" ref="pcg_445203"/> <field name="sequence" eval="10"/> <field name="type_tax_use">purchase</field> - <field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tag_fr_73'),ref('l10n_fr.tag_fr_82')])]"/> + <field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tag_fr_73'),ref('l10n_fr.tag_fr_64')])]"/> <field name="tax_group_id" ref="tax_group_intra_21"/> </record> diff --git a/addons/l10n_nl/data/account.account.template.csv b/addons/l10n_nl/data/account.account.template.csv index ef2fd529278..2164c15119f 100644 --- a/addons/l10n_nl/data/account.account.template.csv +++ b/addons/l10n_nl/data/account.account.template.csv @@ -324,6 +324,9 @@ "8043","Omzet buiten EU werk derden","8043","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" "8044","Omzet Intercompany werk derden","8044","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" "8090","Diverse overige opbrengsten","8090","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" +"8110","Installatie/afstandsverkopen binnen EU handelsgoederen 1","80011","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" +"8120","Installatie/afstandsverkopen binnen EU handelsgoederen 2","80012","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" +"8130","Installatie/afstandsverkopen binnen EU handelsgoederen 3","80013","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_11","False" "8920","Koersverschillen","8920","account.data_account_type_revenue","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_31","False" "9011","Resultaat deelneming 1","9011","account.data_account_type_other_income","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_12","False" "9012","Resultaat deelneming 2","9012","account.data_account_type_other_income","l10n_nl.l10nnl_chart_template","l10n_nl.account_tag_12","False" diff --git a/addons/l10n_nl/data/account_fiscal_position_account_template.xml b/addons/l10n_nl/data/account_fiscal_position_account_template.xml index ab156438382..81647963b10 100644 --- a/addons/l10n_nl/data/account_fiscal_position_account_template.xml +++ b/addons/l10n_nl/data/account_fiscal_position_account_template.xml @@ -92,5 +92,30 @@ <field name="account_dest_id" ref="8022" /> </record> + <!-- Installatie / afstandsverkopen --> + <record + id="fiscal_position_account_installatie_afstand_1" + model="account.fiscal.position.account.template"> + <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report" /> + <field name="account_src_id" ref="8001" /> + <field name="account_dest_id" ref="8110" /> + </record> + + <record + id="fiscal_position_account_installatie_afstand_2" + model="account.fiscal.position.account.template"> + <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report" /> + <field name="account_src_id" ref="8011" /> + <field name="account_dest_id" ref="8120" /> + </record> + + <record + id="fiscal_position_account_installatie_afstand_3" + model="account.fiscal.position.account.template"> + <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report" /> + <field name="account_src_id" ref="8021" /> + <field name="account_dest_id" ref="8130" /> + </record> + </data> -</openerp>
\ No newline at end of file +</openerp> diff --git a/addons/l10n_nl/data/account_fiscal_position_tax_template.xml b/addons/l10n_nl/data/account_fiscal_position_tax_template.xml index e59c852ef24..05e54233bcf 100644 --- a/addons/l10n_nl/data/account_fiscal_position_tax_template.xml +++ b/addons/l10n_nl/data/account_fiscal_position_tax_template.xml @@ -34,7 +34,7 @@ <record id="position_tax_extracom_d_0" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_0_d"/> - <field name="tax_dest_id" ref="btw_X3"/> + <field name="tax_dest_id" ref="btw_X1"/> </record> <record id="position_tax_extracom_d_6" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> @@ -49,12 +49,12 @@ <record id="position_tax_extracom_d_21" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_21_d"/> - <field name="tax_dest_id" ref="btw_X3"/> + <field name="tax_dest_id" ref="btw_X1"/> </record> <record id="position_tax_extracom_d_overig" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_overig_d"/> - <field name="tax_dest_id" ref="btw_X3"/> + <field name="tax_dest_id" ref="btw_X1"/> </record> <!-- VAT on buying from outside the EU --> <record id="position_tax_extracom_6" model="account.fiscal.position.tax.template"> @@ -65,7 +65,7 @@ <record id="position_tax_extracom_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_9_buy"/> - <field name="tax_dest_id" ref="btw_E1"/> + <field name="tax_dest_id" ref="btw_E1_9"/> </record> <record id="position_tax_extracom_7" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> @@ -85,7 +85,7 @@ <record id="position_tax_extracom_d_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_9_buy_d"/> - <field name="tax_dest_id" ref="btw_E1"/> + <field name="tax_dest_id" ref="btw_E1_9"/> </record> <record id="position_tax_extracom_d_7" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> @@ -95,59 +95,59 @@ <record id="position_tax_extracom_d_8" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_non_eu"/> <field name="tax_src_id" ref="btw_overig_buy_d"/> - <field name="tax_dest_id" ref="btw_E_overig"/> + <field name="tax_dest_id" ref="btw_E_overig_d"/> </record> <!-- EU Countries --> <record id="position_tax_intracom_1" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_0"/> - <field name="tax_dest_id" ref="btw_X0_diensten"/> + <field name="tax_dest_id" ref="btw_X0_producten"/> </record> <record id="position_tax_intracom_2" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_6"/> - <field name="tax_dest_id" ref="btw_X0_diensten"/> + <field name="tax_dest_id" ref="btw_X0_producten"/> </record> <record id="position_tax_intracom_2_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_9"/> - <field name="tax_dest_id" ref="btw_X0_diensten"/> + <field name="tax_dest_id" ref="btw_X0_producten"/> </record> <record id="position_tax_intracom_3" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_21"/> - <field name="tax_dest_id" ref="btw_X0_diensten"/> + <field name="tax_dest_id" ref="btw_X0_producten"/> </record> <record id="position_tax_intracom_4" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_overig"/> - <field name="tax_dest_id" ref="btw_X0_diensten"/> + <field name="tax_dest_id" ref="btw_X0_producten"/> </record> <record id="position_tax_intracom_d_1" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_0_d"/> - <field name="tax_dest_id" ref="btw_X2"/> + <field name="tax_dest_id" ref="btw_X0_diensten"/> </record> <record id="position_tax_intracom_d_2" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_6_d"/> - <field name="tax_dest_id" ref="btw_X2"/> + <field name="tax_dest_id" ref="btw_X0_diensten"/> </record> <record id="position_tax_intracom_d_2_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_9_d"/> - <field name="tax_dest_id" ref="btw_X2"/> + <field name="tax_dest_id" ref="btw_X0_diensten"/> </record> <record id="position_tax_intracom_d_3" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_21_d"/> - <field name="tax_dest_id" ref="btw_X2"/> + <field name="tax_dest_id" ref="btw_X0_diensten"/> </record> <record id="position_tax_intracom_d_4" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_overig_d"/> - <field name="tax_dest_id" ref="btw_X2"/> + <field name="tax_dest_id" ref="btw_X0_diensten"/> </record> <record id="position_tax_intracom_6" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> @@ -172,22 +172,22 @@ <record id="position_tax_intracom_d_6" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_6_buy_d"/> - <field name="tax_dest_id" ref="btw_I_6"/> + <field name="tax_dest_id" ref="btw_I_6_d"/> </record> <record id="position_tax_intracom_d_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_9_buy_d"/> - <field name="tax_dest_id" ref="btw_I_9"/> + <field name="tax_dest_id" ref="btw_I_9_d"/> </record> <record id="position_tax_intracom_d_7" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_21_buy_d"/> - <field name="tax_dest_id" ref="btw_I_21"/> + <field name="tax_dest_id" ref="btw_I_21_d"/> </record> <record id="position_tax_intracom_d_8" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu"/> <field name="tax_src_id" ref="btw_overig_buy_d"/> - <field name="tax_dest_id" ref="btw_I_overig"/> + <field name="tax_dest_id" ref="btw_I_overig_d"/> </record> <!-- BTW verlegd --> @@ -196,6 +196,5 @@ <field name="tax_src_id" ref="btw_21_buy"/> <field name="tax_dest_id" ref="btw_ink_0"/> </record> - </data> </openerp> diff --git a/addons/l10n_nl/data/account_fiscal_position_template.xml b/addons/l10n_nl/data/account_fiscal_position_template.xml index f70c6fc6e1b..a6519cac9d7 100644 --- a/addons/l10n_nl/data/account_fiscal_position_template.xml +++ b/addons/l10n_nl/data/account_fiscal_position_template.xml @@ -28,83 +28,57 @@ <record id="position_tax_eu_no_taxes_report_1" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> <field name="tax_src_id" ref="btw_0"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_2" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_6"/> + <field name="tax_src_id" ref="btw_verk_0"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_3" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_21"/> + <field name="tax_src_id" ref="btw_6"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_4" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_overig"/> + <field name="tax_src_id" ref="btw_9"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_5" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_0_d"/> + <field name="tax_src_id" ref="btw_21"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_6" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_6_d"/> + <field name="tax_src_id" ref="btw_overig"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_7" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_21_d"/> + <field name="tax_src_id" ref="btw_0_d"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_8" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_overig_d"/> + <field name="tax_src_id" ref="btw_6_d"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_9" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_6_buy"/> + <field name="tax_src_id" ref="btw_9_d"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_10" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_6_buy_incl"/> + <field name="tax_src_id" ref="btw_21_d"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> <record id="position_tax_eu_no_taxes_report_11" model="account.fiscal.position.tax.template"> <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_21_buy"/> - </record> - <record id="position_tax_eu_no_taxes_report_12" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_21_buy_incl"/> - </record> - <record id="position_tax_eu_no_taxes_report_13" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_overig_buy"/> - </record> - <record id="position_tax_eu_no_taxes_report_14" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_6_buy_d"/> - </record> - <record id="position_tax_eu_no_taxes_report_15" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_21_buy_d"/> - </record> - <record id="position_tax_eu_no_taxes_report_16" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_overig_buy_d"/> - </record> - <record id="position_tax_eu_no_taxes_report_17" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_verk_0"/> - </record> - <record id="position_tax_eu_no_taxes_report_18" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_ink_0_1"/> - </record> - <record id="position_tax_eu_no_taxes_report_19" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_ink_0_2"/> - </record> - <record id="position_tax_eu_no_taxes_report_20" model="account.fiscal.position.tax.template"> - <field name="position_id" ref="fiscal_position_template_eu_no_taxes_report"/> - <field name="tax_src_id" ref="btw_ink_0"/> + <field name="tax_src_id" ref="btw_overig_d"/> + <field name="tax_dest_id" ref="btw_X2"/> </record> - </data> </openerp> diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js index 77f33d152c0..fc084b48204 100644 --- a/addons/mail/static/src/js/document_viewer.js +++ b/addons/mail/static/src/js/document_viewer.js @@ -200,7 +200,7 @@ var DocumentViewer = Widget.extend({ */ _onDownload: function (e) { e.preventDefault(); - window.location = '/web/content/' + this.activeAttachment.id + '?download=true'; + window.location = '/web/content/' + this.modelName + '/' + this.activeAttachment.id + '/' + 'datas' + '?download=true'; }, /** * @private diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 2d569425119..2c48732e933 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -318,9 +318,9 @@ class MassMailingCampaign(models.Model): campaign_id = fields.Many2one('utm.campaign', 'campaign_id', required=True, ondelete='cascade', help="This name helps you tracking your different campaign efforts, e.g. Fall_Drive, Christmas_Special") source_id = fields.Many2one('utm.source', string='Source', - help="This is the link source, e.g. Search Engine, another domain,or name of email list", default=lambda self: self.env.ref('utm.utm_source_newsletter')) + help="This is the link source, e.g. Search Engine, another domain,or name of email list", default=lambda self: self.env.ref('utm.utm_source_newsletter', False)) medium_id = fields.Many2one('utm.medium', string='Medium', - help="This is the delivery method, e.g. Postcard, Email, or Banner Ad", default=lambda self: self.env.ref('utm.utm_medium_email')) + help="This is the delivery method, e.g. Postcard, Email, or Banner Ad", default=lambda self: self.env.ref('utm.utm_medium_email', False)) tag_ids = fields.Many2many( 'mail.mass_mailing.tag', 'mail_mass_mailing_tag_rel', 'tag_id', 'campaign_id', string='Tags') diff --git a/addons/mrp/report/mrp_report_bom_structure.py b/addons/mrp/report/mrp_report_bom_structure.py index 9a7bda5717d..b95c1bcf658 100644 --- a/addons/mrp/report/mrp_report_bom_structure.py +++ b/addons/mrp/report/mrp_report_bom_structure.py @@ -205,10 +205,10 @@ class ReportBomStructure(models.AbstractModel): def _get_pdf_line(self, bom_id, product_id=False, qty=1, child_bom_ids=[], unfolded=False): - data = self._get_bom(bom_id=bom_id, product_id=product_id, line_qty=qty) + data = self._get_bom(bom_id=bom_id, product_id=product_id.id, line_qty=qty) def get_sub_lines(bom, product_id, line_qty, line_id, level): - data = self._get_bom(bom_id=bom.id, product_id=product_id, line_qty=line_qty, line_id=line_id, level=level) + data = self._get_bom(bom_id=bom.id, product_id=product_id.id, line_qty=line_qty, line_id=line_id, level=level) bom_lines = data['components'] lines = [] for bom_line in bom_lines: diff --git a/addons/payment/models/account_payment.py b/addons/payment/models/account_payment.py index 21c0b5530dd..220cb37db38 100644 --- a/addons/payment/models/account_payment.py +++ b/addons/payment/models/account_payment.py @@ -71,6 +71,11 @@ class AccountPayment(models.Model): return transactions + def action_validate_invoice_payment(self): + res = super(AccountPayment, self).action_validate_invoice_payment() + self.mapped('payment_transaction_id').filtered(lambda x: x.state == 'done' and not x.is_processed)._post_process_after_done() + return res + @api.multi def post(self): # Post the payments "normally" if no transactions are needed. diff --git a/addons/payment_buckaroo/tests/test_buckaroo.py b/addons/payment_buckaroo/tests/test_buckaroo.py index e23b1f0c002..c78c998304d 100644 --- a/addons/payment_buckaroo/tests/test_buckaroo.py +++ b/addons/payment_buckaroo/tests/test_buckaroo.py @@ -32,12 +32,12 @@ class BuckarooForm(BuckarooCommon): # ---------------------------------------- form_values = { - 'add_returndata': '', + 'add_returndata': '/payment/process', 'Brq_websitekey': self.buckaroo.brq_websitekey, 'Brq_amount': '2240.0', 'Brq_currency': 'EUR', 'Brq_invoicenumber': 'SO004', - 'Brq_signature': 'aa6fe072afdd9d1b463d55f43e6df4b272d3529a', # update me + 'Brq_signature': 'f09bb79451a7ddef3178462ea52b07e55d34e99e', # update me 'brq_test': 'True', 'Brq_return': urls.url_join(base_url, BuckarooController._return_url), 'Brq_returncancel': urls.url_join(base_url, BuckarooController._cancel_url), diff --git a/addons/payment_paypal/tests/test_paypal.py b/addons/payment_paypal/tests/test_paypal.py index b8158508a2a..c285829f08d 100644 --- a/addons/payment_paypal/tests/test_paypal.py +++ b/addons/payment_paypal/tests/test_paypal.py @@ -67,6 +67,7 @@ class PaypalForm(PaypalCommon): 'return': urls.url_join(base_url, PaypalController._return_url), 'notify_url': urls.url_join(base_url, PaypalController._notify_url), 'cancel_return': urls.url_join(base_url, PaypalController._cancel_url), + 'custom': '{"return_url": "/payment/process"}', } # check form result @@ -140,7 +141,7 @@ class PaypalForm(PaypalCommon): 'item_name': u'test_ref_2', 'address_country': u'France', 'charset': u'windows-1252', - 'custom': u'', + 'custom': u'{"return_url": "/payment/process"}', 'notify_version': u'3.7', 'address_name': u'Norbert Poilu', 'pending_reason': u'multi_currency', diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 35cc2d39837..959a0de6e2e 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -331,6 +331,12 @@ class ProductTemplate(models.Model): raise ValidationError(_('The default Unit of Measure and the purchase Unit of Measure must be in the same category.')) return True + @api.constrains('attribute_line_ids') + def _check_attribute_line(self): + if any(len(template.attribute_line_ids) != len(template.attribute_line_ids.mapped('attribute_id')) for template in self): + raise ValidationError(_('You cannot define two attribute lines for the same attribute.')) + return True + @api.onchange('uom_id') def _onchange_uom_id(self): if self.uom_id: diff --git a/addons/project/data/project_data.xml b/addons/project/data/project_data.xml index 7198ffe017b..65fc05e27b7 100644 --- a/addons/project/data/project_data.xml +++ b/addons/project/data/project_data.xml @@ -2,16 +2,6 @@ <odoo> <data noupdate="1"> - <!-- sale_timesheet and project define the same field without depending on each, which causes the field to be deleted when the module that created it - is deleted. To avoid this, we create xmlids manually for this field in both modules to prevent accidental deletion. To fix in saas-7 by moving the field definition--> - <record id="duplicate_field_xmlid" model="ir.model.data"> - <field name="res_id" search="[('model','=','res.company'),('name','=','project_time_mode_id')]" model="ir.model.fields"/> - <field name="model">ir.model.fields</field> - <field name="module">project</field> - <field name="name">project_time_mode_id_duplicate_xmlid</field> - <field name="noupdate">True</field> - </record> - <record id="ir_cron_rating_project" model="ir.cron"> <field name="name">Project: Send rating</field> <field name="model_id" ref="project.model_project_project"/> diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py index eaa71775476..9f63039afd7 100644 --- a/addons/purchase/models/account_invoice.py +++ b/addons/purchase/models/account_invoice.py @@ -131,7 +131,7 @@ class AccountInvoice(models.Model): res = super(AccountInvoice, self)._onchange_partner_id() if payment_term_id: self.payment_term_id = payment_term_id - if not self.env.context.get('default_journal_id') and self.partner_id and self.currency_id and\ + if not self.env.context.get('default_journal_id') and self.partner_id and\ self.type in ['in_invoice', 'in_refund'] and\ self.currency_id != self.partner_id.property_purchase_currency_id and\ self.partner_id.property_purchase_currency_id.id: @@ -172,6 +172,11 @@ class AccountInvoice(models.Model): invoice.message_post(body=message) return result + def _get_onchange_create(self): + res = super()._get_onchange_create() + res['_onchange_partner_id'].append('currency_id') + return res + class AccountInvoiceLine(models.Model): """ Override AccountInvoice_line to add the link to the purchase order line it is related to""" diff --git a/addons/purchase_stock/report/purchase_report_templates.xml b/addons/purchase_stock/report/purchase_report_templates.xml index 8e5adc9d45d..0c5a42fd0da 100644 --- a/addons/purchase_stock/report/purchase_report_templates.xml +++ b/addons/purchase_stock/report/purchase_report_templates.xml @@ -1,22 +1,32 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <template id="report_purchaseorder_document" inherit_id="purchase.report_purchaseorder_document"> - <xpath expr="//div[@name='purchase_shipping_address']" position="after"> - <div t-if="not o.dest_address_id and o.picking_type_id and o.picking_type_id.warehouse_id"> - <span t-field="o.picking_type_id.warehouse_id.name"/> - <div t-field="o.picking_type_id.warehouse_id.partner_id" t-options='{"widget": "contact", "fields": ["address", "phone"], "no_marker": True, "phone_icons": True}'/> - </div> - </xpath> - </template> + <template id="report_purchaseorder_document" inherit_id="purchase.report_purchaseorder_document"> + <xpath expr="//t[@t-if='o.dest_address_id']" position="after"> + <t t-else=""> + <t t-set="information_block"> + <strong>Shipping address:</strong> + <div t-if="o.picking_type_id and o.picking_type_id.warehouse_id"> + <span t-field="o.picking_type_id.warehouse_id.name"/> + <div t-field="o.picking_type_id.warehouse_id.partner_id" t-options='{"widget": "contact", "fields": ["address", "phone"], "no_marker": True, "phone_icons": True}'/> + </div> + </t> + </t> + </xpath> + </template> - <template id="report_purchasequotation_document" inherit_id="purchase.report_purchasequotation_document"> - <xpath expr="//div[@name='purchase_shipping_address']" position="after"> - <div t-if="not o.dest_address_id and o.picking_type_id.warehouse_id"> - <span t-field="o.picking_type_id.warehouse_id.name"/> - <div t-field="o.picking_type_id.warehouse_id.partner_id" t-options='{"widget": "contact", "fields": ["address", "phone"], "no_marker": True, "phone_icons": True}'/> - </div> - </xpath> - </template> + <template id="report_purchasequotation_document" inherit_id="purchase.report_purchasequotation_document"> + <xpath expr="//t[@t-if='o.dest_address_id']" position="after"> + <t t-else=""> + <t t-set="information_block"> + <strong>Shipping address:</strong> + <div t-if="o.picking_type_id and o.picking_type_id.warehouse_id"> + <span t-field="o.picking_type_id.warehouse_id.name"/> + <div t-field="o.picking_type_id.warehouse_id.partner_id" t-options='{"widget": "contact", "fields": ["address", "phone"], "no_marker": True, "phone_icons": True}'/> + </div> + </t> + </t> + </xpath> + </template> </odoo> diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py index 6602a8462bd..a102ec9762d 100644 --- a/addons/repair/models/repair.py +++ b/addons/repair/models/repair.py @@ -599,17 +599,24 @@ class RepairLine(models.Model): 'title': _('No pricelist found.'), 'message': _('You have to select a pricelist in the Repair form !\n Please set one before choosing a product.')} + return {'warning': warning} else: - price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner) - if price is False: - warning = { - 'title': _('No valid pricelist line found.'), - 'message': - _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")} - else: - self.price_unit = price - if warning: + self._onchange_product_uom() + + @api.onchange('product_uom') + def _onchange_product_uom(self): + partner = self.repair_id.partner_id + pricelist = self.repair_id.pricelist_id + if pricelist and self.product_id and self.type != 'remove': + price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner, uom_id=self.product_uom.id) + if price is False: + warning = { + 'title': _('No valid pricelist line found.'), + 'message': + _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")} return {'warning': warning} + else: + self.price_unit = price class RepairFee(models.Model): @@ -659,14 +666,21 @@ class RepairFee(models.Model): 'title': _('No pricelist found.'), 'message': _('You have to select a pricelist in the Repair form !\n Please set one before choosing a product.')} + return {'warning': warning} else: - price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner) + self._onchange_product_uom() + + @api.onchange('product_uom') + def _onchange_product_uom(self): + partner = self.repair_id.partner_id + pricelist = self.repair_id.pricelist_id + if pricelist and self.product_id: + price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner, uom_id=self.product_uom.id) if price is False: warning = { 'title': _('No valid pricelist line found.'), 'message': _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")} + return {'warning': warning} else: self.price_unit = price - if warning: - return {'warning': warning} diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml index edce182dcfc..28a5d105dfc 100644 --- a/addons/sale/report/sale_report_templates.xml +++ b/addons/sale/report/sale_report_templates.xml @@ -70,29 +70,26 @@ <table class="table table-sm o_main_table"> <thead> <tr> - <t t-set="colspan" t-value="5"/> <th class="text-left">Description</th> <th class="text-right">Quantity</th> <th class="text-right">Unit Price</th> <th t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line"> <span>Disc.(%)</span> - <t t-set="colspan" t-value="colspan+1"/> </th> <th class="text-right">Taxes</th> - <th class="text-right"> - <t groups="account.group_show_line_subtotals_tax_excluded">Amount</t> - <t groups="account.group_show_line_subtotals_tax_included">Total Price</t> - </th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_excluded">Amount</th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_included">Total Price</th> </tr> </thead> <tbody class="sale_tbody"> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> <t t-foreach="doc.order_line" t-as="line"> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <t t-set="current_subtotal_tax_excluded" t-value="current_subtotal_tax_excluded + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> + <t t-set="current_subtotal_tax_included" t-value="current_subtotal_tax_included + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> <tr t-att-class="'bg-200 font-weight-bold o_line_section' if line.display_type == 'line_section' else 'font-italic o_line_note' if line.display_type == 'line_note' else ''"> <t t-if="not line.display_type"> @@ -110,20 +107,23 @@ <td class="text-right"> <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_id))"/> </td> - <td class="text-right o_price_total"> - <span t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <span t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_excluded"> + <span t-field="line.price_subtotal"/> + </td> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_included"> + <span t-field="line.price_total"/> </td> </t> <t t-if="line.display_type == 'line_section'"> - <td t-att-colspan="99"> + <td colspan="99"> <span t-field="line.name"/> </td> <t t-set="current_section" t-value="line"/> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> </t> <t t-if="line.display_type == 'line_note'"> - <td t-att-colspan="99"> + <td colspan="99"> <span t-field="line.name"/> </td> </t> @@ -131,12 +131,17 @@ <t t-if="current_section and (line_last or doc.order_line[line_index+1].display_type == 'line_section')"> <tr class="is-subtotal text-right"> - <td t-att-colspan="99"> + <td colspan="99" groups="account.group_show_line_subtotals_tax_excluded,account.group_show_line_subtotals_tax_included"> <strong class="mr16">Subtotal</strong> <span - t-esc="current_subtotal" + groups="account.group_show_line_subtotals_tax_excluded" + t-esc="current_subtotal_tax_excluded" t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}' /> + <span groups="account.group_show_line_subtotals_tax_included"> | <span + t-esc="current_subtotal_tax_included" + t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}' + /></span> </td> </tr> </t> diff --git a/addons/sale/views/sale_portal_templates.xml b/addons/sale/views/sale_portal_templates.xml index a4a00162af9..2e43b590490 100644 --- a/addons/sale/views/sale_portal_templates.xml +++ b/addons/sale/views/sale_portal_templates.xml @@ -424,29 +424,26 @@ <table class="table table-sm" id="sales_order_table"> <thead class="bg-100"> <tr> - <t t-set="colspan" t-value="6"/> <th class="text-left">Products</th> <th class="text-right">Quantity</th> <th t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}">Unit Price</th> <th t-if="display_discount" t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}"> <span>Discount</span> - <t t-set="colspan" t-value="colspan+1"/> </th> <th t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">Taxes</th> - <th class="text-right" > - <span groups="account.group_show_line_subtotals_tax_excluded">Amount</span> - <span groups="account.group_show_line_subtotals_tax_included">Total Price</span> - </th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_excluded">Amount</th> + <th class="text-right" groups="account.group_show_line_subtotals_tax_included">Total Price</th> </tr> </thead> <tbody class="sale_tbody"> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> <t t-foreach="sale_order.order_line" t-as="line"> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <t t-set="current_subtotal_tax_excluded" t-value="current_subtotal_tax_excluded + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> + <t t-set="current_subtotal_tax_included" t-value="current_subtotal_tax_included + line.price_total" groups="account.group_show_line_subtotals_tax_included"/> <tr t-att-class="'bg-200 font-weight-bold o_line_section' if line.display_type == 'line_section' else 'font-italic o_line_note' if line.display_type == 'line_note' else ''"> <t t-if="not line.display_type"> @@ -477,20 +474,23 @@ <td t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"> <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_id))"/> </td> - <td class="text-right"> - <span t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/> - <span t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_excluded"> + <span t-field="line.price_subtotal"/> + </td> + <td class="text-right o_price_total" groups="account.group_show_line_subtotals_tax_included"> + <span t-field="line.price_total"/> </td> </t> <t t-if="line.display_type == 'line_section'"> - <td t-att-colspan="colspan"> + <td colspan="99"> <span t-field="line.name"/> </td> <t t-set="current_section" t-value="line"/> - <t t-set="current_subtotal" t-value="0"/> + <t t-set="current_subtotal_tax_excluded" t-value="0"/> + <t t-set="current_subtotal_tax_included" t-value="0"/> </t> <t t-if="line.display_type == 'line_note'"> - <td t-att-colspan="colspan"> + <td colspan="99"> <span t-field="line.name"/> </td> </t> @@ -498,12 +498,17 @@ <t t-if="current_section and (line_last or sale_order.order_line[line_index+1].display_type == 'line_section')"> <tr class="is-subtotal text-right"> - <td t-att-colspan="colspan"> + <td colspan="99"> <strong class="mr16">Subtotal</strong> <span - t-esc="current_subtotal" - t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}' + groups="account.group_show_line_subtotals_tax_excluded" + t-esc="current_subtotal_tax_excluded" + t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}' /> + <span groups="account.group_show_line_subtotals_tax_included"> | <span + t-esc="current_subtotal_tax_included" + t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}' + /></span> </td> </tr> </t> diff --git a/addons/stock/wizard/stock_warn_insufficient_qty.py b/addons/stock/wizard/stock_warn_insufficient_qty.py index 50247d130bf..3e480c73e83 100644 --- a/addons/stock/wizard/stock_warn_insufficient_qty.py +++ b/addons/stock/wizard/stock_warn_insufficient_qty.py @@ -34,3 +34,7 @@ class StockWarnInsufficientQtyScrap(models.TransientModel): def action_done(self): return self.scrap_id.do_scrap() + + def action_cancel(self): + # FIXME in master: we should not have created the scrap in a first place + return self.scrap_id.sudo().unlink() diff --git a/addons/stock/wizard/stock_warn_insufficient_qty_views.xml b/addons/stock/wizard/stock_warn_insufficient_qty_views.xml index f6fb8eee99e..01de1f8e482 100644 --- a/addons/stock/wizard/stock_warn_insufficient_qty_views.xml +++ b/addons/stock/wizard/stock_warn_insufficient_qty_views.xml @@ -44,6 +44,9 @@ <xpath expr="//field[@name='product_id']" position="after"> <field name="scrap_id" invisible="1"/> </xpath> + <xpath expr="//button[@name='cancel_button']" position="replace"> + <button string="Discard" name="action_cancel" type="object" class="btn-primary"/> + </xpath> </field> </record> </odoo> diff --git a/addons/web/static/src/js/chrome/abstract_action.js b/addons/web/static/src/js/chrome/abstract_action.js index 1b258ccc6f6..cf85a278884 100644 --- a/addons/web/static/src/js/chrome/abstract_action.js +++ b/addons/web/static/src/js/chrome/abstract_action.js @@ -91,20 +91,20 @@ var AbstractAction = Widget.extend(ActionMixin, { */ willStart: function () { var self = this; + var defs = [this._super.apply(this, arguments)]; if (this.hasControlPanel) { var params = this.controlPanelParams; - var def; if (this.loadControlPanel) { - def = this + defs.push(this .loadFieldView(params.modelName, params.context || {}, params.viewId, 'search') .then(function (fieldsView) { params.viewInfo = { arch: fieldsView.arch, fields: fieldsView.fields, }; - }); + })); } - return Promise.resolve(def).then(function () { + return Promise.all(defs).then(function () { var controlPanelView = new self.config.ControlPanelView(params); return controlPanelView.getController(self).then(function (controlPanel) { self._controlPanel = controlPanel; @@ -112,7 +112,7 @@ var AbstractAction = Widget.extend(ActionMixin, { }); }); } - return Promise.resolve(); + return Promise.all(defs); }, /** * @override diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js index 8630b6b9364..807411144e9 100644 --- a/addons/web/static/src/js/core/dialog.js +++ b/addons/web/static/src/js/core/dialog.js @@ -231,13 +231,13 @@ var Dialog = Widget.extend({ this.$modal.remove(); } - if (!isFocusSet) { - var modals = $('body > .modal').filter(':visible'); - if (modals.length) { + var modals = $('body > .modal').filter(':visible'); + if (modals.length) { + if (!isFocusSet) { modals.last().focus(); - // Keep class modal-open (deleted by bootstrap hide fnct) on body to allow scrolling inside the modal - $('body').addClass('modal-open'); } + // Keep class modal-open (deleted by bootstrap hide fnct) on body to allow scrolling inside the modal + $('body').addClass('modal-open'); } }, /** diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index 9d8cf04f30f..1bcf4fbb298 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -75,9 +75,11 @@ return AbstractModel.extend({ .utc(); } else { // default hours in the user's timezone - start.hours(7).add(-this.getSession().getTZOffset(start), 'minutes'); - end.hours(19).add(-this.getSession().getTZOffset(end), 'minutes'); + start.hours(7); + end.hours(19); } + start.add(-this.getSession().getTZOffset(start), 'minutes'); + end.add(-this.getSession().getTZOffset(end), 'minutes'); } } else { start.add(-this.getSession().getTZOffset(start), 'minutes'); diff --git a/addons/web/static/src/scss/form_view.scss b/addons/web/static/src/scss/form_view.scss index cb9567a323b..51082e3357f 100644 --- a/addons/web/static/src/scss/form_view.scss +++ b/addons/web/static/src/scss/form_view.scss @@ -685,6 +685,11 @@ .o_field_widget { margin-bottom: $o-form-spacing-unit * 2; + + > .o_field_widget { + margin-bottom: 0; + } + &.o_field_boolean { margin-right: 0; } diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 1641dfa0730..96bd4a4d633 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -285,6 +285,68 @@ QUnit.module('relational_fields', { form.destroy(); }); + QUnit.test('focus when closing many2one modal in many2one modal', async function (assert) { + assert.expect(12); + + var form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="trululu"/>' + + '</form>', + res_id: 2, + archs: { + 'partner,false,form': '<form><field name="trululu"/></form>' + }, + mockRPC: function (route, args) { + if (args.method === 'get_formview_id') { + return Promise.resolve(false); + } + return this._super(route, args); + }, + }); + + // Open many2one modal + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_external_button')); + + var $originalModal = $('.modal-dialog'); + var $focusedModal = $(document.activeElement).closest('.modal-dialog'); + + assert.equal($originalModal.length, 1, 'There should be one modal'); + assert.equal($originalModal[0], $focusedModal[0], 'Modal is focused'); + assert.ok($('body').hasClass('modal-open'), 'Modal is said opened'); + + // Open many2one modal of field in many2one modal + await testUtils.dom.click($originalModal.find('.o_external_button')); + var $modals = $('.modal-dialog'); + $focusedModal = $(document.activeElement).closest('.modal-dialog'); + + assert.equal($modals.length, 2, 'There should be two modals'); + assert.equal($modals[1], $focusedModal[0], 'Last modal is focused'); + assert.ok($('body').hasClass('modal-open'), 'Modal is said opened'); + + // Close second modal + await testUtils.dom.click($modals.last().find('button[class="close"]')); + var $modal = $('.modal-dialog'); + $focusedModal = $(document.activeElement).closest('.modal-dialog'); + + assert.equal($modal.length, 1, 'There should be one modal'); + assert.equal($modal[0], $originalModal[0], 'First modal is still opened'); + assert.equal($modal[0], $focusedModal[0], 'Modal is focused'); + assert.ok($('body').hasClass('modal-open'), 'Modal is said opened'); + + // Close first modal + await testUtils.dom.click($modal.find('button[class="close"]')); + $modal = $('.modal-dialog.modal-lg'); + + assert.equal($modal.length, 0, 'There should be no modal'); + assert.notOk($('body').hasClass('modal-open'), 'Modal is not said opened'); + + form.destroy(); + }); + QUnit.test('one2many from a model that has been sorted', async function (assert) { assert.expect(1); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 8061df08af4..9f637c4fdc5 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -2267,6 +2267,61 @@ QUnit.module('Views', { calendar.destroy(); }); + QUnit.test('timezone does not affect drag and drop', async function (assert) { + assert.expect(6); + + var calendar = await createCalendarView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar date_start="start" mode="month">'+ + '<field name="name"/>'+ + '<field name="start"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + mockRPC: function (route, args) { + if (args.method === "write") { + assert.deepEqual(args.args[0], [6], "event 6 is moved") + assert.deepEqual(args.args[1].start, "2016-11-29 08:00:00", + "event moved to 27th nov 16h00 +40 hours timezone") + } + return this._super(route, args); + }, + session: { + getTZOffset: function () { + return -2400; // 40 hours timezone + }, + }, + }); + + var events = calendar.$('.fc-event').map(function () { + return $(this).text().trim().replace(/\s+/g, '|'); + }); + + assert.strictEqual(events[0], "event|1|12/09/2016|08:00:00"); + assert.strictEqual(events[5], "event|6|12/16/2016|16:00:00"); + + // Move event 6 as on first day of month view (27th november 2016) + await testUtils.dragAndDrop( + calendar.$('.fc-event').eq(5), + calendar.$('.fc-day-top').first() + ); + await testUtils.nextTick(); + + events = calendar.$('.fc-event').map(function () { + return $(this).text().trim().replace(/\s+/g, '|'); + }); + + assert.strictEqual(events[0], "event|6|11/27/2016|16:00:00"); + assert.strictEqual(events[1], "event|1|12/09/2016|08:00:00"); + + calendar.destroy(); + }); + QUnit.test('form_view_id attribute works (for creating events)', async function (assert) { assert.expect(1); diff --git a/addons/website/static/src/scss/website.backend.scss b/addons/website/static/src/scss/website.backend.scss index f669a8f4644..d066b2e0bd0 100644 --- a/addons/website/static/src/scss/website.backend.scss +++ b/addons/website/static/src/scss/website.backend.scss @@ -224,7 +224,6 @@ .ActiveUsers { position: relative; float: right; - top: -60px; right: 10px; border: 1px solid gray('200'); font-weight: 300; diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml index 973643998bd..e0496d09cfb 100644 --- a/addons/website_blog/views/website_blog_templates.xml +++ b/addons/website_blog/views/website_blog_templates.xml @@ -447,10 +447,10 @@ <div class="card-body"> <ul class="nav nav-pills flex-column"> <t t-foreach="nav_list" t-as="year"> - <li data-toggle="collapse" t-att-data-target="'#' + year" aria-expanded="false" class="nav-item blog_post_year_collapse mt8"> + <li data-toggle="collapse" t-att-data-target="'#b_' + year" aria-expanded="false" class="nav-item blog_post_year_collapse mt8"> <i t-attf-class="fa #{'fa-chevron-down' if not date and year_index == 0 else 'fa-chevron-right'} mr4" role="img" aria-label="Next year" title="Next year"/><span t-esc="year"/> </li> - <ul t-attf-class="blog_post_year collapse nav nav-pills flex-column #{not date and year_index == 0 and 'in'}" t-att-id="year" role="menu"> + <ul t-attf-class="blog_post_year collapse nav nav-pills flex-column #{not date and year_index == 0 and 'in'}" t-att-id="'b_' + year" role="menu"> <t t-foreach="nav_list[year]" t-as="months"> <li t-if="months['date_begin'] == date" class="nav-item"> <a role="menuitem" t-ignore="True" t-attf-href="#{blog_url(date_begin=False, date_end=False)}" class="nav-link active"><t t-esc="months['month']"/><span class="float-right badge badge-pill" t-esc="months['post_date_count']"/></a> diff --git a/addons/website_sale/data/data.xml b/addons/website_sale/data/data.xml index 7d70a0b45eb..21e1ea7cf5c 100644 --- a/addons/website_sale/data/data.xml +++ b/addons/website_sale/data/data.xml @@ -36,7 +36,7 @@ </record> <record model="product.pricelist" id="product.list0"> - <field name="selectable" eval="False" /> + <field name="selectable" eval="True" /> <field name="website_id" eval="False"/> </record> </data> diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index c4735d3f287..3705d7b3cb3 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -91,7 +91,7 @@ class ProductPricelist(models.Model): Change in this method should be reflected in `_get_website_pricelists_domain`. """ self.ensure_one() - return self.website_id.id == website_id or (not self.website_id and (self.selectable or self.code)) + return self.website_id.id == website_id or (not self.website_id and (self.selectable or self.sudo().code)) def _get_website_pricelists_domain(self, website_id): ''' Check above `_is_available_on_website` for explanation. diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index dd3ba9d2879..899d74e7439 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -287,7 +287,8 @@ class SaleOrder(models.Model): @api.multi def action_recovery_email_send(self): - self._portal_ensure_token() + for order in self: + order._portal_ensure_token() composer_form_view_id = self.env.ref('mail.email_compose_message_wizard_form').id try: default_template = self.env.ref('website_sale.mail_template_sale_cart_recovery', raise_if_not_found=False) |
