[IMP] tests: common.Form, can't write on invisible fields
In the web client, in a real use case, it's not possible to write on fields which are invisible, as it's not possible to write on fields which are readonly. This is a first step in the goal to change the behavior of the `groups=` attribute in the back-end views, to remove them for the view instead of making them invisible. This is mainly to reduce the diff of the revision that will introduce the mentioned above behavior change. As nodes with `groups=` will be removed from the view when the user doesn't have the group, it's no longer possible to set a value on a field having a `groups=` the user doesn't have in the `Form` test class, as the field will no longer be at all in the view. However, these unit tests shouldn't have been able to set values on invisible fields in the first place. This revision therefore aims to correct the unit tests setting value on fields which were invisible because the user executing the test was not part of the required group(s) for these fields to be visible in the view. closes odoo/odoo#94337 Related: odoo/enterprise#28936 Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This commit is contained in:
@@ -385,7 +385,14 @@ class AccountTestInvoicingCommon(TransactionCase):
|
||||
.with_company(company or cls.env.company) \
|
||||
.with_context(default_move_type=move_type, account_predictive_bills_disable_prediction=True))
|
||||
move_form.invoice_date = invoice_date or fields.Date.from_string('2019-01-01')
|
||||
move_form.date = move_form.invoice_date
|
||||
# According to the state or type of the invoice, the date field is sometimes visible or not
|
||||
# Besides, the date field can be put multiple times in the view
|
||||
# "invisible": "['|', ('state', '!=', 'draft'), ('auto_post', '!=', 'at_date')]"
|
||||
# "invisible": ['|', '|', ('state', '!=', 'draft'), ('auto_post', '=', 'no'), ('auto_post', '=', 'at_date')]
|
||||
# "invisible": "['&', ('move_type', 'in', ['out_invoice', 'out_refund', 'out_receipt']), ('quick_edit_mode', '=', False)]"
|
||||
# :TestAccountMoveOutInvoiceOnchanges, :TestAccountMoveOutRefundOnchanges, .test_00_debit_note_out_invoice, :TestAccountEdi
|
||||
if not move_form._get_modifier('date', 'invisible'):
|
||||
move_form.date = move_form.invoice_date
|
||||
move_form.partner_id = partner or cls.partner_a
|
||||
|
||||
for product in (products or []):
|
||||
|
||||
@@ -849,6 +849,8 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
})
|
||||
|
||||
def test_in_invoice_line_onchange_cash_rounding_1(self):
|
||||
# Required for `invoice_cash_rounding_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
|
||||
# Test 'add_invoice_line' rounding
|
||||
move_form = Form(self.invoice)
|
||||
# Add a cash rounding having 'add_invoice_line'.
|
||||
@@ -1193,6 +1195,12 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
})
|
||||
|
||||
def test_in_invoice_onchange_past_invoice_1(self):
|
||||
if self.env.ref('purchase.group_purchase_manager', raise_if_not_found=False):
|
||||
# `purchase` adds a view which makes `invoice_vendor_bill_id` invisible
|
||||
# for purchase users
|
||||
# https://github.com/odoo/odoo/blob/385884afd31f25d61e99d139ecd4c574d99a1863/addons/purchase/views/account_move_views.xml#L26
|
||||
self.env.user.groups_id -= self.env.ref('purchase.group_purchase_manager')
|
||||
self.env.user.groups_id -= self.env.ref('purchase.group_purchase_user')
|
||||
copy_invoice = self.invoice.copy()
|
||||
|
||||
move_form = Form(self.invoice)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=bad-whitespace
|
||||
from lxml import etree
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.tests.common import Form
|
||||
from odoo.tests import tagged
|
||||
@@ -533,6 +535,8 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon):
|
||||
})
|
||||
|
||||
def test_in_refund_line_onchange_cash_rounding_1(self):
|
||||
# Required for `invoice_cash_rounding_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
|
||||
# Test 'add_invoice_line' rounding
|
||||
move_form = Form(self.invoice)
|
||||
# Add a cash rounding having 'add_invoice_line'.
|
||||
@@ -878,6 +882,20 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon):
|
||||
|
||||
def test_in_refund_onchange_past_invoice_1(self):
|
||||
copy_invoice = self.invoice.copy()
|
||||
if self.env.ref('purchase.group_purchase_manager', raise_if_not_found=False):
|
||||
# `purchase` adds a view which makes `invoice_vendor_bill_id` invisible
|
||||
# for purchase users
|
||||
# https://github.com/odoo/odoo/blob/385884afd31f25d61e99d139ecd4c574d99a1863/addons/purchase/views/account_move_views.xml#L26
|
||||
self.env.user.groups_id -= self.env.ref('purchase.group_purchase_manager')
|
||||
self.env.user.groups_id -= self.env.ref('purchase.group_purchase_user')
|
||||
# 'invisible': ['|', ('state', '!=', 'draft'), ('move_type', '!=', 'in_invoice')]
|
||||
# This is an in_refund invoice, `invoice_vendor_bill_id` is not supposed to be visible
|
||||
# and therefore not supposed to be changed.
|
||||
view = self.env.ref('account.view_move_form')
|
||||
tree = etree.fromstring(view.arch)
|
||||
for node in tree.xpath('//field[@name="invoice_vendor_bill_id"]'):
|
||||
del node.attrib['attrs']
|
||||
view.arch = etree.tostring(tree)
|
||||
|
||||
move_form = Form(self.invoice)
|
||||
move_form.invoice_line_ids.remove(0)
|
||||
|
||||
@@ -1453,6 +1453,8 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
])
|
||||
|
||||
def test_out_invoice_line_onchange_cash_rounding_1(self):
|
||||
# Required for `invoice_cash_rounding_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
|
||||
# Test 'add_invoice_line' rounding
|
||||
move_form = Form(self.invoice)
|
||||
# Add a cash rounding having 'add_invoice_line'.
|
||||
@@ -1977,7 +1979,8 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
a custom reversal date.
|
||||
'''
|
||||
move_form = Form(self.invoice)
|
||||
move_form.date = '2016-01-01'
|
||||
# `date` is invisible in the view, the date of the invoice should be set using `invoice_date` instead
|
||||
move_form.invoice_date = '2016-01-01'
|
||||
move_form.currency_id = self.currency_data['currency']
|
||||
move_form.save()
|
||||
|
||||
@@ -3459,6 +3462,8 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
move_form.partner_id = self.partner_a
|
||||
|
||||
# Quick edit total amount not activated yet
|
||||
# As quick edit total is not yet activated, it's invisible by default in the view
|
||||
move_form._view['modifiers']['quick_edit_total_amount']['invisible'] = False
|
||||
move_form.quick_edit_total_amount = 100.0
|
||||
invoice = move_form.save()
|
||||
self.assertEqual(invoice.amount_total, 0.0)
|
||||
|
||||
@@ -532,6 +532,8 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon):
|
||||
})
|
||||
|
||||
def test_out_refund_line_onchange_cash_rounding_1(self):
|
||||
# Required for `invoice_cash_rounding_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
|
||||
# Test 'add_invoice_line' rounding
|
||||
move_form = Form(self.invoice)
|
||||
# Add a cash rounding having 'add_invoice_line'.
|
||||
|
||||
@@ -3536,6 +3536,8 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon):
|
||||
""" Test the CABA entries generated from an invoice with almost
|
||||
equal lines, different only on analytic accounting
|
||||
"""
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# Make the tax account reconcilable
|
||||
self.tax_account_1.reconcile = True
|
||||
|
||||
|
||||
@@ -200,10 +200,14 @@ class TestAccountPayment(AccountTestInvoicingCommon):
|
||||
|
||||
def test_payment_move_sync_onchange(self):
|
||||
|
||||
pay_form = Form(self.env['account.payment'].with_context(default_journal_id=self.company_data['default_journal_bank'].id))
|
||||
pay_form = Form(self.env['account.payment'].with_context(
|
||||
default_journal_id=self.company_data['default_journal_bank'].id,
|
||||
# The `partner_type` is set through the window action context in the web client
|
||||
# the field is otherwise invisible in the form.
|
||||
default_partner_type='customer',
|
||||
))
|
||||
pay_form.amount = 50.0
|
||||
pay_form.payment_type = 'inbound'
|
||||
pay_form.partner_type = 'customer'
|
||||
pay_form.partner_id = self.partner_a
|
||||
payment = pay_form.save()
|
||||
|
||||
@@ -246,8 +250,12 @@ class TestAccountPayment(AccountTestInvoicingCommon):
|
||||
|
||||
# ==== Check editing the account.payment ====
|
||||
|
||||
# `partner_type` on payment is always invisible. It's supposed to be set through a context `default_` key
|
||||
# In this case the goal of the test is to take an existing customer payment and change it to a supplier payment,
|
||||
# which is not supposed to be possible through the web interface.
|
||||
# So, change the payment partner_type beforehand rather than in the form view.
|
||||
payment.partner_type = 'supplier'
|
||||
pay_form = Form(payment)
|
||||
pay_form.partner_type = 'supplier'
|
||||
pay_form.currency_id = self.currency_data['currency']
|
||||
pay_form.partner_id = self.partner_a
|
||||
payment = pay_form.save()
|
||||
|
||||
@@ -73,7 +73,6 @@ class TestAccountInvoiceRounding(AccountTestInvoicingCommon):
|
||||
with Form(self.invoice) as move_form:
|
||||
move_form.invoice_payment_term_id = pay_term
|
||||
move_form.invoice_date = invoice_date
|
||||
move_form.date = invoice_date
|
||||
self.assertEqual(
|
||||
self.invoice.line_ids.filtered(
|
||||
lambda l: l.account_id == self.company_data['default_account_receivable']
|
||||
|
||||
+157
-147
@@ -287,105 +287,110 @@ class TestCRMLead(TestCrmCommon):
|
||||
phone and email fields. Phone especially has some corner cases due to
|
||||
automatic formatting (notably with onchange in form view). """
|
||||
lead, partner = self.lead_1.with_user(self.env.user), self.contact_2
|
||||
lead_form = Form(lead)
|
||||
# This is a type == 'lead', not a type == 'opportunity'
|
||||
# {'invisible': ['|', ('type', '=', 'opportunity'), ('is_partner_visible', '=', False)]}
|
||||
# lead.is_partner_visible = bool(lead.type == 'opportunity' or lead.partner_id or is_debug_mode)
|
||||
# Hence, debug mode required for `partner_id` to be visible
|
||||
with self.debug_mode():
|
||||
lead_form = Form(lead)
|
||||
|
||||
# reset partner phone to a local number and prepare formatted / sanitized values
|
||||
partner_phone, partner_mobile = self.test_phone_data[2], self.test_phone_data[1]
|
||||
partner_phone_formatted = phone_format(partner_phone, 'US', '1')
|
||||
partner_phone_sanitized = phone_format(partner_phone, 'US', '1', force_format='E164')
|
||||
partner_mobile_formatted = phone_format(partner_mobile, 'US', '1')
|
||||
partner_mobile_sanitized = phone_format(partner_mobile, 'US', '1', force_format='E164')
|
||||
partner_email, partner_email_normalized = self.test_email_data[2], self.test_email_data_normalized[2]
|
||||
self.assertEqual(partner_phone_formatted, '+1 202-555-0888')
|
||||
self.assertEqual(partner_phone_sanitized, self.test_phone_data_sanitized[2])
|
||||
self.assertEqual(partner_mobile_formatted, '+1 202-555-0999')
|
||||
self.assertEqual(partner_mobile_sanitized, self.test_phone_data_sanitized[1])
|
||||
# ensure initial data
|
||||
self.assertEqual(partner.phone, partner_phone)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
self.assertEqual(partner.email, partner_email)
|
||||
# reset partner phone to a local number and prepare formatted / sanitized values
|
||||
partner_phone, partner_mobile = self.test_phone_data[2], self.test_phone_data[1]
|
||||
partner_phone_formatted = phone_format(partner_phone, 'US', '1')
|
||||
partner_phone_sanitized = phone_format(partner_phone, 'US', '1', force_format='E164')
|
||||
partner_mobile_formatted = phone_format(partner_mobile, 'US', '1')
|
||||
partner_mobile_sanitized = phone_format(partner_mobile, 'US', '1', force_format='E164')
|
||||
partner_email, partner_email_normalized = self.test_email_data[2], self.test_email_data_normalized[2]
|
||||
self.assertEqual(partner_phone_formatted, '+1 202-555-0888')
|
||||
self.assertEqual(partner_phone_sanitized, self.test_phone_data_sanitized[2])
|
||||
self.assertEqual(partner_mobile_formatted, '+1 202-555-0999')
|
||||
self.assertEqual(partner_mobile_sanitized, self.test_phone_data_sanitized[1])
|
||||
# ensure initial data
|
||||
self.assertEqual(partner.phone, partner_phone)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
self.assertEqual(partner.email, partner_email)
|
||||
|
||||
# LEAD/PARTNER SYNC: email and phone are propagated to lead
|
||||
# as well as mobile (who does not trigger the reverse sync)
|
||||
lead_form.partner_id = partner
|
||||
self.assertEqual(lead_form.email_from, partner_email)
|
||||
self.assertEqual(lead_form.phone, partner_phone_formatted,
|
||||
'Lead: form automatically formats numbers')
|
||||
self.assertEqual(lead_form.mobile, partner_mobile_formatted,
|
||||
'Lead: form automatically formats numbers')
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
# LEAD/PARTNER SYNC: email and phone are propagated to lead
|
||||
# as well as mobile (who does not trigger the reverse sync)
|
||||
lead_form.partner_id = partner
|
||||
self.assertEqual(lead_form.email_from, partner_email)
|
||||
self.assertEqual(lead_form.phone, partner_phone_formatted,
|
||||
'Lead: form automatically formats numbers')
|
||||
self.assertEqual(lead_form.mobile, partner_mobile_formatted,
|
||||
'Lead: form automatically formats numbers')
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.phone, partner_phone,
|
||||
'Lead / Partner: partner values sent to lead')
|
||||
self.assertEqual(lead.email_from, partner_email,
|
||||
'Lead / Partner: partner values sent to lead')
|
||||
self.assertEqual(lead.email_normalized, partner_email_normalized,
|
||||
'Lead / Partner: equal emails should lead to equal normalized emails')
|
||||
self.assertEqual(lead.phone, partner_phone_formatted,
|
||||
'Lead / Partner: partner values (formatted) sent to lead')
|
||||
self.assertEqual(lead.mobile, partner_mobile_formatted,
|
||||
'Lead / Partner: partner values (formatted) sent to lead')
|
||||
self.assertEqual(lead.phone_sanitized, partner_mobile_sanitized,
|
||||
'Lead: phone_sanitized computed field on mobile')
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.phone, partner_phone,
|
||||
'Lead / Partner: partner values sent to lead')
|
||||
self.assertEqual(lead.email_from, partner_email,
|
||||
'Lead / Partner: partner values sent to lead')
|
||||
self.assertEqual(lead.email_normalized, partner_email_normalized,
|
||||
'Lead / Partner: equal emails should lead to equal normalized emails')
|
||||
self.assertEqual(lead.phone, partner_phone_formatted,
|
||||
'Lead / Partner: partner values (formatted) sent to lead')
|
||||
self.assertEqual(lead.mobile, partner_mobile_formatted,
|
||||
'Lead / Partner: partner values (formatted) sent to lead')
|
||||
self.assertEqual(lead.phone_sanitized, partner_mobile_sanitized,
|
||||
'Lead: phone_sanitized computed field on mobile')
|
||||
|
||||
# for email_from, if only formatting differs, warning should not appear and
|
||||
# email on partner should not be updated
|
||||
lead_form.email_from = '"Hermes Conrad" <%s>' % partner_email_normalized
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.email, partner_email)
|
||||
# for email_from, if only formatting differs, warning should not appear and
|
||||
# email on partner should not be updated
|
||||
lead_form.email_from = '"Hermes Conrad" <%s>' % partner_email_normalized
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.email, partner_email)
|
||||
|
||||
# for phone, if only formatting differs, warning should not appear and
|
||||
# phone on partner should not be updated
|
||||
lead_form.phone = partner_phone_sanitized
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.phone, partner_phone)
|
||||
# for phone, if only formatting differs, warning should not appear and
|
||||
# phone on partner should not be updated
|
||||
lead_form.phone = partner_phone_sanitized
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.phone, partner_phone)
|
||||
|
||||
# LEAD/PARTNER SYNC: lead updates partner
|
||||
new_email = '"John Zoidberg" <john.zoidberg@test.example.com>'
|
||||
new_email_normalized = 'john.zoidberg@test.example.com'
|
||||
lead_form.email_from = new_email
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
new_phone = '+1 202 555 7799'
|
||||
new_phone_formatted = phone_format(new_phone, 'US', '1')
|
||||
lead_form.phone = new_phone
|
||||
self.assertEqual(lead_form.phone, new_phone_formatted)
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
# LEAD/PARTNER SYNC: lead updates partner
|
||||
new_email = '"John Zoidberg" <john.zoidberg@test.example.com>'
|
||||
new_email_normalized = 'john.zoidberg@test.example.com'
|
||||
lead_form.email_from = new_email
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
new_phone = '+1 202 555 7799'
|
||||
new_phone_formatted = phone_format(new_phone, 'US', '1')
|
||||
lead_form.phone = new_phone
|
||||
self.assertEqual(lead_form.phone, new_phone_formatted)
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.email, new_email)
|
||||
self.assertEqual(partner.email_normalized, new_email_normalized)
|
||||
self.assertEqual(partner.phone, new_phone_formatted)
|
||||
lead_form.save()
|
||||
self.assertEqual(partner.email, new_email)
|
||||
self.assertEqual(partner.email_normalized, new_email_normalized)
|
||||
self.assertEqual(partner.phone, new_phone_formatted)
|
||||
|
||||
# LEAD/PARTNER SYNC: mobile does not update partner
|
||||
new_mobile = '+1 202 555 6543'
|
||||
new_mobile_formatted = phone_format(new_mobile, 'US', '1')
|
||||
lead_form.mobile = new_mobile
|
||||
lead_form.save()
|
||||
self.assertEqual(lead.mobile, new_mobile_formatted)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
# LEAD/PARTNER SYNC: mobile does not update partner
|
||||
new_mobile = '+1 202 555 6543'
|
||||
new_mobile_formatted = phone_format(new_mobile, 'US', '1')
|
||||
lead_form.mobile = new_mobile
|
||||
lead_form.save()
|
||||
self.assertEqual(lead.mobile, new_mobile_formatted)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
|
||||
# LEAD/PARTNER SYNC: reseting lead values also resets partner for email
|
||||
# and phone, but not for mobile
|
||||
lead_form.email_from, lead_form.phone, lead.mobile = False, False, False
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
lead_form.save()
|
||||
self.assertFalse(partner.email)
|
||||
self.assertFalse(partner.email_normalized)
|
||||
self.assertFalse(partner.phone)
|
||||
self.assertFalse(lead.phone)
|
||||
self.assertFalse(lead.mobile)
|
||||
self.assertFalse(lead.phone_sanitized)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
# if SMS is uninstalled, phone_sanitized is not available on partner
|
||||
if 'phone_sanitized' in partner:
|
||||
self.assertEqual(partner.phone_sanitized, partner_mobile_sanitized,
|
||||
'Partner sanitized should be computed on mobile')
|
||||
# LEAD/PARTNER SYNC: reseting lead values also resets partner for email
|
||||
# and phone, but not for mobile
|
||||
lead_form.email_from, lead_form.phone, lead.mobile = False, False, False
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
lead_form.save()
|
||||
self.assertFalse(partner.email)
|
||||
self.assertFalse(partner.email_normalized)
|
||||
self.assertFalse(partner.phone)
|
||||
self.assertFalse(lead.phone)
|
||||
self.assertFalse(lead.mobile)
|
||||
self.assertFalse(lead.phone_sanitized)
|
||||
self.assertEqual(partner.mobile, partner_mobile)
|
||||
# if SMS is uninstalled, phone_sanitized is not available on partner
|
||||
if 'phone_sanitized' in partner:
|
||||
self.assertEqual(partner.phone_sanitized, partner_mobile_sanitized,
|
||||
'Partner sanitized should be computed on mobile')
|
||||
|
||||
@users('user_sales_manager')
|
||||
def test_crm_lead_partner_sync_email_phone_corner_cases(self):
|
||||
@@ -401,69 +406,74 @@ class TestCRMLead(TestCrmCommon):
|
||||
'mobile': '',
|
||||
})
|
||||
|
||||
lead_form = Form(lead)
|
||||
self.assertEqual(lead_form.email_from, test_email)
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
# This is a type == 'lead', not a type == 'opportunity'
|
||||
# {'invisible': ['|', ('type', '=', 'opportunity'), ('is_partner_visible', '=', False)]}
|
||||
# lead.is_partner_visible = bool(lead.type == 'opportunity' or lead.partner_id or is_debug_mode)
|
||||
# Hence, debug mode required for `partner_id` to be visible
|
||||
with self.debug_mode():
|
||||
lead_form = Form(lead)
|
||||
self.assertEqual(lead_form.email_from, test_email)
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
|
||||
# email: False versus empty string
|
||||
lead_form.partner_id = contact
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.email_from = ''
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
lead_form.email_from = False
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
# email: False versus empty string
|
||||
lead_form.partner_id = contact
|
||||
self.assertTrue(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.email_from = ''
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
lead_form.email_from = False
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
|
||||
# phone: False versus empty string
|
||||
lead_form.phone = '+1 202-555-0888'
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
lead_form.phone = ''
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.phone = False
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
# phone: False versus empty string
|
||||
lead_form.phone = '+1 202-555-0888'
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
lead_form.phone = ''
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.phone = False
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
|
||||
# email/phone: formatting should not trigger ribbon
|
||||
lead.write({
|
||||
'email_from': '"My Name" <%s>' % test_email,
|
||||
'phone': '+1 202-555-0888',
|
||||
})
|
||||
contact.write({
|
||||
'email': '"My Name" <%s>' % test_email,
|
||||
'phone': '+1 202-555-0888',
|
||||
})
|
||||
# email/phone: formatting should not trigger ribbon
|
||||
lead.write({
|
||||
'email_from': '"My Name" <%s>' % test_email,
|
||||
'phone': '+1 202-555-0888',
|
||||
})
|
||||
contact.write({
|
||||
'email': '"My Name" <%s>' % test_email,
|
||||
'phone': '+1 202-555-0888',
|
||||
})
|
||||
|
||||
lead_form = Form(lead)
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.partner_id = contact
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.email_from = '"Another Name" <%s>' % test_email # same email normalized
|
||||
self.assertFalse(lead_form.partner_email_update, 'Formatting-only change should not trigger write')
|
||||
self.assertFalse(lead_form.partner_phone_update, 'Formatting-only change should not trigger write')
|
||||
lead_form.phone = '2025550888' # same number but another format
|
||||
self.assertFalse(lead_form.partner_email_update, 'Formatting-only change should not trigger write')
|
||||
self.assertFalse(lead_form.partner_phone_update, 'Formatting-only change should not trigger write')
|
||||
lead_form = Form(lead)
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.partner_id = contact
|
||||
self.assertFalse(lead_form.partner_email_update)
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
lead_form.email_from = '"Another Name" <%s>' % test_email # same email normalized
|
||||
self.assertFalse(lead_form.partner_email_update, 'Formatting-only change should not trigger write')
|
||||
self.assertFalse(lead_form.partner_phone_update, 'Formatting-only change should not trigger write')
|
||||
lead_form.phone = '2025550888' # same number but another format
|
||||
self.assertFalse(lead_form.partner_email_update, 'Formatting-only change should not trigger write')
|
||||
self.assertFalse(lead_form.partner_phone_update, 'Formatting-only change should not trigger write')
|
||||
|
||||
# wrong value are also propagated
|
||||
lead_form.phone = '666 789456789456789456'
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
# wrong value are also propagated
|
||||
lead_form.phone = '666 789456789456789456'
|
||||
self.assertTrue(lead_form.partner_phone_update)
|
||||
|
||||
# test country propagation allowing to correctly compute sanitized numbers
|
||||
# by adding missing relevant information from contact
|
||||
be_country = self.env.ref('base.be')
|
||||
contact.write({
|
||||
'country_id': be_country.id,
|
||||
'phone': '+32456001122',
|
||||
})
|
||||
lead.write({'country_id': False})
|
||||
lead_form = Form(lead)
|
||||
lead_form.partner_id = contact
|
||||
lead_form.phone = '0456 00 11 22'
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
self.assertEqual(lead_form.country_id, be_country)
|
||||
# test country propagation allowing to correctly compute sanitized numbers
|
||||
# by adding missing relevant information from contact
|
||||
be_country = self.env.ref('base.be')
|
||||
contact.write({
|
||||
'country_id': be_country.id,
|
||||
'phone': '+32456001122',
|
||||
})
|
||||
lead.write({'country_id': False})
|
||||
lead_form = Form(lead)
|
||||
lead_form.partner_id = contact
|
||||
lead_form.phone = '0456 00 11 22'
|
||||
self.assertFalse(lead_form.partner_phone_update)
|
||||
self.assertEqual(lead_form.country_id, be_country)
|
||||
|
||||
|
||||
@users('user_sales_manager')
|
||||
|
||||
@@ -46,6 +46,20 @@ class TestPartner(TestCrmCommon):
|
||||
|
||||
# test form tool
|
||||
partner_form = Form(self.env['res.partner'], 'base.view_partner_form')
|
||||
# `parent_id` is invisible when `is_company` is True (`company_type == 'company'`)
|
||||
# and parent_id is not set
|
||||
# So, set a temporary `parent_id` before setting the contact as company
|
||||
# to make `parent_id` visible in the interface while being a company
|
||||
# <field name="parent_id"
|
||||
# attrs="{
|
||||
# 'invisible': [
|
||||
# '|',
|
||||
# '&', ('is_company','=', True),('parent_id', '=', False),
|
||||
# ('company_name', '!=', False),('company_name', '!=', '')
|
||||
# ]
|
||||
# }"
|
||||
# />
|
||||
partner_form.parent_id = contact_company_1
|
||||
partner_form.company_type = 'company'
|
||||
partner_form.parent_id = contact_company
|
||||
partner_form.name = 'Mom Corp'
|
||||
|
||||
@@ -16,6 +16,8 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
|
||||
'name': 'Automatic Test',
|
||||
'time_type': 'leave',
|
||||
'requires_allocation': 'no',
|
||||
# Required for `request_unit_half` to be visible in the view
|
||||
'request_unit': 'half_day',
|
||||
})
|
||||
|
||||
def test_no_attendances(self):
|
||||
|
||||
@@ -271,6 +271,18 @@ class TestLeaveRequests(TestHrHolidaysCommon):
|
||||
leave_form.holiday_status_id = self.holidays_type_1
|
||||
leave_form.request_date_from = date(2019, 5, 6)
|
||||
leave_form.request_date_to = date(2019, 5, 6)
|
||||
# TODO: The test is wrong by modifying `date_from` and `date_to`, which are invisible
|
||||
# It should edit only `request_date_from` and `request_date_to` instead
|
||||
# And there is really a bug. Using the web client, when you put your PC in Auckland timezone,
|
||||
# and the admin preferences in Auckland Timezone
|
||||
# and create a time off for the current day, the computation is completely wrong
|
||||
# and compute the date to before the date from *-)
|
||||
# For instance, for a time-off from 06/16/2022 to 06/16/2022 (1 day) it computes
|
||||
# 06/16/2022 08:00:00 as date_from and 06/15/2022 17:00:00 as date_to
|
||||
# Bug reported to the rd-fun-vidange channel to the dev who introduced the bug
|
||||
# https://discord.com/channels/678381219515465750/687337760452902925/986918361768263710
|
||||
leave_form._view['modifiers']['date_from']['invisible'] = False
|
||||
leave_form._view['modifiers']['date_to']['invisible'] = False
|
||||
leave_form.date_from = datetime(2019, 5, 6, 0, 0, 0)
|
||||
leave_form.date_to = datetime(2019, 5, 6, 23, 59, 59)
|
||||
leave = leave_form.save()
|
||||
|
||||
@@ -111,9 +111,9 @@ class TestHrLeaveStressDays(TransactionCase):
|
||||
|
||||
with self.assertRaises(ValidationError), Form(self.env['hr.leave'].with_user(self.employee_user.id).with_context(default_employee_id=self.employee_emp.id)) as leave_form:
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.date_from = datetime(2021, 11, 1)
|
||||
leave_form.date_to = datetime(2021, 11, 1)
|
||||
leave_form.request_date_from = datetime(2021, 11, 1)
|
||||
leave_form.request_date_to = datetime(2021, 11, 1)
|
||||
self.assertFalse(leave_form.has_stress_day)
|
||||
|
||||
leave_form.date_to = datetime(2021, 11, 5)
|
||||
leave_form.request_date_to = datetime(2021, 11, 5)
|
||||
self.assertTrue(leave_form.has_stress_day)
|
||||
|
||||
@@ -17,6 +17,9 @@ class TestUBLCommon(AccountEdiTestCommon):
|
||||
def setUpClass(cls, chart_template_ref=None, edi_format_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
|
||||
|
||||
# Required for `product_uom_id` to be visible in the form views
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
|
||||
# Ensure the testing currency is using a valid ISO code.
|
||||
real_usd = cls.env.ref('base.USD')
|
||||
real_usd.name = 'FUSD'
|
||||
|
||||
@@ -122,8 +122,10 @@ class TestMailingListMerge(MassMailCommon):
|
||||
active_model='mailing.list'
|
||||
))
|
||||
merge_form.new_list_name = False
|
||||
merge_form.dest_list_id = self.mailing_list_3
|
||||
merge_form.merge_options = 'existing'
|
||||
# Need to set `merge_options` before `dest_lid_id` so `dest_list_id` is visible
|
||||
# `'invisible': [('merge_options', '=', 'new')]`
|
||||
merge_form.dest_list_id = self.mailing_list_3
|
||||
merge_form.archive_src_lists = False
|
||||
result_list = merge_form.save().action_mailing_lists_merge()
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class TestMrpCommon(common2.TestStockCommon):
|
||||
login='hilda',
|
||||
email='h.h@example.com',
|
||||
notification_type='inbox',
|
||||
groups='mrp.group_mrp_user, stock.group_stock_user, mrp.group_mrp_byproducts',
|
||||
groups='mrp.group_mrp_user, stock.group_stock_user, mrp.group_mrp_byproducts, uom.group_uom',
|
||||
)
|
||||
cls.user_mrp_manager = mail_new_test_user(
|
||||
cls.env,
|
||||
@@ -74,8 +74,11 @@ class TestMrpCommon(common2.TestStockCommon):
|
||||
login='gary',
|
||||
email='g.g@example.com',
|
||||
notification_type='inbox',
|
||||
groups='mrp.group_mrp_manager, stock.group_stock_user, mrp.group_mrp_byproducts',
|
||||
groups='mrp.group_mrp_manager, stock.group_stock_user, mrp.group_mrp_byproducts, uom.group_uom',
|
||||
)
|
||||
# Required for `product_uom_id` to be visible in the view
|
||||
# This class is used by a lot of tests which sets `product_uom_id` on `mrp.production`
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
|
||||
cls.workcenter_1 = cls.env['mrp.workcenter'].create({
|
||||
'name': 'Nuclear Workcenter',
|
||||
|
||||
@@ -85,6 +85,8 @@ class TestMrpProductionBackorder(TestMrpCommon):
|
||||
should be MO/001-02.
|
||||
Check that all MO are reachable through the procurement group.
|
||||
"""
|
||||
# Required for `manufacture_steps` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_adv_location")
|
||||
with Form(self.warehouse) as warehouse:
|
||||
warehouse.manufacture_steps = 'pbm'
|
||||
|
||||
@@ -128,6 +130,8 @@ class TestMrpProductionBackorder(TestMrpCommon):
|
||||
should be MO/001-02.
|
||||
Check that all MO are reachable through the procurement group.
|
||||
"""
|
||||
# Required for `manufacture_steps` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_adv_location")
|
||||
with Form(self.warehouse) as warehouse:
|
||||
warehouse.manufacture_steps = 'pbm_sam'
|
||||
production, _, product_to_build, product_to_use_1, product_to_use_2 = self.generate_mo(qty_base_1=4, qty_final=4, picking_type_id=self.warehouse.manu_type_id)
|
||||
|
||||
@@ -496,6 +496,8 @@ class TestBoM(TestMrpCommon):
|
||||
'name': 'Deserts Table'
|
||||
})
|
||||
|
||||
# Required to display `operation_ids` in the form view
|
||||
self.env.user.groups_id += self.env.ref("mrp.group_mrp_routings")
|
||||
with Form(bom_crumble) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = butter
|
||||
@@ -660,6 +662,8 @@ class TestBoM(TestMrpCommon):
|
||||
'name': 'Deserts Table'
|
||||
})
|
||||
|
||||
# Required to display `operation_ids` in the form view
|
||||
self.env.user.groups_id += self.env.ref("mrp.group_mrp_routings")
|
||||
with Form(bom_drawer) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = screw
|
||||
|
||||
@@ -134,6 +134,11 @@ class TestMrpMulticompany(common.TransactionCase):
|
||||
})
|
||||
mo_form = Form(self.env['mrp.production'].with_user(self.user_a))
|
||||
mo_form.product_id = product
|
||||
# The mo must be confirmed, no longer in draft, in order for `lot_producing_id` to be visible in the view
|
||||
# <div class="o_row" attrs="{'invisible': ['|', ('state', '=', 'draft'), ('product_tracking', 'in', ('none', False))]}">
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo_form = Form(mo)
|
||||
mo_form.lot_producing_id = lot_b
|
||||
mo = mo_form.save()
|
||||
with self.assertRaises(UserError):
|
||||
|
||||
@@ -339,6 +339,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
|
||||
def test_update_quantity_4(self):
|
||||
""" Workcenter 1 has 10' start time and 5' stop time """
|
||||
# Required for `workerorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
bom = self.env['mrp.bom'].create({
|
||||
'product_id': self.product_6.id,
|
||||
'product_tmpl_id': self.product_6.product_tmpl_id.id,
|
||||
@@ -517,6 +519,11 @@ class TestMrpOrder(TestMrpCommon):
|
||||
|
||||
self.assertEqual(production.move_raw_ids.mapped('manual_consumption'), [False, True, True])
|
||||
|
||||
# <field name="qty_producing" attrs="{'invisible': [('state', '=', 'draft')]}"/>
|
||||
production.action_confirm()
|
||||
production.action_assign()
|
||||
production.is_locked = False
|
||||
|
||||
# test no updating
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 5
|
||||
@@ -689,6 +696,11 @@ class TestMrpOrder(TestMrpCommon):
|
||||
|
||||
self.stock_shelf_2 = self.stock_location_14
|
||||
mo, _, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot', qty_base_1=10, qty_final=1)
|
||||
|
||||
# Required for `lot_producing_id` to be visible in the view
|
||||
# <field name="lot_producing_id" attrs="{'invisible': [('product_tracking', 'in', ('none', False))]}"/>
|
||||
p_final.tracking = 'lot'
|
||||
|
||||
self.assertEqual(len(mo), 1, 'MO should have been created')
|
||||
|
||||
first_lot_for_p1 = self.env['stock.lot'].create({
|
||||
@@ -999,6 +1011,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
byproduct3 none 1.0 dozen
|
||||
Check qty producing update and moves finished values.
|
||||
"""
|
||||
# Required for `byproduct_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_byproducts')
|
||||
dozen = self.env.ref('uom.product_uom_dozen')
|
||||
self.byproduct1 = self.env['product.product'].create({
|
||||
'name': 'Byproduct 1',
|
||||
@@ -2368,6 +2382,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
Create a second one in 10 minutes (expected should NOT go from 15 to 12.5, it should go from 15 to 10)
|
||||
"""
|
||||
# First production, the default is 60 and there is 0 productions of that operation
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
production_form = Form(self.env['mrp.production'])
|
||||
production_form.bom_id = self.bom_4
|
||||
production = production_form.save()
|
||||
@@ -2375,6 +2391,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production.action_confirm()
|
||||
production.button_plan()
|
||||
# Production planned, time to start, I produce all the 1 product
|
||||
# 'invisible': [('state', '=', 'draft')]
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 1
|
||||
with production_form.workorder_ids.edit(0) as wo:
|
||||
wo.duration = 15 # in 15 minutes
|
||||
@@ -2390,6 +2408,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production.action_confirm()
|
||||
production.button_plan()
|
||||
# Production planned, time to start, I produce all the 1 product
|
||||
# 'invisible': [('state', '=', 'draft')]
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 1
|
||||
with production_form.workorder_ids.edit(0) as wo:
|
||||
wo.duration = 10 # In 10 minutes this time
|
||||
@@ -2410,6 +2430,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
Test that when tracking the 2 last production, if we make one with under capacity, and one with normal capacity,
|
||||
the two are equivalent (1 done with capacity 2 in 10mn = 2 done with capacity 2 in 10mn)
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
production_form = Form(self.env['mrp.production'])
|
||||
production_form.bom_id = self.bom_5
|
||||
production = production_form.save()
|
||||
@@ -2417,6 +2439,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production.button_plan()
|
||||
|
||||
# Production planned, time to start, I produce all the 1 product
|
||||
# 'invisible': [('state', '=', 'draft')]
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 1
|
||||
with production_form.workorder_ids.edit(0) as wo:
|
||||
wo.duration = 10 # in 10 minutes
|
||||
@@ -2434,6 +2458,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production.action_confirm()
|
||||
production.button_plan()
|
||||
# Production planned, time to start, I produce all the 2 product
|
||||
# 'invisible': [('state', '=', 'draft')]
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 2
|
||||
with production_form.workorder_ids.edit(0) as wo:
|
||||
wo.duration = 10 # In 10 minutes this time
|
||||
@@ -2457,6 +2483,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
5 -> 30mn
|
||||
...
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
production_form = Form(self.env['mrp.production'])
|
||||
production_form.bom_id = self.bom_6
|
||||
production = production_form.save()
|
||||
@@ -2464,6 +2492,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production.button_plan()
|
||||
|
||||
# Production planned, time to start, I produce all the 1 product
|
||||
# 'invisible': [('state', '=', 'draft')]
|
||||
production_form = Form(production)
|
||||
production_form.qty_producing = 1
|
||||
with production_form.workorder_ids.edit(0) as wo:
|
||||
wo.duration = 10 # in 10 minutes
|
||||
@@ -2760,6 +2790,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
"""
|
||||
Check that the work order is started only once when clicking the start button several times.
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
production_form = Form(self.env['mrp.production'])
|
||||
production_form.bom_id = self.bom_2
|
||||
production_form.product_qty = 1
|
||||
@@ -2869,6 +2901,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
-> The user replans one of the WO: the warnings should disappear and the
|
||||
WO should be postponed.
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
mos = self.env['mrp.production']
|
||||
for _ in range(2):
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
@@ -2899,6 +2933,8 @@ class TestMrpOrder(TestMrpCommon):
|
||||
-> The user replans one of the WO: the warnings should disappear and the
|
||||
WO should be postponed.
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
mos = self.env['mrp.production']
|
||||
for _ in range(2):
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
|
||||
@@ -681,6 +681,8 @@ class TestProcurement(TestMrpCommon):
|
||||
This test ensures that, when running the scheduler, the generated MOs are based
|
||||
on the correct BoMs
|
||||
"""
|
||||
# Required for `picking_type_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
warehouse = self.env.ref('stock.warehouse0')
|
||||
|
||||
stock_location01 = warehouse.lot_stock_id
|
||||
|
||||
@@ -11,6 +11,10 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# Required for `uom_id` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
# Required for `manufacture_steps` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('stock.group_adv_location')
|
||||
# Create warehouse
|
||||
cls.customer_location = cls.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
||||
warehouse_form = Form(cls.env['stock.warehouse'])
|
||||
|
||||
@@ -107,6 +107,8 @@ class TestAnalyticAccount(TransactionCase):
|
||||
"""Test when workcenter and MO are using the same analytic account, no
|
||||
duplicated lines will be post.
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
# set wc analytic account to be the same of the one on the bom
|
||||
self.workcenter.costs_hour_account_id = self.analytic_account
|
||||
|
||||
@@ -147,6 +149,8 @@ class TestAnalyticAccount(TransactionCase):
|
||||
"""Test when workcenter and MO are using the same analytic account, no
|
||||
duplicated lines will be post.
|
||||
"""
|
||||
# Required for `workorder_ids` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
|
||||
# set wc analytic account to be different from the one on the bom
|
||||
wc_analytic_account = self.env['account.analytic.account'].create({'name': 'wc_analytic_account'})
|
||||
self.workcenter.costs_hour_account_id = wc_analytic_account
|
||||
|
||||
@@ -19,6 +19,8 @@ class TestBomPrice(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# Required for `product_uom_id ` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
cls.Product = cls.env['product.product']
|
||||
cls.Bom = cls.env['mrp.bom']
|
||||
|
||||
|
||||
@@ -160,6 +160,9 @@ class TestStockLandedCostsMrp(ValuationReconciliationTestCommon):
|
||||
man_order = man_order_form.save()
|
||||
man_order.action_confirm()
|
||||
# produce product
|
||||
# To edit `qty_producing`, the mo must no be draft. It's not thanks to the above `action_confirm()`
|
||||
# but the values of the form do not update automatically, it must be reloaded.
|
||||
man_order_form = Form(man_order)
|
||||
man_order_form.qty_producing = 1
|
||||
man_order_form.save()
|
||||
man_order.button_mark_done()
|
||||
|
||||
@@ -237,6 +237,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
|
||||
picking. Checks that the delivery and MO for its components are
|
||||
automatically created.
|
||||
"""
|
||||
# Required for `location_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
# Tick "manufacture" and MTO on self.comp2
|
||||
mto_route = self.env.ref('stock.route_warehouse0_mto')
|
||||
mto_route.active = True
|
||||
|
||||
@@ -1008,6 +1008,8 @@ class TestVariantsArchive(common.TestProductCommon):
|
||||
def test_uom_update_variant(self):
|
||||
""" Changing the uom on the template do not behave the same
|
||||
as changing on the product product."""
|
||||
# Required for `uom_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("uom.group_uom")
|
||||
units = self.env.ref('uom.product_uom_unit')
|
||||
cm = self.env.ref('uom.product_uom_cm')
|
||||
template = self.env['product.template'].create({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from contextlib import contextmanager
|
||||
from lxml import etree
|
||||
|
||||
from odoo.tests.common import TransactionCase, Form
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
@@ -257,10 +258,24 @@ class TestMultiCompanyProject(TestMultiCompanyCommon):
|
||||
|
||||
# set parent on existing orphan task; the onchange will set the correct company and subtask project
|
||||
self.task_2.write({'project_id': False})
|
||||
with Form(self.task_2) as task_form:
|
||||
task_form.name = 'Test Task 2 becomes child of Task 1 (other company)'
|
||||
task_form.parent_id = self.task_1
|
||||
task = task_form.save()
|
||||
# For `parent_id` to be visible in the view, you need
|
||||
# 1. The debug mode
|
||||
# 2. `allow_subtasks` to be true
|
||||
# <field name="parent_id" attrs="{'invisible': [('allow_subtasks', '=', False)]}" groups="base.group_no_one"/>
|
||||
# `allow_subtasks` is a related to `allow_subtasks` on the project
|
||||
# as the point of the test is to test the behavior of the task `_compute_project_id` when there is no project,
|
||||
# `allow_subtasks` is by default invisible, and you shouldn't therefore be able to change it.
|
||||
# So, to make it visible, temporary modify the view to make it visible even when `allow_subtasks` is `False`.
|
||||
view = self.env.ref('project.view_task_form2').sudo()
|
||||
tree = etree.fromstring(view.arch)
|
||||
for node in tree.xpath('//field[@name="parent_id"][@attrs]'):
|
||||
node.attrib.pop('attrs')
|
||||
view.arch = etree.tostring(tree)
|
||||
with self.debug_mode():
|
||||
with Form(self.task_2) as task_form:
|
||||
task_form.name = 'Test Task 2 becomes child of Task 1 (other company)'
|
||||
task_form.parent_id = self.task_1
|
||||
task = task_form.save()
|
||||
|
||||
self.assertEqual(task.company_id, task.project_id.company_id, "The company of the orphan subtask should be the one from its project.")
|
||||
|
||||
@@ -268,13 +283,28 @@ class TestMultiCompanyProject(TestMultiCompanyCommon):
|
||||
# set up default subtask project
|
||||
self.project_company_a.write({'allow_subtasks': True})
|
||||
|
||||
# For `parent_id` to be visible in the view, you need
|
||||
# 1. The debug mode
|
||||
# 2. `allow_subtasks` to be true
|
||||
# <field name="parent_id" attrs="{'invisible': [('allow_subtasks', '=', False)]}" groups="base.group_no_one"/>
|
||||
# `allow_subtasks` is a related to `allow_subtasks` on the project
|
||||
# as the point of the test is to test the behavior of the task `_compute_project_id` when there is no project,
|
||||
# `allow_subtasks` is by default invisible, and you shouldn't therefore be able to change it.
|
||||
# So, to make it visible, temporary modify the view to make it visible even when `allow_subtasks` is `False`.
|
||||
view = self.env.ref('project.view_task_form2').sudo()
|
||||
tree = etree.fromstring(view.arch)
|
||||
for node in tree.xpath('//field[@name="parent_id"][@attrs]'):
|
||||
node.attrib.pop('attrs')
|
||||
view.arch = etree.tostring(tree)
|
||||
|
||||
with self.sudo('employee-a'):
|
||||
with self.allow_companies([self.company_a.id, self.company_b.id]):
|
||||
with Form(self.env['project.task'].with_context({'tracking_disable': True})) as task_form:
|
||||
task_form.name = 'Test Subtask in company B'
|
||||
task_form.parent_id = self.task_1
|
||||
with self.debug_mode():
|
||||
with Form(self.env['project.task'].with_context({'tracking_disable': True})) as task_form:
|
||||
task_form.name = 'Test Subtask in company B'
|
||||
task_form.parent_id = self.task_1
|
||||
|
||||
task = task_form.save()
|
||||
task = task_form.save()
|
||||
|
||||
self.assertEqual(task.project_id, self.task_1.project_id, "The default project of a subtask should be the default subtask project of the project from the mother task")
|
||||
self.assertEqual(task.company_id, task.project_id.company_id, "The company of the orphan subtask should be the one from its project.")
|
||||
|
||||
@@ -465,6 +465,9 @@ class TestProjectrecurrence(TransactionCase):
|
||||
tasks = self.env['project.task'].search(domain)
|
||||
return tasks, len(tasks), len(tasks.filtered('parent_id'))
|
||||
|
||||
# Required for `child_ids` to be visible in the view
|
||||
# {'invisible': [('allow_subtasks', '=', False)]}
|
||||
self.project_recurring.allow_subtasks = True
|
||||
parent_task = self.env['project.task'].create({
|
||||
'name': 'Parent Task',
|
||||
'project_id': self.project_recurring.id
|
||||
@@ -558,6 +561,9 @@ class TestProjectrecurrence(TransactionCase):
|
||||
return len(tasks), len(tasks.filtered('parent_id'))
|
||||
|
||||
# Phase 0 : Initialize test case
|
||||
# Required for `child_ids` to be visible in the view
|
||||
# {'invisible': [('allow_subtasks', '=', False)]}
|
||||
self.project_recurring.allow_subtasks = True
|
||||
parent_task = self.env['project.task'].create({
|
||||
'name': 'Parent Task',
|
||||
'project_id': self.project_recurring.id
|
||||
|
||||
@@ -144,6 +144,10 @@ class TestProjectSharing(TestProjectSharingCommon):
|
||||
3.2) Create a sub-task
|
||||
3.3) Create a second sub-task
|
||||
"""
|
||||
# 0) Allow to create subtasks in the project tasks
|
||||
# Required for `child_ids` to be visible in the view
|
||||
# {'invisible': [('allow_subtasks', '=', False)]}
|
||||
self.project_cows.allow_subtasks = True
|
||||
# 1) Give the 'read' access mode to a portal user in a project and try to create task with this user.
|
||||
with self.assertRaises(AccessError, msg="Should not accept the portal user create a task in the project when he has not the edit access right."):
|
||||
with self.get_project_sharing_form_view(self.task_cow.with_context({'tracking_disable': True, 'default_project_id': self.project_cows.id}), self.user_portal) as form:
|
||||
|
||||
@@ -72,8 +72,10 @@ class TestProjectSubtasks(TestProjectCommon):
|
||||
"""
|
||||
form_views = self.env['ir.ui.view'].search([('model', '=', 'project.task'), ('type', '=', 'form')])
|
||||
for form_view in form_views:
|
||||
with Form(self.env['project.task'].with_context({'tracking_disable': True, 'default_project_id': self.project_pigs.id}), view=form_view) as task_form:
|
||||
task_form.name = 'Test Task 1'
|
||||
task_form = Form(self.env['project.task'].with_context({'tracking_disable': True, 'default_project_id': self.project_pigs.id, 'default_name': 'Test Task 1'}), view=form_view)
|
||||
# Some views have the `name` field invisible
|
||||
# As the goal is simply to test the default project field and not the name, we can skip setting the name
|
||||
# in the view and set it using `default_name` instead
|
||||
task = task_form.save()
|
||||
|
||||
self.assertEqual(task.project_id, self.project_pigs, "The project should be assigned from the default project, form_view name : %s." % form_view.name)
|
||||
@@ -148,27 +150,29 @@ class TestProjectSubtasks(TestProjectCommon):
|
||||
self.assertEqual(self.task_1.child_ids.display_project_id, self.project_goats, "Display Project of the task should be well assigned")
|
||||
self.assertEqual(self.task_1.child_ids.project_id, self.project_goats, "Changing display project id on a subtask should change project id")
|
||||
|
||||
# 6)
|
||||
with Form(self.task_1.child_ids.with_context({'tracking_disable': True})) as subtask_form:
|
||||
subtask_form.parent_id = self.env['project.task']
|
||||
orphan_subtask = subtask_form.save()
|
||||
# Debug mode required for `parent_id` to be visible in the view
|
||||
with self.debug_mode():
|
||||
# 6)
|
||||
with Form(self.task_1.child_ids.with_context({'tracking_disable': True})) as subtask_form:
|
||||
subtask_form.parent_id = self.env['project.task']
|
||||
orphan_subtask = subtask_form.save()
|
||||
|
||||
self.assertEqual(orphan_subtask.display_project_id, self.project_goats, "Display Project of the task should be well assigned")
|
||||
self.assertEqual(orphan_subtask.project_id, self.project_goats, "Changing display project id on a subtask should change project id")
|
||||
self.assertFalse(orphan_subtask.parent_id, "Parent should be false")
|
||||
self.assertEqual(orphan_subtask.display_project_id, self.project_goats, "Display Project of the task should be well assigned")
|
||||
self.assertEqual(orphan_subtask.project_id, self.project_goats, "Changing display project id on a subtask should change project id")
|
||||
self.assertFalse(orphan_subtask.parent_id, "Parent should be false")
|
||||
|
||||
# 7)
|
||||
with Form(self.task_1.with_context({'tracking_disable': True})) as task_form:
|
||||
with task_form.child_ids.new() as subtask_form:
|
||||
subtask_form.name = 'Test Subtask 1'
|
||||
subtask_form.display_project_id = self.project_goats
|
||||
with Form(self.task_1.child_ids.with_context({'tracking_disable': True})) as subtask_form:
|
||||
subtask_form.display_project_id = self.env['project.project']
|
||||
subtask_form.parent_id = self.env['project.task']
|
||||
orphan_subtask = subtask_form.save()
|
||||
# 7)
|
||||
with Form(self.task_1.with_context({'tracking_disable': True})) as task_form:
|
||||
with task_form.child_ids.new() as subtask_form:
|
||||
subtask_form.name = 'Test Subtask 1'
|
||||
subtask_form.display_project_id = self.project_goats
|
||||
with Form(self.task_1.child_ids.with_context({'tracking_disable': True})) as subtask_form:
|
||||
subtask_form.display_project_id = self.env['project.project']
|
||||
subtask_form.parent_id = self.env['project.task']
|
||||
orphan_subtask = subtask_form.save()
|
||||
|
||||
self.assertEqual(orphan_subtask.project_id, self.project_pigs, "Removing parent should not change project")
|
||||
self.assertEqual(orphan_subtask.display_project_id, self.project_pigs, "Removing parent should make the display project set as project.")
|
||||
self.assertEqual(orphan_subtask.project_id, self.project_pigs, "Removing parent should not change project")
|
||||
self.assertEqual(orphan_subtask.display_project_id, self.project_pigs, "Removing parent should make the display project set as project.")
|
||||
|
||||
def test_subtask_stage(self):
|
||||
"""
|
||||
|
||||
@@ -179,6 +179,8 @@ class TestPurchase(AccountTestInvoicingCommon):
|
||||
according to the product_qty. Also check product_qty or product_packaging
|
||||
are correctly calculated when one of them changed.
|
||||
"""
|
||||
# Required for `product_packaging_qty` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('product.group_stock_packaging')
|
||||
packaging_single = self.env['product.packaging'].create({
|
||||
'name': "I'm a packaging",
|
||||
'product_id': self.product_a.id,
|
||||
|
||||
@@ -304,6 +304,8 @@ class TestPurchaseToInvoice(AccountTestInvoicingCommon):
|
||||
""" Tests whether, when an analytic account rule is set, and user changes manually the analytic account on
|
||||
the po, it is the same that is mentioned in the bill.
|
||||
"""
|
||||
# Required for `analytic.group_analytic_accounting` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
analytic_account_default = self.env['account.analytic.account'].create({'name': 'default'})
|
||||
analytic_account_manual = self.env['account.analytic.account'].create({'name': 'manual'})
|
||||
|
||||
|
||||
@@ -41,7 +41,39 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
||||
f = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
f.invoice_date = f.date
|
||||
f.partner_id = po.partner_id
|
||||
f.purchase_id = po
|
||||
# <field name="invoice_vendor_bill_id" position="after">
|
||||
# <field name="purchase_id" invisible="1"/>
|
||||
# <label for="purchase_vendor_bill_id" string="Auto-Complete" class="oe_edit_only"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}" />
|
||||
# <field name="purchase_vendor_bill_id" nolabel="1"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}"
|
||||
# class="oe_edit_only"
|
||||
# domain="partner_id and [('company_id', '=', company_id), ('partner_id.commercial_partner_id', '=', commercial_partner_id)] or [('company_id', '=', company_id)]"
|
||||
# placeholder="Select a purchase order or an old bill"
|
||||
# context="{'show_total_amount': True}"
|
||||
# options="{'no_create': True, 'no_open': True}"/>
|
||||
# </field>
|
||||
# @api.onchange('purchase_vendor_bill_id', 'purchase_id')
|
||||
# def _onchange_purchase_auto_complete(self):
|
||||
# ...
|
||||
# elif self.purchase_vendor_bill_id.purchase_order_id:
|
||||
# self.purchase_id = self.purchase_vendor_bill_id.purchase_order_id
|
||||
# self.purchase_vendor_bill_id = False
|
||||
# purchase_vendor_bill_id = fields.Many2one('purchase.bill.union'
|
||||
# class PurchaseBillUnion(models.Model):
|
||||
# _name = 'purchase.bill.union'
|
||||
# ...
|
||||
# def init(self):
|
||||
# self.env.cr.execute("""
|
||||
# ...
|
||||
# SELECT
|
||||
# -id, name, ...
|
||||
# id as purchase_order_id
|
||||
# FROM purchase_order
|
||||
# ...
|
||||
# )""")
|
||||
# ...
|
||||
f.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-po.id)
|
||||
invoice = f.save()
|
||||
invoice.action_post()
|
||||
po.flush_model()
|
||||
|
||||
@@ -53,7 +53,7 @@ class TestValuationReconciliation(ValuationReconciliationTestCommon):
|
||||
move_form.invoice_date = date
|
||||
move_form.partner_id = self.partner_a
|
||||
move_form.currency_id = self.currency_data['currency']
|
||||
move_form.purchase_id = purchase_order
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-purchase_order.id)
|
||||
return move_form.save()
|
||||
|
||||
def test_shipment_invoice(self):
|
||||
|
||||
@@ -449,6 +449,8 @@ class TestCreatePicking(common.TestProductCommon):
|
||||
'Delivery deadline date should be changed.')
|
||||
|
||||
def test_07_differed_schedule_date(self):
|
||||
# Required for `reception_steps` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
warehouse = self.env['stock.warehouse'].search([], limit=1)
|
||||
|
||||
with Form(warehouse) as w:
|
||||
|
||||
@@ -27,6 +27,8 @@ class TestOnchangeProductId(TransactionCase):
|
||||
cls.supplierinfo_model = cls.env["product.supplierinfo"]
|
||||
|
||||
def test_onchange_product_id(self):
|
||||
# Required for `product_uom` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('uom.group_uom')
|
||||
|
||||
uom_id = self.product_uom_model.search([('name', '=', 'Units')])[0]
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
|
||||
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.partner_id = self.partner_a
|
||||
move_form.purchase_id = self.po
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-self.po.id)
|
||||
self.invoice = move_form.save()
|
||||
|
||||
self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [5.0, 5.0], 'Purchase: all products should be invoiced"')
|
||||
@@ -110,7 +110,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = self.partner_a
|
||||
move_form.purchase_id = self.po
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-self.po.id)
|
||||
self.invoice = move_form.save()
|
||||
self.invoice.action_post()
|
||||
|
||||
@@ -141,6 +141,13 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_refund'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = self.partner_a
|
||||
# Not supposed to see/change the purchase order of a refund invoice by default
|
||||
# <field name="purchase_id" invisible="1"/>
|
||||
# <label for="purchase_vendor_bill_id" string="Auto-Complete" class="oe_edit_only"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}" />
|
||||
# <field name="purchase_vendor_bill_id" nolabel="1"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}"
|
||||
move_form._view['modifiers']['purchase_id']['invisible'] = False
|
||||
move_form.purchase_id = self.po
|
||||
self.invoice = move_form.save()
|
||||
move_form = Form(self.invoice)
|
||||
|
||||
@@ -106,6 +106,8 @@ class TestReorderingRule(TransactionCase):
|
||||
- Increase the quantity on the PO, the extra quantity should follow the push rules and
|
||||
thus go to stock
|
||||
"""
|
||||
# Required for `warehouse_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
warehouse_1 = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1)
|
||||
subloc_1 = self.env['stock.location'].create({'name': 'subloc_1', 'location_id': warehouse_1.lot_stock_id.id})
|
||||
subloc_2 = self.env['stock.location'].create({'name': 'subloc_2', 'location_id': warehouse_1.lot_stock_id.id})
|
||||
@@ -216,6 +218,8 @@ class TestReorderingRule(TransactionCase):
|
||||
})
|
||||
|
||||
# create reordering rules
|
||||
# Required for `warehouse_id` to be visible in the view
|
||||
self.env['res.users'].browse(2).groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'].with_user(2))
|
||||
orderpoint_form.warehouse_id = warehouse_1
|
||||
orderpoint_form.location_id = outside_loc
|
||||
@@ -617,6 +621,8 @@ class TestReorderingRule(TransactionCase):
|
||||
If the user triggers each orderpoint separately, it should still produce two
|
||||
different purchase order lines (one for each orderpoint)
|
||||
"""
|
||||
# Required for `warehouse_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1)
|
||||
stock_location = warehouse.lot_stock_id
|
||||
sub_location = self.env['stock.location'].create({'name': 'subloc_1', 'location_id': stock_location.id})
|
||||
|
||||
@@ -382,7 +382,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = self.partner_id
|
||||
move_form.purchase_id = po1
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-po1.id)
|
||||
invoice_po1 = move_form.save()
|
||||
invoice_po1.action_post()
|
||||
|
||||
@@ -408,7 +408,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = self.partner_id
|
||||
move_form.purchase_id = po2
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-po2.id)
|
||||
invoice_po2 = move_form.save()
|
||||
invoice_po2.action_post()
|
||||
|
||||
@@ -433,6 +433,14 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_refund'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = self.partner_id
|
||||
|
||||
# Not supposed to see/change the purchase order of a refund invoice by default
|
||||
# <field name="purchase_id" invisible="1"/>
|
||||
# <label for="purchase_vendor_bill_id" string="Auto-Complete" class="oe_edit_only"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}" />
|
||||
# <field name="purchase_vendor_bill_id" nolabel="1"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}"
|
||||
move_form._view['modifiers']['purchase_id']['invisible'] = False
|
||||
move_form.purchase_id = po2
|
||||
with move_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.quantity = 10
|
||||
@@ -468,7 +476,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = order.partner_id
|
||||
move_form.purchase_id = order
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-order.id)
|
||||
with move_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.price_unit = 15.0
|
||||
invoice = move_form.save()
|
||||
@@ -1164,7 +1172,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
# Create an invoice with a different price and a discount
|
||||
invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
invoice_form.invoice_date = invoice_form.date
|
||||
invoice_form.purchase_id = order
|
||||
invoice_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-order.id)
|
||||
with invoice_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.price_unit = 100.0
|
||||
line_form.discount = 10.0
|
||||
@@ -1211,7 +1219,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
# Create an invoice with a different price and a discount
|
||||
invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
invoice_form.invoice_date = invoice_form.date
|
||||
invoice_form.purchase_id = order
|
||||
invoice_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-order.id)
|
||||
with invoice_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.tax_ids.clear()
|
||||
line_form.discount = 10.0
|
||||
@@ -1258,7 +1266,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
# Create an invoice with a different price and a discount
|
||||
invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
invoice_form.invoice_date = invoice_form.date
|
||||
invoice_form.purchase_id = order
|
||||
invoice_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-order.id)
|
||||
with invoice_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.price_unit = 100.0
|
||||
line_form.discount = 10.0
|
||||
|
||||
@@ -326,6 +326,8 @@ class TestRepair(AccountTestInvoicingCommon):
|
||||
"""Tests functionality of creating a repair directly from a return picking,
|
||||
i.e. repair can be made and defaults to appropriate return values. """
|
||||
# test return
|
||||
# Required for `location_dest_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
picking_form = Form(self.env['stock.picking'])
|
||||
picking_form.picking_type_id = self.stock_warehouse.return_type_id
|
||||
picking_form.partner_id = self.res_partner_1
|
||||
|
||||
@@ -35,6 +35,8 @@ class TestReInvoice(TestSaleCommon):
|
||||
)
|
||||
|
||||
def test_at_cost(self):
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
""" Test vendor bill at cost for product based on ordered and delivered quantities. """
|
||||
# create SO line and confirm SO (with only one line)
|
||||
sale_order_line1 = self.env['sale.order.line'].create({
|
||||
@@ -146,6 +148,8 @@ class TestReInvoice(TestSaleCommon):
|
||||
""" Test invoicing vendor bill at sales price for products based on delivered and ordered quantities. Check no existing SO line is incremented, but when invoicing a
|
||||
second time, increment only the delivered so line.
|
||||
"""
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# create SO line and confirm SO (with only one line)
|
||||
sale_order_line1 = self.env['sale.order.line'].create({
|
||||
'product_id': self.company_data['product_delivery_sales_price'].id,
|
||||
@@ -216,6 +220,8 @@ class TestReInvoice(TestSaleCommon):
|
||||
|
||||
def test_no_expense(self):
|
||||
""" Test invoicing vendor bill with no policy. Check nothing happen. """
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# confirm SO
|
||||
sale_order_line = self.env['sale.order.line'].create({
|
||||
'product_id': self.company_data['product_delivery_no'].id,
|
||||
|
||||
@@ -583,6 +583,8 @@ class TestSaleOrder(TestSaleCommon):
|
||||
according to the product_qty. Also check product_qty or product_packaging
|
||||
are correctly calculated when one of them changed.
|
||||
"""
|
||||
# Required for `product_packaging_qty` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('product.group_stock_packaging')
|
||||
partner = self.env['res.partner'].create({'name': "I'm a partner"})
|
||||
product_tmpl = self.env['product.template'].create({'name': "I'm a product"})
|
||||
product = product_tmpl.product_variant_id
|
||||
@@ -768,6 +770,8 @@ class TestSaleOrder(TestSaleCommon):
|
||||
self.assertEqual(line.untaxed_amount_to_invoice, line.price_subtotal)
|
||||
|
||||
def test_discount_and_amount_undiscounted(self):
|
||||
# Required for `discount` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('product.group_discount_per_so_line')
|
||||
"""When adding a discount on a SO line, this test ensures that amount undiscounted is
|
||||
consistent with the used tax"""
|
||||
sale_order = self.env['sale.order'].create({
|
||||
|
||||
@@ -444,6 +444,8 @@ class TestSaleToInvoice(TestSaleCommon):
|
||||
""" Tests whether, when an analytic account rule is set and the so has an analytic account,
|
||||
the default analytic acount doesn't replace the one from the so in the invoice.
|
||||
"""
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
analytic_account_default = self.env['account.analytic.account'].create({'name': 'default'})
|
||||
analytic_account_so = self.env['account.analytic.account'].create({'name': 'so'})
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ class TestMultistepManufacturing(TestMrpCommon):
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Required for `uom_id ` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
# Required for `manufacture_steps` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('stock.group_adv_location')
|
||||
|
||||
cls.env.ref('stock.route_warehouse0_mto').active = True
|
||||
cls.MrpProduction = cls.env['mrp.production']
|
||||
# Create warehouse
|
||||
|
||||
@@ -15,6 +15,8 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
# Required for `uom_id` to be visible in the view
|
||||
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
|
||||
cls.env.ref('stock.route_warehouse0_mto').active = True
|
||||
|
||||
# Useful models
|
||||
@@ -213,7 +215,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
|
||||
"""
|
||||
for comp in components:
|
||||
f = Form(self.env['stock.move'])
|
||||
f.name = 'Test Receipt Components'
|
||||
# <field name="name" invisible="1"/>
|
||||
f.location_id = self.env.ref('stock.stock_location_suppliers')
|
||||
f.location_dest_id = warehouse.lot_stock_id
|
||||
f.product_id = comp
|
||||
|
||||
@@ -17,7 +17,9 @@ class TestSaleMrpLeadTime(TestStockCommon):
|
||||
cls.env.ref('stock.route_warehouse0_mto').active = True
|
||||
# Update the product_1 with type, route, Manufacturing Lead Time and Customer Lead Time
|
||||
with Form(cls.product_1) as p1:
|
||||
p1.type = 'product'
|
||||
# `type` is invisible in the view,
|
||||
# and it's a compute field based on `detailed_type` which is the field visible in the view
|
||||
p1.detailed_type = 'product'
|
||||
p1.produce_delay = 5.0
|
||||
p1.sale_delay = 5.0
|
||||
p1.route_ids.clear()
|
||||
@@ -26,7 +28,9 @@ class TestSaleMrpLeadTime(TestStockCommon):
|
||||
|
||||
# Update the product_2 with type
|
||||
with Form(cls.product_2) as p2:
|
||||
p2.type = 'consu'
|
||||
# `type` is invisible in the view,
|
||||
# and it's a compute field based on `detailed_type` which is the field visible in the view
|
||||
p2.detailed_type = 'consu'
|
||||
|
||||
# Create Bill of materials for product_1
|
||||
with Form(cls.env['mrp.bom']) as bom:
|
||||
|
||||
@@ -10,6 +10,8 @@ from odoo.tools import mute_logger
|
||||
class TestSaleMrpProcurement(TransactionCase):
|
||||
|
||||
def test_sale_mrp(self):
|
||||
# Required for `uom_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('uom.group_uom')
|
||||
self.env.ref('stock.route_warehouse0_mto').active = True
|
||||
warehouse0 = self.env.ref('stock.warehouse0')
|
||||
# In order to test the sale_mrp module in OpenERP, I start by creating a new product 'Slider Mobile'
|
||||
@@ -77,6 +79,10 @@ class TestSaleMrpProcurement(TransactionCase):
|
||||
to avoid generating multiple deliveries
|
||||
to the customer location
|
||||
"""
|
||||
# Required for `uom_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('uom.group_uom')
|
||||
# Required for `manufacture_step` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
self.env.ref('stock.route_warehouse0_mto').active = True
|
||||
# Create warehouse
|
||||
self.customer_location = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
||||
|
||||
@@ -436,6 +436,12 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
||||
with Form(self.env['project.project'].with_context({'tracking_disable': True})) as project_form:
|
||||
project_form.name = 'Test Billable Project'
|
||||
project_form.allow_billable = True
|
||||
# `sale_line_employee_ids` is not visible if `partner_id` is not set
|
||||
# As the behavior of the test is to check the partner on the project
|
||||
# is set to the partner of the order line, temporary make the field visible
|
||||
# even if it's not the case in the reality, in the web client
|
||||
# {'invisible': ['|', ('allow_billable', '=', False), ('partner_id', '=', False)]}
|
||||
project_form._view['modifiers']['sale_line_employee_ids']['invisible'] = False
|
||||
with project_form.sale_line_employee_ids.new() as mapping_form:
|
||||
mapping_form.employee_id = self.employee_manager
|
||||
mapping_form.sale_line_id = self.so.order_line[:1]
|
||||
|
||||
@@ -52,6 +52,8 @@ class TestReInvoice(TestCommonSaleTimesheet):
|
||||
|
||||
def test_at_cost(self):
|
||||
""" Test vendor bill at cost for product based on ordered and delivered quantities. """
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# create SO line and confirm SO (with only one line)
|
||||
sale_order_line1 = self.env['sale.order.line'].create({
|
||||
'product_id': self.company_data['product_order_cost'].id,
|
||||
@@ -144,6 +146,8 @@ class TestReInvoice(TestCommonSaleTimesheet):
|
||||
""" Test invoicing vendor bill at sales price for products based on delivered and ordered quantities. Check no existing SO line is incremented, but when invoicing a
|
||||
second time, increment only the delivered so line.
|
||||
"""
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# create SO line and confirm SO (with only one line)
|
||||
sale_order_line1 = self.env['sale.order.line'].create({
|
||||
'product_id': self.company_data['product_delivery_sales_price'].id,
|
||||
@@ -231,6 +235,8 @@ class TestReInvoice(TestCommonSaleTimesheet):
|
||||
|
||||
def test_no_expense(self):
|
||||
""" Test invoicing vendor bill with no policy. Check nothing happen. """
|
||||
# Required for `analytic_account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
# confirm SO
|
||||
sale_order_line = self.env['sale.order.line'].create({
|
||||
'product_id': self.company_data['product_order_no'].id,
|
||||
|
||||
@@ -1176,6 +1176,8 @@ class StockMove(TransactionCase):
|
||||
"""Receive a package. Test the package will be move to a child location
|
||||
with correct storage category.
|
||||
"""
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_tracking_lot")
|
||||
# storage category
|
||||
storage_category = self.env['stock.storage.category'].create({
|
||||
'name': "storage category"
|
||||
@@ -1240,6 +1242,8 @@ class StockMove(TransactionCase):
|
||||
"""Receive package with same package type twice. Check putaway rule can
|
||||
be applied on the first one but not the second one due to no space.
|
||||
"""
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_tracking_lot")
|
||||
# storage category
|
||||
storage_category = self.env['stock.storage.category'].create({
|
||||
'name': "storage category"
|
||||
@@ -1341,6 +1345,8 @@ class StockMove(TransactionCase):
|
||||
only accept new product when empty. Check putaway rule can be applied on
|
||||
the first one but not the second one.
|
||||
"""
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_tracking_lot")
|
||||
# storage category
|
||||
storage_category = self.env['stock.storage.category'].create({
|
||||
'name': "storage category",
|
||||
@@ -1443,6 +1449,8 @@ class StockMove(TransactionCase):
|
||||
accept same product. Check putaway rule can be applied on the first one
|
||||
but not the second one.
|
||||
"""
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_tracking_lot")
|
||||
# storage category
|
||||
storage_category = self.env['stock.storage.category'].create({
|
||||
'name': "storage category",
|
||||
|
||||
@@ -2102,6 +2102,8 @@ class TestSinglePicking(TestStockCommon):
|
||||
self.assertEqual(delivery_order.show_mark_as_todo, False)
|
||||
|
||||
def test_owner_1(self):
|
||||
# Required for `owner_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref("stock.group_tracking_owner")
|
||||
"""Make a receipt, set an owner and validate"""
|
||||
owner1 = self.env['res.partner'].create({'name': 'owner'})
|
||||
receipt = self.env['stock.picking'].create({
|
||||
@@ -2169,7 +2171,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
), view='stock.view_picking_form')
|
||||
receipt_form.partner_id = partner
|
||||
receipt_form.picking_type_id = picking_type
|
||||
receipt_form.location_id = supplier_location
|
||||
# <field name="location_id" attrs="{'invisible': [('picking_type_code', '=', 'incoming')]}"
|
||||
receipt_form.location_dest_id = stock_location
|
||||
receipt = receipt_form.save()
|
||||
with receipt_form.move_line_nosuggest_ids.new() as move_line:
|
||||
|
||||
@@ -22,14 +22,20 @@ class TestMultiCompany(TransactionCase):
|
||||
cls.user_a = cls.env['res.users'].create({
|
||||
'name': 'user company a with access to company b',
|
||||
'login': 'user a',
|
||||
'groups_id': [(6, 0, [group_user.id, group_stock_manager.id])],
|
||||
'groups_id': [(6, 0, [
|
||||
group_user.id,
|
||||
group_stock_manager.id,
|
||||
])],
|
||||
'company_id': cls.company_a.id,
|
||||
'company_ids': [(6, 0, [cls.company_a.id, cls.company_b.id])]
|
||||
})
|
||||
cls.user_b = cls.env['res.users'].create({
|
||||
'name': 'user company b with access to company a',
|
||||
'login': 'user b',
|
||||
'groups_id': [(6, 0, [group_user.id, group_stock_manager.id])],
|
||||
'groups_id': [(6, 0, [
|
||||
group_user.id,
|
||||
group_stock_manager.id,
|
||||
])],
|
||||
'company_id': cls.company_b.id,
|
||||
'company_ids': [(6, 0, [cls.company_a.id, cls.company_b.id])]
|
||||
})
|
||||
@@ -218,6 +224,8 @@ class TestMultiCompany(TransactionCase):
|
||||
def test_orderpoint_1(self):
|
||||
"""As a user of company A, create an orderpoint for company B. Check itsn't possible to
|
||||
use a warehouse of companny A"""
|
||||
# Required for `warehouse_id` and `location_id` to be visible in the view
|
||||
self.user_a.groups_id += self.env.ref("stock.group_stock_multi_locations")
|
||||
product = self.env['product.product'].create({
|
||||
'type': 'product',
|
||||
'name': 'shared product',
|
||||
@@ -237,6 +245,8 @@ class TestMultiCompany(TransactionCase):
|
||||
"""As a user of Company A, check it is not possible to change the company on an existing
|
||||
orderpoint to Company B.
|
||||
"""
|
||||
# Required for `warehouse_id` and `location_id` to be visible in the view
|
||||
self.user_a.groups_id += self.env.ref("stock.group_stock_multi_locations")
|
||||
product = self.env['product.product'].create({
|
||||
'type': 'product',
|
||||
'name': 'shared product',
|
||||
|
||||
@@ -459,9 +459,17 @@ class TestPacking(TestPackingCommon):
|
||||
|
||||
# Cancels the internal transfer and creates a new one.
|
||||
internal_transfer.action_cancel()
|
||||
internal_form = Form(self.env['stock.picking'])
|
||||
# @api.depends('picking_type_id.show_operations')
|
||||
# def _compute_show_operations(self):
|
||||
# ...
|
||||
# if self.env.context.get('force_detailed_view'):
|
||||
# picking.show_operations = True
|
||||
internal_form = Form(self.env['stock.picking'].with_context(force_detailed_view=True))
|
||||
internal_form.picking_type_id = self.warehouse.int_type_id
|
||||
internal_form.location_id = self.warehouse.wh_input_stock_loc_id
|
||||
# The test specifically removes the ability to see the location fields
|
||||
# grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
# self.env.user.write({'groups_id': [(3, grp_multi_loc.id)]})
|
||||
# Hence, `internal_form.location_id` shouldn't be changed
|
||||
with internal_form.package_level_ids_details.new() as pack_line:
|
||||
pack_line.package_id = receipt_package.package_id
|
||||
internal_transfer = internal_form.save()
|
||||
@@ -598,9 +606,17 @@ class TestPacking(TestPackingCommon):
|
||||
|
||||
# Cancels the internal transfer and creates a new one.
|
||||
internal_transfer.action_cancel()
|
||||
internal_form = Form(self.env['stock.picking'])
|
||||
# @api.depends('picking_type_id.show_operations')
|
||||
# def _compute_show_operations(self):
|
||||
# ...
|
||||
# if self.env.context.get('force_detailed_view'):
|
||||
# picking.show_operations = True
|
||||
internal_form = Form(self.env['stock.picking'].with_context(force_detailed_view=True))
|
||||
internal_form.picking_type_id = self.warehouse.int_type_id
|
||||
internal_form.location_id = self.warehouse.wh_input_stock_loc_id
|
||||
# The test specifically removes the ability to see the location fields
|
||||
# grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
# self.env.user.write({'groups_id': [(3, grp_multi_loc.id)]})
|
||||
# Hence, `internal_form.location_id` shouldn't be changed
|
||||
with internal_form.package_level_ids_details.new() as pack_line:
|
||||
pack_line.package_id = receipt_package.package_id
|
||||
internal_transfer = internal_form.save()
|
||||
@@ -736,6 +752,11 @@ class TestPacking(TestPackingCommon):
|
||||
self.warehouse.delivery_steps = 'ship_only'
|
||||
package = self.env["stock.quant.package"].create({"name": "Src Pack"})
|
||||
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 100, package_id=package)
|
||||
# Required for `package_level_ids_details` to be visible in the view
|
||||
# <page string="Detailed Operations" attrs="{'invisible': [('show_operations', '=', False)]}">
|
||||
# <field name="package_level_ids_details"
|
||||
# attrs="{'invisible': ['|', ('picking_type_entire_packs', '=', False), ('show_operations', '=', False)]}"
|
||||
self.warehouse.out_type_id.show_operations = True
|
||||
self.warehouse.out_type_id.show_entire_packs = True
|
||||
picking = self.env['stock.picking'].create({
|
||||
'location_id': self.stock_location.id,
|
||||
@@ -791,7 +812,12 @@ class TestPacking(TestPackingCommon):
|
||||
move.product_id = self.productA
|
||||
move.product_uom_qty = 75
|
||||
picking.action_assign()
|
||||
with Form(picking) as picking_form:
|
||||
# @api.depends('picking_type_id.show_operations')
|
||||
# def _compute_show_operations(self):
|
||||
# ...
|
||||
# if self.env.context.get('force_detailed_view'):
|
||||
# picking.show_operations = True
|
||||
with Form(picking.with_context(force_detailed_view=True)) as picking_form:
|
||||
with picking_form.package_level_ids_details.new() as package_level:
|
||||
package_level.package_id = package
|
||||
with Form(picking) as picking_form:
|
||||
@@ -873,6 +899,12 @@ class TestPacking(TestPackingCommon):
|
||||
picking.action_put_in_pack()
|
||||
picking.button_validate()
|
||||
|
||||
# Required for `package_level_ids_details` to be visible in the view
|
||||
# <page string="Detailed Operations" attrs="{'invisible': [('show_operations', '=', False)]}">
|
||||
# <field name="package_level_ids_details"
|
||||
# attrs="{'invisible': ['|', ('picking_type_entire_packs', '=', False), ('show_operations', '=', False)]}"
|
||||
delivery_type.show_operations = True
|
||||
delivery_type.show_entire_packs = True
|
||||
picking, _, _ = create_picking(delivery_type, delivery_type.default_location_src_id, self.customer_location)
|
||||
packB = picking.package_level_ids[1]
|
||||
with Form(picking) as picking_form:
|
||||
@@ -938,6 +970,8 @@ class TestPacking(TestPackingCommon):
|
||||
self.productA.weight = 1.0
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_stock_storage_categories').id)]})
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_stock_multi_locations').id)]})
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_tracking_lot').id)]})
|
||||
|
||||
package_type = self.env['stock.package.type'].create({
|
||||
'name': "Super Pallet",
|
||||
@@ -1049,6 +1083,8 @@ class TestPacking(TestPackingCommon):
|
||||
self.productB.weight = 1.0
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_stock_storage_categories').id)]})
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_stock_multi_locations').id)]})
|
||||
# Required for `result_package_id` to be visible in the view
|
||||
self.env.user.write({'groups_id': [(4, self.env.ref('stock.group_tracking_lot').id)]})
|
||||
|
||||
package_type = self.env['stock.package.type'].create({
|
||||
'name': "Super Pallet",
|
||||
|
||||
@@ -110,6 +110,8 @@ class TestProcRule(TransactionCase):
|
||||
self.assertEqual(move_dest.date_deadline, new_deadline, msg='deadline date should be unchanged')
|
||||
|
||||
def test_reordering_rule_1(self):
|
||||
# Required for `location_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
warehouse = self.env['stock.warehouse'].search([], limit=1)
|
||||
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
|
||||
orderpoint_form.product_id = self.product
|
||||
@@ -156,6 +158,9 @@ class TestProcRule(TransactionCase):
|
||||
reordering rule (RR). Add extra product to already confirmed picking => automatically
|
||||
run another RR
|
||||
"""
|
||||
# Required for `location_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
||||
|
||||
self.productA = self.env['product.product'].create({
|
||||
'name': 'Desk Combination',
|
||||
'type': 'product',
|
||||
|
||||
@@ -1181,11 +1181,15 @@ class TestReports(TestReportsCommon):
|
||||
delivery_form.partner_id = self.partner
|
||||
delivery_form.picking_type_id = picking_type_by_date
|
||||
delivery_form.scheduled_date = datetime.now() + timedelta(days=5)
|
||||
delivery_form.priority = '1'
|
||||
with delivery_form.move_ids_without_package.new() as move_line:
|
||||
move_line.product_id = self.product
|
||||
move_line.product_uom_qty = 3
|
||||
delivery_by_date_priority = delivery_form.save()
|
||||
# <field name="priority" attrs="{'invisible': [('name','=','/')]}"/>
|
||||
# The priority field is not visible until the name is set,
|
||||
# which is done after a first save / the `create`
|
||||
delivery_form.priority = '1'
|
||||
delivery_by_date_priority = delivery_form.save()
|
||||
delivery_by_date_priority.action_confirm()
|
||||
|
||||
# 'at_confirm' reservation => reservation_date = today
|
||||
|
||||
@@ -536,6 +536,8 @@ class TestWarehouse(TestStockCommon):
|
||||
self.assertFalse(warehouse.pack_type_id.active)
|
||||
|
||||
def test_toggle_active_warehouse_2(self):
|
||||
# Required for `delivery_steps` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
wh = Form(self.env['stock.warehouse'])
|
||||
wh.name = "The attic of Willy"
|
||||
wh.code = "WIL"
|
||||
|
||||
@@ -1011,6 +1011,8 @@ class TestAngloSaxonAccounting(TestStockValuationCommon):
|
||||
"""
|
||||
When reversing an invoice that contains some anglo-saxo AML, the new anglo-saxo AML should have the same value
|
||||
"""
|
||||
# Required for `account_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_account_readonly')
|
||||
self.product1.categ_id.property_cost_method = 'average'
|
||||
|
||||
self._make_in_move(self.product1, 2, unit_cost=10)
|
||||
|
||||
@@ -67,6 +67,8 @@ class TestDropship(common.TransactionCase):
|
||||
self.assertAlmostEqual(pol2.product_qty, sol2.product_uom_qty)
|
||||
|
||||
def test_00_dropship(self):
|
||||
# Required for `route_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
|
||||
# Create a vendor
|
||||
supplier_dropship = self.env['res.partner'].create({'name': 'Vendor of Dropshipping test'})
|
||||
|
||||
@@ -10,6 +10,8 @@ from odoo.tests import tagged, common, Form
|
||||
class TestLifoPrice(ValuationReconciliationTestCommon):
|
||||
|
||||
def test_lifoprice(self):
|
||||
# Required for `uom_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('uom.group_uom')
|
||||
|
||||
# Set product category removal strategy as LIFO
|
||||
product_category_001 = self.env['product.category'].create({
|
||||
@@ -27,7 +29,18 @@ class TestLifoPrice(ValuationReconciliationTestCommon):
|
||||
product_form.name = 'LIFO Ice Cream'
|
||||
product_form.detailed_type = 'product'
|
||||
product_form.categ_id = product_category_001
|
||||
product_form.list_price = 100.0
|
||||
# <field name="list_price" position="attributes">
|
||||
# <attribute name="attrs">{'readonly': [('product_variant_count', '>', 1)]}</attribute>
|
||||
# <attribute name="invisible">1</attribute>
|
||||
# </field>
|
||||
# <field name="list_price" position="after">
|
||||
# <field name="lst_price" class="oe_inline" widget='monetary' options="{'currency_field': 'currency_id', 'field_digits': True}"/>
|
||||
# </field>
|
||||
# @api.onchange('lst_price')
|
||||
# def _set_product_lst_price(self):
|
||||
# ...
|
||||
# product.write({'list_price': value})
|
||||
product_form.lst_price = 100.0
|
||||
product_form.uom_id = self.env.ref('uom.product_uom_kgm')
|
||||
product_form.uom_po_id = self.env.ref('uom.product_uom_kgm')
|
||||
# these are not available (visible) in either product or variant
|
||||
@@ -78,9 +91,17 @@ class TestLifoPrice(ValuationReconciliationTestCommon):
|
||||
|
||||
# Let us send some goods
|
||||
self.company_data['default_warehouse'].out_type_id.show_operations = False
|
||||
out_form = Form(self.env['stock.picking'])
|
||||
# <field name="immediate_transfer" invisible="1"/>
|
||||
# def _get_action(self, action_xmlid):
|
||||
# ...
|
||||
# context = {
|
||||
# ...
|
||||
# 'default_immediate_transfer': default_immediate_tranfer,
|
||||
# ...
|
||||
# }
|
||||
# ...
|
||||
out_form = Form(self.env['stock.picking'].with_context(default_immediate_transfer=True))
|
||||
out_form.picking_type_id = self.company_data['default_warehouse'].out_type_id
|
||||
out_form.immediate_transfer = True
|
||||
with out_form.move_ids_without_package.new() as move:
|
||||
move.product_id = product_lifo_icecream
|
||||
move.quantity_done = 20.0
|
||||
|
||||
@@ -7,6 +7,10 @@ from odoo.tests import common, Form
|
||||
class TestProcurementException(common.TransactionCase):
|
||||
|
||||
def test_00_procurement_exception(self):
|
||||
# Required for `partner_invoice_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_delivery_invoice_address')
|
||||
# Required for `route_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('stock.group_adv_location')
|
||||
|
||||
res_partner_2 = self.env['res.partner'].create({'name': 'My Test Partner'})
|
||||
res_partner_address = self.env['res.partner'].create({
|
||||
@@ -17,7 +21,18 @@ class TestProcurementException(common.TransactionCase):
|
||||
# I create a product with no supplier define for it.
|
||||
product_form = Form(self.env['product.product'])
|
||||
product_form.name = 'product with no seller'
|
||||
product_form.list_price = 20.00
|
||||
# <field name="list_price" position="attributes">
|
||||
# <attribute name="attrs">{'readonly': [('product_variant_count', '>', 1)]}</attribute>
|
||||
# <attribute name="invisible">1</attribute>
|
||||
# </field>
|
||||
# <field name="list_price" position="after">
|
||||
# <field name="lst_price" class="oe_inline" widget='monetary' options="{'currency_field': 'currency_id', 'field_digits': True}"/>
|
||||
# </field>
|
||||
# @api.onchange('lst_price')
|
||||
# def _set_product_lst_price(self):
|
||||
# ...
|
||||
# product.write({'list_price': value})
|
||||
product_form.lst_price = 20.00
|
||||
product_form.categ_id = self.env.ref('product.product_category_1')
|
||||
product_with_no_seller = product_form.save()
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class TestStockValuation(ValuationReconciliationTestCommon):
|
||||
# create the vendor bill
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.partner_id = vendor1
|
||||
move_form.purchase_id = self.purchase_order1
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-self.purchase_order1.id)
|
||||
move_form.invoice_date = move_form.date
|
||||
for i in range(len(self.purchase_order1.order_line)):
|
||||
with move_form.invoice_line_ids.edit(i) as line_form:
|
||||
|
||||
@@ -409,7 +409,7 @@ class TestLandedCostsWithPurchaseAndInv(TestStockValuationLCCommon):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.invoice_date = move_form.date
|
||||
move_form.partner_id = order.partner_id
|
||||
move_form.purchase_id = order
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-order.id)
|
||||
move = move_form.save()
|
||||
move.action_post()
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from lxml import etree
|
||||
|
||||
from odoo import fields
|
||||
from odoo.addons.survey.tests import common
|
||||
@@ -17,6 +18,16 @@ class TestSurveyInvite(common.TestSurveyCommon):
|
||||
res = super(TestSurveyInvite, self).setUp()
|
||||
# by default signup not allowed
|
||||
self.env["ir.config_parameter"].set_param('auth_signup.invitation_scope', 'b2b')
|
||||
view = self.env.ref('survey.survey_invite_view_form').sudo()
|
||||
tree = etree.fromstring(view.arch)
|
||||
# Remove the invisible on `emails` to be able to test the onchange `_onchange_emails`
|
||||
# which raises an error when attempting to change `emails`
|
||||
# while the survey is set with `users_login_required` to True
|
||||
# By default, `<field name="emails"/>` is invisible when `survey_users_login_required` is True,
|
||||
# making it normally impossible to change by the user in the web client by default.
|
||||
# For tests `test_survey_invite_authentication_nosignup` and `test_survey_invite_token_internal`
|
||||
tree.xpath('//field[@name="emails"]')[0].attrib.pop('attrs')
|
||||
view.arch = etree.tostring(tree)
|
||||
return res
|
||||
|
||||
@users('survey_manager')
|
||||
|
||||
@@ -91,9 +91,12 @@ class TestCrmPerformance(CrmPerformanceCase):
|
||||
""" Test a single lead creation using Form with a partner """
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(user_sales_leads=189): # tcf only: 180 - com runbot: 172
|
||||
self.env.cr._now = self.reference_now # force create_date to check schedulers
|
||||
with Form(self.env['crm.lead']) as lead_form:
|
||||
lead_form.partner_id = self.partners[0]
|
||||
lead_form.name = 'Test Lead'
|
||||
with self.debug_mode():
|
||||
# {'invisible': ['|', ('type', '=', 'opportunity'), ('is_partner_visible', '=', False)]}
|
||||
# lead.is_partner_visible = bool(lead.type == 'opportunity' or lead.partner_id or is_debug_mode)
|
||||
with Form(self.env['crm.lead']) as lead_form:
|
||||
lead_form.partner_id = self.partners[0]
|
||||
lead_form.name = 'Test Lead'
|
||||
|
||||
_lead = lead_form.save()
|
||||
|
||||
|
||||
@@ -109,14 +109,17 @@ class TestEventPerformance(EventPerformanceCase):
|
||||
# no type, no website
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(event_user=206): # tef only: 179? - com runbot: 160
|
||||
self.env.cr._now = self.reference_now # force create_date to check schedulers
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.website_menu = False
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
_event = event_form.save()
|
||||
# Require for `website_menu` to be visible
|
||||
# <div name="event_menu_configuration" groups="base.group_no_one">
|
||||
with self.debug_mode():
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.website_menu = False
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
_event = event_form.save()
|
||||
|
||||
@users('event_user')
|
||||
@warmup
|
||||
@@ -127,14 +130,17 @@ class TestEventPerformance(EventPerformanceCase):
|
||||
# no type, website
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(event_user=671): # tef only: 638? - com runbot: 571 - ent runbot: 671
|
||||
self.env.cr._now = self.reference_now # force create_date to check schedulers
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.website_menu = True
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
_event = event_form.save()
|
||||
# Require for `website_menu` to be visible
|
||||
# <div name="event_menu_configuration" groups="base.group_no_one">
|
||||
with self.debug_mode():
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.website_menu = True
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
_event = event_form.save()
|
||||
|
||||
@users('event_user')
|
||||
@warmup
|
||||
@@ -146,13 +152,16 @@ class TestEventPerformance(EventPerformanceCase):
|
||||
# type and website
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(event_user=700): # tef only: 601 - com runbot: 604 - ent runbot: 700
|
||||
self.env.cr._now = self.reference_now # force create_date to check schedulers
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.event_type_id = event_type
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
# Require for `website_menu` to be visible
|
||||
# <div name="event_menu_configuration" groups="base.group_no_one">
|
||||
with self.debug_mode():
|
||||
with Form(self.env['event.event']) as event_form:
|
||||
event_form.name = 'Test Event'
|
||||
event_form.date_begin = self.reference_now + timedelta(days=1)
|
||||
event_form.date_end = self.reference_now + timedelta(days=5)
|
||||
event_form.event_type_id = event_type
|
||||
if has_social:
|
||||
event_form.social_menu = False
|
||||
|
||||
@users('event_user')
|
||||
@warmup
|
||||
|
||||
@@ -208,10 +208,9 @@ class TestActivityFlow(TestActivityCommon):
|
||||
'summary': 'Email Summary',
|
||||
})
|
||||
call_activity_type = ActivityType.create({'name': 'call'})
|
||||
with Form(self.env['mail.activity'].with_context(default_res_model_id=self.env['ir.model']._get_id('mail.test.activity'))) as ActivityForm:
|
||||
ActivityForm.res_model_id = self.env['ir.model']._get('mail.test.activity')
|
||||
ActivityForm.res_id = self.test_record.id
|
||||
|
||||
with Form(self.env['mail.activity'].with_context(default_res_model_id=self.env['ir.model']._get_id('mail.test.activity'), default_res_id=self.test_record.id)) as ActivityForm:
|
||||
# `res_model_id` and `res_id` are invisible, see view `mail.mail_activity_view_form_popup`
|
||||
# they must be set using defaults, see `action_feedback_schedule_next`
|
||||
ActivityForm.activity_type_id = call_activity_type
|
||||
# activity summary should be empty
|
||||
self.assertEqual(ActivityForm.summary, False)
|
||||
|
||||
@@ -12,6 +12,8 @@ class TestFormCreate(TransactionCase):
|
||||
"""
|
||||
|
||||
def test_create_res_partner(self):
|
||||
# Required for `property_account_payable_id`, `property_account_receivable_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_account_readonly')
|
||||
partner_form = Form(self.env['res.partner'])
|
||||
partner_form.name = 'a partner'
|
||||
# YTI: Clean that brol
|
||||
|
||||
@@ -121,7 +121,12 @@ class TestPartner(TransactionCase):
|
||||
self.env['res.partner'].with_context(default_lang='de_DE'),
|
||||
'base.view_partner_form'
|
||||
)
|
||||
partner_form.is_company = True
|
||||
# <field name="is_company" invisible="1"/>
|
||||
# <field name="company_type" widget="radio" options="{'horizontal': true}"/>
|
||||
# @api.onchange('company_type')
|
||||
# def onchange_company_type(self):
|
||||
# self.is_company = (self.company_type == 'company')
|
||||
partner_form.company_type = 'company'
|
||||
partner_form.name = "Test Company"
|
||||
self.assertEqual(partner_form.lang, 'de_DE', "New partner's lang should take default from context")
|
||||
with partner_form.child_ids.new() as child:
|
||||
|
||||
@@ -277,7 +277,9 @@ class TestUsers2(TransactionCase):
|
||||
user_groups_ids = [str(group_id) for group_id in sorted(user_groups.ids)]
|
||||
group_field_name = f"sel_groups_{'_'.join(user_groups_ids)}"
|
||||
|
||||
user_form = Form(self.env['res.users'], view='base.view_users_form')
|
||||
# <group col="4" attrs="{'invisible': [('sel_groups_1_9_10', '!=', 1)]}" groups="base.group_no_one" class="o_label_nowrap">
|
||||
with self.debug_mode():
|
||||
user_form = Form(self.env['res.users'], view='base.view_users_form')
|
||||
user_form.name = "Test"
|
||||
user_form.login = "Test"
|
||||
self.assertFalse(user_form.share)
|
||||
|
||||
+53
-5
@@ -52,6 +52,7 @@ from odoo import api
|
||||
from odoo.models import BaseModel
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.osv import expression
|
||||
from odoo.osv.expression import normalize_domain, TRUE_LEAF, FALSE_LEAF
|
||||
from odoo.service import security
|
||||
from odoo.sql_db import BaseCursor, Cursor
|
||||
@@ -438,6 +439,23 @@ class BaseCase(unittest.TestCase, metaclass=MetaCase):
|
||||
self.uid = old_uid
|
||||
self.env = self.env(user=self.uid)
|
||||
|
||||
@contextmanager
|
||||
def debug_mode(self):
|
||||
""" Enable the effects of group 'base.group_no_one'; mainly useful with :class:`Form`. """
|
||||
origin_user_has_groups = BaseModel.user_has_groups
|
||||
|
||||
def user_has_groups(self, groups):
|
||||
group_set = set(groups.split(','))
|
||||
if '!base.group_no_one' in group_set:
|
||||
return False
|
||||
elif 'base.group_no_one' in group_set:
|
||||
group_set.remove('base.group_no_one')
|
||||
return not group_set or origin_user_has_groups(self, ','.join(group_set))
|
||||
return origin_user_has_groups(self, groups)
|
||||
|
||||
with patch('odoo.models.BaseModel.user_has_groups', user_has_groups):
|
||||
yield
|
||||
|
||||
@contextmanager
|
||||
def _assertRaises(self, exception, *, msg=None):
|
||||
""" Context manager that clears the environment upon failure. """
|
||||
@@ -1935,19 +1953,46 @@ class Form(object):
|
||||
* pre-processed modifiers (map of modifier name to json-loaded domain)
|
||||
* pre-processed onchanges list
|
||||
"""
|
||||
inherited_modifiers = ['invisible']
|
||||
fvg['fields'].setdefault('id', {'type': 'id'})
|
||||
# pre-resolve modifiers & bind to arch toplevel
|
||||
modifiers = fvg['modifiers'] = {'id': {'required': False, 'readonly': True}}
|
||||
modifiers = fvg['modifiers'] = {'id': {'required': [FALSE_LEAF], 'readonly': [TRUE_LEAF]}}
|
||||
contexts = fvg['contexts'] = {}
|
||||
order = fvg['fields_ordered'] = []
|
||||
for f in fvg['tree'].xpath('.//field[count(ancestor::field) = %s]' % fvg['tree'].xpath('count(ancestor::field)')):
|
||||
field_level = fvg['tree'].xpath('count(ancestor::field)')
|
||||
for f in fvg['tree'].xpath('.//field[count(ancestor::field) = %s]' % field_level):
|
||||
fname = f.get('name')
|
||||
order.append(fname)
|
||||
|
||||
modifiers[fname] = {
|
||||
modifier: bool(domain) if isinstance(domain, int) else normalize_domain(domain)
|
||||
node_modifiers = {
|
||||
modifier: ([TRUE_LEAF] if domain else [FALSE_LEAF]) if isinstance(domain, int) else normalize_domain(domain)
|
||||
for modifier, domain in json.loads(f.get('modifiers', '{}')).items()
|
||||
}
|
||||
|
||||
for a in f.xpath('ancestor::*[@modifiers][count(ancestor::field) = %s]' % field_level):
|
||||
ancestor_modifiers = json.loads(a.get('modifiers'))
|
||||
for modifier in inherited_modifiers:
|
||||
if modifier in ancestor_modifiers:
|
||||
domain = ancestor_modifiers[modifier]
|
||||
ancestor_domain = ([TRUE_LEAF] if domain else [FALSE_LEAF]) if isinstance(domain, int) else normalize_domain(domain)
|
||||
node_domain = node_modifiers.get(modifier, [])
|
||||
# Combine the field modifiers with his ancestor modifiers with an OR connector
|
||||
# e.g. A field is invisible if its own invisible modifier is True
|
||||
# OR if one of its ancestor invisible modifier is True
|
||||
node_modifiers[modifier] = expression.OR([ancestor_domain, node_domain])
|
||||
|
||||
if fname in modifiers:
|
||||
# The field is multiple times in the view, combine the modifier domains with an AND connector
|
||||
# e.g. a field is invisible if all occurences of the field are invisible in the view.
|
||||
# e.g. a field is readonly if all occurences of the field are readonly in the view.
|
||||
for modifier in set(node_modifiers.keys()).union(modifiers[fname].keys()):
|
||||
modifiers[fname][modifier] = expression.AND([
|
||||
modifiers[fname].get(modifier, [FALSE_LEAF]),
|
||||
node_modifiers.get(modifier, [FALSE_LEAF]),
|
||||
])
|
||||
else:
|
||||
modifiers[fname] = node_modifiers
|
||||
|
||||
ctx = f.get('context')
|
||||
if ctx:
|
||||
contexts[fname] = ctx
|
||||
@@ -2096,9 +2141,10 @@ class Form(object):
|
||||
assert descr['type'] not in ('many2many', 'one2many'), \
|
||||
"Can't set an o2m or m2m field, manipulate the corresponding proxies"
|
||||
|
||||
# TODO: consider invisible to be the same as readonly?
|
||||
assert not self._get_modifier(field, 'readonly'), \
|
||||
"can't write on readonly field {}".format(field)
|
||||
assert not self._get_modifier(field, 'invisible'), \
|
||||
"can't write on invisible field {}".format(field)
|
||||
|
||||
if descr['type'] == 'many2one':
|
||||
assert isinstance(value, BaseModel) and value._name == descr['relation']
|
||||
@@ -2491,6 +2537,8 @@ class X2MProxy(object):
|
||||
def _assert_editable(self):
|
||||
assert not self._parent._get_modifier(self._field, 'readonly'),\
|
||||
'field %s is not editable' % self._field
|
||||
assert not self._parent._get_modifier(self._field, 'invisible'),\
|
||||
'field %s is not visible' % self._field
|
||||
|
||||
class O2MProxy(X2MProxy):
|
||||
""" O2MProxy()
|
||||
|
||||
Reference in New Issue
Block a user