[FIX] event_sale: recompute seats on SO deletion

When deleting a SO with an event ticket, the number of attendees becomes
incorrect

To reproduce the error:
1. In Settings, enable "Tickets"
2. On website, register an attendee to event E
3. In module Events, open E

Error: The number of attendees (X) is incorrect. If the user clicks on
it, there are X-1 attendees: the one added on step 2 has been deleted
but the number is not updated

When deleting a SO or a SO line, the associated registration is deleted:
https://github.com/odoo/odoo/blob/3fd3fc5f782f1422f578ad38e3fad444130273a8/addons/event_sale/models/event.py#L197-L198
This is the problem: it won't trigger the `compute` methods.

In the case above, this method won't be called:
https://github.com/odoo/odoo/blob/72ce1b867dc81672e6a73a586542b20216388a05/addons/event/models/event.py#L176
So the number of seats won't be updated

This fix suggests deleting the registrations from the ORM in order to
trigger the `compute` methods.

Note: Writing the tests revealed another problem. When deleting the SO,
if a wizard `registration.editor` exists and is linked to the SO, the
deletion will trigger an SQL constraint. This is the reason why the
`ondelete` has been added to the field `sale_order_id`

OPW-2452760

closes odoo/odoo#73260

X-original-commit: 89ddb7533b82160f09b7815a292c209f8d39ece5
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
This commit is contained in:
Adrien Widart
2021-07-05 17:52:19 +00:00
parent 88ae867203
commit 92e41b6ca6
3 changed files with 78 additions and 6 deletions
+11
View File
@@ -47,6 +47,10 @@ class SaleOrder(models.Model):
for sale_order in self:
sale_order.attendee_count = attendee_count_data.get(sale_order.id, 0)
def unlink(self):
self.order_line._unlink_associated_registrations()
return super(SaleOrder, self).unlink()
class SaleOrderLine(models.Model):
@@ -120,6 +124,13 @@ class SaleOrderLine(models.Model):
# we call this to force update the default name
self.product_id_change()
def unlink(self):
self._unlink_associated_registrations()
return super(SaleOrderLine, self).unlink()
def _unlink_associated_registrations(self):
self.env['event.registration'].search([('sale_order_line_id', 'in', self.ids)]).unlink()
def get_sale_order_line_multiline_description_sale(self, product):
""" We override this method because we decided that:
The default description of a sales order line containing a ticket must be different than the default description when no ticket is present.
+66 -5
View File
@@ -2,6 +2,8 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.event_sale.tests.common import TestEventSaleCommon
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.tests import tagged
from odoo.tests.common import users
@@ -13,20 +15,59 @@ class TestEventSale(TestEventSaleCommon):
def setUpClass(cls):
super(TestEventSale, cls).setUpClass()
product = cls.env['product.product'].create({
'name': 'Event',
'type': 'service',
'event_ok': True,
})
cls.user_salesperson = mail_new_test_user(cls.env, login='user_salesman', groups='sales_team.group_sale_salesman')
cls.ticket = cls.env['event.event.ticket'].create({
'name': 'First Ticket',
'product_id': cls.event_product.id,
'seats_max': 30,
'event_id': cls.event_0.id,
})
cls.event_0.write({
'event_ticket_ids': [
(5, 0),
(6, 0, cls.ticket.ids),
(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,
})
],
})
cls.sale_order = cls.env['sale.order'].create({
'partner_id': cls.env.ref('base.res_partner_2').id,
'note': 'Invoice after delivery',
'payment_term_id': cls.env.ref('account.account_payment_term_end_following_month').id
})
# In the sales order I add some sales order lines. i choose event product
cls.env['sale.order.line'].create({
'product_id': product.id,
'price_unit': 190.50,
'product_uom': cls.env.ref('uom.product_uom_unit').id,
'product_uom_qty': 1.0,
'order_id': cls.sale_order.id,
'name': 'sales order line',
'event_id': cls.event_0.id,
'event_ticket_id': cls.ticket.id,
})
cls.register_person = cls.env['registration.editor'].create({
'sale_order_id': cls.sale_order.id,
'event_registration_ids': [(0, 0, {
'event_id': cls.event_0.id,
'name': 'Administrator',
'email': 'abc@example.com',
'sale_order_line_id': cls.sale_order.order_line.id,
})],
})
# 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,
@@ -209,3 +250,23 @@ class TestEventSale(TestEventSaleCommon):
})
sol.product_id_change()
self.assertEqual(so.amount_total, 660.0, "Ticket is $1000 but the event product is on a pricelist 10 -> 6. So, $600 + a 10% tax.")
@users('user_salesman')
def test_unlink_so(self):
""" This test ensures that when deleting a sale order, if the latter is linked to an event registration,
the number of expected seats will be correctly updated """
event = self.env['event.event'].browse(self.event_0.ids)
self.register_person.action_make_registration()
self.assertEqual(event.seats_expected, 1)
self.sale_order.unlink()
self.assertEqual(event.seats_expected, 0)
@users('user_salesman')
def test_unlink_soline(self):
""" This test ensures that when deleting a sale order line, if the latter is linked to an event registration,
the number of expected seats will be correctly updated """
event = self.env['event.event'].browse(self.event_0.ids)
self.register_person.action_make_registration()
self.assertEqual(event.seats_expected, 1)
self.sale_order.order_line.unlink()
self.assertEqual(event.seats_expected, 0)
@@ -7,7 +7,7 @@ class RegistrationEditor(models.TransientModel):
_name = "registration.editor"
_description = 'Edit Attendee Details on Sales Confirmation'
sale_order_id = fields.Many2one('sale.order', 'Sales Order', required=True)
sale_order_id = fields.Many2one('sale.order', 'Sales Order', required=True, ondelete='cascade')
event_registration_ids = fields.One2many('registration.editor.line', 'editor_id', string='Registrations to Edit')
@api.model