[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:
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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),
|
||||
})
|
||||
|
||||
@@ -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,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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user