add portal_event_registration
This commit is contained in:
parent
18fd73ed1b
commit
de0520d5a8
9 changed files with 393 additions and 0 deletions
3
portal_event_registration/__init__.py
Normal file
3
portal_event_registration/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import controllers, models
|
||||||
18
portal_event_registration/__manifest__.py
Normal file
18
portal_event_registration/__manifest__.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Portal Event Registration",
|
||||||
|
"summary": "Allows portal users to view their event registrations "
|
||||||
|
"and upload attachments to the chatter.",
|
||||||
|
"version": "18.0.1.0.0",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"author": "Custom",
|
||||||
|
"depends": ["event", "portal"],
|
||||||
|
"data": [
|
||||||
|
"security/security.xml",
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
"views/portal_templates.xml",
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
}
|
||||||
3
portal_event_registration/controllers/__init__.py
Normal file
3
portal_event_registration/controllers/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import portal
|
||||||
117
portal_event_registration/controllers/portal.py
Normal file
117
portal_event_registration/controllers/portal.py
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import _, http
|
||||||
|
from odoo.exceptions import AccessError, MissingError
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal
|
||||||
|
from odoo.addons.portal.controllers.portal import pager as portal_pager
|
||||||
|
|
||||||
|
|
||||||
|
class EventRegistrationPortal(CustomerPortal):
|
||||||
|
|
||||||
|
def _prepare_home_portal_values(self, counters):
|
||||||
|
values = super()._prepare_home_portal_values(counters)
|
||||||
|
if "event_count" in counters:
|
||||||
|
Registration = request.env["event.registration"]
|
||||||
|
partner = request.env.user.partner_id
|
||||||
|
domain = self._get_event_registration_domain(partner)
|
||||||
|
values["event_count"] = (
|
||||||
|
Registration.search_count(domain)
|
||||||
|
if Registration.has_access("read")
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_event_registration_domain(self, partner):
|
||||||
|
return [
|
||||||
|
("partner_id", "child_of", [partner.commercial_partner_id.id]),
|
||||||
|
("state", "!=", "cancel"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _get_event_searchbar_sortings(self):
|
||||||
|
return {
|
||||||
|
"date": {"label": _("Event Date"), "order": "event_begin_date desc"},
|
||||||
|
"name": {"label": _("Event Name"), "order": "event_id asc"},
|
||||||
|
"state": {"label": _("Status"), "order": "state asc"},
|
||||||
|
}
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/events", "/my/events/page/<int:page>"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_events(self, page=1, sortby=None, **kw):
|
||||||
|
partner = request.env.user.partner_id
|
||||||
|
Registration = request.env["event.registration"]
|
||||||
|
domain = self._get_event_registration_domain(partner)
|
||||||
|
|
||||||
|
searchbar_sortings = self._get_event_searchbar_sortings()
|
||||||
|
if not sortby:
|
||||||
|
sortby = "date"
|
||||||
|
order = searchbar_sortings[sortby]["order"]
|
||||||
|
|
||||||
|
total = (
|
||||||
|
Registration.search_count(domain) if Registration.has_access("read") else 0
|
||||||
|
)
|
||||||
|
pager = portal_pager(
|
||||||
|
url="/my/events",
|
||||||
|
url_args={"sortby": sortby},
|
||||||
|
total=total,
|
||||||
|
page=page,
|
||||||
|
step=self._items_per_page,
|
||||||
|
)
|
||||||
|
registrations = (
|
||||||
|
Registration.search(
|
||||||
|
domain,
|
||||||
|
order=order,
|
||||||
|
limit=self._items_per_page,
|
||||||
|
offset=pager["offset"],
|
||||||
|
)
|
||||||
|
if Registration.has_access("read")
|
||||||
|
else Registration
|
||||||
|
)
|
||||||
|
|
||||||
|
request.session["my_events_history"] = registrations.ids[:100]
|
||||||
|
|
||||||
|
values = self._prepare_portal_layout_values()
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"registrations": registrations,
|
||||||
|
"page_name": "event",
|
||||||
|
"pager": pager,
|
||||||
|
"sortby": sortby,
|
||||||
|
"searchbar_sortings": searchbar_sortings,
|
||||||
|
"default_url": "/my/events",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("portal_event_registration.portal_my_events", values)
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/events/<int:registration_id>"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_event_detail(self, registration_id, access_token=None, **kw):
|
||||||
|
try:
|
||||||
|
registration_sudo = self._document_check_access(
|
||||||
|
"event.registration", registration_id, access_token=access_token
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my")
|
||||||
|
|
||||||
|
values = self._prepare_portal_layout_values()
|
||||||
|
values["registration"] = registration_sudo
|
||||||
|
values = self._get_page_view_values(
|
||||||
|
registration_sudo,
|
||||||
|
access_token,
|
||||||
|
values,
|
||||||
|
"my_events_history",
|
||||||
|
False,
|
||||||
|
**kw,
|
||||||
|
)
|
||||||
|
return request.render(
|
||||||
|
"portal_event_registration.portal_my_event_detail", values
|
||||||
|
)
|
||||||
3
portal_event_registration/models/__init__.py
Normal file
3
portal_event_registration/models/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import event_registration
|
||||||
11
portal_event_registration/models/event_registration.py
Normal file
11
portal_event_registration/models/event_registration.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models
|
||||||
|
|
||||||
|
|
||||||
|
class EventRegistration(models.Model):
|
||||||
|
_inherit = "event.registration"
|
||||||
|
|
||||||
|
# Allow portal users (who only have read access) to post messages
|
||||||
|
# and upload attachments via the portal chatter.
|
||||||
|
_mail_post_access = "read"
|
||||||
3
portal_event_registration/security/ir.model.access.csv
Normal file
3
portal_event_registration/security/ir.model.access.csv
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_event_event_portal,event.event.portal,event.model_event_event,base.group_portal,1,0,0,0
|
||||||
|
access_event_registration_portal,event.registration.portal,event.model_event_registration,base.group_portal,1,0,0,0
|
||||||
|
30
portal_event_registration/security/security.xml
Normal file
30
portal_event_registration/security/security.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- Allow portal users to read events where they have a registration -->
|
||||||
|
<record id="event_registration_portal_rule" model="ir.rule">
|
||||||
|
<field name="name">Event Registration: portal users see own registrations</field>
|
||||||
|
<field name="model_id" ref="event.model_event_registration"/>
|
||||||
|
<field name="domain_force">
|
||||||
|
[('partner_id', 'child_of', [user.commercial_partner_id.id])]
|
||||||
|
</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||||
|
<field name="perm_read" eval="True"/>
|
||||||
|
<field name="perm_write" eval="False"/>
|
||||||
|
<field name="perm_create" eval="False"/>
|
||||||
|
<field name="perm_unlink" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Allow portal users to read events where they are registered -->
|
||||||
|
<record id="event_event_portal_rule" model="ir.rule">
|
||||||
|
<field name="name">Event Event: portal users see events with own registrations</field>
|
||||||
|
<field name="model_id" ref="event.model_event_event"/>
|
||||||
|
<field name="domain_force">
|
||||||
|
[('registration_ids.partner_id', 'child_of', [user.commercial_partner_id.id])]
|
||||||
|
</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||||
|
<field name="perm_read" eval="True"/>
|
||||||
|
<field name="perm_write" eval="False"/>
|
||||||
|
<field name="perm_create" eval="False"/>
|
||||||
|
<field name="perm_unlink" eval="False"/>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
205
portal_event_registration/views/portal_templates.xml
Normal file
205
portal_event_registration/views/portal_templates.xml
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ===== Breadcrumbs ===== -->
|
||||||
|
<template
|
||||||
|
id="portal_my_home_menu_event"
|
||||||
|
name="Portal layout: event menu entries"
|
||||||
|
inherit_id="portal.portal_breadcrumbs"
|
||||||
|
priority="25"
|
||||||
|
>
|
||||||
|
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
|
||||||
|
<li
|
||||||
|
t-if="page_name == 'event' or registration"
|
||||||
|
t-attf-class="breadcrumb-item #{'active' if not registration else ''}"
|
||||||
|
>
|
||||||
|
<a t-if="registration" t-attf-href="/my/events?{{ keep_query() }}">My Events</a>
|
||||||
|
<t t-else="">My Events</t>
|
||||||
|
</li>
|
||||||
|
<li t-if="registration" class="breadcrumb-item active">
|
||||||
|
<t t-out="registration.event_id.name"/>
|
||||||
|
</li>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ===== Portal Home entry ===== -->
|
||||||
|
<template
|
||||||
|
id="portal_my_home_event"
|
||||||
|
name="My Events"
|
||||||
|
customize_show="True"
|
||||||
|
inherit_id="portal.portal_my_home"
|
||||||
|
priority="25"
|
||||||
|
>
|
||||||
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="before">
|
||||||
|
<t t-set="portal_client_category_enable" t-value="True"/>
|
||||||
|
</xpath>
|
||||||
|
<div id="portal_client_category" position="inside">
|
||||||
|
<t t-call="portal.portal_docs_entry">
|
||||||
|
<t t-set="title">My Events</t>
|
||||||
|
<t t-set="url" t-value="'/my/events'"/>
|
||||||
|
<t t-set="text">View the events you are registered for</t>
|
||||||
|
<t t-set="placeholder_count" t-value="'event_count'"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ===== List: /my/events ===== -->
|
||||||
|
<template id="portal_my_events" name="My Event Registrations">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<t t-set="breadcrumbs_searchbar" t-value="True"/>
|
||||||
|
|
||||||
|
<t t-call="portal.portal_searchbar">
|
||||||
|
<t t-set="title">My Events</t>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<div t-if="not registrations" class="alert alert-warning" role="alert">
|
||||||
|
You have no active registrations for any event.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<t t-if="registrations" t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr class="active">
|
||||||
|
<th>Event</th>
|
||||||
|
<th class="text-end">Start Date</th>
|
||||||
|
<th class="text-end">End Date</th>
|
||||||
|
<th class="text-center">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<t t-foreach="registrations" t-as="reg">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a t-attf-href="/my/events/#{reg.id}">
|
||||||
|
<t t-out="reg.event_id.name"/>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<span t-field="reg.event_begin_date" t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<span t-field="reg.event_end_date" t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<span
|
||||||
|
t-if="reg.state == 'open'"
|
||||||
|
class="badge rounded-pill text-bg-success"
|
||||||
|
><i class="fa fa-fw fa-check"/> Registered</span>
|
||||||
|
<span
|
||||||
|
t-elif="reg.state == 'done'"
|
||||||
|
class="badge rounded-pill text-bg-primary"
|
||||||
|
><i class="fa fa-fw fa-star"/> Attended</span>
|
||||||
|
<span
|
||||||
|
t-elif="reg.state == 'draft'"
|
||||||
|
class="badge rounded-pill text-bg-warning"
|
||||||
|
><i class="fa fa-fw fa-clock-o"/> Pending</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ===== Detail: /my/events/<id> ===== -->
|
||||||
|
<template id="portal_my_event_detail" name="Event Registration Detail">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<div class="row mt16 o_portal_sidebar">
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<t t-call="portal.portal_record_sidebar">
|
||||||
|
<t t-set="classes" t-value="'col-12 col-lg-3 d-print-none'"/>
|
||||||
|
<t t-set="entries">
|
||||||
|
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
|
||||||
|
<li class="list-group-item flex-grow-1">
|
||||||
|
<div class="small mb-1 fw-bold text-uppercase">Status</div>
|
||||||
|
<span
|
||||||
|
t-if="registration.state == 'open'"
|
||||||
|
class="badge rounded-pill text-bg-success"
|
||||||
|
><i class="fa fa-check"/> Registered</span>
|
||||||
|
<span
|
||||||
|
t-elif="registration.state == 'done'"
|
||||||
|
class="badge rounded-pill text-bg-primary"
|
||||||
|
><i class="fa fa-star"/> Attended</span>
|
||||||
|
<span
|
||||||
|
t-elif="registration.state == 'draft'"
|
||||||
|
class="badge rounded-pill text-bg-warning"
|
||||||
|
><i class="fa fa-clock-o"/> Pending</span>
|
||||||
|
<span
|
||||||
|
t-elif="registration.state == 'cancel'"
|
||||||
|
class="badge rounded-pill text-bg-danger"
|
||||||
|
><i class="fa fa-times"/> Cancelled</span>
|
||||||
|
</li>
|
||||||
|
<li t-if="registration.event_id.organizer_id" class="list-group-item flex-grow-1">
|
||||||
|
<div class="small mb-1 fw-bold text-uppercase">Organizer</div>
|
||||||
|
<t t-out="registration.event_id.organizer_id.name"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<div id="portal_event_content" class="col-12 col-lg-9">
|
||||||
|
<div class="o_portal_html_view shadow p-3">
|
||||||
|
<div class="o_portal_html_loader text-center">
|
||||||
|
<i class="fa fa-circle-o-notch fa-spin fa-2x fa-fw text-black-50"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Event header -->
|
||||||
|
<div class="pb-3 border-bottom">
|
||||||
|
<h2>
|
||||||
|
<t t-out="registration.event_id.name"/>
|
||||||
|
</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<strong>Start:</strong>
|
||||||
|
<span t-field="registration.event_begin_date"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<strong>End:</strong>
|
||||||
|
<span t-field="registration.event_end_date"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<t t-if="registration.event_id.address_id">
|
||||||
|
<div class="mt-2">
|
||||||
|
<strong>Location:</strong>
|
||||||
|
<span t-field="registration.event_id.address_id"
|
||||||
|
t-options="{'widget': 'contact', 'fields': ['address']}"/>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Attendee details -->
|
||||||
|
<div class="mt-3">
|
||||||
|
<h4>Registration Details</h4>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<td><t t-out="registration.name"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr t-if="registration.email">
|
||||||
|
<th>Email</th>
|
||||||
|
<td><t t-out="registration.email"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr t-if="registration.phone">
|
||||||
|
<th>Phone</th>
|
||||||
|
<td><t t-out="registration.phone"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr t-if="registration.event_ticket_id">
|
||||||
|
<th>Ticket Type</th>
|
||||||
|
<td><t t-out="registration.event_ticket_id.name"/></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chatter with attachments -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h4>Messages & Documents</h4>
|
||||||
|
<t t-call="portal.message_thread"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue