[IMP] event(_sale): improve attendees integration
Purpose ======= Improve the attendees management: improve views, actions, (views, actions). Specifications ============== In order to allow state management in batch, state field is made editable in multi edit mode of registrations. That way event managers are able to work in batch. It required to move some code currently called in custom action-called methods directly in write. It makes sense to consider that some required code is called by writing on state field instead of depending on calling the right method. Indeed there is not much "business" code to move: calling mail schedulers on confirmation, and putting the closing date when closing. Event and registration tree views are improved, some fields are now editable in multi edit mode. When a user register on a event from website, it will create a sale order and a partner (the customer of the SO). Set automatically the partner of the registration to the partner of the sale order. Task ID 2119333 PR #40949
This commit is contained in:
committed by
Thibault Delavallée
parent
b8966ac660
commit
1296681cbd
@@ -61,9 +61,21 @@ class EventRegistration(models.Model):
|
||||
def create(self, vals):
|
||||
registration = super(EventRegistration, self).create(vals)
|
||||
if registration._check_auto_confirmation():
|
||||
registration.sudo().confirm_registration()
|
||||
registration.sudo().action_confirm()
|
||||
return registration
|
||||
|
||||
def write(self, vals):
|
||||
ret = super(EventRegistration, self).write(vals)
|
||||
|
||||
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
|
||||
@@ -83,23 +95,38 @@ class EventRegistration(models.Model):
|
||||
data.update({key: value for key, value in registration.items() if key in self._fields})
|
||||
return data
|
||||
|
||||
def do_draft(self):
|
||||
def name_get(self):
|
||||
""" Custom name_get implementation to better differentiate registrations
|
||||
linked to a given partner but with different name (one partner buying
|
||||
several registrations)
|
||||
|
||||
* name, partner_id has no name -> take name
|
||||
* partner_id has name, name void or same -> take partner name
|
||||
* both have name: partner + name
|
||||
"""
|
||||
ret_list = []
|
||||
for registration in self:
|
||||
if registration.partner_id.name:
|
||||
if registration.name and registration.name != registration.partner_id.name:
|
||||
name = '%s, %s' % (registration.partner_id.name, registration.name)
|
||||
else:
|
||||
name = registration.partner_id.name
|
||||
else:
|
||||
name = registration.name
|
||||
ret_list.append((registration.id, name))
|
||||
return ret_list
|
||||
|
||||
def action_set_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
|
||||
def confirm_registration(self):
|
||||
def action_confirm(self):
|
||||
self.write({'state': 'open'})
|
||||
|
||||
# auto-trigger after_sub (on subscribe) mail schedulers, if needed
|
||||
onsubscribe_schedulers = self.event_id.event_mail_ids.filtered(
|
||||
lambda s: s.interval_type == 'after_sub')
|
||||
onsubscribe_schedulers.execute()
|
||||
|
||||
def button_reg_close(self):
|
||||
def action_set_done(self):
|
||||
""" Close Registration """
|
||||
for registration in self:
|
||||
registration.write({'state': 'done', 'date_closed': fields.Datetime.now()})
|
||||
self.write({'state': 'done'})
|
||||
|
||||
def button_reg_cancel(self):
|
||||
def action_cancel(self):
|
||||
self.write({'state': 'cancel'})
|
||||
|
||||
@api.onchange('partner_id')
|
||||
|
||||
@@ -47,10 +47,10 @@ class TestEventFlow(TestEventCommon):
|
||||
})
|
||||
|
||||
# EventUser validates registrations
|
||||
test_reg1.button_reg_close()
|
||||
test_reg1.action_set_done()
|
||||
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
|
||||
self.assertEqual(test_event.seats_used, 1, 'Event: incorrect number of attendees after closing registration')
|
||||
test_reg2.button_reg_close()
|
||||
test_reg2.action_set_done()
|
||||
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
|
||||
self.assertEqual(test_event.seats_used, 2, 'Event: incorrect number of attendees after closing registration')
|
||||
|
||||
|
||||
@@ -291,18 +291,21 @@
|
||||
<field name="name">event.event.tree</field>
|
||||
<field name="model">event.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Events" decoration-bf="message_needaction==True" decoration-danger="(seats_min and seats_min>seats_reserved) or (seats_max and seats_max<seats_reserved)">
|
||||
<tree string="Events"
|
||||
decoration-bf="message_needaction==True"
|
||||
decoration-danger="(seats_min and seats_min>seats_reserved) or (seats_max and seats_max<seats_reserved)"
|
||||
multi_edit="1">
|
||||
<field name="name"/>
|
||||
<field name="event_type_id"/>
|
||||
<field name="date_begin"/>
|
||||
<field name="date_end"/>
|
||||
<field name="seats_reserved" sum="Total"/>
|
||||
<field name="seats_min"/>
|
||||
<field name="seats_max" invisible="1"/>
|
||||
<field name="user_id"/>
|
||||
<field name="message_needaction" invisible="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="activity_exception_decoration" widget="activity_exception"/>
|
||||
<field name="event_type_id" readonly="1"/>
|
||||
<field name="date_begin" readonly="1"/>
|
||||
<field name="date_end" readonly="1"/>
|
||||
<field name="seats_reserved" sum="Total" readonly="1"/>
|
||||
<field name="seats_min" readonly="1"/>
|
||||
<field name="seats_max" invisible="1" readonly="1"/>
|
||||
<field name="user_id" readonly="1"/>
|
||||
<field name="message_needaction" invisible="1" readonly="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
|
||||
<field name="activity_exception_decoration" widget="activity_exception" readonly="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -485,18 +488,20 @@
|
||||
<field name="name">event.registration.tree</field>
|
||||
<field name="model">event.registration</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Registration" decoration-bf="message_needaction==True">
|
||||
<field name="create_date"/>
|
||||
<tree string="Registration" decoration-bf="message_needaction==True" multi_edit="1">
|
||||
<field name="create_date" optional="hide"/>
|
||||
<field name="date_open" optional="hide"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="name"/>
|
||||
<field name="email"/>
|
||||
<field name="email" optional="hide"/>
|
||||
<field name="event_id" />
|
||||
<field name="state"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="origin" optional="hide"/>
|
||||
<field name="state" readonly="0"/>
|
||||
<field name="company_id" groups="base.group_multi_company" optional="hide"/>
|
||||
<field name="message_needaction" invisible="1"/>
|
||||
<button name="confirm_registration" string="Confirm Registration" states="draft" type="object" icon="fa-check text-success"/>
|
||||
<button name="button_reg_close" string="Attended the Event" states="open" type="object" icon="fa-level-down text-success"/>
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="fa-times-circle text-danger"/>
|
||||
<button name="action_confirm" string="Confirm Registration" states="draft" type="object" icon="fa-check text-success"/>
|
||||
<button name="action_set_done" string="Attended the Event" states="open" type="object" icon="fa-level-down text-success"/>
|
||||
<button name="action_cancel" string="Cancel Registration" states="draft,open" type="object" icon="fa-times-circle text-danger"/>
|
||||
<field name="activity_exception_decoration" widget="activity_exception"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -509,10 +514,10 @@
|
||||
<form string="Event Registration">
|
||||
<header>
|
||||
<button name="action_send_badge_email" string="Send by Email" type="object" states="open,done" class="oe_highlight"/>
|
||||
<button name="confirm_registration" string="Confirm" states="draft" type="object" class="oe_highlight"/>
|
||||
<button name="button_reg_close" string="Attended" states="open" type="object" class="oe_highlight"/>
|
||||
<button string="Set To Unconfirmed" name="do_draft" states="cancel,done" type="object" />
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object"/>
|
||||
<button name="action_confirm" string="Confirm" states="draft" type="object" class="oe_highlight"/>
|
||||
<button name="action_set_done" string="Attended" states="open" type="object" class="oe_highlight"/>
|
||||
<button name="action_set_draft" string="Set To Unconfirmed" states="cancel,done" type="object" />
|
||||
<button name="action_cancel" string="Cancel Registration" states="draft,open" type="object"/>
|
||||
<field name="state" nolabel="1" colspan="2" widget="statusbar" statusbar_visible="draft,open,done"/>
|
||||
</header>
|
||||
<sheet string="Registration">
|
||||
@@ -552,30 +557,22 @@
|
||||
<field name="email"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click">
|
||||
<div class="oe_kanban_details">
|
||||
<div class="oe_kanban_card oe_kanban_global_click">
|
||||
<div class="float-right">
|
||||
<a class="btn btn-sm btn-success" string="Confirm Registration" name="action_confirm" type="object" states="draft" role="button">
|
||||
<i class="fa fa-check" role="img" aria-label="Confirm button" title="Confirm Registration"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-success" string="Attended the Event" name="action_close" type="object" states="open" role="button">
|
||||
<i class="fa fa-level-down" role="img" aria-label="Attended button" title="Attended the Event"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="oe_kanban_content">
|
||||
<div class="o_kanban_record_top">
|
||||
<div class="o_kanban_record_headings">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="name"/>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="float-right">
|
||||
<a class="btn btn-sm btn-success" string="Confirm Registration" name="confirm_registration" type="object" states="draft" role="button">
|
||||
<i class="fa fa-check" role="img" aria-label="Confirm button" title="Confirm Registration"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-success" string="Attended the Event" name="button_reg_close" type="object" states="open" role="button">
|
||||
<i class="fa fa-level-down" role="img" aria-label="Attended button" title="Attended the Event"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-danger" string="Cancel Registration" name="button_reg_cancel" type="object" states="draft,open" role="button">
|
||||
<i class="fa fa-times" role="img" aria-label="Cancel button" title="Cancel Registration"/>
|
||||
</a>
|
||||
</div>
|
||||
<b class="o_kanban_record_title"><field name="display_name"/></b>
|
||||
</div>
|
||||
<div class="o_kanban_record_body">
|
||||
<field name="event_id"/>
|
||||
</div>
|
||||
<ul>
|
||||
<li><field name="partner_id"/></li>
|
||||
<li><field name="email"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -6,6 +6,16 @@ from odoo import api, fields, models
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = "sale.order"
|
||||
|
||||
def write(self, vals):
|
||||
""" Synchronize partner from SO to registrations. This is done notably
|
||||
in website_sale controller shop/address that updates customer, but not
|
||||
only. """
|
||||
result = super(SaleOrder, self).write(vals)
|
||||
if vals.get('partner_id'):
|
||||
registrations_toupdate = self.env['event.registration'].search([('sale_order_id', 'in', self.ids)])
|
||||
registrations_toupdate.write({'partner_id': vals['partner_id']})
|
||||
return result
|
||||
|
||||
def _action_confirm(self):
|
||||
res = super(SaleOrder, self)._action_confirm()
|
||||
for so in self:
|
||||
@@ -27,10 +37,12 @@ class SaleOrderLine(models.Model):
|
||||
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
event_id = fields.Many2one('event.event', string='Event',
|
||||
help="Choose an event and it will automatically create a registration for this event.")
|
||||
event_ticket_id = fields.Many2one('event.event.ticket', string='Event Ticket', help="Choose "
|
||||
"an event ticket and it will automatically create a registration for this event ticket.")
|
||||
event_id = fields.Many2one(
|
||||
'event.event', string='Event',
|
||||
help="Choose an event and it will automatically create a registration for this event.")
|
||||
event_ticket_id = fields.Many2one(
|
||||
'event.event.ticket', string='Event Ticket',
|
||||
help="Choose an event ticket and it will automatically create a registration for this event ticket.")
|
||||
event_ok = fields.Boolean(related='product_id.event_ok', readonly=True)
|
||||
|
||||
def _update_registrations(self, confirm=True, cancel_to_draft=False, registration_data=None):
|
||||
@@ -43,9 +55,9 @@ class SaleOrderLine(models.Model):
|
||||
for so_line in self.filtered('event_id'):
|
||||
existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id)
|
||||
if confirm:
|
||||
existing_registrations.filtered(lambda self: self.state not in ['open', 'cancel']).confirm_registration()
|
||||
existing_registrations.filtered(lambda self: self.state not in ['open', 'cancel']).action_confirm()
|
||||
if cancel_to_draft:
|
||||
existing_registrations.filtered(lambda self: self.state == 'cancel').do_draft()
|
||||
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 = {}
|
||||
|
||||
@@ -23,6 +23,18 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="event_registration_view_kanban" model="ir.ui.view">
|
||||
<field name="name">event.registration.kanban.inherit</field>
|
||||
<field name="model">event.registration</field>
|
||||
<field name="inherit_id" ref="event.event_registration_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='event_id']" position="after">
|
||||
<br/>
|
||||
<field name="event_ticket_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_event_registration_ticket_form" model="ir.ui.view">
|
||||
<field name="name">event.registration.form.inherit</field>
|
||||
<field name="model">event.registration</field>
|
||||
|
||||
@@ -88,7 +88,7 @@ class SaleOrder(models.Model):
|
||||
('sale_order_id', 'in', self.ids), # To avoid break on multi record set
|
||||
('event_ticket_id', '=', ticket.id),
|
||||
], offset=new_qty, limit=(old_qty - new_qty), order='create_date asc')
|
||||
attendees.button_reg_cancel()
|
||||
attendees.action_cancel()
|
||||
# adding attendees
|
||||
elif ticket and new_qty > old_qty:
|
||||
line = OrderLine.browse(values['line_id'])
|
||||
|
||||
@@ -702,6 +702,7 @@ class WebsiteSale(http.Controller):
|
||||
elif mode[1] == 'shipping':
|
||||
order.partner_shipping_id = partner_id
|
||||
|
||||
# TDE FIXME: don't ever do this
|
||||
order.message_partner_ids = [(4, partner_id), (3, request.website.partner_id.id)]
|
||||
if not errors:
|
||||
return request.redirect(kw.get('callback') or '/shop/confirm_order')
|
||||
|
||||
Reference in New Issue
Block a user