def test_onchange_specific(self): """ test the effect of field-specific onchange method """ discussion = self.env.ref('test_new_api.discussion_0') demo = self.user_demo field_onchange = self.Discussion._onchange_spec() self.assertEqual(field_onchange.get('moderator'), '1') self.assertItemsEqual( strip_prefix('participants.', field_onchange), ['display_name'], ) # first remove demo user from participants discussion.participants -= demo self.assertNotIn(demo, discussion.participants) # check that demo_user is added to participants when set as moderator values = { 'name': discussion.name, 'moderator': demo.id, 'categories': [Command.link(cat.id) for cat in discussion.categories], 'messages': [Command.link(msg.id) for msg in discussion.messages], 'participants': [Command.link(usr.id) for usr in discussion.participants], } self.env.cache.invalidate() result = discussion.onchange(values, 'moderator', field_onchange) self.assertIn('participants', result['value']) self.assertItemsEqual( result['value']['participants'], [Command.clear()] + [Command.link(user.id) for user in discussion.participants + demo], )
def test_50_environment(self): """ Test environment on records. """ # partners and reachable records are attached to self.env partners = self.env['res.partner'].search([('name', 'ilike', 'j'), ('id', 'in', self.partners.ids)]) self.assertEqual(partners.env, self.env) for x in (partners, partners[0], partners[0].company_id): self.assertEqual(x.env, self.env) for p in partners: self.assertEqual(p.env, self.env) # check that the current user can read and modify company data partners[0].company_id.name partners[0].company_id.write({'name': 'Fools'}) # create an environment with a demo user demo = self.env['res.users'].create({ 'name': 'test_environment_demo', 'login': '******', 'password': '******', }) demo_env = self.env(user=demo) self.assertNotEqual(demo_env, self.env) # partners and related records are still attached to self.env self.assertEqual(partners.env, self.env) for x in (partners, partners[0], partners[0].company_id): self.assertEqual(x.env, self.env) for p in partners: self.assertEqual(p.env, self.env) # create record instances attached to demo_env demo_partners = partners.with_user(demo) self.assertEqual(demo_partners.env, demo_env) for x in (demo_partners, demo_partners[0], demo_partners[0].company_id): self.assertEqual(x.env, demo_env) for p in demo_partners: self.assertEqual(p.env, demo_env) # demo user can read but not modify company data demo_partner = self.env['res.partner'].search([ ('name', '=', 'Landon Roberts') ]).with_user(demo) self.assertTrue(demo_partner.company_id, 'This partner is supposed to be linked to a company') demo_partner.company_id.name with self.assertRaises(AccessError): demo_partner.company_id.write({'name': 'Pricks'}) # remove demo user from all groups demo.write({'groups_id': [Command.clear()]}) # demo user can no longer access partner data with self.assertRaises(AccessError): demo_partner.company_id.name
def test_many2many(self): """ Test assignment of many2many field where rules apply. """ ids = [self.id1, self.id2] # create container as superuser, connected to all some_objs container_admin = self.env['test_access_right.container'].create({'some_ids': [Command.set(ids)]}) self.assertItemsEqual(container_admin.some_ids.ids, ids) # check the container as the public user container_user = container_admin.with_user(self.browse_ref('base.public_user')) container_user.invalidate_cache(['some_ids']) self.assertItemsEqual(container_user.some_ids.ids, [self.id1]) # this should not fail container_user.write({'some_ids': [Command.set(ids)]}) container_user.invalidate_cache(['some_ids']) self.assertItemsEqual(container_user.some_ids.ids, [self.id1]) container_admin.invalidate_cache(['some_ids']) self.assertItemsEqual(container_admin.some_ids.ids, ids) # this removes all records container_user.write({'some_ids': [Command.clear()]}) container_user.invalidate_cache(['some_ids']) self.assertItemsEqual(container_user.some_ids.ids, []) container_admin.invalidate_cache(['some_ids']) self.assertItemsEqual(container_admin.some_ids.ids, [])
def test_onchange_editable_compute_one2many(self): # create a record with a computed editable field ('edit') on lines record = self.env['test_new_api.compute_editable'].create({'line_ids': [(0, 0, {'value': 7})]}) self.env.flush_all() line = record.line_ids self.assertRecordValues(line, [{'value': 7, 'edit': 7, 'count': 0}]) # retrieve the onchange spec for calling 'onchange' spec = Form(record)._view['onchange'] # The onchange on 'line_ids' should increment 'count' and keep the value # of 'edit' (this field should not be recomputed), whatever the order of # the fields in the dictionary. This ensures that the value set by the # user on a computed editable field on a line is not lost. line_ids = [ Command.update(line.id, {'value': 8, 'edit': 9, 'count': 0}), Command.create({'value': 8, 'edit': 9, 'count': 0}), ] result = record.onchange({'line_ids': line_ids}, 'line_ids', spec) expected = {'value': { 'line_ids': [ Command.clear(), Command.update(line.id, {'value': 8, 'edit': 9, 'count': 8}), Command.create({'value': 8, 'edit': 9, 'count': 8}), ], }} self.assertEqual(result, expected) # change dict order in lines, and try again line_ids = [ (op, id_, dict(reversed(list(vals.items())))) for op, id_, vals in line_ids ] result = record.onchange({'line_ids': line_ids}, 'line_ids', spec) self.assertEqual(result, expected)
def test_20_crud_create(self): # Do: create a new record in another model self.action.write({ 'state': 'object_create', 'crud_model_id': self.res_country_model.id, 'link_field_id': False, 'fields_lines': [ Command.clear(), Command.create({ 'col1': self.res_country_name_field.id, 'value': 'record.name', 'evaluation_type': 'equation' }), Command.create({ 'col1': self.res_country_code_field.id, 'value': 'record.name[0:2]', 'evaluation_type': 'equation' }) ], }) run_res = self.action.with_context(self.context).run() self.assertFalse( run_res, 'ir_actions_server: create record action correctly finished should return False' ) # Test: new country created country = self.test_country.search([('name', 'ilike', 'TestingPartner') ]) self.assertEqual(len(country), 1, 'ir_actions_server: TODO') self.assertEqual(country.code, 'TE', 'ir_actions_server: TODO')
def test_onchange_one2many_with_domain_on_related_field(self): """ test the value of the one2many field when defined with a domain on a related field""" discussion = self.env.ref('test_new_api.discussion_0') demo = self.user_demo # mimic UI behaviour, so we get subfields # (we need at least subfield: 'important_emails.important') view_info = self.Discussion.get_view(self.env.ref('test_new_api.discussion_form').id, 'form') field_onchange = self.Discussion._onchange_spec(view_info=view_info) self.assertEqual(field_onchange.get('messages'), '1') BODY = "What a beautiful day!" USER = self.env.user # create standalone email email = self.EmailMessage.create({ 'discussion': discussion.id, 'name': "[%s] %s" % ('', USER.name), 'body': BODY, 'author': USER.id, 'important': False, 'email_to': demo.email, }) # check if server-side cache is working correctly self.env.cache.invalidate() self.assertIn(email, discussion.emails) self.assertNotIn(email, discussion.important_emails) email.important = True self.assertIn(email, discussion.important_emails) # check that when trigger an onchange, we don't reset important emails # (force `invalidate` as but appear in onchange only when we get a cache # miss) self.env.cache.invalidate() self.assertEqual(len(discussion.messages), 4) values = { 'name': "Foo Bar", 'moderator': demo.id, 'categories': [Command.link(cat.id) for cat in discussion.categories], 'messages': [Command.link(msg.id) for msg in discussion.messages], 'participants': [Command.link(usr.id) for usr in discussion.participants], 'important_messages': [Command.link(msg.id) for msg in discussion.important_messages], 'important_emails': [Command.link(eml.id) for eml in discussion.important_emails], } self.env.cache.invalidate() result = discussion.onchange(values, 'name', field_onchange) self.assertEqual( result['value']['important_emails'], [Command.clear(), Command.update(email.id, { 'name': u'[Foo Bar] %s' % USER.name, 'body': BODY, 'author': USER.name_get()[0], 'size': len(BODY), 'important': True, 'email_to': demo.email, })], )
def test_08_purchases_multi_linkages(self): """Directly link POs to each other as 'Alternatives': check linking/unlinking POs that are already linked correctly work.""" pos = [] for _ in range(5): pos += self.env['purchase.order'].create({ 'partner_id': self.res_partner_1.id, }).ids pos = self.env['purchase.order'].browse(pos) po_1, po_2, po_3, po_4, po_5 = pos po_1.alternative_po_ids |= po_2 po_3.alternative_po_ids |= po_4 groups = self.env['purchase.order.group'].search([('order_ids', 'in', pos.ids)]) self.assertEqual(len(po_1.alternative_po_ids), 2, "PO1 and PO2 should only be linked to each other") self.assertEqual(len(po_3.alternative_po_ids), 2, "PO3 and PO4 should only be linked to each other") self.assertEqual( len(groups), 2, "There should only be 2 groups: (PO1,PO2) and (PO3,PO4)") # link non-linked PO to already linked PO po_5.alternative_po_ids |= po_4 groups = self.env['purchase.order.group'].search([('order_ids', 'in', pos.ids)]) self.assertEqual(len(po_3.alternative_po_ids), 3, "PO3 should now be linked to PO4 and PO5") self.assertEqual(len(po_4.alternative_po_ids), 3, "PO4 should now be linked to PO3 and PO5") self.assertEqual(len(po_5.alternative_po_ids), 3, "PO5 should now be linked to PO3 and PO4") self.assertEqual( len(groups), 2, "There should only be 2 groups: (PO1,PO2) and (PO3,PO4,PO5)") # link already linked PO to already linked PO po_5.alternative_po_ids |= po_1 groups = self.env['purchase.order.group'].search([('order_ids', 'in', pos.ids)]) self.assertEqual(len(po_1.alternative_po_ids), 5, "All 5 POs should be linked to each other now") self.assertEqual( len(groups), 1, "There should only be 1 group containing all 5 POs (other group should have auto-deleted" ) # remove all links, make sure group auto-deletes (pos - po_5).alternative_po_ids = [Command.clear()] groups = self.env['purchase.order.group'].search([('order_ids', 'in', pos.ids)]) self.assertEqual( len(po_5.alternative_po_ids), 0, "Last PO should auto unlink from itself since group should have auto-deleted" ) self.assertEqual(len(groups), 0, "The group should have auto-deleted")
def test_write_base_one2many_with_constraint(self): """ Write on one2many field with lines being deleted and created. """ rec = self.env['test_performance.base'].create({'name': 'Y'}) rec.write({'line_ids': [Command.create({'value': val}) for val in range(12)]}) # This write() will raise because of the unique index if the unlink() is # not performed before the create() rec.write({'line_ids': [Command.clear()] + [Command.create({'value': val}) for val in range(6)]}) self.assertEqual(len(rec.line_ids), 6)
def _compute_outbound_payment_method_line_ids(self): for journal in self: pay_method_line_ids_commands = [Command.clear()] if journal.type in ('bank', 'cash'): default_methods = journal._default_outbound_payment_methods() pay_method_line_ids_commands += [Command.create({ 'name': pay_method.name, 'payment_method_id': pay_method.id, }) for pay_method in default_methods] journal.outbound_payment_method_line_ids = pay_method_line_ids_commands
def test_name_search_with_sudo(self): """Check that _name_search return correct values with sudo """ no_access_user = self.env['res.users'].create({ 'login': '******', 'name': 'no_access', 'groups_id': [Command.clear()], }) document = self.env['test_access_right.ticket'].with_user(no_access_user) res = document.sudo().name_search('Need help here') #Invalide cache in case the name is already there #and will not trigget check_access_rights when #the name_get will access the name self.document.invalidate_cache(fnames=['name']) self.assertEqual(res[0][1], "Need help here")
def _compute_suitable_payment_token_ids(self): for wizard in self: if wizard.can_edit_wizard and wizard.use_electronic_payment_method: related_partner_ids = ( wizard.partner_id | wizard.partner_id.commercial_partner_id | wizard.partner_id.commercial_partner_id.child_ids )._origin wizard.suitable_payment_token_ids = self.env['payment.token'].sudo().search([ ('company_id', '=', wizard.company_id.id), ('acquirer_id.capture_manually', '=', False), ('partner_id', 'in', related_partner_ids.ids), ('acquirer_id.journal_id', '=', wizard.journal_id.id), ]) else: wizard.suitable_payment_token_ids = [Command.clear()]
def _compute_suitable_payment_token_ids(self): for payment in self: related_partner_ids = ( payment.partner_id | payment.partner_id.commercial_partner_id | payment.partner_id.commercial_partner_id.child_ids)._origin if payment.use_electronic_payment_method: payment.suitable_payment_token_ids = self.env[ 'payment.token'].sudo().search([ ('company_id', '=', payment.company_id.id), ('acquirer_id.capture_manually', '=', False), ('partner_id', 'in', related_partner_ids.ids), ('acquirer_id.journal_id', '=', payment.journal_id.id), ]) else: payment.suitable_payment_token_ids = [Command.clear()]
def test_01_account_tour(self): # Reset country and fiscal country, so that fields added by localizations are # hidden and non-required, and don't make the tour crash. # Also remove default taxes from the company and its accounts, to avoid inconsistencies # with empty fiscal country. self.env.company.write({ 'country_id': None, # Also resets account_fiscal_country_id 'account_sale_tax_id': None, 'account_purchase_tax_id': None, }) account_with_taxes = self.env['account.account'].search([('tax_ids', '!=', False), ('company_id', '=', self.env.company.id)]) account_with_taxes.write({ 'tax_ids': [Command.clear()], }) # This tour doesn't work with demo data on runbot all_moves = self.env['account.move'].search([('move_type', '!=', 'entry')]) all_moves.button_draft() all_moves.with_context(force_delete=True).unlink() self.start_tour("/web", 'account_tour', login="******")
def _compute_details(self): for wizard in self: commands = [Command.clear()] if wizard.counter < 1 or not wizard.production_id: wizard.production_detailed_vals_ids = commands continue quantity = float_round(wizard.product_qty / wizard.counter, precision_rounding=wizard.product_uom_id.rounding) remaining_quantity = wizard.product_qty for _ in range(wizard.counter - 1): commands.append(Command.create({ 'quantity': quantity, 'user_id': wizard.production_id.user_id, 'date': wizard.production_id.date_planned_start, })) remaining_quantity = float_round(remaining_quantity - quantity, precision_rounding=wizard.product_uom_id.rounding) commands.append(Command.create({ 'quantity': remaining_quantity, 'user_id': wizard.production_id.user_id, 'date': wizard.production_id.date_planned_start, })) wizard.production_detailed_vals_ids = commands
def test_write_base_many2many(self): """ Write on many2many field. """ rec1 = self.env['test_performance.base'].create({'name': 'X'}) # create N tags on rec1: O(N) queries with self.assertQueryCount(4): rec1.invalidate_cache() rec1.write({'tag_ids': [Command.create({'name': 0})]}) self.assertEqual(len(rec1.tag_ids), 1) with self.assertQueryCount(14): rec1.invalidate_cache() rec1.write({ 'tag_ids': [Command.create({'name': val}) for val in range(1, 12)] }) self.assertEqual(len(rec1.tag_ids), 12) tags = rec1.tag_ids # update N tags: O(N) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec1.write({ 'tag_ids': [Command.update(tag.id, {'name': 'X'}) for tag in tags[0]] }) self.assertEqual(rec1.tag_ids, tags) with self.assertQueryCount(3): rec1.invalidate_cache() rec1.write({ 'tag_ids': [Command.update(tag.id, {'name': 'X'}) for tag in tags[1:]] }) self.assertEqual(rec1.tag_ids, tags) # delete N tags: O(1) queries with self.assertQueryCount(__system__=8, demo=8): rec1.invalidate_cache() rec1.write( {'tag_ids': [Command.delete(tag.id) for tag in tags[0]]}) self.assertEqual(rec1.tag_ids, tags[1:]) with self.assertQueryCount(__system__=8, demo=8): rec1.invalidate_cache() rec1.write( {'tag_ids': [Command.delete(tag.id) for tag in tags[1:]]}) self.assertFalse(rec1.tag_ids) self.assertFalse(tags.exists()) rec1.write( {'tag_ids': [Command.create({'name': val}) for val in range(12)]}) tags = rec1.tag_ids # unlink N tags: O(1) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec1.write( {'tag_ids': [Command.unlink(tag.id) for tag in tags[0]]}) self.assertEqual(rec1.tag_ids, tags[1:]) with self.assertQueryCount(3): rec1.invalidate_cache() rec1.write( {'tag_ids': [Command.unlink(tag.id) for tag in tags[1:]]}) self.assertFalse(rec1.tag_ids) self.assertTrue(tags.exists()) rec2 = self.env['test_performance.base'].create({'name': 'X'}) # link N tags from rec1 to rec2: O(1) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.link(tag.id) for tag in tags[0]]}) self.assertEqual(rec2.tag_ids, tags[0]) with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.link(tag.id) for tag in tags[1:]]}) self.assertEqual(rec2.tag_ids, tags) with self.assertQueryCount(2): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.link(tag.id) for tag in tags[1:]]}) self.assertEqual(rec2.tag_ids, tags) # empty N tags in rec2: O(1) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.clear()]}) self.assertFalse(rec2.tag_ids) self.assertTrue(tags.exists()) with self.assertQueryCount(2): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.clear()]}) self.assertFalse(rec2.tag_ids) # set N tags in rec2: O(1) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.set(tags.ids)]}) self.assertEqual(rec2.tag_ids, tags) with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.set(tags[:8].ids)]}) self.assertEqual(rec2.tag_ids, tags[:8]) with self.assertQueryCount(4): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.set(tags[4:].ids)]}) self.assertEqual(rec2.tag_ids, tags[4:]) with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.set(tags.ids)]}) self.assertEqual(rec2.tag_ids, tags) with self.assertQueryCount(2): rec1.invalidate_cache() rec2.write({'tag_ids': [Command.set(tags.ids)]}) self.assertEqual(rec2.tag_ids, tags)
def test_write_base_one2many(self): """ Write on one2many field. """ rec1 = self.env['test_performance.base'].create({'name': 'X'}) # create N lines on rec1: O(N) queries with self.assertQueryCount(3): rec1.invalidate_cache() rec1.write({'line_ids': [Command.create({'value': 0})]}) self.assertEqual(len(rec1.line_ids), 1) with self.assertQueryCount(15): rec1.invalidate_cache() rec1.write({ 'line_ids': [Command.create({'value': val}) for val in range(1, 12)] }) self.assertEqual(len(rec1.line_ids), 12) lines = rec1.line_ids # update N lines: O(N) queries with self.assertQueryCount(6): rec1.invalidate_cache() rec1.write({ 'line_ids': [Command.update(line.id, {'value': 42}) for line in lines[0]] }) self.assertEqual(rec1.line_ids, lines) with self.assertQueryCount(26): rec1.invalidate_cache() rec1.write({ 'line_ids': [ Command.update(line.id, {'value': 42 + line.id}) for line in lines[1:] ] }) self.assertEqual(rec1.line_ids, lines) # delete N lines: O(1) queries with self.assertQueryCount(14): rec1.invalidate_cache() rec1.write( {'line_ids': [Command.delete(line.id) for line in lines[0]]}) self.assertEqual(rec1.line_ids, lines[1:]) with self.assertQueryCount(12): rec1.invalidate_cache() rec1.write( {'line_ids': [Command.delete(line.id) for line in lines[1:]]}) self.assertFalse(rec1.line_ids) self.assertFalse(lines.exists()) rec1.write({ 'line_ids': [Command.create({'value': val}) for val in range(12)] }) lines = rec1.line_ids # unlink N lines: O(1) queries with self.assertQueryCount(14): rec1.invalidate_cache() rec1.write( {'line_ids': [Command.unlink(line.id) for line in lines[0]]}) self.assertEqual(rec1.line_ids, lines[1:]) with self.assertQueryCount(12): rec1.invalidate_cache() rec1.write( {'line_ids': [Command.unlink(line.id) for line in lines[1:]]}) self.assertFalse(rec1.line_ids) self.assertFalse(lines.exists()) rec1.write({ 'line_ids': [Command.create({'value': val}) for val in range(12)] }) lines = rec1.line_ids rec2 = self.env['test_performance.base'].create({'name': 'X'}) # link N lines from rec1 to rec2: O(1) queries with self.assertQueryCount(8): rec1.invalidate_cache() rec2.write( {'line_ids': [Command.link(line.id) for line in lines[0]]}) self.assertEqual(rec1.line_ids, lines[1:]) self.assertEqual(rec2.line_ids, lines[0]) with self.assertQueryCount(8): rec1.invalidate_cache() rec2.write( {'line_ids': [Command.link(line.id) for line in lines[1:]]}) self.assertFalse(rec1.line_ids) self.assertEqual(rec2.line_ids, lines) with self.assertQueryCount(4): rec1.invalidate_cache() rec2.write( {'line_ids': [Command.link(line.id) for line in lines[0]]}) self.assertEqual(rec2.line_ids, lines) with self.assertQueryCount(4): rec1.invalidate_cache() rec2.write( {'line_ids': [Command.link(line.id) for line in lines[1:]]}) self.assertEqual(rec2.line_ids, lines) # empty N lines in rec2: O(1) queries with self.assertQueryCount(13): rec1.invalidate_cache() rec2.write({'line_ids': [Command.clear()]}) self.assertFalse(rec2.line_ids) with self.assertQueryCount(3): rec1.invalidate_cache() rec2.write({'line_ids': [Command.clear()]}) self.assertFalse(rec2.line_ids) rec1.write({ 'line_ids': [Command.create({'value': val}) for val in range(12)] }) lines = rec1.line_ids # set N lines in rec2: O(1) queries with self.assertQueryCount(8): rec1.invalidate_cache() rec2.write({'line_ids': [Command.set(lines[0].ids)]}) self.assertEqual(rec1.line_ids, lines[1:]) self.assertEqual(rec2.line_ids, lines[0]) with self.assertQueryCount(6): rec1.invalidate_cache() rec2.write({'line_ids': [Command.set(lines.ids)]}) self.assertFalse(rec1.line_ids) self.assertEqual(rec2.line_ids, lines) with self.assertQueryCount(4): rec1.invalidate_cache() rec2.write({'line_ids': [Command.set(lines.ids)]}) self.assertEqual(rec2.line_ids, lines)
def test_event_configuration_tickets_from_type(self): """ Test data computation (related to tickets) of event coming from its event.type template. This test uses pretty low level Form data checks, as manipulations in a non-saved Form are required to highlight an undesired behavior when switching event_type templates : event_ticket_ids not linked to a registration were generated and kept when switching between different templates in the Form, which could rapidly lead to a substantial amount of undesired lines. """ # setup test records event_type_default = self.env['event.type'].create({ 'name': 'Type Default', 'auto_confirm': True }) event_type_tickets = self.env['event.type'].create({ 'name': 'Type Tickets', 'auto_confirm': False }) event_type_tickets.write({ 'event_type_ticket_ids': [ Command.clear(), Command.create({ 'name': 'Default Ticket', 'seats_max': 10, }) ] }) event = self.env['event.event'].create({ 'name': 'Event', 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), 'event_type_id': event_type_default.id }) event.write({ 'event_ticket_ids': [ Command.clear(), Command.create({ 'name': 'Registration Ticket', 'seats_max': 10, }) ] }) ticket = event.event_ticket_ids[0] registration = self._create_registrations(event, 1) # link the ticket to the registration registration.write({'event_ticket_id': ticket.id}) # start test scenario event_form = Form(event) # verify that the ticket is linked to the event in the form self.assertEqual( set( map(lambda m: m.get('name', None), event_form.event_ticket_ids._records)), set(['Registration Ticket'])) # switch to an event_type with a ticket template which should be computed event_form.event_type_id = event_type_tickets # verify that both tickets are computed self.assertEqual( set( map(lambda m: m.get('name', None), event_form.event_ticket_ids._records)), set(['Registration Ticket', 'Default Ticket'])) # switch back to an event_type without default tickets event_form.event_type_id = event_type_default # verify that the ticket linked to the registration was kept, and the other removed self.assertEqual( set( map(lambda m: m.get('name', None), event_form.event_ticket_ids._records)), set(['Registration Ticket']))
def test_event_configuration_mails_from_type(self): """ Test data computation (related to mails) of event coming from its event.type template. This test uses pretty low level Form data checks, as manipulations in a non-saved Form are required to highlight an undesired behavior when switching event_type templates : event_mail_ids not linked to a registration were generated and kept when switching between different templates in the Form, which could rapidly lead to a substantial amount of undesired lines. """ # setup test records event_type_default = self.env['event.type'].create({ 'name': 'Type Default', 'auto_confirm': True }) event_type_mails = self.env['event.type'].create({ 'name': 'Type Mails', 'auto_confirm': False }) event_type_mails.write({ 'event_type_mail_ids': [ Command.clear(), Command.create({ 'notification_type': 'mail', 'interval_nbr': 77, 'interval_unit': 'days', 'interval_type': 'after_event', 'template_ref': 'mail.template,%i' % self.env['ir.model.data']._xmlid_to_res_id( 'event.event_reminder'), }) ] }) event = self.env['event.event'].create({ 'name': 'Event', 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), 'event_type_id': event_type_default.id }) event.write({ 'event_mail_ids': [ Command.clear(), Command.create({ 'notification_type': 'mail', 'interval_unit': 'now', 'interval_type': 'after_sub', 'template_ref': 'mail.template,%i' % self.env['ir.model.data']._xmlid_to_res_id( 'event.event_subscription'), }) ] }) mail = event.event_mail_ids[0] registration = self._create_registrations(event, 1) self.assertEqual(registration.state, 'open') # event auto confirms # verify that mail is linked to the registration self.assertEqual( set(mail.mapped('mail_registration_ids.registration_id.id')), set([registration.id])) # start test scenario event_form = Form(event) # verify that mail is linked to the event in the form self.assertEqual( set( map(lambda m: m.get('id', None), event_form.event_mail_ids._records)), set([mail.id])) # switch to an event_type with a mail template which should be computed event_form.event_type_id = event_type_mails # verify that 2 mails were computed self.assertEqual(len(event_form.event_mail_ids._records), 2) # verify that the mail linked to the registration was kept self.assertTrue( filter(lambda m: m.get('id', None) == mail.id, event_form.event_mail_ids._records)) # since the other computed event.mail is to be created from an event.type.mail template, # verify that its attributes are the correct ones computed_mail = next( filter(lambda m: m.get('id', None) != mail.id, event_form.event_mail_ids._records), {}) self.assertEqual(computed_mail.get('interval_nbr', None), 77) self.assertEqual(computed_mail.get('interval_unit', None), 'days') self.assertEqual(computed_mail.get('interval_type', None), 'after_event') # switch back to an event type without a mail template event_form.event_type_id = event_type_default # verify that the mail linked to the registration was kept, and the other removed self.assertEqual( set( map(lambda m: m.get('id', None), event_form.event_mail_ids._records)), set([mail.id]))
def test_event_configuration_booths_from_type(self): """ Test data computation (related to booths) of event coming from its event.type template. """ # setup test records event_type_nobooth = self.env['event.type'].create({ 'name': 'No booth', }) event_type_wbooths = self.env['event.type'].create({ 'name': 'Using booths', 'event_type_booth_ids': [ Command.clear(), Command.create({ 'name': 'Standard Booth', 'booth_category_id': self.event_booth_category_1.id, }), Command.create({ 'name': 'Premium Booth', 'booth_category_id': self.event_booth_category_2.id, }) ] }) # no booth by default as no booths on type event = self.env['event.event'].create({ 'name': 'Event', 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), 'event_type_id': event_type_nobooth.id }) self.assertEqual(event.event_booth_ids, self.env['event.booth']) # manually create booths: ok event.write({ 'event_booth_ids': [ Command.create({ 'name': 'Custom Standard Booth 1', 'booth_category_id': self.event_booth_category_1.id, }), Command.create({ 'name': 'Custom Standard Booth 2', 'booth_category_id': self.event_booth_category_1.id, }) ] }) self.assertEqual(event.event_booth_count, 2) self.assertEqual(event.event_booth_count_available, 2) self.assertEqual(event.event_booth_category_ids, self.event_booth_category_1) self.assertEqual(event.event_booth_ids[1].message_partner_ids, self.env['res.partner']) # updating partner is independent from availability event.event_booth_ids[1].write({'partner_id': self.event_customer.id}) self.assertEqual(event.event_booth_count, 2) self.assertEqual(event.event_booth_count_available, 2) self.assertEqual(event.event_booth_ids[1].message_partner_ids, self.event_customer) # one booth is sold event.event_booth_ids[1].write({'state': 'unavailable'}) self.assertEqual(event.event_booth_count, 2) self.assertEqual(event.event_booth_count_available, 1) # partner is reset: booth still unavailable but follower removed event.event_booth_ids[1].write({'partner_id': False}) self.assertEqual(event.event_booth_count, 2) self.assertEqual(event.event_booth_count_available, 1) self.assertEqual(event.event_booth_ids[1].message_partner_ids, self.env['res.partner']) # change event type to one using booths: include event type booths and keep reserved booths with Form(event) as event_form: event_form.event_type_id = event_type_wbooths self.assertEqual(event.event_booth_count, 3) self.assertEqual( set(r['name'] for r in event.event_booth_ids), set(('Custom Standard Booth 2', 'Standard Booth', 'Premium Booth')), 'Should keep booths with reservation, remove unused ones and add type ones' ) self.assertEqual(event.event_booth_count_available, 2) self.assertEqual( event.event_booth_category_ids, self.event_booth_category_1 + self.event_booth_category_2)
def test_loyalty_free_product_loyalty_program(self): # In this program, each whiteboard pen gives 1 point. # 4 points can be used to get a free whiteboard pen. loyalty_program = self.env['loyalty.program'].create({ 'name': 'Buy 4 whiteboard_pen, Take 1 whiteboard_pen', 'program_type': 'loyalty', 'trigger': 'auto', 'applies_on': 'both', 'rule_ids': [(0, 0, { 'product_ids': self.whiteboard_pen.ids, 'reward_point_mode': 'unit', 'minimum_qty': 1, })], 'reward_ids': [(0, 0, { 'reward_type': 'product', 'reward_product_id': self.whiteboard_pen.id, 'reward_product_qty': 1, 'required_points': 4, })], }) partner_aaa = self.env['res.partner'].create({'name': 'Test Partner AAA'}) partner_bbb = self.env['res.partner'].create({'name': 'Test Partner BBB'}) partner_ccc = self.env['res.partner'].create({'name': 'Test Partner CCC'}) self.main_pos_config.write({ 'promo_program_ids': [Command.clear()], 'module_pos_loyalty': True, 'loyalty_program_id': loyalty_program.id, }) # Part 1 self.start_tour( "/pos/web?config_id=%d" % self.main_pos_config.id, "PosLoyaltyLoyaltyProgram1", login="******", ) aaa_loyalty_card = loyalty_program.coupon_ids.filtered(lambda coupon: coupon.partner_id.id == partner_aaa.id) self.assertEqual(loyalty_program.pos_order_count, 1) self.assertAlmostEqual(aaa_loyalty_card.points, 4) # Part 2 self.start_tour( "/pos/web?config_id=%d" % self.main_pos_config.id, "PosLoyaltyLoyaltyProgram2", login="******", ) self.assertEqual(loyalty_program.pos_order_count, 2, msg='Only 2 orders should have reward lines.') self.assertAlmostEqual(aaa_loyalty_card.points, 1) bbb_loyalty_card = loyalty_program.coupon_ids.filtered(lambda coupon: coupon.partner_id.id == partner_bbb.id) ccc_loyalty_card = loyalty_program.coupon_ids.filtered(lambda coupon: coupon.partner_id.id == partner_ccc.id) self.assertAlmostEqual(bbb_loyalty_card.points, 3, msg='Reference: Order3_BBB') self.assertAlmostEqual(ccc_loyalty_card.points, 4, msg='Reference: Order2_CCC') reward_orderline = self.main_pos_config.current_session_id.order_ids[-1].lines.filtered(lambda line: line.is_reward_line) self.assertEqual(len(reward_orderline.ids), 0, msg='Reference: Order4_no_reward. Last order should have no reward line.')
def test_mail_mail_attachment_access(self): mail = self.env['mail.mail'].create({ 'body_html': 'Test', 'email_to': '*****@*****.**', 'partner_ids': [(4, self.user_employee.partner_id.id)], 'attachment_ids': [ (0, 0, { 'name': 'file 1', 'datas': 'c2VjcmV0' }), (0, 0, { 'name': 'file 2', 'datas': 'c2VjcmV0' }), (0, 0, { 'name': 'file 3', 'datas': 'c2VjcmV0' }), (0, 0, { 'name': 'file 4', 'datas': 'c2VjcmV0' }), ], }) def _patched_check(self, *args, **kwargs): if self.env.is_superuser(): return if any(attachment.name in ('file 2', 'file 4') for attachment in self): raise AccessError('No access') mail.invalidate_recordset() new_attachment = self.env['ir.attachment'].create({ 'name': 'new file', 'datas': 'c2VjcmV0', }) with patch.object(type(self.env['ir.attachment']), 'check', _patched_check): # Sanity check self.assertEqual(mail.restricted_attachment_count, 2) self.assertEqual(len(mail.unrestricted_attachment_ids), 2) self.assertEqual(mail.unrestricted_attachment_ids.mapped('name'), ['file 1', 'file 3']) # Add a new attachment mail.write({ 'unrestricted_attachment_ids': [Command.link(new_attachment.id)], }) self.assertEqual(mail.restricted_attachment_count, 2) self.assertEqual(len(mail.unrestricted_attachment_ids), 3) self.assertEqual(mail.unrestricted_attachment_ids.mapped('name'), ['file 1', 'file 3', 'new file']) self.assertEqual(len(mail.attachment_ids), 5) # Remove an attachment mail.write({ 'unrestricted_attachment_ids': [Command.unlink(new_attachment.id)], }) self.assertEqual(mail.restricted_attachment_count, 2) self.assertEqual(len(mail.unrestricted_attachment_ids), 2) self.assertEqual(mail.unrestricted_attachment_ids.mapped('name'), ['file 1', 'file 3']) self.assertEqual(len(mail.attachment_ids), 4) # Reset command mail.invalidate_recordset() mail.write({'unrestricted_attachment_ids': [Command.clear()]}) self.assertEqual(len(mail.unrestricted_attachment_ids), 0) self.assertEqual(len(mail.attachment_ids), 2) # Read in SUDO mail.invalidate_recordset() self.assertEqual(mail.sudo().restricted_attachment_count, 2) self.assertEqual(len(mail.sudo().unrestricted_attachment_ids), 0)
def test_onchange_one2many_multi(self): """ test the effect of multiple onchange methods on one2many fields """ partner1 = self.env['res.partner'].create({'name': 'A partner'}) multi = self.env['test_new_api.multi'].create({'partner': partner1.id}) line1 = multi.lines.create({'multi': multi.id}) field_onchange = multi._onchange_spec() self.assertEqual( field_onchange, { 'name': '1', 'partner': '1', 'lines': None, 'lines.name': None, 'lines.partner': None, 'lines.tags': None, 'lines.tags.name': None, }) values = multi._convert_to_write( {key: multi[key] for key in ('name', 'partner', 'lines')}) self.assertEqual( values, { 'name': partner1.name, 'partner': partner1.id, 'lines': [Command.set([line1.id])], }) # modify 'partner' # -> set 'partner' on all lines # -> recompute 'name' # -> set 'name' on all lines partner2 = self.env['res.partner'].create({'name': 'A second partner'}) values = { 'name': partner1.name, 'partner': partner2.id, # this one just changed 'lines': [ Command.set([line1.id]), Command.create({ 'name': False, 'partner': False, 'tags': [Command.clear()] }) ], } self.env.cache.invalidate() result = multi.onchange(values, 'partner', field_onchange) self.assertEqual( result['value'], { 'name': partner2.name, 'lines': [ Command.clear(), Command.update( line1.id, { 'name': partner2.name, 'partner': (partner2.id, partner2.name), 'tags': [Command.clear()], }), Command.create({ 'name': partner2.name, 'partner': (partner2.id, partner2.name), 'tags': [Command.clear()], }), ], }) # do it again, but this time with a new tag on the second line values = { 'name': partner1.name, 'partner': partner2.id, # this one just changed 'lines': [ Command.set([line1.id]), Command.create({ 'name': False, 'partner': False, 'tags': [Command.clear(), Command.create({'name': 'Tag'})] }) ], } self.env.cache.invalidate() result = multi.onchange(values, 'partner', field_onchange) expected_value = { 'name': partner2.name, 'lines': [ Command.clear(), Command.update( line1.id, { 'name': partner2.name, 'partner': (partner2.id, partner2.name), 'tags': [Command.clear()], }), Command.create({ 'name': partner2.name, 'partner': (partner2.id, partner2.name), 'tags': [Command.clear(), Command.create({'name': 'Tag'})], }), ], } self.assertEqual(result['value'], expected_value) # ensure ID is not returned when asked and a many2many record is set to be created self.env.cache.invalidate() result = multi.onchange( values, 'partner', dict(field_onchange, **{'lines.tags.id': None})) self.assertEqual(result['value'], expected_value) # ensure inverse of one2many field is not returned self.env.cache.invalidate() result = multi.onchange(values, 'partner', dict(field_onchange, **{'lines.multi': None})) self.assertEqual(result['value'], expected_value)
def test_onchange_one2many(self): """ test the effect of onchange() on one2many fields """ USER = self.env.user # create an independent message message1 = self.Message.create({'body': "ABC"}) message2 = self.Message.create({'body': "ABC"}) self.assertEqual(message1.name, "[%s] %s" % ('', USER.name)) field_onchange = self.Discussion._onchange_spec() self.assertEqual(field_onchange.get('name'), '1') self.assertEqual(field_onchange.get('messages'), '1') self.assertItemsEqual( strip_prefix('messages.', field_onchange), ['author', 'body', 'name', 'size', 'important'], ) # modify discussion name values = { 'name': "Foo", 'categories': [], 'moderator': False, 'participants': [], 'messages': [ Command.link(message1.id), Command.link(message2.id), Command.update(message2.id, {'body': "XYZ"}), Command.create({ 'name': "[%s] %s" % ('', USER.name), 'body': "ABC", 'author': USER.id, 'size': 3, 'important': False, }), ], } self.env.cache.invalidate() result = self.Discussion.onchange(values, 'name', field_onchange) self.assertIn('messages', result['value']) self.assertEqual( result['value']['messages'], [ Command.clear(), Command.update( message1.id, { 'name': "[%s] %s" % ("Foo", USER.name), 'body': "ABC", 'author': USER.name_get()[0], 'size': 3, 'important': False, }), Command.update( message2.id, { 'name': "[%s] %s" % ("Foo", USER.name), 'body': "XYZ", # this must be sent back 'author': USER.name_get()[0], 'size': 3, 'important': False, }), Command.create({ 'name': "[%s] %s" % ("Foo", USER.name), 'body': "ABC", 'author': USER.name_get()[0], 'size': 3, 'important': False, }), ]) # ensure onchange changing one2many without subfield works one_level_fields = { k: v for k, v in field_onchange.items() if k.count('.') < 1 } values = dict(values, name='{generate_dummy_message}') result = self.Discussion.with_context( generate_dummy_message=True).onchange(values, 'name', one_level_fields) self.assertEqual(result['value']['messages'], [ Command.clear(), Command.link(message1.id), Command.link(message2.id), Command.create({}), Command.create({}), ])
def action_return_to_list(self): self.production_detailed_vals_ids = [Command.clear()] self.counter = 0 action = self.env['ir.actions.actions']._for_xml_id('mrp.action_mrp_production_split_multi') action['res_id'] = self.production_split_multi_id.id return action
def _compute_available_payment_method_ids(self): """ Compute the available payment methods id by respecting the following rules: Methods of mode 'unique' cannot be used twice on the same company Methods of mode 'multi' cannot be used twice on the same journal """ method_information = self.env['account.payment.method']._get_payment_method_information() pay_methods = self.env['account.payment.method'].search([('code', 'in', list(method_information.keys()))]) pay_method_by_code = {x.code + x.payment_type: x for x in pay_methods} unique_pay_methods = [k for k, v in method_information.items() if v['mode'] == 'unique'] pay_methods_by_company = {} pay_methods_by_journal = {} if unique_pay_methods: self._cr.execute(''' SELECT journal.id, journal.company_id, ARRAY_AGG(DISTINCT apm.id) FROM account_payment_method_line apml JOIN account_journal journal ON journal.id = apml.journal_id JOIN account_payment_method apm ON apm.id = apml.payment_method_id WHERE apm.code IN %s GROUP BY journal.id, journal.company_id ''', [tuple(unique_pay_methods)]) for journal_id, company_id, payment_method_ids in self._cr.fetchall(): pay_methods_by_company[company_id] = set(payment_method_ids) pay_methods_by_journal[journal_id] = set(payment_method_ids) pay_method_ids_commands_x_journal = {j: [Command.clear()] for j in self} for payment_type in ('inbound', 'outbound'): for code, vals in method_information.items(): payment_method = pay_method_by_code.get(code + payment_type) if not payment_method: continue # Get the domain of the journals on which the current method is usable. method_domain = payment_method._get_payment_method_domain() for journal in self.filtered_domain(method_domain): protected_pay_method_ids = pay_methods_by_company.get(journal.company_id._origin.id, set()) \ - pay_methods_by_journal.get(journal._origin.id, set()) if payment_type == 'inbound': lines = journal.inbound_payment_method_line_ids else: lines = journal.outbound_payment_method_line_ids already_used = payment_method in lines.payment_method_id is_protected = payment_method.id in protected_pay_method_ids if vals['mode'] == 'unique' and (already_used or is_protected): continue # Only the manual payment method can be used multiple time on a single journal. if payment_method.code != "manual" and already_used: continue pay_method_ids_commands_x_journal[journal].append(Command.link(payment_method.id)) for journal, pay_method_ids_commands in pay_method_ids_commands_x_journal.items(): journal.available_payment_method_ids = pay_method_ids_commands