[FIX] *: product back2basics post-freeze fixes

This should have been a fixup of 37eb0dfbb54db1c062276cd8c172bf8dac9e557b but we needed
to freeze 🤷‍♂️

closes odoo/odoo#77344

closes odoo/odoo#77876

Related: odoo/enterprise#21425
Related: odoo/enterprise#21467
Signed-off-by: Quentin De Paoli (qdp) <qdp@openerp.com>
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
wan
2021-10-11 10:15:49 +00:00
committed by william-andre
parent d3f4ce1152
commit 9b0baa3aa4
34 changed files with 54 additions and 50 deletions
+1 -1
View File
@@ -94,7 +94,7 @@
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group name="delivery_details">
<field name="product_id" context="{'default_type': 'service', 'default_sale_ok': False, 'default_purchase_ok': False, 'default_invoice_policy': 'order'}" />
<field name="product_id" context="{'default_detailed_type': 'service', 'default_sale_ok': False, 'default_purchase_ok': False, 'default_invoice_policy': 'order'}" />
<field name="invoice_policy" widget="radio" attrs="{'invisible': ['|', ('delivery_type', 'in', ('fixed', 'base_on_rule')), ('integration_level', '=', 'rate')]}"/>
<label for="margin" string="Margin on Rate"/>
<div>
+1 -1
View File
@@ -9,7 +9,7 @@ class ProductTemplate(models.Model):
detailed_type = fields.Selection(selection_add=[
('event_booth', 'Event Booth'),
], ondelete={'event_booth': 'set default'})
], ondelete={'event_booth': 'set service'})
@api.onchange('detailed_type')
def _onchange_type_event_booth(self):
@@ -10,7 +10,7 @@
<group name="main" position="inside">
<group string="Booth Details">
<field name="currency_id" invisible="1"/>
<field name="product_id" context="{'default_detailed_type': 'event_booth', 'default_type': 'service'}"/>
<field name="product_id" context="{'default_detailed_type': 'event_booth', 'default_detailed_type': 'service'}"/>
<field name="price" widget="monetary" options="{'currency_field': 'currency_id'}"/>
</group>
</group>
+1 -1
View File
@@ -8,7 +8,7 @@ class ProductTemplate(models.Model):
detailed_type = fields.Selection(selection_add=[
('event', 'Event Ticket'),
], ondelete={'event': 'set default'})
], ondelete={'event': 'set service'})
@api.onchange('detailed_type')
def _onchange_type_event(self):
+1 -1
View File
@@ -10,7 +10,7 @@ class ProductTemplate(models.Model):
detailed_type = fields.Selection(selection_add=[
('gift', 'Gift Card'),
], ondelete={'gift': 'set default'})
], ondelete={'gift': 'set service'})
def _detailed_type_mapping(self):
type_mapping = super()._detailed_type_mapping()
+1 -1
View File
@@ -552,7 +552,7 @@
<field name="res_model">product.product</field>
<field name="view_mode">kanban,tree,form</field>
<field name="search_view_id" ref="product.product_search_form_view"/>
<field name="context">{"default_can_be_expensed": 1, 'default_type': 'service'}</field>
<field name="context">{"default_can_be_expensed": 1, 'default_detailed_type': 'service'}</field>
<field name="domain">[('can_be_expensed', '=', True)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
+1 -1
View File
@@ -113,7 +113,7 @@
<field name="name">Membership Products</field>
<field name="res_model">product.template</field>
<field name="domain">[('membership','=',True), ('type', '=', 'service')]</field>
<field name="context">{'membership':True, 'type':'service', 'default_membership': True, 'default_type': 'service'}</field>
<field name="context">{'membership':True, 'type':'service', 'default_membership': True, 'default_detailed_type': 'service'}</field>
<field name="search_view_id" ref="membership_product_search_form_view"/>
</record>
+1 -1
View File
@@ -179,7 +179,7 @@ class TestKitPicking(common.TestMrpCommon):
def create_product(name):
p = Form(self.env['product.product'])
p.name = name
p.type = 'product'
p.detailed_type = 'product'
return p.save()
# Create a kit 'kit_parent' :
+4 -4
View File
@@ -51,9 +51,9 @@
<group>
<group>
<field name="active" invisible="1"/>
<field name="product_tmpl_id" context="{'default_type': 'product'}"/>
<field name="product_tmpl_id" context="{'default_detailed_type': 'product'}"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="product_id" groups="product.group_product_variant" context="{'default_type': 'product'}"/>
<field name="product_id" groups="product.group_product_variant" context="{'default_detailed_type': 'product'}"/>
<label for="product_qty" string="Quantity"/>
<div class="o_row">
<field name="product_qty"/>
@@ -83,7 +83,7 @@
<tree string="Components" editable="bottom">
<field name="company_id" invisible="1"/>
<field name="sequence" widget="handle"/>
<field name="product_id" context="{'default_type': 'product'}"/>
<field name="product_id" context="{'default_detailed_type': 'product'}"/>
<field name="product_tmpl_id" invisible="1"/>
<button name="action_see_attachments" type="object" icon="fa-files-o" aria-label="Product Attachments" title="Product Attachments" class="float-right oe_read_only"/>
<field name="attachments_count" class="text-left oe_read_only"
@@ -117,7 +117,7 @@
<field name="company_id" invisible="1"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="sequence" widget="handle"/>
<field name="product_id" context="{'default_type': 'product'}"/>
<field name="product_id" context="{'default_detailed_type': 'product'}"/>
<field name="product_qty"/>
<field name="product_uom_id" groups="uom.group_uom"/>
<field name="cost_share" optional="hide"/>
+3 -3
View File
@@ -169,7 +169,7 @@
<field name="use_create_components_lots" invisible="1"/>
<field name="show_lot_ids" invisible="1"/>
<field name="product_tracking" invisible="1"/>
<field name="product_id" context="{'default_type': 'product'}" attrs="{'readonly': [('state', '!=', 'draft')]}" default_focus="1"/>
<field name="product_id" context="{'default_detailed_type': 'product'}" attrs="{'readonly': [('state', '!=', 'draft')]}" default_focus="1"/>
<field name="product_tmpl_id" invisible="1"/>
<field name="forecasted_issue" invisible="1"/>
<field name="product_description_variants" attrs="{'invisible': [('product_description_variants', 'in', (False, ''))], 'readonly': [('state', '!=', 'draft')]}"/>
@@ -252,7 +252,7 @@
context="{'default_date': date_planned_start, 'default_date_deadline': date_deadline, 'default_location_id': location_src_id, 'default_location_dest_id': production_location_id, 'default_state': 'draft', 'default_raw_material_production_id': id, 'default_picking_type_id': picking_type_id, 'default_company_id': company_id}"
attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}" options="{'delete': [('state', '=', 'draft')]}">
<tree default_order="is_done,sequence" editable="bottom">
<field name="product_id" force_save="1" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '|', ('move_lines_count', '&gt;', 0), ('state', '=', 'cancel'), '&amp;', ('state', '!=', 'draft'), ('additional', '=', False) ]}"/>
<field name="product_id" force_save="1" required="1" context="{'default_detailed_type': 'product'}" attrs="{'readonly': ['|', '|', ('move_lines_count', '&gt;', 0), ('state', '=', 'cancel'), '&amp;', ('state', '!=', 'draft'), ('additional', '=', False) ]}"/>
<field name="location_id" string="From" readonly="1" groups="stock.group_stock_multi_locations" optional="show"/>
<field name="move_line_ids" invisible="1">
<tree>
@@ -331,7 +331,7 @@
<field name="move_byproduct_ids" context="{'default_date': date_planned_finished, 'default_date_deadline': date_deadline, 'default_location_id': production_location_id, 'default_location_dest_id': location_src_id, 'default_state': 'draft', 'default_production_id': id, 'default_picking_type_id': picking_type_id, 'default_company_id': company_id}" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}" options="{'delete': [('state', '=', 'draft')]}">
<tree default_order="is_done,sequence" decoration-muted="is_done" editable="bottom">
<field name="byproduct_id" invisible="1"/>
<field name="product_id" context="{'default_type': 'product'}" domain="[('id', '!=', parent.product_id)]" required="1"/>
<field name="product_id" context="{'default_detailed_type': 'product'}" domain="[('id', '!=', parent.product_id)]" required="1"/>
<field name="location_dest_id" string="To" readonly="1" groups="stock.group_stock_multi_locations"/>
<field name="move_line_ids" invisible="1">
+1 -1
View File
@@ -52,7 +52,7 @@
<field name="res_model">product.template</field>
<field name="search_view_id" ref="mrp_product_template_search_view"/>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{"search_default_consumable": 1, 'default_type': 'product'}</field>
<field name="context">{"search_default_consumable": 1, 'default_detailed_type': 'product'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No product found. Let's create one!
+1 -1
View File
@@ -27,7 +27,7 @@
<field
name="down_payment_product_id"
domain="[('type', '=', 'service'), '|', ('company_id', '=', company_id), ('company_id', '=', False)]"
context="{'default_type': 'service', 'default_taxes_id': False }"
context="{'default_detailed_type': 'service', 'default_taxes_id': False }"
/>
</div>
</div>
+12 -7
View File
@@ -55,7 +55,6 @@ class ProductTemplate(models.Model):
('consu', 'Consumable'),
('service', 'Service')
],
default='consu',
compute='_compute_type',
store=True,
readonly=False,
@@ -417,12 +416,12 @@ class ProductTemplate(models.Model):
for record in self:
record.type = type_mapping.get(record.detailed_type, record.detailed_type)
# @api.constrains('type', 'detailed_type')
# def _constrains_detailed_type(self):
# type_mapping = self._detailed_type_mapping()
# for record in self:
# if record.type != type_mapping.get(record.detailed_type, record.detailed_type):
# raise ValidationError(_("The Type of this product doesn't match the Detailed Type"))
@api.constrains('type', 'detailed_type')
def _constrains_detailed_type(self):
type_mapping = self._detailed_type_mapping()
for record in self:
if record.type != type_mapping.get(record.detailed_type, record.detailed_type):
raise ValidationError(_("The Type of this product doesn't match the Detailed Type"))
@api.constrains('uom_id', 'uom_po_id')
def _check_uom(self):
@@ -445,6 +444,12 @@ class ProductTemplate(models.Model):
return {}
def _sanitize_vals(self, vals):
"""Sanitize vales for writing/creating product templates and variants.
Values need to be sanitized to keep values synchronized, and to be able to preprocess the
vals in extensions of create/write.
:param vals: create/write values dictionary
"""
if 'type' in vals and 'detailed_type' not in vals:
if vals['type'] not in self.mapped('type'):
vals['detailed_type'] = vals['type']
@@ -147,7 +147,7 @@ class TestSaleMrpFlow(TransactionCase):
def _create_product(self, name, uom_id, routes=()):
p = Form(self.env['product.product'])
p.name = name
p.type = 'product'
p.detailed_type = 'product'
p.uom_id = uom_id
p.uom_po_id = uom_id
p.route_ids.clear()
@@ -419,7 +419,7 @@
Product used for down payments
</div>
<div class="text-muted">
<field name="deposit_default_product_id" context="{'default_type': 'service'}"/>
<field name="deposit_default_product_id" context="{'default_detailed_type': 'service'}"/>
</div>
</div>
</div>
+1 -1
View File
@@ -22,7 +22,7 @@
</record>
<record id="hr_expense.hr_expense_product" model="ir.actions.act_window">
<field name="context">{"default_can_be_expensed": 1, 'default_type': 'service',
<field name="context">{"default_can_be_expensed": 1, 'default_detailed_type': 'service',
'default_invoice_policy':'delivery', 'default_expense_policy' : 'cost'}</field>
</record>
@@ -32,7 +32,7 @@ class TestSaleMrpProcurement(TransactionCase):
product.categ_id = product_category_allproductssellable0
product.list_price = 200.0
product.name = 'Slider Mobile'
product.type = 'product'
product.detailed_type = 'product'
product.uom_id = uom_unit
product.uom_po_id = uom_unit
product.route_ids.clear()
+1 -1
View File
@@ -57,7 +57,7 @@ class ProductTemplate(models.Model):
if product.service_policy:
product.invoice_policy, product.service_type = SERVICE_TO_GENERAL.get(product.service_policy, (False, False))
@api.depends('service_tracking', 'service_policy')
@api.depends('service_tracking', 'service_policy', 'type')
def _compute_product_tooltip(self):
super()._compute_product_tooltip()
for record in self.filtered(lambda record: record.type == 'service'):
@@ -43,7 +43,7 @@
<field name="res_model">product.template</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="sale_timesheet.product_template_view_search_sale_timesheet"/>
<field name="context">{'search_default_services': 1, 'default_type': 'service'}</field>
<field name="context">{'search_default_services': 1, 'default_detailed_type': 'service'}</field>
</record>
</odoo>
@@ -33,7 +33,7 @@
<group>
<field name="display_create_order" invisible="1"/>
<field name="pricing_type" invisible="1" widget="radio"/>
<field name="timesheet_product_id" string="Default Service" invisible="1" context="{'default_type': 'service', 'default_service_policy': 'delivered_timesheet', 'default_service_type': 'timesheet'}"/>
<field name="timesheet_product_id" string="Default Service" invisible="1" context="{'default_detailed_type': 'service', 'default_service_policy': 'delivered_timesheet', 'default_service_type': 'timesheet'}"/>
<field name="sale_order_id" invisible="1" options="{'no_create': True, 'no_edit': True, 'delete': False, 'no_open': True}"/>
<field name="sale_line_id" string="Default Sales Order Item" options="{'no_create': True, 'no_edit': True, 'delete': False, 'no_open': True}"/>
</group>
+2 -2
View File
@@ -605,10 +605,10 @@ class ProductTemplate(models.Model):
help="This user will be responsible of the next activities related to logistic operations for this product.")
detailed_type = fields.Selection(selection_add=[
('product', 'Storable Product')
], tracking=True, ondelete={'product': 'set default'})
], tracking=True, ondelete={'product': 'set consu'})
type = fields.Selection(selection_add=[
('product', 'Storable Product')
], tracking=True, ondelete={'product': 'set default'})
], ondelete={'product': 'set consu'})
property_stock_production = fields.Many2one(
'stock.location', "Production Location",
company_dependent=True, check_company=True, domain="[('usage', '=', 'production'), '|', ('company_id', '=', False), ('company_id', '=', allowed_company_ids[0])]",
+1 -1
View File
@@ -457,7 +457,7 @@
<field name="res_model">product.template</field>
<field name="view_mode">kanban,tree,form</field>
<field name="search_view_id" ref="product_template_search_form_view_stock"/>
<field name="context">{"search_default_consumable": 1, 'default_type': 'product'}</field>
<field name="context">{"search_default_consumable": 1, 'default_detailed_type': 'product'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No product found. Let's create one!
+1 -1
View File
@@ -251,7 +251,7 @@
<field name="priority">1000</field>
<field name="arch" type="xml">
<tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done&gt;product_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id">
<field name="product_id" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', ('state', '=', 'done'), ('move_id', '!=', False)]}"/>
<field name="product_id" required="1" context="{'default_detailed_type': 'product'}" attrs="{'readonly': ['|', ('state', '=', 'done'), ('move_id', '!=', False)]}"/>
<field name="company_id" invisible="1"/>
<field name="move_id" invisible="1"/>
<field name="picking_id" invisible="1"/>
+1 -1
View File
@@ -375,7 +375,7 @@
<field name="product_uom_category_id" invisible="1"/>
<field name="has_tracking" invisible="1"/>
<field name="display_assign_serial" invisible="1"/>
<field name="product_id" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '&amp;', ('state', '!=', 'draft'), ('additional', '=', False), ('move_lines_count', '&gt;', 0)]}"/>
<field name="product_id" required="1" context="{'default_detailed_type': 'product'}" attrs="{'readonly': ['|', '&amp;', ('state', '!=', 'draft'), ('additional', '=', False), ('move_lines_count', '&gt;', 0)]}"/>
<field name="description_picking" string="Description" optional="hide"/>
<field name="date" invisible="1"/>
<field name="date_deadline" optional="hide"/>
@@ -31,7 +31,7 @@
</div>
<group name="main_group">
<group>
<field name="product_id" context="{'default_type': 'product', 'default_tracking': 'lot'}" readonly="context.get('set_product_readonly', False)" force_save="1" help="Product this lot/serial number contains. You cannot change it anymore if it has already been moved."/>
<field name="product_id" context="{'default_detailed_type': 'product', 'default_tracking': 'lot'}" readonly="context.get('set_product_readonly', False)" force_save="1" help="Product this lot/serial number contains. You cannot change it anymore if it has already been moved."/>
<label for="product_qty" attrs="{'invisible': [('display_complete', '=', False)]}"/>
<div class="o_row" attrs="{'invisible': [('display_complete', '=', False)]}">
<field name="product_qty"/>
+1 -1
View File
@@ -46,7 +46,7 @@
</div>
<group>
<group>
<field name="product_id" context="{'default_type': 'product'}"/>
<field name="product_id" context="{'default_detailed_type': 'product'}"/>
<label for="scrap_qty"/>
<div class="o_row">
<field name="scrap_qty"/>
@@ -847,9 +847,9 @@ class TestStockValuationChangeValuation(TestStockValuationCommon):
'property_stock_journal': self.stock_journal.id,
})
# Try to change the product category with a `default_type` key in the context and
# Try to change the product category with a `default_detailed_type` key in the context and
# check it doesn't break the account move generation.
self.product1.with_context(default_type='product').categ_id = cat2
self.product1.with_context(default_detailed_type='product').categ_id = cat2
self.assertEqual(self.product1.categ_id, cat2)
self.assertEqual(self.product1.value_svl, 100)
@@ -898,4 +898,3 @@ class TestStockValuationChangeValuation(TestStockValuationCommon):
# An accounting entry should only be created for the emptying now that the category is manual.
self.assertEqual(len(self.product1.stock_valuation_layer_ids.mapped('account_move_id')), 2)
self.assertEqual(len(self.product1.stock_valuation_layer_ids), 3)
@@ -26,7 +26,7 @@ class TestCrossdock(common.TransactionCase):
p_f = Form(self.env['product.template'])
p_f.name = 'PCE'
p_f.type = 'product'
p_f.detailed_type = 'product'
p_f.categ_id = self.env.ref('product.product_category_1')
p_f.list_price = 100.0
with p_f.seller_ids.new() as seller:
@@ -65,7 +65,7 @@
<tree string="Cost Lines" editable="bottom">
<field name="product_id"
domain="[('landed_cost_ok', '=', True)]"
context="{'default_landed_cost_ok': True, 'default_type': 'service'}"/>
context="{'default_landed_cost_ok': True, 'default_detailed_type': 'service'}"/>
<field name="name"/>
<field name="account_id" options="{'no_create': True}"/>
<field name="split_method"/>
@@ -60,7 +60,7 @@
<tree editable="top" decoration-muted="state == 'cancel'" string="Move Lines" default_order="location_id">
<field name="tracking" invisible="1"/>
<field name="state" invisible="1"/>
<field name="product_id" context="{'default_type': 'product'}" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="product_id" context="{'default_detailed_type': 'product'}" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="picking_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"
options="{'no_create_edit': True}" domain="[('id', 'in', parent.picking_ids)]"/>
<field name="lot_id" groups="stock.group_production_lot" attrs="{'readonly': [('tracking', 'not in', ['lot', 'serial'])]}"/>
@@ -11,8 +11,8 @@ class PricelistItem(models.Model):
msg = ''
if self.applied_on == '3_global' or self.applied_on == '2_product_category':
msg = _("A pricelist item with a positive min. quantity will not be applied to the event tickets products.")
elif ((self.applied_on == '1_product' and self.product_tmpl_id.type == 'event') or
(self.applied_on == '0_product_variant' and self.product_id.type == 'event')):
elif ((self.applied_on == '1_product' and self.product_tmpl_id.detailed_type == 'event') or
(self.applied_on == '0_product_variant' and self.product_id.detailed_type == 'event')):
msg = _("A pricelist item with a positive min. quantity cannot be applied to this event tickets product.")
if msg:
return {'warning':
+1 -1
View File
@@ -8,4 +8,4 @@ class Website(models.Model):
def sale_product_domain(self):
# remove product event from the website content grid and list view (not removed in detail view)
return ['&'] + super(Website, self).sale_product_domain() + [('type', '!=', 'event')]
return ['&'] + super(Website, self).sale_product_domain() + [('detailed_type', '!=', 'event')]
@@ -8,7 +8,7 @@
<xpath expr="//field[@name='enroll']" position="after">
<field name="product_id"
attrs="{'invisible': [('enroll', '!=', 'payment')], 'required': [('enroll', '=', 'payment')]}"
context="{'default_type': 'service', 'default_invoice_policy': 'order', 'default_purchase_ok': False, 'default_sale_ok': True, 'default_website_published': True}"/>
context="{'default_detailed_type': 'service', 'default_invoice_policy': 'order', 'default_purchase_ok': False, 'default_sale_ok': True, 'default_website_published': True}"/>
</xpath>
<xpath expr="//button[@name='action_redirect_to_members']" position="after">
<button name="action_view_sales"
+2 -2
View File
@@ -187,8 +187,8 @@
<group>
<group>
<span class="o_form_label o_td_label" name="address_name">
<field name="type" groups="base.group_no_one" attrs="{'invisible': [('is_company','=', True)], 'required': [('is_company','!=', True)], 'readonly': [('user_ids', '!=', [])]}" class="font-weight-bold"/>
<b class="position-absolute" attrs="{'invisible': [('is_company', '=', False)]}">Address</b>
<field name="type" attrs="{'invisible': [('is_company','=', True)], 'required': [('is_company','!=', True)], 'readonly': [('user_ids', '!=', [])]}" class="font-weight-bold"/>
<b attrs="{'invisible': [('is_company', '=', False)]}">Address</b>
</span>
<div class="o_address_format">
<field name="street" placeholder="Street..." class="o_address_street"