bemade_sports_clinic: portal prototype is functional.
This commit is contained in:
parent
f6f6ef1ef3
commit
825e6fd651
5 changed files with 235 additions and 11 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
from odoo.addons.portal.controllers.portal import CustomerPortal
|
from odoo.addons.portal.controllers.portal import CustomerPortal, pager
|
||||||
from odoo import http
|
from odoo import http, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class TeamStaffPortal(CustomerPortal):
|
class TeamStaffPortal(CustomerPortal):
|
||||||
|
|
@ -8,10 +9,12 @@ class TeamStaffPortal(CustomerPortal):
|
||||||
teams_domain = self._prepare_teams_domain()
|
teams_domain = self._prepare_teams_domain()
|
||||||
players_domain = self._prepare_players_domain(teams_domain)
|
players_domain = self._prepare_players_domain(teams_domain)
|
||||||
rtn['teams_count'] = http.request.env['res.partner'].search_count(teams_domain)
|
rtn['teams_count'] = http.request.env['res.partner'].search_count(teams_domain)
|
||||||
rtn['players_count'] = http.request.env['sports.patient'].search_count(players_domain)
|
rtn['players_count'] = http.request.env['sports.patient'].search_count(
|
||||||
|
players_domain)
|
||||||
return rtn
|
return rtn
|
||||||
|
|
||||||
def _prepare_teams_domain(self):
|
@classmethod
|
||||||
|
def _prepare_teams_domain(cls):
|
||||||
user = http.request.env.user
|
user = http.request.env.user
|
||||||
partner = http.request.env.user.partner_id
|
partner = http.request.env.user.partner_id
|
||||||
return [
|
return [
|
||||||
|
|
@ -19,13 +22,69 @@ class TeamStaffPortal(CustomerPortal):
|
||||||
('type', '=', 'team'),
|
('type', '=', 'team'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def _prepare_players_domain(self, teams_domain):
|
@classmethod
|
||||||
|
def _prepare_players_domain(cls, teams_domain):
|
||||||
team_ids = http.request.env['res.partner'].search(teams_domain).ids
|
team_ids = http.request.env['res.partner'].search(teams_domain).ids
|
||||||
return [
|
return [
|
||||||
('team_ids', 'in', team_ids),
|
('team_ids', 'in', team_ids),
|
||||||
]
|
]
|
||||||
|
|
||||||
# @http.route(route=['/my/teams'], type=http, auth='user', website=True)
|
@http.route(route=['/my/teams'], type='http', auth='user', website=True)
|
||||||
# def view_teams(self, ):
|
def view_teams(self, page=0, **kw):
|
||||||
# pass
|
""" Display the list of teams that a portal user has access to """
|
||||||
|
Teams = http.request.env['res.partner']
|
||||||
|
domain = self._prepare_teams_domain()
|
||||||
|
teams_count = Teams.search_count(domain)
|
||||||
|
pgr = pager(url='/my/teams', total=teams_count,
|
||||||
|
page=page, step=10, scope=10)
|
||||||
|
teams = http.request.env['res.partner'].search(self._prepare_teams_domain(),
|
||||||
|
offset=pgr['offset'],
|
||||||
|
limit=teams_count)
|
||||||
|
return http.request.render(template='bemade_sports_clinic.portal_my_teams',
|
||||||
|
qcontext={
|
||||||
|
'teams_count': teams_count,
|
||||||
|
'teams': teams,
|
||||||
|
'pager': pgr,
|
||||||
|
'page_name': 'my_teams',
|
||||||
|
})
|
||||||
|
|
||||||
|
@http.route(route=['/my/team/<int:team_id>'], type='http', auth='user', website=True)
|
||||||
|
def view_team(self, team_id, page=0, **kw):
|
||||||
|
""" Display the information for a team including its list of players """
|
||||||
|
team = http.request.env['res.partner'].browse(team_id)
|
||||||
|
if not team:
|
||||||
|
raise UserError(_('This team could not be found.'))
|
||||||
|
players_count = team.player_count
|
||||||
|
pgr = pager(url=f'/my/team/{team_id}', total=players_count, page=page, step=10,
|
||||||
|
scope=10)
|
||||||
|
players = http.request.env['sports.patient'].search([
|
||||||
|
('team_ids', 'in', team_id),
|
||||||
|
], offset=pgr['offset'], limit=players_count)
|
||||||
|
return http.request.render(
|
||||||
|
template='bemade_sports_clinic.portal_my_team_players',
|
||||||
|
qcontext={
|
||||||
|
'team': team,
|
||||||
|
'players_count': players_count,
|
||||||
|
'players': players,
|
||||||
|
'pager': pgr,
|
||||||
|
'page_name': 'my_teams',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@http.route(route=['/my/players'], type='http', auth='user', website=True)
|
||||||
|
def view_players(self, page=0, **kw):
|
||||||
|
""" Display the list of players that the portal user has access to """
|
||||||
|
teams_domain = self._prepare_teams_domain()
|
||||||
|
players_domain = self._prepare_players_domain(teams_domain)
|
||||||
|
players_count = http.request.env['sports.patient'].search_count(players_domain)
|
||||||
|
pgr = pager(url='/my/players', total=players_count, page=page, step=10, scope=10)
|
||||||
|
players = http.request.env['sports.patient'].search(players_domain,
|
||||||
|
offset=pgr['offset'],
|
||||||
|
limit=players_count)
|
||||||
|
return http.request.render(template='bemade_sports_clinic.portal_my_players',
|
||||||
|
qcontext={
|
||||||
|
'players_count': players_count,
|
||||||
|
'players': players,
|
||||||
|
'pager': pgr,
|
||||||
|
'page_name': 'my_players',
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_carabins')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_carabins')])]"/>
|
||||||
<field name="date_of_birth">2001-08-23</field>
|
<field name="date_of_birth">2001-08-23</field>
|
||||||
<field name="email">jean.carabin@edudiants.umontreal.ca</field>
|
<field name="email">jean.carabin@edudiants.umontreal.ca</field>
|
||||||
|
<field name="player_status">match</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="patient_2" model="sports.patient">
|
<record id="patient_2" model="sports.patient">
|
||||||
<field name="first_name">Rémi</field>
|
<field name="first_name">Rémi</field>
|
||||||
|
|
@ -30,6 +31,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_carabins')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_carabins')])]"/>
|
||||||
<field name="date_of_birth">2002-05-17</field>
|
<field name="date_of_birth">2002-05-17</field>
|
||||||
<field name="email">remi.lafracture@edudiants.umontreal.ca</field>
|
<field name="email">remi.lafracture@edudiants.umontreal.ca</field>
|
||||||
|
<field name="player_status">practice</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="team_carabins_hockey" model="res.partner">
|
<record id="team_carabins_hockey" model="res.partner">
|
||||||
<field name="name">Carabins (Hockey féminin)</field>
|
<field name="name">Carabins (Hockey féminin)</field>
|
||||||
|
|
@ -43,6 +45,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_carabins_hockey')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_carabins_hockey')])]"/>
|
||||||
<field name="date_of_birth">2001-08-23</field>
|
<field name="date_of_birth">2001-08-23</field>
|
||||||
<field name="email">jeanne.carabine@edudiants.umontreal.ca</field>
|
<field name="email">jeanne.carabine@edudiants.umontreal.ca</field>
|
||||||
|
<field name="player_status">match</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="patient_4" model="sports.patient">
|
<record id="patient_4" model="sports.patient">
|
||||||
<field name="first_name">Rimée</field>
|
<field name="first_name">Rimée</field>
|
||||||
|
|
@ -50,6 +53,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_carabins_hockey')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_carabins_hockey')])]"/>
|
||||||
<field name="date_of_birth">2004-11-22</field>
|
<field name="date_of_birth">2004-11-22</field>
|
||||||
<field name="email">rimee.lafracture@edudiants.umontreal.ca</field>
|
<field name="email">rimee.lafracture@edudiants.umontreal.ca</field>
|
||||||
|
<field name="player_status">practice</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="partner_org_2" model="res.partner">
|
<record id="partner_org_2" model="res.partner">
|
||||||
<field name="name">Université Concordia</field>
|
<field name="name">Université Concordia</field>
|
||||||
|
|
@ -72,6 +76,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_stingers')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_stingers')])]"/>
|
||||||
<field name="date_of_birth">2003-11-02</field>
|
<field name="date_of_birth">2003-11-02</field>
|
||||||
<field name="email">jo_stinger@encs.concordia.ca</field>
|
<field name="email">jo_stinger@encs.concordia.ca</field>
|
||||||
|
<field name="player_status">match</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="patient_6" model="sports.patient">
|
<record id="patient_6" model="sports.patient">
|
||||||
<field name="first_name">Jimmy</field>
|
<field name="first_name">Jimmy</field>
|
||||||
|
|
@ -79,6 +84,7 @@
|
||||||
<field name="team_ids" eval="[(6, 0, [ref('team_stingers')])]"/>
|
<field name="team_ids" eval="[(6, 0, [ref('team_stingers')])]"/>
|
||||||
<field name="date_of_birth">2001-01-05</field>
|
<field name="date_of_birth">2001-01-05</field>
|
||||||
<field name="email">jim_bee@jmsb.concordia.ca</field>
|
<field name="email">jim_bee@jmsb.concordia.ca</field>
|
||||||
|
<field name="player_status">match</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="injury_1" model="sports.patient.injury">
|
<record id="injury_1" model="sports.patient.injury">
|
||||||
<field name="injury_date_time">2023-05-17 18:53:00</field>
|
<field name="injury_date_time">2023-05-17 18:53:00</field>
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,10 @@ class Patient(models.Model):
|
||||||
])
|
])
|
||||||
injury_ids = fields.One2many(comodel_name='sports.patient.injury',
|
injury_ids = fields.One2many(comodel_name='sports.patient.injury',
|
||||||
inverse_name='patient_id',
|
inverse_name='patient_id',
|
||||||
string='Injuries',
|
string='Injuries', )
|
||||||
groups='bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
|
||||||
predicted_return_date = fields.Date(compute='_compute_predicted_return_date', )
|
predicted_return_date = fields.Date(compute='_compute_predicted_return_date', )
|
||||||
|
is_injured = fields.Boolean(compute='_compute_is_injured')
|
||||||
|
injured_since = fields.Date(compute='_compute_is_injured')
|
||||||
|
|
||||||
# authorized_users = fields.One2many(compute='_compute_authorized_users', store=True)
|
# authorized_users = fields.One2many(compute='_compute_authorized_users', store=True)
|
||||||
#
|
#
|
||||||
|
|
@ -69,11 +70,24 @@ class Patient(models.Model):
|
||||||
else:
|
else:
|
||||||
rec.predicted_return_date = False
|
rec.predicted_return_date = False
|
||||||
|
|
||||||
|
@api.depends('first_name', 'last_name')
|
||||||
def _compute_name(self):
|
def _compute_name(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.name = ((rec.first_name or "") + " " + (rec.last_name or
|
rec.name = ((rec.first_name or "") + " " + (rec.last_name or
|
||||||
"")).strip()
|
"")).strip()
|
||||||
|
|
||||||
|
@api.depends('injury_ids.is_resolved')
|
||||||
|
def _compute_is_injured(self):
|
||||||
|
injured = self.filtered(
|
||||||
|
lambda r: r.injury_ids.filtered(lambda i: not i.is_resolved))
|
||||||
|
for rec in injured:
|
||||||
|
rec.is_injured = True
|
||||||
|
rec.injured_since = rec.injury_ids.sorted('injury_date_time')[
|
||||||
|
-1].injury_date_time.date()
|
||||||
|
for rec in self - injured:
|
||||||
|
rec.is_injured = False
|
||||||
|
rec.injured_since = False
|
||||||
|
|
||||||
|
|
||||||
class PatientContact(models.Model):
|
class PatientContact(models.Model):
|
||||||
_name = 'sports.patient.contact'
|
_name = 'sports.patient.contact'
|
||||||
|
|
@ -111,6 +125,7 @@ class PatientInjury(models.Model):
|
||||||
('is_treatment_professional', '=',
|
('is_treatment_professional', '=',
|
||||||
True)], )
|
True)], )
|
||||||
predicted_return_date = fields.Date(tracking=True)
|
predicted_return_date = fields.Date(tracking=True)
|
||||||
|
is_resolved = fields.Boolean(compute="_compute_is_resolved")
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
super().write(vals)
|
super().write(vals)
|
||||||
|
|
@ -119,7 +134,6 @@ class PatientInjury(models.Model):
|
||||||
- self.message_follower_ids.mapped('partner_id'))
|
- self.message_follower_ids.mapped('partner_id'))
|
||||||
self.message_subscribe(to_subscribe.ids)
|
self.message_subscribe(to_subscribe.ids)
|
||||||
|
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals_list):
|
def create(self, vals_list):
|
||||||
super().write(vals_list)
|
super().write(vals_list)
|
||||||
|
|
@ -127,3 +141,8 @@ class PatientInjury(models.Model):
|
||||||
to_subscribe = (rec.treatment_professional_ids
|
to_subscribe = (rec.treatment_professional_ids
|
||||||
- rec.message_follower_ids.mapped('partner_id'))
|
- rec.message_follower_ids.mapped('partner_id'))
|
||||||
rec.message_subscribe(to_subscribe.ids)
|
rec.message_subscribe(to_subscribe.ids)
|
||||||
|
|
||||||
|
@api.depends('predicted_return_date')
|
||||||
|
def _compute_is_resolved(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.is_resolved = rec.predicted_return_date < date.today()
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ class Partner(models.Model):
|
||||||
column1='team_id',
|
column1='team_id',
|
||||||
column2='patient_id',
|
column2='patient_id',
|
||||||
string='Players')
|
string='Players')
|
||||||
|
player_count = fields.Integer(compute="_compute_player_counts")
|
||||||
|
injured_count = fields.Integer(compute="_compute_player_counts")
|
||||||
type = fields.Selection(selection_add=[('team', 'Sports Team'), ])
|
type = fields.Selection(selection_add=[('team', 'Sports Team'), ])
|
||||||
staff_partner_ids = fields.Many2many(comodel_name='res.partner',
|
staff_partner_ids = fields.Many2many(comodel_name='res.partner',
|
||||||
relation='sports_team_staff_partner_rel',
|
relation='sports_team_staff_partner_rel',
|
||||||
|
|
@ -53,3 +55,8 @@ class Partner(models.Model):
|
||||||
'bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
'bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||||
for rec in user_partners:
|
for rec in user_partners:
|
||||||
rec.is_treatment_professional = group in rec.user_ids.groups_id
|
rec.is_treatment_professional = group in rec.user_ids.groups_id
|
||||||
|
|
||||||
|
def _compute_player_counts(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.player_count = len(rec.patient_ids)
|
||||||
|
rec.injured_count = len(rec.patient_ids.filtered(lambda p: p.is_injured))
|
||||||
|
|
@ -15,5 +15,138 @@
|
||||||
</t>
|
</t>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
<template id="portal_my_teams">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<h1>Your Teams</h1>
|
||||||
|
<t t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Team Name</th>
|
||||||
|
<th>Parent Organization</th>
|
||||||
|
<th>Total Players</th>
|
||||||
|
<th>Injured</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="teams" t-as="team">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>
|
||||||
|
<a t-attf-href="/my/team/{{ team.id }}"
|
||||||
|
t-field="team.name"/>
|
||||||
|
</strong>
|
||||||
|
</td>
|
||||||
|
<td><span t-field="team.parent_id"/></td>
|
||||||
|
<td><span t-field="team.player_count"/></td>
|
||||||
|
<td><span t-field="team.injured_count"/></td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
<template id="portal_my_team_players">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<h1><span t-field="team.name"/> Players</h1>
|
||||||
|
<t t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Play Status</th>
|
||||||
|
<th>Injured</th>
|
||||||
|
<th>Injured Since</th>
|
||||||
|
<th>Estimated Return Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="players" t-as="player">
|
||||||
|
<tr>
|
||||||
|
<t t-set="injured"
|
||||||
|
t-value="'Yes' if player.is_injured else 'No'"/>
|
||||||
|
<td>
|
||||||
|
<strong><span t-field="player.name"/></strong>
|
||||||
|
</td>
|
||||||
|
<td><span t-field="player.player_status"/></td>
|
||||||
|
<td><span t-out="injured"/></td>
|
||||||
|
<td>
|
||||||
|
<span t-field="player.injured_since"
|
||||||
|
t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="player.predicted_return_date"
|
||||||
|
t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
<template id="portal_my_players">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<h1>Your Players</h1>
|
||||||
|
<t t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Teams</th>
|
||||||
|
<th>Play Status</th>
|
||||||
|
<th>Injured</th>
|
||||||
|
<th>Injured Since</th>
|
||||||
|
<th>Estimated Return Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="players" t-as="player">
|
||||||
|
<tr>
|
||||||
|
<t t-set="injured"
|
||||||
|
t-value="'Yes' if player.is_injured else 'No'"/>
|
||||||
|
<td>
|
||||||
|
<strong><span t-field="player.name"/></strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul style="list-style-type: none;">
|
||||||
|
<t t-foreach="player.team_ids" t-as="team">
|
||||||
|
<li>
|
||||||
|
<a t-attf-href="/my/team/{{ team.id }}"
|
||||||
|
t-field="team.name"/>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td><span t-field="player.player_status"/></td>
|
||||||
|
<td><span t-out="injured"/></td>
|
||||||
|
<td>
|
||||||
|
<span t-field="player.injured_since"
|
||||||
|
t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="player.predicted_return_date"
|
||||||
|
t-options="{'widget': 'date'}"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
<template id="portal_breadcrumbs" inherit_id="portal.portal_breadcrumbs">
|
||||||
|
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
|
||||||
|
<li t-if="page_name == 'my_teams'"
|
||||||
|
t-attf-class="breadcrumb-item #{'active ' if not team else ''}">
|
||||||
|
<a t-if="team"
|
||||||
|
t-attf-href="/my/teams?{{ keep_query() }}">Teams</a>
|
||||||
|
<t t-else="">Teams</t>
|
||||||
|
</li>
|
||||||
|
<li t-if="team" class="breadcrumb-item active" t-esc="team.name"/>
|
||||||
|
<li t-if="page_name == 'my_players'"
|
||||||
|
t-attf-class="breadcrumb-item #{'active ' if not player else ''}">
|
||||||
|
<a t-if="player"
|
||||||
|
t-attf-href="/my/players?{{ keep_query() }}">Players</a>
|
||||||
|
<t t-else="">Players</t>
|
||||||
|
</li>
|
||||||
|
<li t-if="player" class="breadcrumb-item active" t-esc="player.name"/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
Loading…
Reference in a new issue