diff --git a/addons/event/tests/common.py b/addons/event/tests/common.py index dab3e3339a1..126a839805f 100644 --- a/addons/event/tests/common.py +++ b/addons/event/tests/common.py @@ -42,12 +42,21 @@ class TestEventCommon(common.SavepointCase): groups='base.group_user,event.group_event_manager', ) - cls.customer = cls.env['res.partner'].create({ + cls.event_customer = cls.env['res.partner'].create({ 'name': 'Constantin Customer', 'email': 'constantin@test.example.com', 'country_id': cls.env.ref('base.be').id, 'phone': '0485112233', + 'mobile': False, }) + cls.event_customer2 = cls.env['res.partner'].create({ + 'name': 'Constantin Customer 2', + 'email': 'constantin2@test.example.com', + 'country_id': cls.env.ref('base.be').id, + 'phone': '0456987654', + 'mobile': '0456654321', + }) + cls.event_type_complex = cls.env['event.type'].create({ 'name': 'Update Type', 'auto_confirm': True, diff --git a/addons/event/tests/test_event_flow.py b/addons/event/tests/test_event_flow.py index a1bd3ffcd35..e1602efe73e 100644 --- a/addons/event/tests/test_event_flow.py +++ b/addons/event/tests/test_event_flow.py @@ -27,19 +27,19 @@ class TestEventUI(TestEventCommon): self.assertFalse(registration_form.mobile) # trigger onchange - registration_form.partner_id = self.customer - self.assertEqual(registration_form.name, self.customer.name) - self.assertEqual(registration_form.email, self.customer.email) - self.assertEqual(registration_form.phone, self.customer.phone) - self.assertEqual(registration_form.mobile, self.customer.mobile) + registration_form.partner_id = self.event_customer + self.assertEqual(registration_form.name, self.event_customer.name) + self.assertEqual(registration_form.email, self.event_customer.email) + self.assertEqual(registration_form.phone, self.event_customer.phone) + self.assertEqual(registration_form.mobile, self.event_customer.mobile) # save, check record matches Form values registration = registration_form.save() - self.assertEqual(registration.partner_id, self.customer) - self.assertEqual(registration.name, self.customer.name) - self.assertEqual(registration.email, self.customer.email) - self.assertEqual(registration.phone, self.customer.phone) - self.assertEqual(registration.mobile, self.customer.mobile) + self.assertEqual(registration.partner_id, self.event_customer) + self.assertEqual(registration.name, self.event_customer.name) + self.assertEqual(registration.email, self.event_customer.email) + self.assertEqual(registration.phone, self.event_customer.phone) + self.assertEqual(registration.mobile, self.event_customer.mobile) # allow writing on some fields independently from customer config registration.write({'phone': False, 'mobile': False}) @@ -49,25 +49,18 @@ class TestEventUI(TestEventCommon): # reset partner should not reset other fields registration.write({'partner_id': False}) self.assertEqual(registration.partner_id, self.env['res.partner']) - self.assertEqual(registration.name, self.customer.name) - self.assertEqual(registration.email, self.customer.email) + self.assertEqual(registration.name, self.event_customer.name) + self.assertEqual(registration.email, self.event_customer.email) self.assertFalse(registration.phone) self.assertFalse(registration.mobile) # update to a new partner not through UI -> update only void feilds - customer2 = self.env['res.partner'].create({ - 'name': 'Constantin Customer 2', - 'email': 'constantin2@test.example.com', - 'country_id': self.env.ref('base.be').id, - 'phone': '0456987654', - 'mobile': '0456654321', - }) - registration.write({'partner_id': customer2.id}) - self.assertEqual(registration.partner_id, customer2) - self.assertEqual(registration.name, self.customer.name) - self.assertEqual(registration.email, self.customer.email) - self.assertEqual(registration.phone, customer2.phone) - self.assertEqual(registration.mobile, customer2.mobile) + registration.write({'partner_id': self.event_customer2.id}) + self.assertEqual(registration.partner_id, self.event_customer2) + self.assertEqual(registration.name, self.event_customer.name) + self.assertEqual(registration.email, self.event_customer.email) + self.assertEqual(registration.phone, self.event_customer2.phone) + self.assertEqual(registration.mobile, self.event_customer2.mobile) class TestEventFlow(TestEventCommon): diff --git a/addons/event/tests/test_event_internals.py b/addons/event/tests/test_event_internals.py index 51dd7c33258..9a8d4147d81 100644 --- a/addons/event/tests/test_event_internals.py +++ b/addons/event/tests/test_event_internals.py @@ -30,7 +30,7 @@ class TestEventData(TestEventCommon): def test_event_date_computation(self): event = self.event_0.with_user(self.env.user) event.write({ - 'registration_ids': [(0, 0, {'partner_id': self.customer.id, 'name': 'test_reg'})], + 'registration_ids': [(0, 0, {'partner_id': self.event_customer.id, 'name': 'test_reg'})], 'date_begin': datetime(2020, 1, 31, 15, 0, 0), 'date_end': datetime(2020, 4, 5, 18, 0, 0), }) diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py index b3b79a3899c..28426520a18 100644 --- a/addons/event_sale/models/sale_order.py +++ b/addons/event_sale/models/sale_order.py @@ -18,16 +18,11 @@ class SaleOrder(models.Model): registrations_toupdate.write({'partner_id': vals['partner_id']}) return result - def _action_confirm(self): - res = super(SaleOrder, self)._action_confirm() - for so in self: - # confirm registration if it was free (otherwise it will be confirmed once invoice fully paid) - so.order_line._update_registrations(confirm=so.amount_total == 0, cancel_to_draft=False) - return res - def action_confirm(self): res = super(SaleOrder, self).action_confirm() for so in self: + # confirm registration if it was free (otherwise it will be confirmed once invoice fully paid) + so.order_line._update_registrations(confirm=so.amount_total == 0, cancel_to_draft=False) if any(so.order_line.filtered(lambda line: line.event_id)): return self.env['ir.actions.act_window'] \ .with_context(default_sale_order_id=so.id) \ @@ -87,13 +82,17 @@ class SaleOrderLine(models.Model): if cancel_to_draft: existing_registrations.filtered(lambda self: self.state == 'cancel').action_set_draft() + registrations_vals = [] for count in range(int(so_line.product_uom_qty) - len(existing_registrations)): - registration_vals = {} - if registration_data: - registration_vals = registration_data.pop() + values = { + 'sale_order_line_id': so_line.id, + 'sale_order_id': so_line.order_id.id + } # TDE CHECK: auto confirmation - registration_vals['sale_order_line_id'] = so_line.id - Registration.create(registration_vals) + if registration_data: + values.update(registration_data.pop()) + registrations_vals.append(values) + Registration.create(registrations_vals) return True @api.onchange('product_id') diff --git a/addons/event_sale/tests/common.py b/addons/event_sale/tests/common.py index 698a52c9805..bc4be1d8f20 100644 --- a/addons/event_sale/tests/common.py +++ b/addons/event_sale/tests/common.py @@ -2,9 +2,10 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.sales_team.tests.common import TestSalesCommon -class TestEventSaleCommon(TestEventCommon): +class TestEventSaleCommon(TestEventCommon, TestSalesCommon): @classmethod def setUpClass(cls): diff --git a/addons/event_sale/tests/test_event_sale.py b/addons/event_sale/tests/test_event_sale.py index 70a38f88395..f41949a5fb5 100644 --- a/addons/event_sale/tests/test_event_sale.py +++ b/addons/event_sale/tests/test_event_sale.py @@ -1,69 +1,155 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import common +from odoo.addons.event_sale.tests.common import TestEventSaleCommon +from odoo.tests import tagged +from odoo.tests.common import users -class EventSaleTest(common.TransactionCase): +@tagged('event_flow') +class TestEventSale(TestEventSaleCommon): - def setUp(self): - super(EventSaleTest, self).setUp() + @classmethod + def setUpClass(cls): + super(TestEventSale, cls).setUpClass() - self.EventRegistration = self.env['event.registration'] - - # First I create an event product - product = self.env['product.product'].create({ - 'name': 'test_formation', - 'type': 'service', - 'event_ok': True, + cls.event_0.write({ + 'event_ticket_ids': [ + (5, 0), + (0, 0, { + 'name': 'First Ticket', + 'product_id': cls.event_product.id, + 'seats_max': 30, + }), (0, 0, { + 'name': 'Second Ticket', + 'product_id': cls.event_product.id, + }) + ], }) - # I create an event from the same type than my product - event = self.env['event.event'].create({ - 'name': 'test_event', - 'event_type_id': 1, - 'date_end': '2012-01-01 19:05:15', - 'date_begin': '2012-01-01 18:05:15' + # make a SO for a customer, selling some tickets + cls.customer_so = cls.env['sale.order'].with_user(cls.user_sales_salesman).create({ + 'partner_id': cls.event_customer.id, }) - ticket = self.env['event.event.ticket'].create({ - 'name': 'test_ticket', - 'product_id': product.id, - 'event_id': event.id, - }) + @users('user_sales_salesman') + def test_event_crm_sale(self): + TICKET1_COUNT, TICKET2_COUNT = 3, 1 + customer_so = self.customer_so.with_user(self.env.user) + ticket1 = self.event_0.event_ticket_ids[0] + ticket2 = self.event_0.event_ticket_ids[1] - # I create a sales order - self.sale_order = self.env['sale.order'].create({ - 'partner_id': self.env['res.partner'].create({'name': 'My Attendee'}).id, - 'note': 'Invoice after delivery', - 'payment_term_id': self.env.ref('account.account_payment_term_end_following_month').id - }) + # PREPARE SO DATA + # ------------------------------------------------------------ - # In the sales order I add some sales order lines. i choose event product - self.env['sale.order.line'].create({ - 'product_id': product.id, - 'price_unit': 190.50, - 'product_uom': self.env.ref('uom.product_uom_unit').id, - 'product_uom_qty': 8.0, - 'order_id': self.sale_order.id, - 'name': 'sales order line', - 'event_id': event.id, - 'event_ticket_id': ticket.id, + # adding some tickets to SO + customer_so.write({ + 'order_line': [ + (0, 0, { + 'event_id': self.event_0.id, + 'event_ticket_id': ticket1.id, + 'product_id': ticket1.product_id.id, + 'product_uom_qty': TICKET1_COUNT, + }), (0, 0, { + 'event_id': self.event_0.id, + 'event_ticket_id': ticket2.id, + 'product_id': ticket2.product_id.id, + 'product_uom_qty': TICKET2_COUNT, + 'price_unit': 50, + }) + ] }) + ticket1_line = customer_so.order_line.filtered(lambda line: line.event_ticket_id == ticket1) + ticket2_line = customer_so.order_line.filtered(lambda line: line.event_ticket_id == ticket2) + self.assertEqual(customer_so.amount_untaxed, TICKET1_COUNT * 10 + TICKET2_COUNT * 50) - # In the event registration I add some attendee detail lines. i choose event product - self.register_person = self.env['registration.editor'].create({ - 'sale_order_id': self.sale_order.id, - 'event_registration_ids': [(0, 0, { - 'event_id': event.id, - 'name': 'Administrator', - 'email': 'abc@example.com' - })], + # one existing registration for first ticket + ticket1_reg1 = self.env['event.registration'].create({ + 'event_id': self.event_0.id, + 'event_ticket_id': ticket1.id, + 'partner_id': self.event_customer2.id, + 'sale_order_id': customer_so.id, + 'sale_order_line_id': ticket1_line.id, }) + self.assertEqual(ticket1_reg1.partner_id, self.event_customer) + for field in ['name', 'email', 'phone', 'mobile']: + self.assertEqual(ticket1_reg1[field], self.event_customer[field]) - def test_00_create_event_product(self): - # I click apply to create attendees - self.register_person.action_make_registration() - # I check if a registration is created - registrations = self.EventRegistration.search([('sale_order_id', '=', self.sale_order.id)]) - self.assertTrue(registrations, "The registration is not created.") + # EVENT REGISTRATION EDITOR + # ------------------------------------------------------------ + + # use event registration editor to create missing lines and update details + editor = self.env['registration.editor'].with_context({ + 'default_sale_order_id': customer_so.id + }).create({}) + self.assertEqual(len(editor.event_registration_ids), TICKET1_COUNT + TICKET2_COUNT) + self.assertEqual(editor.sale_order_id, customer_so) + self.assertEqual(editor.event_registration_ids.sale_order_line_id, ticket1_line | ticket2_line) + + # check line linked to existing registration (ticket1_reg1) + ticket1_editor_reg1 = editor.event_registration_ids.filtered(lambda line: line.registration_id) + for field in ['name', 'email', 'phone', 'mobile']: + self.assertEqual(ticket1_editor_reg1[field], ticket1_reg1[field]) + + # check new lines + ticket1_editor_other = editor.event_registration_ids.filtered(lambda line: not line.registration_id and line.event_ticket_id == ticket1) + self.assertEqual(len(ticket1_editor_other), 2) + ticket2_editor_other = editor.event_registration_ids.filtered(lambda line: not line.registration_id and line.event_ticket_id == ticket2) + self.assertEqual(len(ticket2_editor_other), 1) + + # update lines in editor and save them + ticket1_editor_other[0].write({ + 'name': 'ManualEntry1', + 'email': 'manual.email.1@test.example.com', + 'phone': '+32456111111', + }) + ticket1_editor_other[1].write({ + 'name': 'ManualEntry2', + 'email': 'manual.email.2@test.example.com', + 'mobile': '+32456222222', + }) + editor.action_make_registration() + + # check editor correctly created new registrations with information coming from it or SO as fallback + self.assertEqual(len(self.event_0.registration_ids), TICKET1_COUNT + TICKET2_COUNT) + new_registrations = self.event_0.registration_ids - ticket1_reg1 + self.assertEqual(new_registrations.sale_order_id, customer_so) + ticket1_new_reg = new_registrations.filtered(lambda reg: reg.event_ticket_id == ticket1) + ticket2_new_reg = new_registrations.filtered(lambda reg: reg.event_ticket_id == ticket2) + self.assertEqual(len(ticket1_new_reg), 2) + self.assertEqual(len(ticket2_new_reg), 1) + self.assertEqual( + set(ticket1_new_reg.mapped('name')), + set(['ManualEntry1', 'ManualEntry2']) + ) + self.assertEqual( + set(ticket1_new_reg.mapped('email')), + set(['manual.email.1@test.example.com', 'manual.email.2@test.example.com']) + ) + self.assertEqual( + set(ticket1_new_reg.mapped('phone')), + set(['+32456111111', self.event_customer.phone]) + ) + self.assertEqual( + set(ticket1_new_reg.mapped('mobile')), + set(['+32456222222', self.event_customer.mobile]) + ) + for field in ['name', 'email', 'phone', 'mobile']: + self.assertEqual(ticket2_new_reg[field], self.event_customer[field]) + + # ADDING MANUAL LINES ON SO + # ------------------------------------------------------------ + + ticket2_line.write({'product_uom_qty': 3}) + editor_action = customer_so.action_confirm() + self.assertEqual(customer_so.state, 'sale') + self.assertEqual(customer_so.amount_untaxed, TICKET1_COUNT * 10 + (TICKET2_COUNT + 2) * 50) + + # check confirm of SO correctly created new registrations with information coming from SO + self.assertEqual(len(self.event_0.registration_ids), 6) # 3 for each ticket now + new_registrations = self.event_0.registration_ids - (ticket1_reg1 | ticket1_new_reg | ticket2_new_reg) + self.assertEqual(new_registrations.event_ticket_id, ticket2) + self.assertEqual(new_registrations.partner_id, self.customer_so.partner_id) + + self.assertEqual(editor_action['type'], 'ir.actions.act_window') + self.assertEqual(editor_action['res_model'], 'registration.editor') diff --git a/addons/event_sale/wizard/event_edit_registration.py b/addons/event_sale/wizard/event_edit_registration.py index 29c00065856..9db556ba804 100644 --- a/addons/event_sale/wizard/event_edit_registration.py +++ b/addons/event_sale/wizard/event_edit_registration.py @@ -41,6 +41,10 @@ class RegistrationEditor(models.TransientModel): 'event_id': so_line.event_id.id, 'event_ticket_id': so_line.event_ticket_id.id, 'sale_order_line_id': so_line.id, + 'name': so_line.order_partner_id.name, + 'email': so_line.order_partner_id.email, + 'phone': so_line.order_partner_id.phone, + 'mobile': so_line.order_partner_id.mobile, }]) res['event_registration_ids'] = attendee_list res = self._convert_to_write(res) @@ -48,15 +52,17 @@ class RegistrationEditor(models.TransientModel): def action_make_registration(self): self.ensure_one() + registrations_to_create = [] for registration_line in self.event_registration_ids: values = registration_line.get_registration_data() if registration_line.registration_id: registration_line.registration_id.write(values) else: - self.env['event.registration'].create(values) - if self.env.context.get('active_model') == 'sale.order': - for order in self.env['sale.order'].browse(self.env.context.get('active_ids', [])): - order.order_line._update_registrations(confirm=False) + registrations_to_create.append(values) + + self.env['event.registration'].create(registrations_to_create) + self.sale_order_id.order_line._update_registrations(confirm=self.sale_order_id.amount_total == 0) + return {'type': 'ir.actions.act_window_close'} @@ -64,6 +70,7 @@ class RegistrationEditorLine(models.TransientModel): """Event Registration""" _name = "registration.editor.line" _description = 'Edit Attendee Line on Sales Confirmation' + _order = "id desc" editor_id = fields.Many2one('registration.editor') sale_order_line_id = fields.Many2one('sale.order.line', string='Sales Order Line') diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py index 48b6b19936c..f0c5351801f 100644 --- a/addons/website_event/controllers/main.py +++ b/addons/website_event/controllers/main.py @@ -332,15 +332,14 @@ class WebsiteEventController(http.Controller): return list(registrations.values()) def _create_attendees_from_registration_post(self, event, registration_data): - attendees_sudo = request.env['event.registration'].sudo() - + registrations_to_create = [] for registration_values in registration_data: registration_values['event_id'] = event.id if not registration_values.get('partner_id'): registration_values['partner_id'] = request.env.user.partner_id.id - attendees_sudo += request.env['event.registration'].sudo().create(registration_values) + registrations_to_create.append(registration_values) - return attendees_sudo + return request.env['event.registration'].sudo().create(registrations_to_create) @http.route(['''/event//registration/confirm'''], type='http', auth="public", methods=['POST'], website=True) def registration_confirm(self, event, **post): diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py index d9a84510319..00ca7cfd51c 100644 --- a/addons/website_event_sale/controllers/main.py +++ b/addons/website_event_sale/controllers/main.py @@ -29,17 +29,13 @@ class WebsiteEventSaleController(WebsiteEventController): if any(info.get('event_ticket_id') for info in registration_data): order = request.website.sale_get_order(force_create=1) - order_attendee_ids = set() for info in [r for r in registration_data if r.get('event_ticket_id')]: ticket = request.env['event.event.ticket'].sudo().browse(info['event_ticket_id']) - cart_values = order.with_context(event_ticket_id=ticket.id, fixed_price=True)._cart_update(product_id=ticket.product_id.id, add_qty=1, registration_data=[info]) - order_attendee_ids |= set(cart_values.get('attendee_ids', [])) + cart_values = order.with_context(event_ticket_id=ticket.id, fixed_price=True)._cart_update(product_id=ticket.product_id.id, add_qty=1) + info['sale_order_id'] = order.id + info['sale_order_line_id'] = cart_values.get('line_id') - attendees_sudo = super(WebsiteEventSaleController, self)._create_attendees_from_registration_post(event, [r for r in registration_data if not r['event_ticket_id']]) - if order_attendee_ids: - attendees_sudo |= request.env['event.registration'].sudo().browse(order_attendee_ids) - - return attendees_sudo + return super(WebsiteEventSaleController, self)._create_attendees_from_registration_post(event, registration_data) @http.route() def registration_confirm(self, event, **post): diff --git a/addons/website_event_sale/models/sale_order.py b/addons/website_event_sale/models/sale_order.py index 3a7c1c9f307..d092b751366 100644 --- a/addons/website_event_sale/models/sale_order.py +++ b/addons/website_event_sale/models/sale_order.py @@ -91,10 +91,8 @@ class SaleOrder(models.Model): attendees.action_cancel() # adding attendees elif ticket and new_qty > old_qty: - line = OrderLine.browse(values['line_id']) - line._update_registrations(confirm=False, cancel_to_draft=True, registration_data=kwargs.get('registration_data', [])) - # add in return values the registrations, to display them on website (or not) - values['attendee_ids'] = self.env['event.registration'].search([('sale_order_line_id', '=', line.id), ('state', '!=', 'cancel')]).ids + # do not do anything, attendees will be created at SO confirmation if not given previously + pass return values