summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStéphane Debauche <std@odoo.com>2020-01-27 13:54:42 +0000
committerThibault Delavallée <tde@odoo.com>2020-01-28 09:14:43 +0000
commit1296681cbdd92f789a8d0df2abc66bbe4d1075ec (patch)
tree50e9cebe5f59158580cf954d9839e275af27b05e
parentb8966ac660cb6b899cd8e91b513cb2fc321548d7 (diff)
[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
-rw-r--r--addons/event/models/event_registration.py51
-rw-r--r--addons/event/tests/test_event_flow.py4
-rw-r--r--addons/event/views/event_views.xml87
-rw-r--r--addons/event_sale/models/sale_order.py24
-rw-r--r--addons/event_sale/views/event_views.xml12
-rw-r--r--addons/website_event_sale/models/sale_order.py2
-rw-r--r--addons/website_sale/controllers/main.py1
7 files changed, 115 insertions, 66 deletions
diff --git a/addons/event/models/event_registration.py b/addons/event/models/event_registration.py
index 8f940a2812e..3a85bee3e68 100644
--- a/addons/event/models/event_registration.py
+++ b/addons/event/models/event_registration.py
@@ -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')
diff --git a/addons/event/tests/test_event_flow.py b/addons/event/tests/test_event_flow.py
index 6c317b74a02..572e64a8231 100644
--- a/addons/event/tests/test_event_flow.py
+++ b/addons/event/tests/test_event_flow.py
@@ -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')
diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml
index 62acfb7bba0..919c4251c43 100644
--- a/addons/event/views/event_views.xml
+++ b/addons/event/views/event_views.xml
@@ -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&gt;seats_reserved) or (seats_max and seats_max&lt;seats_reserved)">
+ <tree string="Events"
+ decoration-bf="message_needaction==True"
+ decoration-danger="(seats_min and seats_min&gt;seats_reserved) or (seats_max and seats_max&lt;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>
diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py
index 39699ca6584..10a8e0a5e2c 100644
--- a/addons/event_sale/models/sale_order.py
+++ b/addons/event_sale/models/sale_order.py
@@ -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 = {}
diff --git a/addons/event_sale/views/event_views.xml b/addons/event_sale/views/event_views.xml
index 9856e1cb2bf..1d685751a9e 100644
--- a/addons/event_sale/views/event_views.xml
+++ b/addons/event_sale/views/event_views.xml
@@ -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>
diff --git a/addons/website_event_sale/models/sale_order.py b/addons/website_event_sale/models/sale_order.py
index 5dcf1bb34ba..662217167ad 100644
--- a/addons/website_event_sale/models/sale_order.py
+++ b/addons/website_event_sale/models/sale_order.py
@@ -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'])
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index ef31b599501..7bafe8e00f9 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -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')