diff --git a/addons/account/controllers/mail.py b/addons/account/controllers/mail.py
index 564856b909c..71c06faa44d 100644
--- a/addons/account/controllers/mail.py
+++ b/addons/account/controllers/mail.py
@@ -24,7 +24,7 @@ class MailController(MailController):
except AccessError:
if record_sudo.access_token and consteq(record_sudo.access_token, access_token):
record_action = record_sudo.with_context(
- force_website=True).get_access_action(uid)
+ force_website=True).get_access_action()
if record_action['type'] == 'ir.actions.act_url':
return werkzeug.utils.redirect(record_action['url'])
return super(MailController, cls)._redirect_to_record(model, res_id, access_token=access_token)
diff --git a/addons/account/models/account.py b/addons/account/models/account.py
index cc303ec1309..7179b7f05f9 100644
--- a/addons/account/models/account.py
+++ b/addons/account/models/account.py
@@ -177,6 +177,8 @@ class AccountAccount(models.Model):
@api.onchange('internal_type')
def onchange_internal_type(self):
self.reconcile = self.internal_type in ('receivable', 'payable')
+ if self.internal_type == 'liquidity':
+ self.reconcile = False
@api.onchange('code')
def onchange_code(self):
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 4baac419a5f..249480c0ee4 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1475,7 +1475,7 @@ class AccountInvoiceLine(models.Model):
ondelete='set null', index=True, oldname='uos_id')
product_id = fields.Many2one('product.product', string='Product',
ondelete='restrict', index=True)
- product_image = fields.Binary('Product Image', related="product_id.image", store=False)
+ product_image = fields.Binary('Product Image', related="product_id.image", store=False, readonly=True)
account_id = fields.Many2one('account.account', string='Account',
required=True, domain=[('deprecated', '=', False)],
default=_default_account,
diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml
index 40f01b1e1bc..c0aa8478ca1 100644
--- a/addons/account/views/account_view.xml
+++ b/addons/account/views/account_view.xml
@@ -22,8 +22,8 @@
| Description | diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 99aa3a2df2f..f21de36c28f 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -1193,6 +1193,7 @@ class MailThread(models.AbstractModel): # if a new thread is created, parent is irrelevant message_dict.pop('parent_id', None) thread = MessageModel.message_new(message_dict, custom_values) + thread_id = thread.id else: if thread_id: raise ValueError("Posting a message without model should be with a null res_id, to create a private message.") diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 59901756398..9ea923168a1 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -235,7 +235,7 @@ class MassMailingCampaign(models.Model): mass_mailing_ids = fields.One2many( 'mail.mass_mailing', 'mass_mailing_campaign_id', string='Mass Mailings') - unique_ab_testing = fields.Boolean(string='Allow A/B Testing', default=True, + unique_ab_testing = fields.Boolean(string='Allow A/B Testing', default=False, help='If checked, recipients will be mailed only once for the whole campaign. ' 'This lets you send different mailings to randomly selected recipients and test ' 'the effectiveness of the mailings, without causing duplicate messages.') diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 8eb6b272f24..c2211e894c7 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -465,7 +465,7 @@ class PosOrder(models.Model): def _filtered_for_reconciliation(self): filter_states = ['invoiced', 'done'] - if self.env['ir.config_parameter'].get_param('point_of_sale.order_reconcile_mode', 'all') == 'partner_only': + if self.env['ir.config_parameter'].sudo().get_param('point_of_sale.order_reconcile_mode', 'all') == 'partner_only': return self.filtered(lambda order: order.state in filter_states and order.partner_id) return self.filtered(lambda order: order.state in filter_states) diff --git a/addons/point_of_sale/tests/test_anglo_saxon.py b/addons/point_of_sale/tests/test_anglo_saxon.py index b6d27af9505..8bc642ab7ce 100644 --- a/addons/point_of_sale/tests/test_anglo_saxon.py +++ b/addons/point_of_sale/tests/test_anglo_saxon.py @@ -36,9 +36,13 @@ class TestAngloSaxonCommon(common.TransactionCase): self.product = self.product.copy({'name': 'New product','standard_price': 100}) self.company.anglo_saxon_accounting = True self.product.categ_id = self.category + self.product.property_account_expense_id = account_expense + self.product.property_account_income_id = self.account sale_journal = self.env['account.journal'].create({'name': 'POS journal', 'type': 'sale', 'code': 'POS00'}) self.pos_config.journal_id = sale_journal self.cash_journal = self.env['account.journal'].create({'name': 'CASH journal', 'type': 'cash', 'code': 'CSH00'}) + self.pos_config.invoice_journal_id = False + self.pos_config.journal_ids = [self.cash_journal.id] class TestAngloSaxonFlow(TestAngloSaxonCommon): diff --git a/addons/portal/controllers/mail.py b/addons/portal/controllers/mail.py index 89dbded3676..1abf05b4e63 100644 --- a/addons/portal/controllers/mail.py +++ b/addons/portal/controllers/mail.py @@ -37,7 +37,7 @@ def _message_post_helper(res_model='', res_id=None, message='', token='', nosubs access_as_sudo = _has_token_access(res_model, res_id, token=token) if access_as_sudo: record = record.sudo() - if request.env.user == request.env.ref('base.public_user'): + if request.env.user._is_public(): author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id else: if not author_id: diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 525fed94200..98d1e3392c5 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -123,6 +123,7 @@ class ProductProduct(models.Model): image_medium = fields.Binary( "Medium-sized image", compute='_compute_images', inverse='_set_image_medium', help="Image of the product variant (Medium-sized image of product template if false).") + is_product_variant = fields.Boolean(compute='_compute_is_product_variant') standard_price = fields.Float( 'Cost', company_dependent=True, @@ -150,6 +151,10 @@ class ProductProduct(models.Model): def _get_invoice_policy(self): return False + def _compute_is_product_variant(self): + for product in self: + product.is_product_variant = True + def _compute_product_price(self): prices = {} pricelist_id_or_name = self._context.get('pricelist') diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 34fc7b6f978..c4566a7d981 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -239,10 +239,7 @@ class ProductTemplate(models.Model): def _compute_is_product_variant(self): for template in self: - if template._name == 'product.template': - template.is_product_variant = False - else: - template.is_product_variant = True + template.is_product_variant = False @api.model def _get_weight_uom_id_from_ir_config_parameter(self): diff --git a/addons/product/tests/common.py b/addons/product/tests/common.py index cc812db81a2..559b8b9dcfa 100644 --- a/addons/product/tests/common.py +++ b/addons/product/tests/common.py @@ -36,6 +36,7 @@ class TestProductCommon(common.SavepointCase): cls.product_1 = Product.create({ 'name': 'Courage', 'type': 'consu', + 'default_code': 'PROD-1', 'uom_id': cls.uom_dunit.id, 'uom_po_id': cls.uom_dunit.id}) diff --git a/addons/product/tests/test_variants.py b/addons/product/tests/test_variants.py index 804bbc55c95..92ca4522566 100644 --- a/addons/product/tests/test_variants.py +++ b/addons/product/tests/test_variants.py @@ -60,6 +60,14 @@ class TestVariants(common.TestProductCommon): self.size_attr_value_l = self.env['product.attribute.value'].create({'name': 'L', 'attribute_id': self.size_attr.id}) return res + def test_variants_is_product_variant(self): + template = self.product_7_template + variants = template.product_variant_ids + self.assertFalse(template.is_product_variant, + 'Product template is not a variant') + self.assertEqual({True}, set(v.is_product_variant for v in variants), + 'Product variants are variants') + def test_variants_creation_mono(self): test_template = self.env['product.template'].create({ 'name': 'Sofa', diff --git a/addons/project/models/project.py b/addons/project/models/project.py index abfee026479..896e972f6d5 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -271,7 +271,9 @@ class Project(models.Model): def map_tasks(self, new_project_id): """ copy and map tasks from old to new project """ tasks = self.env['project.task'] - for task in self.tasks: + # We want to copy archived task, but do not propagate an active_test context key + task_ids = self.env['project.task'].with_context(active_test=False).search([('project_id', '=', self.id)]).ids + for task in self.env['project.task'].browse(task_ids): # preserve task name and stage, normally altered during copy defaults = {'stage_id': task.stage_id.id, 'name': task.name} @@ -283,7 +285,6 @@ class Project(models.Model): def copy(self, default=None): if default is None: default = {} - self = self.with_context(active_test=False) if not default.get('name'): default['name'] = _("%s (copy)") % (self.name) project = super(Project, self).copy(default) diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 8d85df10b3d..7b524b9513a 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -731,7 +731,7 @@
|---|