[IMP] event: clean code about synchronizing partner / sale order line

PURPOSE

This commit is part of ticket model support directly in event application.

SPECIFICATIONS

In this commit we make a quixotic attempt to clean call chain implied by
making registrations online, either in event frontend (website_event) or
with eCommerce inclusion (website_event_sale). Purpose is to get rid of some
preparation and data management methods to handle most of the code directly
at CRUD level whenever it makes sense.

We notably

  * move at create and write level support of partner_id update: updating
    its name / email / phone / mobile;
  * move at create and write level support of sale_order-id update: updating
    event, ticket, partner;

Using that and some code cleaning some methods are removed and call chain
is a bit reduced.

LINKS

Task ID 2177281
Community PR #43488
This commit is contained in:
Thibault Delavallée
2020-01-30 15:18:08 +00:00
parent 623a226beb
commit ec121565cc
5 changed files with 91 additions and 66 deletions
+49 -39
View File
@@ -49,52 +49,53 @@ class EventRegistration(models.Model):
if registration.event_id.seats_availability == 'limited' and registration.event_id.seats_max and registration.event_id.seats_available < (1 if registration.state == 'draft' else 0):
raise ValidationError(_('No more seats available for this event.'))
def _check_auto_confirmation(self):
if self._context.get('registration_force_draft'):
return False
if any(not registration.event_id.auto_confirm or
(not registration.event_id.seats_available and registration.event_id.seats_availability == 'limited') for registration in self):
return False
return True
@api.onchange('partner_id')
def _onchange_partner(self):
if self.partner_id:
self.update(self._synchronize_partner_values(self.partner_id))
# ------------------------------------------------------------
# CRUD
# ------------------------------------------------------------
@api.model
def create(self, vals):
# update missing pieces of information from partner
if vals.get('partner_id'):
partner_vals = self._synchronize_partner_values(
self.env['res.partner'].browse(vals['partner_id'])
)
vals = dict(partner_vals, **vals)
registration = super(EventRegistration, self).create(vals)
if registration._check_auto_confirmation():
registration.sudo().action_confirm()
return registration
def write(self, vals):
if vals.get('state') == 'done' and 'date_closed' not in vals:
vals['date_closed'] = fields.Datetime.now()
ret = super(EventRegistration, self).write(vals)
# update missing pieces of information from partner
if vals.get('partner_id'):
partner_vals = self._synchronize_partner_values(
self.env['res.partner'].browse(vals['partner_id'])
)
for registration in self:
partner_info = dict((key, val) for key, val in partner_vals.items() if not registration[key])
if partner_info:
registration.write(partner_info)
if vals.get('state') == 'open':
# auto-trigger after_sub (on subscribe) mail schedulers, if needed
onsubscribe_schedulers = self.mapped('event_id.event_mail_ids').filtered(lambda s: s.interval_type == 'after_sub')
onsubscribe_schedulers.execute()
elif vals.get('state') == 'done' and 'date_closed' not in vals:
vals['date_closed'] = fields.Datetime.now()
return ret
@api.model
def _prepare_attendee_values(self, registration):
""" Method preparing the values to create new attendees based on a
sales order line. It takes some registration data (dict-based) that are
optional values coming from an external input like a web page. This method
is meant to be inherited in various addons that sell events. """
partner_id = registration.pop('partner_id', self.env.user.partner_id)
event_id = registration.pop('event_id', False)
data = {
'name': registration.get('name', partner_id.name),
'phone': registration.get('phone', partner_id.phone),
'mobile': registration.get('mobile', partner_id.mobile),
'email': registration.get('email', partner_id.email),
'partner_id': partner_id.id,
'event_id': event_id and event_id.id or False,
}
data.update({key: value for key, value in registration.items() if key in self._fields})
return data
def name_get(self):
""" Custom name_get implementation to better differentiate registrations
linked to a given partner but with different name (one partner buying
@@ -116,6 +117,26 @@ class EventRegistration(models.Model):
ret_list.append((registration.id, name))
return ret_list
def _check_auto_confirmation(self):
if self._context.get('registration_force_draft'):
return False
if any(not registration.event_id.auto_confirm or
(not registration.event_id.seats_available and registration.event_id.seats_availability == 'limited') for registration in self):
return False
return True
def _synchronize_partner_values(self, partner):
if partner:
contact_id = partner.address_get().get('contact', False)
if contact_id:
contact = self.env['res.partner'].browse(contact_id)
return dict((fname, contact[fname]) for fname in ['name', 'email', 'phone', 'mobile'] if contact[fname])
return {}
# ------------------------------------------------------------
# ACTIONS / BUSINESS
# ------------------------------------------------------------
def action_set_draft(self):
self.write({'state': 'draft'})
@@ -129,17 +150,6 @@ class EventRegistration(models.Model):
def action_cancel(self):
self.write({'state': 'cancel'})
@api.onchange('partner_id')
def _onchange_partner(self):
if self.partner_id:
contact_id = self.partner_id.address_get().get('contact', False)
if contact_id:
contact = self.env['res.partner'].browse(contact_id)
self.name = contact.name or self.name
self.email = contact.email or self.email
self.phone = contact.phone or self.phone
self.mobile = contact.mobile or self.mobile
def _message_get_suggested_recipients(self):
recipients = super(EventRegistration, self)._message_get_suggested_recipients()
public_users = self.env['res.users'].sudo()
+26 -17
View File
@@ -41,29 +41,38 @@ class EventRegistration(models.Model):
@api.model
def create(self, vals):
if vals.get('sale_order_line_id'):
so_line_vals = self._synchronize_so_line_values(
self.env['sale.order.line'].browse(vals['sale_order_line_id'])
)
vals.update(so_line_vals)
res = super(EventRegistration, self).create(vals)
if res.origin or res.sale_order_id:
res.message_post_with_view('mail.message_origin_link',
res.message_post_with_view(
'mail.message_origin_link',
values={'self': res, 'origin': res.sale_order_id},
subtype_id=self.env.ref('mail.mt_note').id)
return res
@api.model
def _prepare_attendee_values(self, registration):
""" Override to add sale related stuff """
line_id = registration.get('sale_order_line_id')
if line_id:
registration.setdefault('partner_id', line_id.order_id.partner_id)
att_data = super(EventRegistration, self)._prepare_attendee_values(registration)
if line_id and line_id.event_ticket_id.sale_available:
att_data.update({
'event_id': line_id.event_id.id,
'event_ticket_id': line_id.event_ticket_id.id,
'origin': line_id.order_id.name,
'sale_order_id': line_id.order_id.id,
'sale_order_line_id': line_id.id,
})
return att_data
def write(self, vals):
if vals.get('sale_order_line_id'):
so_line_vals = self._synchronize_so_line_values(
self.env['sale.order.line'].browse(vals['sale_order_line_id'])
)
vals.update(so_line_vals)
return super(EventRegistration, self).write(vals)
def _synchronize_so_line_values(self, so_line):
if so_line:
return {
'partner_id': so_line.order_id.partner_id.id,
'event_id': so_line.event_id.id,
'event_ticket_id': so_line.event_ticket_id.id,
'origin': so_line.order_id.name,
'sale_order_id': so_line.order_id.id,
'sale_order_line_id': so_line.id,
}
return {}
def summary(self):
res = super(EventRegistration, self).summary()
+4 -5
View File
@@ -60,13 +60,12 @@ class SaleOrderLine(models.Model):
existing_registrations.filtered(lambda self: self.state == 'cancel').action_set_draft()
for count in range(int(so_line.product_uom_qty) - len(existing_registrations)):
registration = {}
registration_vals = {}
if registration_data:
registration = registration_data.pop()
registration_vals = registration_data.pop()
# TDE CHECK: auto confirmation
registration['sale_order_line_id'] = so_line
Registration.with_context(registration_force_draft=True).create(
Registration._prepare_attendee_values(registration))
registration_vals['sale_order_line_id'] = so_line.id
Registration.with_context(registration_force_draft=True).create(registration_vals)
return True
@api.onchange('product_id')
+5 -4
View File
@@ -290,10 +290,11 @@ class WebsiteEventController(http.Controller):
Attendees = request.env['event.registration']
registrations = self._process_registration_details(post)
for registration in registrations:
registration['event_id'] = event
Attendees += Attendees.sudo().create(
Attendees._prepare_attendee_values(registration))
for registration_vals in registrations:
registration_vals['event_id'] = event.id
if not registration_vals.get('partner_id'):
registration_vals['partner_id'] = request.env.user.partner_id.id
Attendees += Attendees.sudo().create(registration_vals)
urls = event._get_event_resource_urls()
return request.render("website_event.registration_complete", {
@@ -29,6 +29,12 @@ class WebsiteEventSaleController(WebsiteEventController):
tickets = request.env['event.event.ticket'].browse(tuple(ticket_post))
return [{'id': ticket.id, 'name': ticket.name, 'quantity': ticket_post[ticket.id], 'price': ticket.price} for ticket in tickets if ticket_post[ticket.id]]
def _process_registration_details(self, details):
res = super(WebsiteEventSaleController, self)._process_registration_details(details)
for registration_vals in res:
registration_vals['event_ticket_id'] = int(registration_vals.pop('ticket_id')) if registration_vals.get('ticket_id') else False
return res
@http.route()
def registration_confirm(self, event, **post):
order = request.website.sale_get_order(force_create=1)
@@ -36,7 +42,7 @@ class WebsiteEventSaleController(WebsiteEventController):
registrations = self._process_registration_details(post)
for registration in registrations:
ticket = request.env['event.event.ticket'].sudo().browse(int(registration['ticket_id']))
ticket = request.env['event.event.ticket'].sudo().browse(int(registration['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=[registration])
attendee_ids |= set(cart_values.get('attendee_ids', []))