mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-10-25 23:40:05 -05:00
[PATCH] Upstream patch - 05022023
This commit is contained in:
1 parent
fc680e12a0
commit
64e0e10b2a
15 files changed
+227
-39
No files matched your search
@@ -194,7 +194,7 @@ class ImDispatch(object):
|
||||
self.started = True
|
||||
return self
|
||||
|
||||
dispatch = None
|
||||
if not flectra.multi_process or flectra.evented:
|
||||
# We only use the event dispatcher in threaded and gevent mode
|
||||
dispatch = ImDispatch()
|
||||
# Partially undo a2ed3d3d5bdb6025a1ba14ad557a115a86413e65
|
||||
# IMDispatch has a lazy start, so we could initialize it anyway
|
||||
# And this avoids the Bus unavailable error messages
|
||||
dispatch = ImDispatch()
|
||||
@@ -29,10 +29,11 @@ class ImLivechatChannel(models.Model):
|
||||
# attribute fields
|
||||
name = fields.Char('Name', required=True, help="The name of the channel")
|
||||
button_text = fields.Char('Text of the Button', default='Have a Question? Chat with us.',
|
||||
help="Default text displayed on the Livechat Support Button")
|
||||
help="Default text displayed on the Livechat Support Button", translate=True)
|
||||
default_message = fields.Char('Welcome Message', default='How may I help you?',
|
||||
help="This is an automated 'welcome' message that your visitor will see when they initiate a new conversation.")
|
||||
input_placeholder = fields.Char('Chat Input Placeholder', help='Text that prompts the user to initiate the chat.')
|
||||
help="This is an automated 'welcome' message that your visitor will see when they initiate a new conversation.",
|
||||
translate=True)
|
||||
input_placeholder = fields.Char('Chat Input Placeholder', help='Text that prompts the user to initiate the chat.', translate=True)
|
||||
header_background_color = fields.Char(default="#009EFB", help="Default background color of the channel header once open")
|
||||
title_color = fields.Char(default="#FFFFFF", help="Default title color of the channel once open")
|
||||
button_background_color = fields.Char(default="#878787", help="Default background color of the Livechat button")
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
|
||||
<!-- (17) CUIT -->
|
||||
<t t-if="o.partner_id.vat and o.partner_id.l10n_latam_identification_type_id and o.partner_id.l10n_latam_identification_type_id.l10n_ar_afip_code != '99'">
|
||||
<br/><strong><t t-esc="o.partner_id.l10n_latam_identification_type_id.name or o.company_id.country_id.vat_label" id="inv_tax_id_label"/>:</strong> <span t-esc="o.partner_id.l10n_ar_formatted_vat if o.partner_id.l10n_latam_identification_type_id.is_vat else o.partner_id.vat"/>
|
||||
<br/><strong><t t-esc="o.partner_id.l10n_latam_identification_type_id.name or o.company_id.country_id.vat_label" id="inv_tax_id_label"/>:</strong> <span t-esc="o.partner_id.l10n_ar_formatted_vat if o.partner_id.l10n_ar_vat else o.partner_id.vat"/>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
<NumeroLinea t-esc="line_dict['line_number']"/>
|
||||
<CodiceArticolo t-if="line.product_id.barcode">
|
||||
<CodiceTipo>EAN</CodiceTipo>
|
||||
<CodiceValore t-esc="format_alphanumeric(line.product_id.barcode)"/>
|
||||
<CodiceValore t-esc="format_alphanumeric(line.product_id.barcode)[:35]"/>
|
||||
</CodiceArticolo>
|
||||
<CodiceArticolo t-elif="line.product_id.default_code">
|
||||
<CodiceTipo>INTERNAL</CodiceTipo>
|
||||
<CodiceValore t-esc="format_alphanumeric(line.product_id.default_code)"/>
|
||||
<CodiceValore t-esc="format_alphanumeric(line.product_id.default_code)[:35]"/>
|
||||
</CodiceArticolo>
|
||||
<Descrizione t-esc="format_alphanumeric(line_dict['description'])"/>
|
||||
<Descrizione t-esc="format_alphanumeric(line_dict['description'])[:1000]"/>
|
||||
<Quantita t-esc="format_numbers(abs(line.quantity))"/>
|
||||
<UnitaMisura t-if="line.product_uom_id.category_id != env.ref('uom.product_uom_categ_unit')" t-esc="format_alphanumeric(line.product_uom_id.name)"/>
|
||||
<UnitaMisura t-if="line.product_uom_id and line.product_uom_id.category_id != env.ref('uom.product_uom_categ_unit')" t-esc="format_alphanumeric(line.product_uom_id.name)[:10]"/>
|
||||
<PrezzoUnitario t-esc="'%.06f' % (line_dict['unit_price'])"/>
|
||||
<ScontoMaggiorazione t-if="line.discount != 0">
|
||||
<Tipo t-esc="discount_type(line.discount)"/>
|
||||
@@ -52,9 +52,9 @@
|
||||
<ContattiTrasmittente>
|
||||
<Telefono t-if="sender_partner.phone" t-esc="format_alphanumeric(format_phone(sender_partner.phone))"/>
|
||||
<Telefono t-elif="sender_partner.mobile" t-esc="format_alphanumeric(format_phone(sender_partner.mobile))"/>
|
||||
<Email t-if="sender_partner.email" t-esc="sender_partner.email"/>
|
||||
<Email t-if="sender_partner.email" t-esc="sender_partner.email[:256]"/>
|
||||
</ContattiTrasmittente>
|
||||
<PECDestinatario t-if="not is_self_invoice and partner.l10n_it_pec_email" t-esc="partner.l10n_it_pec_email"/>
|
||||
<PECDestinatario t-if="not is_self_invoice and partner.l10n_it_pec_email" t-esc="partner.l10n_it_pec_email[:256]"/>
|
||||
</DatiTrasmissione>
|
||||
<CedentePrestatore>
|
||||
<DatiAnagrafici>
|
||||
@@ -203,10 +203,10 @@
|
||||
|
||||
<template id="account_invoice_it_FatturaPA_sede">
|
||||
<Sede>
|
||||
<Indirizzo><t t-if="partner.street" t-esc="format_alphanumeric(partner.street)"/> <t t-if="partner.street2" t-esc="format_alphanumeric(partner.street2)"/></Indirizzo>
|
||||
<CAP><t t-if="partner.country_id.code != 'IT'" t-esc="'00000'"/><t t-else="" t-esc="partner.zip"/></CAP>
|
||||
<Comune t-esc="format_alphanumeric(partner.city)"/>
|
||||
<Provincia t-if="partner.country_id.code == 'IT'" t-esc="partner.state_id.code"/>
|
||||
<Indirizzo><t t-if="partner.street or partner.street2" t-esc="format_alphanumeric((partner.street or '') + ' ' + (partner.street2 or ''))[:60]"/></Indirizzo>
|
||||
<CAP><t t-if="partner.country_id.code != 'IT'" t-esc="'00000'"/><t t-elif="partner.zip" t-esc="partner.zip"/></CAP>
|
||||
<Comune t-esc="format_alphanumeric(partner.city[:60])"/>
|
||||
<Provincia t-if="partner.country_id.code == 'IT' and partner.state_id" t-esc="partner.state_id.code[:2]"/>
|
||||
<Nazione t-esc="partner.country_id.code"/>
|
||||
</Sede>
|
||||
</template>
|
||||
|
||||
@@ -1415,7 +1415,7 @@ class MrpProduction(models.Model):
|
||||
move.product_uom_qty = move.quantity_done
|
||||
# MRP do not merge move, catch the result of _action_done in order
|
||||
# to get extra moves.
|
||||
moves_to_do = moves_to_do._action_done()
|
||||
moves_to_do = moves_to_do._action_done(cancel_backorder=cancel_backorder)
|
||||
moves_to_do = order.move_raw_ids.filtered(lambda x: x.state == 'done') - moves_not_to_do
|
||||
|
||||
finish_moves = order.move_finished_ids.filtered(lambda m: m.product_id == order.product_id and m.state not in ('done', 'cancel'))
|
||||
@@ -1560,7 +1560,7 @@ class MrpProduction(models.Model):
|
||||
|
||||
backorders = productions_to_backorder._generate_backorder_productions(close_mo=close_mo)
|
||||
productions_not_to_backorder._post_inventory(cancel_backorder=True)
|
||||
productions_to_backorder._post_inventory(cancel_backorder=False)
|
||||
productions_to_backorder._post_inventory(cancel_backorder=True)
|
||||
|
||||
# if completed products make other confirmed/partially_available moves available, assign them
|
||||
done_move_finished_ids = (productions_to_backorder.move_finished_ids | productions_not_to_backorder.move_finished_ids).filtered(lambda m: m.state == 'done')
|
||||
|
||||
@@ -111,7 +111,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
# check that copy handles moves correctly
|
||||
mo_copy = man_order.copy()
|
||||
self.assertEqual(mo_copy.state, 'draft', "Copied production order should be draft.")
|
||||
self.assertEqual(len(mo_copy.move_raw_ids), 2, "Incorrect number of component moves [i.e. no 0 qty moves should be copied].")
|
||||
self.assertEqual(len(mo_copy.move_raw_ids), 4, "Incorrect number of component moves [i.e. no 0 qty moves should be copied].")
|
||||
self.assertEqual(len(mo_copy.move_finished_ids), 1, "Incorrect number of moves for products to produce [i.e. cancelled moves should not be copied")
|
||||
self.assertEqual(mo_copy.move_finished_ids.product_uom_qty, 2, "Incorrect qty of products to produce")
|
||||
|
||||
@@ -120,7 +120,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
self.assertEqual(mo_copy.state, 'cancel')
|
||||
mo_copy_2 = mo_copy.copy()
|
||||
self.assertEqual(mo_copy_2.state, 'draft', "Copied production order should be draft.")
|
||||
self.assertEqual(len(mo_copy_2.move_raw_ids), 2, "Incorrect number of component moves.")
|
||||
self.assertEqual(len(mo_copy_2.move_raw_ids), 4, "Incorrect number of component moves.")
|
||||
self.assertEqual(len(mo_copy_2.move_finished_ids), 1, "Incorrect number of moves for products to produce [i.e. copying a cancelled MO should copy its cancelled moves]")
|
||||
self.assertEqual(mo_copy_2.move_finished_ids.product_uom_qty, 2, "Incorrect qty of products to produce")
|
||||
|
||||
@@ -197,6 +197,45 @@ class TestMrpOrder(TestMrpCommon):
|
||||
self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1, 10, 1, 1])
|
||||
self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.qty_done'), [1, 10, 1, 1])
|
||||
|
||||
def test_under_consumption(self):
|
||||
""" Consume less component quantity than the initial demand.
|
||||
Before done:
|
||||
p1, to consume = 1, consumed = 0
|
||||
p2, to consume = 10, consumed = 5
|
||||
After done:
|
||||
p1, to consume = 1, consumed = 0, state = cancel
|
||||
p2, to consume = 5, consumed = 5, state = done
|
||||
p2, to consume = 5, consumed = 0, state = cancel
|
||||
"""
|
||||
mo, _bom, _p_final, _p1, _p2 = self.generate_mo(qty_base_1=10, qty_final=1, qty_base_2=1)
|
||||
mo.action_assign()
|
||||
# check is_quantity_done_editable
|
||||
mo_form = Form(mo)
|
||||
mo_form.qty_producing = 1
|
||||
mo = mo_form.save()
|
||||
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
|
||||
with details_operation_form.move_line_ids.edit(0) as ml:
|
||||
ml.qty_done = 0
|
||||
details_operation_form.save()
|
||||
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
|
||||
with details_operation_form.move_line_ids.edit(0) as ml:
|
||||
ml.qty_done = 5
|
||||
details_operation_form.save()
|
||||
|
||||
self.assertEqual(len(mo.move_raw_ids), 2)
|
||||
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 2)
|
||||
self.assertEqual(mo.move_raw_ids[0].move_line_ids.mapped('qty_done'), [0])
|
||||
self.assertEqual(mo.move_raw_ids[1].move_line_ids.mapped('qty_done'), [5])
|
||||
self.assertEqual(mo.move_raw_ids[0].quantity_done, 0)
|
||||
self.assertEqual(mo.move_raw_ids[1].quantity_done, 5)
|
||||
mo.button_mark_done()
|
||||
self.assertEqual(len(mo.move_raw_ids), 3)
|
||||
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 1)
|
||||
self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [0, 5, 0])
|
||||
self.assertEqual(mo.move_raw_ids.mapped('product_uom_qty'), [1, 5, 5])
|
||||
self.assertEqual(mo.move_raw_ids.mapped('state'), ['cancel', 'done', 'cancel'])
|
||||
self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.qty_done'), [5])
|
||||
|
||||
def test_update_quantity_1(self):
|
||||
""" Build 5 final products with different consumed lots,
|
||||
then edit the finished quantity and update the Manufacturing
|
||||
@@ -1768,6 +1807,40 @@ class TestMrpOrder(TestMrpCommon):
|
||||
self.assertEqual(mo.workorder_ids[1].date_planned_start, tuesday.replace(hour=1))
|
||||
self.assertEqual(mo.workorder_ids[1].date_planned_finished, tuesday.replace(hour=2))
|
||||
|
||||
def test_backorder_with_underconsumption(self):
|
||||
""" Check that the components of the backorder have the correct quantities
|
||||
when there is underconsumption in the initial MO
|
||||
"""
|
||||
mo, _, _, p1, p2 = self.generate_mo(qty_final=20, qty_base_1=1, qty_base_2=1)
|
||||
mo.action_confirm()
|
||||
mo.qty_producing = 10
|
||||
mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity_done = 5
|
||||
mo.move_raw_ids.filtered(lambda m: m.product_id == p2).quantity_done = 10
|
||||
action = mo.button_mark_done()
|
||||
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
|
||||
backorder.save().action_backorder()
|
||||
mo_backorder = mo.procurement_group_id.mrp_production_ids[-1]
|
||||
|
||||
# Check quantities of the original MO
|
||||
self.assertEqual(mo.product_uom_qty, 10.0)
|
||||
self.assertEqual(mo.qty_produced, 10.0)
|
||||
move_prod_1_done = mo.move_raw_ids.filtered(lambda m: m.product_id == p1 and m.state == 'done')
|
||||
self.assertEqual(sum(move_prod_1_done.mapped('quantity_done')), 5)
|
||||
self.assertEqual(sum(move_prod_1_done.mapped('product_uom_qty')), 5)
|
||||
move_prod_1_cancel = mo.move_raw_ids.filtered(lambda m: m.product_id == p1 and m.state == 'cancel')
|
||||
self.assertEqual(sum(move_prod_1_cancel.mapped('quantity_done')), 0)
|
||||
self.assertEqual(sum(move_prod_1_cancel.mapped('product_uom_qty')), 5)
|
||||
move_prod_2 = mo.move_raw_ids.filtered(lambda m: m.product_id == p2)
|
||||
self.assertEqual(sum(move_prod_2.mapped('quantity_done')), 10)
|
||||
self.assertEqual(sum(move_prod_2.mapped('product_uom_qty')), 10)
|
||||
|
||||
# Check quantities of the backorder MO
|
||||
self.assertEqual(mo_backorder.product_uom_qty, 10.0)
|
||||
move_prod_1_bo = mo_backorder.move_raw_ids.filtered(lambda m: m.product_id == p1)
|
||||
move_prod_2_bo = mo_backorder.move_raw_ids.filtered(lambda m: m.product_id == p2)
|
||||
self.assertEqual(sum(move_prod_1_bo.mapped('product_uom_qty')), 10.0)
|
||||
self.assertEqual(sum(move_prod_2_bo.mapped('product_uom_qty')), 10.0)
|
||||
|
||||
def test_products_with_variants(self):
|
||||
"""Check for product with different variants with same bom"""
|
||||
product = self.env['product.template'].create({
|
||||
|
||||
@@ -537,9 +537,12 @@ class PosSession(models.Model):
|
||||
for move in stock_moves:
|
||||
exp_key = move.product_id._get_product_accounts()['expense']
|
||||
out_key = move.product_id.categ_id.property_stock_account_output_categ_id
|
||||
amount = move.product_qty * move.product_id._compute_average_price(0, move.product_qty, move)
|
||||
signed_product_qty = move.product_qty
|
||||
if move._is_in():
|
||||
signed_product_qty *= -1
|
||||
amount = signed_product_qty * move.product_id._compute_average_price(0, move.product_qty, move)
|
||||
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
if move.location_id.usage == 'customer':
|
||||
if move._is_in():
|
||||
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
else:
|
||||
stock_output[out_key] = self._update_amounts(stock_output[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
@@ -563,9 +566,12 @@ class PosSession(models.Model):
|
||||
for move in stock_moves:
|
||||
exp_key = move.product_id._get_product_accounts()['expense']
|
||||
out_key = move.product_id.categ_id.property_stock_account_output_categ_id
|
||||
amount = move.product_qty * move.product_id._compute_average_price(0, move.product_qty, move)
|
||||
signed_product_qty = move.product_qty
|
||||
if move._is_in():
|
||||
signed_product_qty *= -1
|
||||
amount = signed_product_qty * move.product_id._compute_average_price(0, move.product_qty, move)
|
||||
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
if move.location_id.usage == 'customer':
|
||||
if move._is_in():
|
||||
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
else:
|
||||
stock_output[out_key] = self._update_amounts(stock_output[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
|
||||
@@ -247,3 +247,30 @@ class TestPoSStock(TestPoSCommon):
|
||||
|
||||
# close the session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
def test_04_order_refund(self):
|
||||
self.categ4 = self.env['product.category'].create({
|
||||
'name': 'Category 4',
|
||||
'property_cost_method': 'fifo',
|
||||
'property_valuation': 'real_time',
|
||||
})
|
||||
self.product4 = self.create_product('Product 4', self.categ4, 30.0, 15.0)
|
||||
|
||||
self.open_new_session()
|
||||
orders = []
|
||||
orders.append(self.create_ui_order_data([(self.product4, 1)]))
|
||||
order = self.env['pos.order'].create_from_ui(orders)
|
||||
|
||||
refund_action = self.env['pos.order'].browse(order[0]['id']).refund()
|
||||
refund = self.env['pos.order'].browse(refund_action['res_id'])
|
||||
|
||||
payment_context = {"active_ids": refund.ids, "active_id": refund.id}
|
||||
refund_payment = self.env['pos.make.payment'].with_context(**payment_context).create({
|
||||
'amount': refund.amount_total,
|
||||
'payment_method_id': self.cash_pm.id,
|
||||
})
|
||||
refund_payment.with_context(**payment_context).check()
|
||||
|
||||
self.pos_session.action_pos_session_validate()
|
||||
expense_account_move_line = self.env['account.move.line'].search([('account_id', '=', self.expense_account.id)])
|
||||
self.assertEqual(expense_account_move_line.balance, 0.0, "Expense account should be 0.0")
|
||||
@@ -279,6 +279,8 @@ class Repair(models.Model):
|
||||
return True
|
||||
|
||||
def action_repair_cancel(self):
|
||||
if self.state == 'done':
|
||||
raise UserError(_("You cannot cancel a completed repair order."))
|
||||
invoice_to_cancel = self.filtered(lambda repair: repair.invoice_id.state == 'draft').invoice_id
|
||||
if invoice_to_cancel:
|
||||
invoice_to_cancel.button_cancel()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<button name="print_repair_order" states="draft" string="Print Quotation" type="object"/>
|
||||
<button name="action_repair_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
|
||||
<button name="action_repair_cancel" string="Cancel Repair" type="object" confirm="Draft invoices for this order will be cancelled. Do you confirm the action?" attrs="{'invisible':['|', ('state', '=', 'cancel'), ('invoice_state', '!=', 'draft')]}"/>
|
||||
<button name="action_repair_cancel" string="Cancel Repair" type="object" attrs="{'invisible': ['|', ('state','=', 'cancel',), ('invoice_state', '=', 'draft')]}"/>
|
||||
<button name="action_repair_cancel" string="Cancel Repair" type="object" attrs="{'invisible': ['|', ('state','in', ('cancel','done')), ('invoice_state', '=', 'draft')]}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,done"/>
|
||||
</header>
|
||||
<sheet string="Repairs order">
|
||||
|
||||
@@ -767,7 +767,7 @@ class ProductTemplate(models.Model):
|
||||
# Forbid changing a product's company when quant(s) exist in another company.
|
||||
quant = self.env['stock.quant'].sudo().search([
|
||||
('product_id', 'in', products_changing_company.product_variant_ids.ids),
|
||||
('company_id', '!=', vals['company_id']),
|
||||
('company_id', 'not in', [vals['company_id'], False]),
|
||||
('quantity', '!=', 0),
|
||||
], order=None, limit=1)
|
||||
if quant:
|
||||
|
||||
@@ -133,6 +133,47 @@ class TestVirtualAvailable(TestStockCommon):
|
||||
self.env['stock.quant']._unlink_zero_quants()
|
||||
product.company_id = company2.id # Should work this time.
|
||||
|
||||
def test_change_product_company_exclude_vendor_and_customer_location(self):
|
||||
""" Checks we can change product company where only exist single company
|
||||
and exist quant in vendor/customer location"""
|
||||
company1 = self.env.ref('base.main_company')
|
||||
customer_location = self.env.ref('stock.stock_location_customers')
|
||||
supplier_location = self.env.ref('stock.stock_location_suppliers')
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Product Single Company',
|
||||
'type': 'product',
|
||||
})
|
||||
# Creates a quant for company 1.
|
||||
self.env['stock.quant'].create({
|
||||
'product_id': product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'location_id': self.location_1.id,
|
||||
'quantity': 5,
|
||||
})
|
||||
# Creates a quant for vendor location.
|
||||
self.env['stock.quant'].create({
|
||||
'product_id': product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'location_id': supplier_location.id,
|
||||
'quantity': -15,
|
||||
})
|
||||
# Creates a quant for customer location.
|
||||
self.env['stock.quant'].create({
|
||||
'product_id': product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'location_id': customer_location.id,
|
||||
'quantity': 10,
|
||||
})
|
||||
# Assigns a company: should be ok because only exist one company (exclude vendor and customer location)
|
||||
product.company_id = company1.id
|
||||
|
||||
# Reset product company to empty
|
||||
product.company_id = False
|
||||
company2 = self.env['res.company'].create({'name': 'Second Company'})
|
||||
# Assigns to another company: should be not okay because exist quants in defferent company (exclude vendor and customer location)
|
||||
with self.assertRaises(UserError):
|
||||
product.company_id = company2.id
|
||||
|
||||
def test_search_qty_available(self):
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Brand new product',
|
||||
|
||||
@@ -474,7 +474,7 @@ return AbstractRenderer.extend({
|
||||
// Detect if the event occurs in just one day
|
||||
// note: add & remove 1 min to avoid issues with 00:00
|
||||
var isSameDayEvent = moment(start).clone().add(1, 'minute').isSame(moment(end).clone().subtract(1, 'minute'), 'day');
|
||||
if (!event.extendedProps.record.allday && isSameDayEvent) {
|
||||
if (!event.allDay && isSameDayEvent) {
|
||||
// For month view: do not show background for non allday, single day events
|
||||
element.addClass('o_cw_nobg');
|
||||
if (event.extendedProps.showTime && !self.hideTime) {
|
||||
@@ -794,7 +794,7 @@ return AbstractRenderer.extend({
|
||||
var isSameDayEvent = start.clone().add(1, 'minute').isSame(end.clone().subtract(1, 'minute'), 'day');
|
||||
|
||||
// Do not display timing if the event occur across multiple days. Otherwise use user's timing preferences
|
||||
if (!this.hideTime && !eventData.extendedProps.record.allday && isSameDayEvent) {
|
||||
if (!this.hideTime && !eventData.allDay && isSameDayEvent) {
|
||||
var dbTimeFormat = this._getDbTimeFormat();
|
||||
|
||||
context.eventTime.time = start.clone().format(dbTimeFormat) + ' - ' + end.clone().format(dbTimeFormat);
|
||||
@@ -813,15 +813,15 @@ return AbstractRenderer.extend({
|
||||
|
||||
if (!this.hideDate) {
|
||||
|
||||
if (eventData.extendedProps.record.allday && isSameDayEvent) {
|
||||
if (eventData.allDay && isSameDayEvent) {
|
||||
context.eventDate.duration = _t("All day");
|
||||
} else if (eventData.extendedProps.record.allday && !isSameDayEvent) {
|
||||
} else if (eventData.allDay && !isSameDayEvent) {
|
||||
var daysLocaleData = moment.localeData();
|
||||
var days = moment.duration(end.diff(start)).days();
|
||||
context.eventDate.duration = daysLocaleData.relativeTime(days, true, 'dd');
|
||||
}
|
||||
|
||||
context.eventDate.date = this._getFormattedDate(start, end, true, eventData.extendedProps.record.allday);
|
||||
context.eventDate.date = this._getFormattedDate(start, end, true, eventData.allDay);
|
||||
}
|
||||
|
||||
return context;
|
||||
@@ -878,10 +878,17 @@ return AbstractRenderer.extend({
|
||||
_renderYearEventPopover: function (date, events, $el) {
|
||||
const groupKeys = [];
|
||||
const groupedEvents = {};
|
||||
const records = {};
|
||||
for(const record of this.state.data) {
|
||||
records[record.id] = record;
|
||||
}
|
||||
for (const event of events) {
|
||||
const start = moment(event.extendedProps.r_start);
|
||||
const end = moment(event.extendedProps.r_end);
|
||||
const key = this._getFormattedDate(start, end, false, event.extendedProps.record.allday);
|
||||
// get the original record to get the real allDay value as
|
||||
// the fullcalendar year view enforce allDay to true
|
||||
const record = records[event.extendedProps.record.id];
|
||||
const key = this._getFormattedDate(start, end, false, record.allDay);
|
||||
if (!(key in groupedEvents)) {
|
||||
groupedEvents[key] = [];
|
||||
groupKeys.push({
|
||||
|
||||
@@ -1374,6 +1374,36 @@ QUnit.module('Views', {
|
||||
calendar.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("all day event attribute", async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data.event.fields.boolfield = { string: "boolean field", type: "boolean" };
|
||||
this.data.event.records[0].boolfield = true;
|
||||
const calendar = await createCalendarView({
|
||||
View: CalendarView,
|
||||
model: 'event',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<calendar date_start="start" date_stop="stop" all_day="boolfield" mode="month">
|
||||
<field name="name"/>
|
||||
</calendar>
|
||||
`,
|
||||
archs: archs,
|
||||
viewOptions: { initialDate },
|
||||
session: { getTZOffset: () => 120 },
|
||||
});
|
||||
|
||||
assert.containsOnce(calendar, ".fc-event[data-event-id=1]");
|
||||
assert.containsNone(calendar, ".fc-event[data-event-id=1].o_cw_nobg", "first event is an all day event");
|
||||
|
||||
assert.containsOnce(calendar, ".fc-event[data-event-id=2].o_cw_nobg", "second event is not an all day event");
|
||||
|
||||
assert.containsN(calendar, ".fc-event[data-event-id=5]", 2);
|
||||
assert.containsNone(calendar, ".fc-event[data-event-id=5].o_cw_nobg", 2, "fifth event is an all day event");
|
||||
|
||||
calendar.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('create all day event in week mode', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
|
||||
@@ -115,11 +115,12 @@ class Menu(models.Model):
|
||||
def _compute_visible(self):
|
||||
for menu in self:
|
||||
visible = True
|
||||
if menu.page_id and not menu.user_has_groups('base.group_user') and \
|
||||
(not menu.page_id.sudo().is_visible or
|
||||
(not menu.page_id.view_id._handle_visibility(do_raise=False) and
|
||||
menu.page_id.view_id.visibility != "password")):
|
||||
visible = False
|
||||
if menu.page_id and not menu.user_has_groups('base.group_user'):
|
||||
page_sudo = menu.page_id.sudo()
|
||||
if (not page_sudo.is_visible
|
||||
or (not page_sudo.view_id._handle_visibility(do_raise=False)
|
||||
and page_sudo.view_id.visibility != "password")):
|
||||
visible = False
|
||||
menu.is_visible = visible
|
||||
|
||||
@api.model
|
||||
|
||||
Reference in new issue
Block a user