[MERGE][REF] (website_)event(_sale): create registrations in batch

PURPOSE

Create event registrations in batch. It will allow to customize group-creation of
registrations, notably with automated rules for crm / event synchronization.

SPECIFICATIONS

Find where registrations are created, and

  * either remove registration creation (cart update)
  * either make it in batch (buying tickets in front-end, using the registration
    editor)

LINKS

Task ID 2258685
Prepare Task ID 2166679 (create leads from registrations)
PR #51341

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2020-05-18 19:38:00 +02:00
committed by GitHub
10 changed files with 200 additions and 112 deletions
+10 -1
View File
@@ -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,
+18 -25
View File
@@ -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):
+1 -1
View File
@@ -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),
})
+11 -12
View File
@@ -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')
+2 -1
View File
@@ -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):
+138 -52
View File
@@ -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')
@@ -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')
+3 -4
View File
@@ -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/<model("event.event"):event>/registration/confirm'''], type='http', auth="public", methods=['POST'], website=True)
def registration_confirm(self, event, **post):
@@ -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):
@@ -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