mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2025-02-25 18:55:21 -06:00
[PATCH] Upstream patch - 04122022
This commit is contained in:
@@ -2685,6 +2685,9 @@ class AccountMove(models.Model):
|
||||
if move.is_invoice(include_receipts=True) and float_compare(move.amount_total, 0.0, precision_rounding=move.currency_id.rounding) < 0:
|
||||
raise UserError(_("You cannot validate an invoice with a negative total amount. You should create a credit note instead. Use the action menu to transform it into a credit note or refund."))
|
||||
|
||||
if move.line_ids.account_id.filtered(lambda account: account.deprecated):
|
||||
raise UserError(_("A line of this move is using a deprecated account, you cannot post it."))
|
||||
|
||||
# Handle case when the invoice_date is not set. In that case, the invoice_date is set at today and then,
|
||||
# lines are recomputed accordingly.
|
||||
# /!\ 'check_move_validity' must be there since the dynamic lines will be recomputed outside the 'onchange'
|
||||
|
||||
@@ -3426,3 +3426,22 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
def test_out_invoice_depreciated_account(self):
|
||||
move = self.env['account.move'].create({
|
||||
'move_type': 'out_invoice',
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'partner_id': self.partner_a.id,
|
||||
'journal_id': self.company_data['default_journal_sale'].id,
|
||||
'invoice_line_ids': [
|
||||
(0, 0, {
|
||||
'name': 'My super product.',
|
||||
'quantity': 1.0,
|
||||
'price_unit': 750.0,
|
||||
'account_id': self.product_a.property_account_income_id.id,
|
||||
})
|
||||
],
|
||||
})
|
||||
self.product_a.property_account_income_id.deprecated = True
|
||||
with self.assertRaises(UserError), self.cr.savepoint():
|
||||
move.action_post()
|
||||
|
||||
@@ -148,6 +148,7 @@ class AccountEdiFormat(models.Model):
|
||||
'net_price_subtotal': taxes_res['total_excluded'],
|
||||
'price_discount_unit': (gross_price_subtotal - line.price_subtotal) / line.quantity if line.quantity else 0.0,
|
||||
'unece_uom_code': line.product_id.product_tmpl_id.uom_id._get_unece_code(),
|
||||
'gross_price_total_unit': line._prepare_edi_vals_to_export()['gross_price_total_unit']
|
||||
}
|
||||
|
||||
for tax_res in taxes_res['taxes']:
|
||||
@@ -159,7 +160,6 @@ class AccountEdiFormat(models.Model):
|
||||
'tax_base_amount': tax_res['base'],
|
||||
'unece_tax_category_code': tax_category_code,
|
||||
})
|
||||
line_template_values['gross_price_total_unit'] = line._prepare_edi_vals_to_export()['gross_price_total_unit']
|
||||
|
||||
template_values['invoice_line_values'].append(line_template_values)
|
||||
|
||||
|
||||
@@ -80,9 +80,9 @@ EU_TAG_MAP = {
|
||||
},
|
||||
# France
|
||||
'l10n_fr.l10n_fr_pcg_chart_template': {
|
||||
'invoice_base_tag': None,
|
||||
'invoice_base_tag': 'l10n_fr.tax_report_E3',
|
||||
'invoice_tax_tag': None,
|
||||
'refund_base_tag': None,
|
||||
'refund_base_tag': 'l10n_fr.tax_report_F8',
|
||||
'refund_tax_tag': None,
|
||||
},
|
||||
# Germany SKR03
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,23 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
from flectra import models, fields
|
||||
from flectra.tools.sql import column_exists, create_column
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
l10n_pe_group_id = fields.Many2one("account.group", related="account_id.group_id", store=True)
|
||||
|
||||
def _auto_init(self):
|
||||
"""
|
||||
Create column to stop ORM from computing it himself (too slow)
|
||||
"""
|
||||
if not column_exists(self.env.cr, self._table, 'l10n_pe_group_id'):
|
||||
create_column(self.env.cr, self._table, 'l10n_pe_group_id', 'int4')
|
||||
self.env.cr.execute("""
|
||||
UPDATE account_move_line line
|
||||
SET l10n_pe_group_id = account.group_id
|
||||
FROM account_account account
|
||||
WHERE account.id = line.account_id
|
||||
""")
|
||||
return super()._auto_init()
|
||||
|
||||
@@ -349,6 +349,7 @@ class PosOrder(models.Model):
|
||||
def action_stock_picking(self):
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('stock.action_picking_tree_ready')
|
||||
action['display_name'] = _('Pickings')
|
||||
action['context'] = {}
|
||||
action['domain'] = [('id', 'in', self.picking_ids.ids)]
|
||||
return action
|
||||
|
||||
@@ -147,6 +147,7 @@ class PosSession(models.Model):
|
||||
def action_stock_picking(self):
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('stock.action_picking_tree_ready')
|
||||
action['display_name'] = _('Pickings')
|
||||
action['context'] = {}
|
||||
action['domain'] = [('id', 'in', self.picking_ids.ids)]
|
||||
return action
|
||||
|
||||
@@ -45,7 +45,7 @@ class PurchaseOrderLine(models.Model):
|
||||
def _compute_qty_received(self):
|
||||
kit_lines = self.env['purchase.order.line']
|
||||
for line in self:
|
||||
if line.qty_received_method == 'stock_moves' and line.move_ids:
|
||||
if line.qty_received_method == 'stock_moves' and line.move_ids.filtered(lambda m: m.state != 'cancel'):
|
||||
kit_bom = self.env['mrp.bom']._bom_find(product=line.product_id, company_id=line.company_id.id, bom_type='phantom')
|
||||
if kit_bom:
|
||||
moves = line.move_ids.filtered(lambda m: m.state == 'done' and not m.scrapped)
|
||||
|
||||
@@ -67,13 +67,22 @@ class StockMove(models.Model):
|
||||
if self.purchase_line_id:
|
||||
purchase_currency = self.purchase_line_id.currency_id
|
||||
if purchase_currency != self.company_id.currency_id:
|
||||
# Do not use price_unit since we want the price tax excluded. And by the way, qty
|
||||
# is in the UOM of the product, not the UOM of the PO line.
|
||||
purchase_price_unit = (
|
||||
self.purchase_line_id.price_subtotal / self.purchase_line_id.product_uom_qty
|
||||
if self.purchase_line_id.product_uom_qty
|
||||
else self.purchase_line_id.price_unit
|
||||
)
|
||||
if(self.purchase_line_id.product_id.cost_method == 'standard'):
|
||||
purchase_price_unit = self.purchase_line_id.product_id.cost_currency_id._convert(
|
||||
self.purchase_line_id.product_id.standard_price,
|
||||
purchase_currency,
|
||||
self.company_id,
|
||||
self.date,
|
||||
round=False,
|
||||
)
|
||||
else:
|
||||
# Do not use price_unit since we want the price tax excluded. And by the way, qty
|
||||
# is in the UOM of the product, not the UOM of the PO line.
|
||||
purchase_price_unit = (
|
||||
self.purchase_line_id.price_subtotal / self.purchase_line_id.product_uom_qty
|
||||
if self.purchase_line_id.product_uom_qty
|
||||
else self.purchase_line_id.price_unit
|
||||
)
|
||||
currency_move_valuation = purchase_currency.round(purchase_price_unit * abs(qty))
|
||||
rslt['credit_line_vals']['amount_currency'] = rslt['credit_line_vals']['credit'] and -currency_move_valuation or currency_move_valuation
|
||||
rslt['credit_line_vals']['currency_id'] = purchase_currency.id
|
||||
|
||||
@@ -527,6 +527,186 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
# has gone to the stock account, and must be reflected in inventory valuation
|
||||
self.assertEqual(self.product1.value_svl, 150)
|
||||
|
||||
def test_standard_valuation_multicurrency(self):
|
||||
company = self.env.user.company_id
|
||||
company.anglo_saxon_accounting = True
|
||||
company.currency_id = self.usd_currency
|
||||
|
||||
date_po = '2019-01-01'
|
||||
|
||||
self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
|
||||
self.product1.property_account_creditor_price_difference = self.price_diff_account
|
||||
self.product1.standard_price = 10
|
||||
|
||||
# SetUp currency and rates 1$ = 2 Euros
|
||||
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", (self.usd_currency.id, company.id))
|
||||
self.env['res.currency.rate'].search([]).unlink()
|
||||
self.env['res.currency.rate'].create({
|
||||
'name': date_po,
|
||||
'rate': 1.0,
|
||||
'currency_id': self.usd_currency.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
|
||||
self.env['res.currency.rate'].create({
|
||||
'name': date_po,
|
||||
'rate': 2,
|
||||
'currency_id': self.eur_currency.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
|
||||
# Create PO
|
||||
po = self.env['purchase.order'].create({
|
||||
'currency_id': self.eur_currency.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': self.product1.name,
|
||||
'product_id': self.product1.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom': self.product1.uom_po_id.id,
|
||||
'price_unit': 100.0, # 50$
|
||||
'date_planned': date_po,
|
||||
}),
|
||||
],
|
||||
})
|
||||
po.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = po.picking_ids[0]
|
||||
receipt.move_lines.quantity_done = 1
|
||||
receipt.button_validate()
|
||||
|
||||
# Create a vendor bill
|
||||
inv = self.env['account.move'].with_context(default_move_type='in_invoice').create({
|
||||
'move_type': 'in_invoice',
|
||||
'invoice_date': date_po,
|
||||
'date': date_po,
|
||||
'currency_id': self.eur_currency.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'name': 'Test',
|
||||
'price_unit': 100.0,
|
||||
'product_id': self.product1.id,
|
||||
'purchase_line_id': po.order_line.id,
|
||||
'quantity': 1.0,
|
||||
'account_id': self.stock_input_account.id,
|
||||
})]
|
||||
})
|
||||
|
||||
inv.action_post()
|
||||
|
||||
# Check what was posted in stock input account
|
||||
input_amls = self.env['account.move.line'].search([('account_id', '=', self.stock_input_account.id)])
|
||||
self.assertEqual(len(input_amls), 3, "Only three lines should have been generated in stock input account: one when receiving the product, one when making the invoice.")
|
||||
invoice_amls = input_amls.filtered(lambda l: l.move_id == inv)
|
||||
picking_aml = input_amls - invoice_amls
|
||||
payable_aml = invoice_amls.filtered(lambda l: l.amount_currency > 0)
|
||||
diff_aml = invoice_amls - payable_aml
|
||||
|
||||
# check USD
|
||||
self.assertAlmostEqual(payable_aml.debit, 50, "Total debit value should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEqual(picking_aml.credit, 10, "credit value for stock should be equal to the standard price of the product.")
|
||||
self.assertAlmostEqual(diff_aml.credit, 40, "credit value for price difference")
|
||||
|
||||
# check EUR
|
||||
self.assertAlmostEqual(payable_aml.amount_currency, 100, "Total debit value should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEqual(picking_aml.amount_currency, -20, "credit value for stock should be equal to the standard price of the product.")
|
||||
self.assertAlmostEqual(diff_aml.amount_currency, -80, "credit value for price difference")
|
||||
|
||||
def test_valuation_multicurecny_with_tax(self):
|
||||
""" Check that a tax without account will increment the stock value.
|
||||
"""
|
||||
|
||||
company = self.env.user.company_id
|
||||
company.anglo_saxon_accounting = True
|
||||
company.currency_id = self.usd_currency
|
||||
|
||||
date_po = '2019-01-01'
|
||||
|
||||
self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
|
||||
self.product1.property_account_creditor_price_difference = self.price_diff_account
|
||||
|
||||
# SetUp currency and rates 1$ = 2Euros
|
||||
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", (self.usd_currency.id, company.id))
|
||||
self.env['res.currency.rate'].search([]).unlink()
|
||||
self.env['res.currency.rate'].create({
|
||||
'name': date_po,
|
||||
'rate': 1.0,
|
||||
'currency_id': self.usd_currency.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
|
||||
self.env['res.currency.rate'].create({
|
||||
'name': date_po,
|
||||
'rate': 2,
|
||||
'currency_id': self.eur_currency.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
|
||||
tax_with_no_account = self.env['account.tax'].create({
|
||||
'name': "Tax with no account",
|
||||
'amount_type': 'fixed',
|
||||
'amount': 5,
|
||||
'sequence': 8,
|
||||
'price_include': True,
|
||||
})
|
||||
|
||||
# Create PO
|
||||
po = self.env['purchase.order'].create({
|
||||
'currency_id': self.eur_currency.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': self.product1.name,
|
||||
'product_id': self.product1.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom': self.product1.uom_po_id.id,
|
||||
'price_unit': 100.0, # 50$
|
||||
'taxes_id': [(4, tax_with_no_account.id)],
|
||||
'date_planned': date_po,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
po.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = po.picking_ids[0]
|
||||
receipt.move_lines.quantity_done = 1
|
||||
receipt.button_validate()
|
||||
|
||||
# Create a vendor bill
|
||||
inv = self.env['account.move'].with_context(default_move_type='in_invoice').create({
|
||||
'move_type': 'in_invoice',
|
||||
'invoice_date': date_po,
|
||||
'date': date_po,
|
||||
'currency_id': self.eur_currency.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'name': 'Test',
|
||||
'price_unit': 100.0,
|
||||
'product_id': self.product1.id,
|
||||
'purchase_line_id': po.order_line.id,
|
||||
'quantity': 1.0,
|
||||
'account_id': self.stock_input_account.id,
|
||||
})]
|
||||
})
|
||||
|
||||
inv.action_post()
|
||||
|
||||
# Check what was posted in stock input account
|
||||
input_amls = self.env['account.move.line'].search([('account_id', '=', self.stock_input_account.id)])
|
||||
self.assertEqual(len(input_amls), 2, "Only two lines should have been generated in stock input account: one when receiving the product, one when making the invoice.")
|
||||
invoice_aml = input_amls.filtered(lambda l: l.move_id == inv)
|
||||
picking_aml = input_amls - invoice_aml
|
||||
|
||||
# check EUR
|
||||
self.assertAlmostEqual(invoice_aml.amount_currency, 100, "Total debit value should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEqual(picking_aml.amount_currency, -95, "credit value for stock should be equal to the untaxed price of the product.")
|
||||
|
||||
def test_average_realtime_anglo_saxon_valuation_multicurrency_same_date(self):
|
||||
"""
|
||||
The PO and invoice are in the same foreign currency.
|
||||
|
||||
@@ -4,7 +4,7 @@ import re
|
||||
import base64
|
||||
import io
|
||||
|
||||
from PyPDF2 import PdfFileReader, PdfFileMerger
|
||||
from PyPDF2 import PdfFileReader, PdfFileMerger, PdfFileWriter
|
||||
from reportlab.platypus import Frame, Paragraph, KeepInFrame
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.lib.pagesizes import A4
|
||||
@@ -144,6 +144,7 @@ class SnailmailLetter(models.Model):
|
||||
if (paperformat.format == 'custom' and paperformat.page_width != 210 and paperformat.page_height != 297) or paperformat.format != 'A4':
|
||||
raise UserError(_("Please use an A4 Paper format."))
|
||||
pdf_bin, unused_filetype = report.with_context(snailmail_layout=not self.cover, lang='en_US')._render_qweb_pdf(self.res_id)
|
||||
pdf_bin = self._overwrite_margins(pdf_bin)
|
||||
if self.cover:
|
||||
pdf_bin = self._append_cover_page(pdf_bin)
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
@@ -457,3 +458,49 @@ class SnailmailLetter(models.Model):
|
||||
out_buff = io.BytesIO()
|
||||
merger.write(out_buff)
|
||||
return out_buff.getvalue()
|
||||
|
||||
def _overwrite_margins(self, invoice_bin: bytes):
|
||||
"""
|
||||
Fill the margins with white for validation purposes.
|
||||
"""
|
||||
pdf_buf = io.BytesIO()
|
||||
canvas = Canvas(pdf_buf, pagesize=A4)
|
||||
canvas.setFillColorRGB(255, 255, 255)
|
||||
page_width = A4[0]
|
||||
page_height = A4[1]
|
||||
|
||||
# Horizontal Margin
|
||||
hmargin_width = page_width
|
||||
hmargin_height = 5 * mm
|
||||
|
||||
# Vertical Margin
|
||||
vmargin_width = 5 * mm
|
||||
vmargin_height = page_height
|
||||
|
||||
# Bottom left square
|
||||
sq_width = 15 * mm
|
||||
|
||||
# Draw the horizontal margins
|
||||
canvas.rect(0, 0, hmargin_width, hmargin_height, stroke=0, fill=1)
|
||||
canvas.rect(0, page_height, hmargin_width, -hmargin_height, stroke=0, fill=1)
|
||||
|
||||
# Draw the vertical margins
|
||||
canvas.rect(0, 0, vmargin_width, vmargin_height, stroke=0, fill=1)
|
||||
canvas.rect(page_width, 0, -vmargin_width, vmargin_height, stroke=0, fill=1)
|
||||
|
||||
# Draw the bottom left white square
|
||||
canvas.rect(0, 0, sq_width, sq_width, stroke=0, fill=1)
|
||||
canvas.save()
|
||||
pdf_buf.seek(0)
|
||||
|
||||
new_pdf = PdfFileReader(pdf_buf)
|
||||
curr_pdf = PdfFileReader(io.BytesIO(invoice_bin))
|
||||
out = PdfFileWriter()
|
||||
for page in curr_pdf.pages:
|
||||
page.mergePage(new_pdf.getPage(0))
|
||||
out.addPage(page)
|
||||
out_stream = io.BytesIO()
|
||||
out.write(out_stream)
|
||||
out_bin = out_stream.getvalue()
|
||||
out_stream.close()
|
||||
return out_bin
|
||||
|
||||
@@ -241,7 +241,8 @@ class StockQuant(models.Model):
|
||||
@api.constrains('quantity')
|
||||
def check_quantity(self):
|
||||
for quant in self:
|
||||
if float_compare(quant.quantity, 1, precision_rounding=quant.product_uom_id.rounding) > 0 and quant.lot_id and quant.product_id.tracking == 'serial':
|
||||
if quant.location_id.usage != 'inventory' and quant.lot_id and quant.product_id.tracking == 'serial' \
|
||||
and float_compare(abs(quant.quantity), 1, precision_rounding=quant.product_uom_id.rounding) > 0:
|
||||
raise ValidationError(_('The serial number has already been assigned: \n Product: %s, Serial Number: %s') % (quant.product_id.display_name, quant.lot_id.name))
|
||||
|
||||
@api.constrains('location_id')
|
||||
|
||||
@@ -226,9 +226,9 @@ class StockPickingBatch(models.Model):
|
||||
precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) == 0)
|
||||
if move_line_ids:
|
||||
res = self.picking_ids[0]._pre_put_in_pack_hook(move_line_ids)
|
||||
res = move_line_ids.picking_id[0]._pre_put_in_pack_hook(move_line_ids)
|
||||
if not res:
|
||||
res = self.picking_ids[0]._put_in_pack(move_line_ids, False)
|
||||
res = move_line_ids.picking_id[0]._put_in_pack(move_line_ids, False)
|
||||
return res
|
||||
else:
|
||||
raise UserError(_("Please add 'Done' quantities to the batch picking to create a new pack."))
|
||||
|
||||
@@ -197,6 +197,7 @@ var SnippetEditor = Widget.extend({
|
||||
if (this.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
this.willDestroyEditors = true;
|
||||
await this.toggleTargetVisibility(!this.$target.hasClass('o_snippet_invisible'));
|
||||
const proms = _.map(this.styles, option => {
|
||||
return option.cleanForSave();
|
||||
@@ -925,6 +926,10 @@ var SnippetEditor = Widget.extend({
|
||||
* @param {FlectraEvent} ev
|
||||
*/
|
||||
_onSnippetOptionVisibilityUpdate: function (ev) {
|
||||
if (this.willDestroyEditors) {
|
||||
// Do not update the option visibilities if we are destroying them.
|
||||
return;
|
||||
}
|
||||
ev.data.show = this._toggleVisibilityStatus(ev.data.show);
|
||||
},
|
||||
/**
|
||||
@@ -1290,6 +1295,7 @@ var SnippetsMenu = Widget.extend({
|
||||
// may be the moment where the public widgets need to be destroyed).
|
||||
this.trigger_up('ready_to_clean_for_save');
|
||||
|
||||
this.willDestroyEditors = true;
|
||||
// Then destroy all snippet editors, making them call their own
|
||||
// "clean for save" methods (and options ones).
|
||||
await this._destroyEditors();
|
||||
@@ -2840,6 +2846,10 @@ var SnippetsMenu = Widget.extend({
|
||||
* @param {FlectraEvent} ev
|
||||
*/
|
||||
_onSnippetOptionVisibilityUpdate: async function (ev) {
|
||||
if (this.willDestroyEditors) {
|
||||
// Do not update the option visibilities if we are destroying them.
|
||||
return;
|
||||
}
|
||||
if (!ev.data.show) {
|
||||
await this._activateSnippet(false);
|
||||
}
|
||||
|
||||
@@ -1939,8 +1939,20 @@ const VisibilityPageOptionUpdate = options.Class.extend({
|
||||
*/
|
||||
async start() {
|
||||
await this._super(...arguments);
|
||||
const shown = await this._isShown();
|
||||
this.trigger_up('snippet_option_visibility_update', {show: shown});
|
||||
// When entering edit mode via the URL (enable_editor) the WebsiteNavbar
|
||||
// is not yet ReadyForActions because it is waiting for its
|
||||
// sub-component EditPageMenu to start edit mode. Then invisible blocks
|
||||
// options start (so this option too). But for isShown() to work, the
|
||||
// navbar must be ReadyForActions. This is the reason why we can't wait
|
||||
// for isShown here, otherwise we would have a deadlock. On one hand the
|
||||
// navbar waiting for the invisible snippets options to be started to be
|
||||
// ReadyForActions and on the other hand this option which needs the
|
||||
// navbar to be ReadyForActions to be started.
|
||||
// TODO in master: Use the data-invisible system to get rid of this
|
||||
// piece of code.
|
||||
this._isShown().then(isShown => {
|
||||
this.trigger_up('snippet_option_visibility_update', {show: isShown});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
// $enable-gradients: true;
|
||||
//
|
||||
// Notice that Flectra already overrides bootstrap variables according to your
|
||||
// choices in the "Customize Theme" dialog, you should first take a look at
|
||||
// it and do customizations this way. Indeed, if you overridde the same
|
||||
// variables, Flectra will either have to ignore them or not be able to make
|
||||
// the "Customize Theme" dialog work for these variables anymore.
|
||||
// choices via the website builder (especially 3rd tab of the editor panel). You
|
||||
// should first take a look at it and do customizations this way. Indeed, if you
|
||||
// override the same variables yourself, Flectra will either have to ignore them or
|
||||
// not be able to make the website builder work properly for these variables
|
||||
// anymore.
|
||||
//
|
||||
|
||||
@@ -1271,7 +1271,21 @@ header {
|
||||
|
||||
@if index(('slideout_slide_hover', 'slideout_shadow'), o-website-value('footer-effect')) {
|
||||
@include media-breakpoint-up(lg) {
|
||||
#wrapwrap.o_footer_effect_enable {
|
||||
// This effect is disabled when a modal is opened. This is the easiest
|
||||
// and probably most stable solution for this problem:
|
||||
// - Add a popup in your page and select it to be for "All pages"
|
||||
// => In that case it ends up in the footer of your page
|
||||
// - Enable the "Slide Hover" effect for your footer
|
||||
//
|
||||
// => In that case, when the popup opens, it is not visible because of
|
||||
// the footer z-index ("Slide Hover" effect) and it actually also
|
||||
// prevents the user to scroll.
|
||||
//
|
||||
// TODO in master, we may want to put such popups elsewhere than in the
|
||||
// footer. When the footer is hidden, this is also a problem: the popup
|
||||
// for all pages cannot be visible ever. This is considered a limitation
|
||||
// in stable versions though.
|
||||
body:not(.modal-open) #wrapwrap.o_footer_effect_enable {
|
||||
> main {
|
||||
@if o-website-value('layout') == 'full' {
|
||||
// Ensure a transparent snippet at the end of the content
|
||||
|
||||
@@ -51,6 +51,7 @@ function clickAndCheck(blockID, expected) {
|
||||
window.focusBlurSnippetsResult = [];
|
||||
|
||||
tour.register('focus_blur_snippets', {
|
||||
test: true,
|
||||
url: '/?enable_editor=1',
|
||||
}, [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ var rpc = require('web.rpc');
|
||||
var tour = require("web_tour.tour");
|
||||
|
||||
tour.register('shop_wishlist_admin', {
|
||||
test: false,
|
||||
test: true,
|
||||
url: '/shop',
|
||||
},
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user