[FW][FIX] event : Changing seats_max could desync seates_reserved

Issue: Sometimes, when changing the Maximum (seats_max) on one of
the tickets of an event, it triggered a recompute for the other tickets

Steps to reproduce :

Install Events
Settings > Event > Enable "Tickets"
Create an event template (or use Sell Online default one) with
Check "Ticketing" and set the line price to 0
Create an event :
with that template
and Autoconfirm checked
Add a line for the Tickets:
name: VIP
price: 10
Save the event

Create two attendees for the event, one for each
Event Ticket (event_ticket_id) and confirm them (on the form, not
Confirm Attendee)

Change the Maximum (seats_max) of one ticket and save
-> the Confirmed (seats_reserved) will be recomputed but the
confirmed for the other ticket will increase as well

Side-Note:
I haven't been able to find a deterministic way to reproduce the bug
but it seems that the bug appear the most when doing all the steps at
once, and trying to not log out or refresh the page.
Also it works best on a runbot or at least with runbot data.

Without my modification, the new test passes on my local odoo server,
but fails on a dump of a runbot on my computer, adding my modification
makes it work on either case

Why is that a bug:
The recomputation seems to fail for some reason, we are setting all
the event/ticket in self to 0, but only update the value of those by
fetching a SQL query so there might be a desync there

opw-2642555

closes odoo/odoo#78023

Forward-port-of: #76492
X-original-commit: f4c936c9dc141de27a77006fb87dd2b63d88ec97
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Signed-off-by: Nathan Marotte <nmarotte@users.noreply.github.com>
This commit is contained in:
Nathan Marotte (nama)
2021-10-08 07:20:01 +00:00
parent b20aeb3a4f
commit 07adca3c69
4 changed files with 59 additions and 3 deletions
+1 -1
View File
@@ -232,7 +232,7 @@ class EventEvent(models.Model):
self._cr.execute(query, (tuple(self.ids),))
res = self._cr.fetchall()
for event_id, state, num in res:
results[event_id][state_field[state]] += num
results[event_id][state_field[state]] = num
# compute seats_available
for event in self:
+4 -2
View File
@@ -98,6 +98,7 @@ class EventTicket(models.Model):
for ticket in self:
ticket.seats_unconfirmed = ticket.seats_reserved = ticket.seats_used = ticket.seats_available = 0
# aggregate registrations by ticket and by state
results = {}
if self.ids:
state_field = {
'draft': 'seats_unconfirmed',
@@ -112,10 +113,11 @@ class EventTicket(models.Model):
self.env['event.registration'].flush(['event_id', 'event_ticket_id', 'state'])
self.env.cr.execute(query, (tuple(self.ids),))
for event_ticket_id, state, num in self.env.cr.fetchall():
ticket = self.browse(event_ticket_id)
ticket[state_field[state]] += num
results.setdefault(event_ticket_id, {})[state_field[state]] = num
# compute seats_available
for ticket in self:
ticket.update(results.get(ticket._origin.id or ticket.id, {}))
if ticket.seats_max > 0:
ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
+1
View File
@@ -4,3 +4,4 @@
from . import test_event_internals
from . import test_event_sale
from . import test_event_sale_ui
from . import test_event_specific
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from dateutil.relativedelta import relativedelta
from odoo.addons.event_sale.tests.common import TestEventSaleCommon
from odoo.tests.common import Form
class TestEventSpecific(TestEventSaleCommon):
def test_event_change_max_seat_no_side_effect(self):
"""
Test that changing the Maximum (seats_max), the seats_reserved of all the ticket do not change
"""
# Enable "sell tickets with sales orders" so that we have a price column on the tickets
# Event template
with Form(self.env['event.type']) as event_type_form:
event_type_form.name = "Pastafarian Event Template"
# Edit the default line
with event_type_form.event_type_ticket_ids.new() as ticket_line:
ticket_line.name = 'Pastafarian Registration'
ticket_line.price = 0
event_type = event_type_form.save()
with Form(self.env['event.event']) as event_event_form:
event_event_form.name = 'Annual Pastafarian Reunion (APR)'
event_event_form.date_begin = datetime.datetime.now() + relativedelta(days=2)
event_event_form.date_end = datetime.datetime.now() + relativedelta(days=3)
event_event_form.event_type_id = event_type # Set the template
event_event_form.auto_confirm = True
# Create second ticket (VIP)
with event_event_form.event_ticket_ids.new() as ticket_line:
ticket_line.name = 'VIP (Very Important Pastafarian)'
ticket_line.price = 10
event_event = event_event_form.save()
# Add two registrations for the event, one registration for each ticket type
for ticket in event_event.event_ticket_ids:
self.env['event.registration'].create({
'event_id': event_event.id,
'event_ticket_id': ticket.id
})
# Edit the maximum
before_confirmed = [t.seats_reserved for t in event_event.event_ticket_ids]
with Form(event_event) as event_event_form:
with event_event_form.event_ticket_ids.edit(0) as ticket_line:
ticket_line.seats_max = ticket_line.seats_max + 1
after_confirmed = [t.seats_reserved for t in event_event.event_ticket_ids]
self.assertEqual(before_confirmed, after_confirmed)