Completes iteration 4 without translations.
This commit is contained in:
parent
44f391802d
commit
d6c40a456e
8 changed files with 96 additions and 31 deletions
|
|
@ -37,7 +37,7 @@
|
|||
'author': 'Bemade Inc.',
|
||||
'website': 'https://www.bemade.org',
|
||||
'license': 'OPL-1',
|
||||
'depends': ['base', 'mail', 'portal'],
|
||||
'depends': ['portal', 'contacts'],
|
||||
'data': [
|
||||
'security/sports_clinic_groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
|
|
|||
|
|
@ -88,10 +88,12 @@ class TeamStaffPortal(CustomerPortal):
|
|||
'page_name': 'my_players',
|
||||
})
|
||||
|
||||
@http.route(route=['/my/players/<int:player_id>'], type='http', auth='user', website=True)
|
||||
def view_player(self, player_id, **kw):
|
||||
@http.route(route=['/my/players/<int:player_id>', '/my/players/<int:player_id>/<int:team_id>'], type='http',
|
||||
auth='user', website=True)
|
||||
def view_player(self, player_id, team_id=None,**kw):
|
||||
""" Display the active injuries for a given player. """
|
||||
player = http.request.env['sports.patient'].browse(player_id)
|
||||
team = team_id and http.request.env['sports.team'].browse(player_id)
|
||||
if not player:
|
||||
raise UserError(_('This player could not be found.'))
|
||||
injuries = player.injury_ids.filtered(lambda r: r.stage == 'active')
|
||||
|
|
@ -100,6 +102,6 @@ class TeamStaffPortal(CustomerPortal):
|
|||
qcontext={
|
||||
'player': player,
|
||||
'injuries': injuries,
|
||||
'page_name': 'my_player_injuries',
|
||||
'team': team
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,18 @@ class Patient(models.Model):
|
|||
last_consultation_date = fields.Date()
|
||||
active_injury_count = fields.Integer(compute='_compute_active_injury_count')
|
||||
|
||||
@api.constrains('match_status', 'practice_status')
|
||||
def constrain_match_and_practice_status(self):
|
||||
""" Avoid invalid combinations of match and practice status:
|
||||
- Yes (match), No (practice)
|
||||
- Yes (match), No Contact (practice)
|
||||
"""
|
||||
# combinations of (match_status, practice_status) that are valid
|
||||
valid_combinations = [('yes', 'yes'), ('no', 'yes'), ('no', 'no_contact'), ('no', 'no')]
|
||||
for rec in self:
|
||||
if (rec.match_status, rec.practice_status) not in valid_combinations:
|
||||
raise ValidationError(_("Invalid combination of match and practice status."))
|
||||
|
||||
@api.depends('injury_ids.stage')
|
||||
def _compute_active_injury_count(self):
|
||||
for rec in self:
|
||||
|
|
@ -64,13 +76,17 @@ class Patient(models.Model):
|
|||
|
||||
@api.depends('match_status', 'practice_status')
|
||||
def _compute_stage(self):
|
||||
stage_map = {
|
||||
('yes', 'yes'): 'healthy',
|
||||
('no', 'yes'): 'practice_ok',
|
||||
('no', 'no_contact'): 'practice_ok',
|
||||
('no', 'no'): 'no_play',
|
||||
}
|
||||
for rec in self:
|
||||
if rec.match_status == 'yes' and rec.practice_status == 'yes':
|
||||
rec.stage = 'healthy'
|
||||
elif rec.match_status == 'no' and rec.practice_status == 'no_contact':
|
||||
rec.stage = 'practice_ok'
|
||||
else:
|
||||
rec.stage = 'no_play'
|
||||
if (rec.match_status, rec.practice_status) not in stage_map:
|
||||
rec.stage = False # not a valid combination, will be caught by constraint if save is attempted
|
||||
continue
|
||||
rec.stage = stage_map[(rec.match_status, rec.practice_status)]
|
||||
|
||||
@api.depends('date_of_birth')
|
||||
def _compute_age(self):
|
||||
|
|
@ -91,9 +107,8 @@ class Patient(models.Model):
|
|||
for rec in self:
|
||||
rec.is_injured = rec.practice_status != 'yes' or rec.match_status != 'yes'
|
||||
if rec.is_injured:
|
||||
rec.injured_since = \
|
||||
rec.injury_ids and rec.injury_ids.filtered(lambda r: not r.stage == 'resolved').sorted(
|
||||
'injury_date_time')[0].injury_date_time
|
||||
unresolved_injuries = rec.injury_ids.filtered(lambda r: not r.stage == 'resolved')
|
||||
rec.injured_since = unresolved_injuries and unresolved_injuries[0].injury_date_time
|
||||
else:
|
||||
rec.injured_since = False
|
||||
|
||||
|
|
@ -160,14 +175,15 @@ class PatientInjury(models.Model):
|
|||
predicted_resolution_date = fields.Date(tracking=True)
|
||||
resolution_date = fields.Date(tracking=True,
|
||||
help="The date when the injury was actually resolved.")
|
||||
stage = fields.Selection(selection=[('active', 'Active'), ('resolved', 'Resolved')], tracking=True, required=True,
|
||||
default='active', readonly=False)
|
||||
stage = fields.Selection(selection=[('active', 'Active'), ('resolved', 'Resolved')], compute='_compute_stage')
|
||||
|
||||
@api.constrains('stage')
|
||||
def constrain_stage_on_resolution_date(self):
|
||||
@api.depends('resolution_date')
|
||||
def _compute_stage(self):
|
||||
for rec in self:
|
||||
if rec.stage == 'resolved' and not rec.resolution_date:
|
||||
raise ValidationError(_('Cannot set an injury as resolved without setting the resolution date first.'))
|
||||
if rec.resolution_date and rec.resolution_date <= date.today():
|
||||
rec.stage = 'resolved'
|
||||
else:
|
||||
rec.stage = 'active'
|
||||
|
||||
def write(self, vals):
|
||||
super().write(vals)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo import models, fields, api, _, Command
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ class TeamStaff(models.Model):
|
|||
sequence = fields.Integer()
|
||||
team_id = fields.Many2one(comodel_name='sports.team', string='Team', required=True)
|
||||
partner_id = fields.Many2one(comodel_name='res.partner', string='Staff Member',
|
||||
required=True)
|
||||
required=True, domain=[('is_company', '=', False)])
|
||||
role = fields.Selection(selection=[
|
||||
('head_coach', 'Head Coach'),
|
||||
('head_trainer', 'Head Trainer'),
|
||||
|
|
@ -66,8 +66,11 @@ class TeamStaff(models.Model):
|
|||
], required=True)
|
||||
phone = fields.Char(related='partner_id.phone', readonly=False)
|
||||
name = fields.Char(related='partner_id.name', readonly=False)
|
||||
parent_id = fields.Many2one(related='partner_id.parent_id', readonly=False, string="Organization")
|
||||
parent_id = fields.Many2one(related='partner_id.parent_id', readonly=False, string="Organization",
|
||||
domain=[('is_company', '=', True)])
|
||||
email = fields.Char(related='parent_id.email', readonly=False)
|
||||
user_ids = fields.One2many(related='partner_id.user_ids', readonly=True)
|
||||
has_portal_access = fields.Boolean(compute='_compute_has_portal_access')
|
||||
|
||||
_sql_constraints = [('team_staff_unique', 'unique(team_id, partner_id)',
|
||||
'Each partner can only be related to a given team once.')]
|
||||
|
|
@ -84,4 +87,22 @@ class TeamStaff(models.Model):
|
|||
@api.onchange('phone')
|
||||
def _onchange_phone_validation(self):
|
||||
if self.phone:
|
||||
self.phone = self.partner_id._phone_format(self.phone, force_format='INTERNATIONAL')
|
||||
self.phone = self.partner_id._phone_format(self.phone, force_format='INTERNATIONAL')
|
||||
|
||||
@api.depends('user_ids', 'user_ids.groups_id')
|
||||
def _compute_has_portal_access(self):
|
||||
for rec in self:
|
||||
rec.has_portal_access = bool(rec.user_ids.filtered(lambda r: r.has_group('base.group_portal'))) or bool(
|
||||
rec.user_ids.filtered(lambda r: r.has_group('base.group_user'))) or bool(rec.partner_id.signup_token)
|
||||
|
||||
def action_revoke_portal_access(self):
|
||||
group_portal = self.env.ref('base.group_portal')
|
||||
group_public = self.env.ref('base.group_public')
|
||||
self.user_ids.write(
|
||||
{'groups_id': [Command.unlink(group_portal.id), Command.link(group_public.id)], 'active': False})
|
||||
# Remove the signup token, so it cannot be used
|
||||
self.partner_id.sudo().signup_token = False
|
||||
|
||||
def action_grant_portal_access(self):
|
||||
wiz = self.env['portal.wizard'].create({'partner_ids': [(4, self.partner_id.id)]})
|
||||
return wiz._action_open_modal()
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@
|
|||
<field name="groups" eval="[(6, 0, [ref('base.group_portal')])]"/>
|
||||
<field name="domain_force">
|
||||
[('id', 'in',
|
||||
user.partner_id.team_staff_rel_ids.mapped('team_id').mapped(
|
||||
'patient_ids').ids)]
|
||||
user.partner_id.team_staff_rel_ids.team_id.patient_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
<tbody>
|
||||
<t t-foreach="players" t-as="player">
|
||||
<t t-set="stage" t-value="player.stage"/>
|
||||
<t t-set="url" t-value="'/my/players/' + str(player.id)"/>
|
||||
<t t-set="url" t-value="'/my/players/' + str(player.id) + '/' + str(team.id)"/>
|
||||
<tr t-attf-class="{{ ('text-danger' if stage == 'no_play'
|
||||
else 'text-warning') if stage != 'healthy'
|
||||
else '' }}">
|
||||
|
|
@ -191,13 +191,26 @@
|
|||
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_teams' and 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 and page_name == 'my_player'" class="breadcrumb-item active">
|
||||
<a t-attf-href="/my/players?{{ keep_query() }}">Players</a>
|
||||
<span t-field="player.name"/>
|
||||
</li>
|
||||
<li t-if="player and team" class="breadcrumb-item">
|
||||
<a href="/my/teams">Teams</a>
|
||||
</li>
|
||||
<li t-if="player" class="breadcrumb-item">
|
||||
<a t-if="team" t-attf-href="/my/team/{{ team.id }}?{{ keep_query() }}">
|
||||
<span t-field="team.name"/>
|
||||
</a>
|
||||
<a t-else="" t-attf-href="/my/players/{{ keep_query() }}">Players</a>
|
||||
</li>
|
||||
<li t-if="player" class="breadcrumb-item active">
|
||||
<span t-field="player.name"/>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<field name="stage" widget="statusbar" options="{'clickable': '1'}" />
|
||||
<field name="stage" widget="statusbar" />
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box"></div>
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<field name="stage" widget="statusbar" options="{'clickable': '1'}"/>
|
||||
<field name="stage" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
|
|
|
|||
|
|
@ -107,6 +107,20 @@
|
|||
<field name="name"/>
|
||||
<field name="role"/>
|
||||
<field name="phone" widget="phone"/>
|
||||
<field name="has_portal_access" invisible="1"/>
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<button name="action_grant_portal_access"
|
||||
type="object" icon="fa-user-plus"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('has_portal_access', '=', True)]}"
|
||||
title="Grant Portal Access"
|
||||
groups="bemade_sports_clinic.group_sports_clinic_admin,base.group_system"/>
|
||||
<button name="action_revoke_portal_access" type="object" icon="fa-ban"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('has_portal_access', '=', False)]}"
|
||||
title="Revoke Portal Access"
|
||||
groups="bemade_sports_clinic.group_sports_clinic_admin,base.group_system"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
|
@ -126,7 +140,7 @@
|
|||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="role"/>
|
||||
</group>
|
||||
|
|
|
|||
Loading…
Reference in a new issue