bemade_sports_clinic: Lots of work on models and views for second iteration.
This commit is contained in:
parent
62a33f633f
commit
d92c124f50
12 changed files with 383 additions and 180 deletions
|
|
@ -42,7 +42,7 @@
|
|||
'security/sports_clinic_groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/sports_clinic_rules.xml',
|
||||
'views/res_partner_views.xml',
|
||||
'views/sports_team_views.xml',
|
||||
'views/sports_clinic_menus.xml',
|
||||
'views/patient_views.xml',
|
||||
'views/sports_clinic_portal_views.xml',
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ class TeamStaffPortal(CustomerPortal):
|
|||
partner = http.request.env.user.partner_id
|
||||
return [
|
||||
('staff_partner_ids', 'in', partner.id),
|
||||
('type', '=', 'team'),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -19,19 +19,39 @@
|
|||
<field name="phone">+1 (514) 343-6111</field>
|
||||
<field name="website">https://www.umontreal.ca</field>
|
||||
</record>
|
||||
<record id="team_carabins" model="res.partner">
|
||||
<record id="team_carabins" model="sports.team">
|
||||
<field name="name">Carabins (Football masculin)</field>
|
||||
<field name="type">team</field>
|
||||
<field name="parent_id" ref="partner_org_1"/>
|
||||
<field name="website">https://carabins.umontreal.ca/football</field>
|
||||
</record>
|
||||
<record id="partner_coach_team_carabins" model="res.partner">
|
||||
<field name="name">Jean U. DeMontreal</field>
|
||||
<field name="email">jean.u.demontreal@carabins.umontreal.ca</field>
|
||||
<field name="parent_id" ref="partner_org_1"/>
|
||||
</record>
|
||||
<record id="carabins_coach_rel" model="sports.team.staff">
|
||||
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
||||
<field name="team_id" ref="team_carabins"/>
|
||||
<field name="role">head_coach</field>
|
||||
</record>
|
||||
<record id="partner_trainer_team_carabins" model="res.partner">
|
||||
<field name="name">Stretch Carabinier</field>
|
||||
<field name="email">streth.carabinier@carabins.umontreal.ca</field>
|
||||
<field name="parent_id" ref="partner_org_1"/>
|
||||
</record>
|
||||
<record id="carabins_trainer_rel" model="sports.team.staff">
|
||||
<field name="partner_id" ref="partner_trainer_team_carabins"/>
|
||||
<field name="team_id" ref="team_carabins"/>
|
||||
<field name="role">head_trainer</field>
|
||||
</record>
|
||||
<record id="patient_1" model="sports.patient">
|
||||
<field name="first_name">Jean</field>
|
||||
<field name="last_name">Carabin</field>
|
||||
<field name="team_ids" eval="[Command.set([ref('team_carabins')])]"/>
|
||||
<field name="date_of_birth">2001-08-23</field>
|
||||
<field name="email">jean.carabin@edudiants.umontreal.ca</field>
|
||||
<field name="player_status">match</field>
|
||||
<field name="match_status">no</field>
|
||||
<field name="practice_status">no</field>
|
||||
</record>
|
||||
<record id="patient_2" model="sports.patient">
|
||||
<field name="first_name">Rémi</field>
|
||||
|
|
@ -39,21 +59,32 @@
|
|||
<field name="team_ids" eval="[Command.set([ref('team_carabins')])]"/>
|
||||
<field name="date_of_birth">2002-05-17</field>
|
||||
<field name="email">remi.lafracture@edudiants.umontreal.ca</field>
|
||||
<field name="player_status">practice</field>
|
||||
<field name="match_status">yes</field>
|
||||
<field name="practice_status">yes</field>
|
||||
</record>
|
||||
<record id="team_carabins_hockey" model="res.partner">
|
||||
<record id="team_carabins_hockey" model="sports.team">
|
||||
<field name="name">Carabins (Hockey féminin)</field>
|
||||
<field name="type">team</field>
|
||||
<field name="parent_id" ref="partner_org_1"/>
|
||||
<field name="website">https://carabins.umontreal.ca/football</field>
|
||||
</record>
|
||||
<record id="carabins_hockey_coach_rel" model="sports.team.staff">
|
||||
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
||||
<field name="team_id" ref="team_carabins_hockey"/>
|
||||
<field name="role">head_coach</field>
|
||||
</record>
|
||||
<record id="carabins_hockey_trainer_rel" model="sports.team.staff">
|
||||
<field name="partner_id" ref="partner_trainer_team_carabins"/>
|
||||
<field name="team_id" ref="team_carabins_hockey"/>
|
||||
<field name="role">head_trainer</field>
|
||||
</record>
|
||||
<record id="patient_3" model="sports.patient">
|
||||
<field name="first_name">Jeanne</field>
|
||||
<field name="last_name">Carabine</field>
|
||||
<field name="team_ids" eval="[Command.set([ref('team_carabins_hockey')])]"/>
|
||||
<field name="date_of_birth">2001-08-23</field>
|
||||
<field name="email">jeanne.carabine@edudiants.umontreal.ca</field>
|
||||
<field name="player_status">match</field>
|
||||
<field name="match_status">no</field>
|
||||
<field name="practice_status">no_contact</field>
|
||||
</record>
|
||||
<record id="patient_4" model="sports.patient">
|
||||
<field name="first_name">Rimée</field>
|
||||
|
|
@ -61,7 +92,8 @@
|
|||
<field name="team_ids" eval="[Command.set([ref('team_carabins_hockey')])]"/>
|
||||
<field name="date_of_birth">2004-11-22</field>
|
||||
<field name="email">rimee.lafracture@edudiants.umontreal.ca</field>
|
||||
<field name="player_status">practice</field>
|
||||
<field name="match_status">yes</field>
|
||||
<field name="practice_status">yes</field>
|
||||
</record>
|
||||
<record id="partner_org_2" model="res.partner">
|
||||
<field name="name">Université Concordia</field>
|
||||
|
|
@ -72,9 +104,8 @@
|
|||
<field name="zip">H3G 1M8</field>
|
||||
<field name="website">https://www.concordia.ca</field>
|
||||
</record>
|
||||
<record id="team_stingers" model="res.partner">
|
||||
<record id="team_stingers" model="sports.team">
|
||||
<field name="name">Stingers (Hockey masculin)</field>
|
||||
<field name="type">team</field>
|
||||
<field name="parent_id" ref="partner_org_2"/>
|
||||
<field name="website">https://stingers.ca/mhockey/</field>
|
||||
</record>
|
||||
|
|
@ -84,7 +115,8 @@
|
|||
<field name="team_ids" eval="[Command.set([ref('team_stingers')])]"/>
|
||||
<field name="date_of_birth">2003-11-02</field>
|
||||
<field name="email">jo_stinger@encs.concordia.ca</field>
|
||||
<field name="player_status">match</field>
|
||||
<field name="match_status">yes</field>
|
||||
<field name="practice_status">yes</field>
|
||||
</record>
|
||||
<record id="patient_6" model="sports.patient">
|
||||
<field name="first_name">Jimmy</field>
|
||||
|
|
@ -92,12 +124,13 @@
|
|||
<field name="team_ids" eval="[Command.set([ref('team_stingers')])]"/>
|
||||
<field name="date_of_birth">2001-01-05</field>
|
||||
<field name="email">jim_bee@jmsb.concordia.ca</field>
|
||||
<field name="player_status">match</field>
|
||||
<field name="match_status">yes</field>
|
||||
<field name="practice_status">yes</field>
|
||||
</record>
|
||||
<record id="injury_1" model="sports.patient.injury">
|
||||
<field name="injury_date_time">2023-05-17 18:53:00</field>
|
||||
<field name="diagnosis">Fracture du fémur</field>
|
||||
<field name="predicted_return_date">2024-02-01</field>
|
||||
<field name="predicted_resolution_date">2024-02-01</field>
|
||||
<field name="patient_id" ref="patient_1"/>
|
||||
<field name="treatment_professional_ids"
|
||||
eval="[Command.set([ref('base.partner_admin')])]"/>
|
||||
|
|
@ -105,7 +138,7 @@
|
|||
<record id="injury_2" model="sports.patient.injury">
|
||||
<field name="injury_date_time">2022-03-17 19:13:00</field>
|
||||
<field name="diagnosis">Entorse cheville droite</field>
|
||||
<field name="predicted_return_date">2022-03-23</field>
|
||||
<field name="predicted_resolution_date">2022-03-23</field>
|
||||
<field name="patient_id" ref="patient_1"/>
|
||||
<field name="treatment_professional_ids"
|
||||
eval="[Command.set([ref('base.partner_admin')])]"/>
|
||||
|
|
@ -113,15 +146,36 @@
|
|||
<record id="injury_3" model="sports.patient.injury">
|
||||
<field name="injury_date_time">2023-10-15 19:55:00</field>
|
||||
<field name="diagnosis">Commotion cérébrale mineure</field>
|
||||
<field name="predicted_return_date">2023-11-01</field>
|
||||
<field name="predicted_resolution_date">2023-11-01</field>
|
||||
<field name="patient_id" ref="patient_3"/>
|
||||
<field name="treatment_professional_ids"
|
||||
eval="[Command.set([ref('base.partner_admin')])]"/>
|
||||
</record>
|
||||
<record id="base.partner_demo_portal" model="res.partner">
|
||||
<field name="parent_id" ref="team_carabins"/>
|
||||
<field name="function">Coach</field>
|
||||
<field name="staff_team_ids" eval="[Command.link(ref('team_carabins'))]"/>
|
||||
<record id="stingers_coach_rel" model="sports.team.staff">
|
||||
<field name="partner_id" ref="base.partner_demo_portal"/>
|
||||
<field name="team_id" ref="team_stingers"/>
|
||||
<field name="role">head_coach</field>
|
||||
</record>
|
||||
<record id="carabins_trainer_user" model="res.users" context="{'no_reset_password': True}">
|
||||
<field name="partner_id" ref="partner_trainer_team_carabins"/>
|
||||
<field name="login">trainer</field>
|
||||
<field name="password">trainer</field>
|
||||
<field name="groups_id" eval="[Command.clear()]"/>
|
||||
</record>
|
||||
<record id="carabins_coach_user" model="res.users" context="{'no_reset_password': True}">
|
||||
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
||||
<field name="login">coach</field>
|
||||
<field name="password">coach</field>
|
||||
<field name="groups_id" eval="[Command.clear()]"/>
|
||||
</record>
|
||||
<record id="base.group_portal" model="res.groups">
|
||||
<field name="users" eval="[Command.link(ref('carabins_trainer_user'))]"/>
|
||||
</record>
|
||||
<record id="base.group_portal" model="res.groups">
|
||||
<field name="users" eval="[Command.link(ref('carabins_coach_user'))]"/>
|
||||
</record>
|
||||
<record id="group_sports_clinic_admin" model="res.groups">
|
||||
<field name="users" eval="[Command.link(ref('base.user_admin'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
from . import patient
|
||||
from . import res_partner
|
||||
from . import sports_team
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from odoo import models, fields, _, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from datetime import date
|
||||
from datetime import date, datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
|
|
@ -9,46 +9,46 @@ class Patient(models.Model):
|
|||
_description = "Patient at a sports medicine clinic."
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
first_name = fields.Char(required=True)
|
||||
last_name = fields.Char(required=True)
|
||||
first_name = fields.Char(required=True, tracking=True)
|
||||
last_name = fields.Char(required=True, tracking=True)
|
||||
name = fields.Char(compute="_compute_name")
|
||||
date_of_birth = fields.Date(
|
||||
groups="bemade_sports_clinic.group_sports_clinic_treatment_professional")
|
||||
groups="bemade_sports_clinic.group_sports_clinic_treatment_professional",
|
||||
tracking=True)
|
||||
age = fields.Integer(compute='_compute_age',
|
||||
groups="bemade_sports_clinic.group_sports_clinic_treatment_professional")
|
||||
groups="bemade_sports_clinic.group_sports_clinic_treatment_professional",
|
||||
tracking=True)
|
||||
phone = fields.Char(unaccent=False,
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user")
|
||||
email = fields.Char(groups="bemade_sports_clinic.group_sports_clinic_user")
|
||||
contact_ids = fields.One2many(comodel_name='sports.patient.contact',
|
||||
inverse_name='patient_id', string='Patient Contacts',
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user")
|
||||
team_ids = fields.Many2many(comodel_name='res.partner',
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user",
|
||||
tracking=True)
|
||||
email = fields.Char(groups="bemade_sports_clinic.group_sports_clinic_user",
|
||||
tracking=True)
|
||||
contact_ids = fields.Many2many(comodel_name='sports.patient.contact',
|
||||
relation="patient_contact_rel",
|
||||
column1="patient_id",
|
||||
column2="contact_id",
|
||||
string='Patient Contacts',
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user")
|
||||
team_ids = fields.Many2many(comodel_name='sports.team',
|
||||
relation='sports_team_patient_rel',
|
||||
column1='patient_id',
|
||||
column2='team_id',
|
||||
string='Teams',
|
||||
domain=[('type', '=', 'team')])
|
||||
player_status = fields.Selection([
|
||||
('practice', 'Practice'),
|
||||
('match', 'Match'),
|
||||
])
|
||||
string='Teams', )
|
||||
match_status = fields.Selection([ # Selection for easy expansion later
|
||||
('yes', 'Yes'),
|
||||
('no', 'No'),
|
||||
], required=True, default='yes', tracking=True)
|
||||
practice_status = fields.Selection([
|
||||
('yes', 'Yes'),
|
||||
('no_contact', 'Yes, no contact'),
|
||||
('no', 'No')], tracking=True, required=True, default='yes')
|
||||
|
||||
injury_ids = fields.One2many(comodel_name='sports.patient.injury',
|
||||
inverse_name='patient_id',
|
||||
string='Injuries', )
|
||||
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)
|
||||
#
|
||||
# @api.depends('injury_ids.treatment_professional_ids', 'team_ids.staff_team_ids',
|
||||
# 'message_follower_ids')
|
||||
# def _compute_authorized_users(self):
|
||||
# for rec in self:
|
||||
# auth_users = self.env['res.users'].search(['|', ('partner_id', 'in',
|
||||
# rec.injury_ids.mapped('treatment_professional_ids').ids),
|
||||
# '|', ('partner_id', 'in', rec.team_ids.mapped('staff_team_ids').ids),
|
||||
# ('partner_id', 'in', rec.message_follower_ids.ids)])
|
||||
predicted_return_date = fields.Date()
|
||||
is_injured = fields.Boolean(compute="_compute_is_injured")
|
||||
|
||||
@api.depends('date_of_birth')
|
||||
def _compute_age(self):
|
||||
|
|
@ -58,35 +58,16 @@ class Patient(models.Model):
|
|||
else:
|
||||
rec.age = relativedelta(date.today(), rec.date_of_birth).years
|
||||
|
||||
@api.depends('injury_ids.predicted_return_date')
|
||||
def _compute_predicted_return_date(self):
|
||||
for rec in self:
|
||||
ongoing_injuries = rec.injury_ids.filtered(
|
||||
lambda r: r.predicted_return_date > date.today()).sorted(
|
||||
'predicted_return_date')
|
||||
if ongoing_injuries:
|
||||
rec.predicted_return_date = ongoing_injuries[-1]. \
|
||||
predicted_return_date
|
||||
else:
|
||||
rec.predicted_return_date = False
|
||||
|
||||
@api.depends('first_name', 'last_name')
|
||||
def _compute_name(self):
|
||||
for rec in self:
|
||||
rec.name = ((rec.first_name or "") + " " + (rec.last_name or
|
||||
"")).strip()
|
||||
|
||||
@api.depends('injury_ids.is_resolved')
|
||||
@api.depends('practice_status', 'match_status')
|
||||
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
|
||||
for rec in self:
|
||||
rec.is_injured = rec.practice_status != 'yes' or rec.match_status != 'yes'
|
||||
|
||||
|
||||
class PatientContact(models.Model):
|
||||
|
|
@ -99,9 +80,13 @@ class PatientContact(models.Model):
|
|||
('Mother', 'mother'),
|
||||
('Father', 'father'),
|
||||
('other', 'Other'),
|
||||
])
|
||||
phone = fields.Char(unaccent=False)
|
||||
patient_id = fields.Many2one(comodel_name='sports.patient', string="Patient")
|
||||
], required=True)
|
||||
phone = fields.Char(unaccent=False, required=True)
|
||||
patient_id = fields.Many2many(comodel_name='sports.patient', string="Patient",
|
||||
relation="patient_contact_rel",
|
||||
column1="contact_id", column2="patient_id",
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user",
|
||||
required=True)
|
||||
|
||||
|
||||
class PatientInjury(models.Model):
|
||||
|
|
@ -111,10 +96,12 @@ class PatientInjury(models.Model):
|
|||
|
||||
patient_id = fields.Many2one(comodel_name='sports.patient',
|
||||
string="Patient",
|
||||
readonly=True)
|
||||
readonly=True,
|
||||
required=True)
|
||||
patient_name = fields.Char(related="patient_id.name")
|
||||
diagnosis = fields.Char(tracking=True)
|
||||
injury_date_time = fields.Datetime(string='Date and Time of Injury')
|
||||
injury_date_time = fields.Datetime(string='Date and Time of Injury', required=True,
|
||||
default=datetime.now())
|
||||
internal_notes = fields.Html(tracking=True)
|
||||
treatment_professional_ids = fields.Many2many(comodel_name='res.partner',
|
||||
relation='patient_injury_treatment_pro_rel',
|
||||
|
|
@ -123,9 +110,9 @@ class PatientInjury(models.Model):
|
|||
string='Treatment Professionals',
|
||||
domain=[
|
||||
('is_treatment_professional', '=',
|
||||
True)], )
|
||||
predicted_return_date = fields.Date(tracking=True)
|
||||
is_resolved = fields.Boolean(compute="_compute_is_resolved")
|
||||
True)], tracking=True)
|
||||
predicted_resolution_date = fields.Date(tracking=True)
|
||||
is_resolved = fields.Boolean(tracking=True, required=True, default=False)
|
||||
|
||||
def write(self, vals):
|
||||
super().write(vals)
|
||||
|
|
@ -142,10 +129,3 @@ class PatientInjury(models.Model):
|
|||
- rec.message_follower_ids.mapped('partner_id'))
|
||||
rec.message_subscribe(to_subscribe.ids)
|
||||
return res
|
||||
|
||||
@api.depends('predicted_return_date')
|
||||
def _compute_is_resolved(self):
|
||||
to_compute = self.filtered(lambda r: r.predicted_return_date)
|
||||
for rec in to_compute:
|
||||
rec.is_resolved = rec.predicted_return_date < date.today()
|
||||
(self - to_compute).is_resolved = False
|
||||
|
|
|
|||
|
|
@ -5,45 +5,16 @@ from odoo.exceptions import UserError
|
|||
class Partner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
patient_ids = fields.Many2many(comodel_name='sports.patient',
|
||||
relation='sports_team_patient_rel',
|
||||
column1='team_id',
|
||||
column2='patient_id',
|
||||
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'), ])
|
||||
staff_partner_ids = fields.Many2many(comodel_name='res.partner',
|
||||
relation='sports_team_staff_partner_rel',
|
||||
column1='team_id',
|
||||
column2='staff_partner_id',
|
||||
string='Staff')
|
||||
staff_team_ids = fields.Many2many(comodel_name='res.partner',
|
||||
relation='sports_team_staff_partner_rel',
|
||||
column1='staff_partner_id',
|
||||
column2='team_id',
|
||||
string='Teams')
|
||||
|
||||
is_treatment_professional = fields.Boolean(
|
||||
compute="_compute_is_treatment_professional",)
|
||||
|
||||
def write(self, vals):
|
||||
teams = self.filtered(lambda r: r.type == 'team')
|
||||
if teams and 'type' in vals and vals['type'] != 'team':
|
||||
if teams.mapped('staff_partner_ids') or teams.mapped('patient_ids'):
|
||||
raise UserError(_('Sports team is related to patients and/or staff. '
|
||||
'Its type cannot be changed until these relations are '
|
||||
'removed.'))
|
||||
return super().write(vals)
|
||||
|
||||
def unlink(self):
|
||||
teams = self.filtered(lambda r: r.type == 'team')
|
||||
if teams:
|
||||
if teams.mapped('staff_partner_ids') or teams.mapped('patient_ids'):
|
||||
raise UserError(_('Sports team is related to patients and/or staff. '
|
||||
'Its type cannot be deleted until these relations are '
|
||||
'removed. You may try archiving it instead.'))
|
||||
return super().unlink()
|
||||
compute="_compute_is_treatment_professional", )
|
||||
owned_team_ids = fields.One2many(comodel_name='sports.team',
|
||||
inverse_name='parent_id')
|
||||
staff_ids = fields.One2many(comodel_name='sports.team.staff',
|
||||
inverse_name='team_id')
|
||||
team_staff_rel_ids = fields.One2many(comodel_name='sports.team.staff',
|
||||
inverse_name='partner_id',
|
||||
string='Teams Served',
|
||||
help='The teams this person works for.')
|
||||
|
||||
@api.depends('user_ids.groups_id')
|
||||
def _compute_is_treatment_professional(self):
|
||||
|
|
@ -54,9 +25,3 @@ class Partner(models.Model):
|
|||
'bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
for rec in user_partners:
|
||||
rec.is_treatment_professional = group in rec.user_ids.groups_id
|
||||
|
||||
@api.depends('patient_ids.is_injured')
|
||||
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))
|
||||
|
|
|
|||
76
bemade_sports_clinic/models/sports_team.py
Normal file
76
bemade_sports_clinic/models/sports_team.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SportsTeam(models.Model):
|
||||
_name = "sports.team"
|
||||
_description = "Sports Team"
|
||||
|
||||
name = fields.Char()
|
||||
patient_ids = fields.Many2many(comodel_name='sports.patient',
|
||||
relation='sports_team_patient_rel',
|
||||
column1='team_id',
|
||||
column2='patient_id',
|
||||
string='Players')
|
||||
player_count = fields.Integer(compute="_compute_player_counts")
|
||||
injured_count = fields.Integer(compute="_compute_player_counts")
|
||||
healthy_count = fields.Integer(compute="_compute_player_counts")
|
||||
parent_id = fields.Many2one(comodel_name='res.partner', string='Parent Organization',
|
||||
ondelete='restrict')
|
||||
staff_ids = fields.One2many(comodel_name='sports.team.staff',
|
||||
inverse_name='team_id')
|
||||
head_coach_id = fields.Many2one(comodel_name='res.partner',
|
||||
compute='_compute_head_coach')
|
||||
head_coach_name = fields.Char(related='head_coach_id.name')
|
||||
head_trainer_id = fields.Many2one(comodel_name='res.partner',
|
||||
compute='_compute_head_trainer')
|
||||
head_trainer_name = fields.Char(related='head_trainer_id.name')
|
||||
website = fields.Char()
|
||||
|
||||
@api.depends('patient_ids.is_injured')
|
||||
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))
|
||||
rec.healthy_count = rec.player_count - rec.injured_count
|
||||
|
||||
@api.depends('staff_ids.role')
|
||||
def _compute_head_coach(self):
|
||||
for rec in self:
|
||||
staff = rec.staff_ids.filtered(lambda r: r.role == 'head_coach')
|
||||
rec.head_coach_id = staff.partner_id if staff else False
|
||||
|
||||
@api.depends('staff_ids.role')
|
||||
def _compute_head_trainer(self):
|
||||
for rec in self:
|
||||
staff = rec.staff_ids.filtered(lambda r: r.role == 'head_trainer')
|
||||
rec.head_trainer_id = staff.partner_id if staff else False
|
||||
|
||||
|
||||
class TeamStaff(models.Model):
|
||||
_name = "sports.team.staff"
|
||||
_description = "Relationship between staff members and their teams."
|
||||
|
||||
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)
|
||||
role = fields.Selection(selection=[
|
||||
('head_coach', 'Head Coach'),
|
||||
('head_trainer', 'Head Trainer'),
|
||||
('coach', 'Coach'),
|
||||
('trainer', 'Trainer'),
|
||||
('other', 'Other')
|
||||
], required=True)
|
||||
|
||||
_sql_constraints = [('team_staff_unique', 'unique(team_id, partner_id)',
|
||||
'Each partner can only be related to a given team once.')]
|
||||
|
||||
@api.constrains('role')
|
||||
def _constrain_role(self):
|
||||
teams = self.mapped('team_id')
|
||||
for team in teams:
|
||||
if len(team.staff_ids.filtered(lambda r: r.role == 'head_coach')) > 1:
|
||||
raise ValidationError(_("A team can have only one head coach."))
|
||||
if len(team.staff_ids.filtered(lambda r: r.role == 'head_trainer')) > 1:
|
||||
raise ValidationError(_("A team can have only one head trainer."))
|
||||
|
|
@ -5,4 +5,9 @@ access_patient_admin,Admin Access for Patients,model_sports_patient,group_sports
|
|||
access_patient_portal,Portal Access for Patients,model_sports_patient,base.group_portal,1,1,1,0
|
||||
access_patient_contact_user,User Access for Patient Contacts,model_sports_patient_contact,group_sports_clinic_user,1,1,1,1
|
||||
access_injury_treatment_pro,Treatment Professional Access for Injuries,model_sports_patient_injury,group_sports_clinic_treatment_professional,1,1,1,1
|
||||
access_injury_portal,Portal Access for Injuries,model_sports_patient_injury,base.group_portal,1,0,0,0
|
||||
access_injury_portal,Portal Access for Injuries,model_sports_patient_injury,base.group_portal,1,0,0,0
|
||||
access_team_user,User Access for Teams,model_sports_team,group_sports_clinic_user,1,1,1,0
|
||||
access_team_admin,Admin Access for Teams,model_sports_team,group_sports_clinic_admin,1,1,1,1
|
||||
access_team_portal,Portal Access for Teams,model_sports_team,base.group_portal,1,0,0,0
|
||||
access_team_staff_user,User Access for Team Staff,model_sports_team_staff,group_sports_clinic_user,1,1,1,1
|
||||
access_team_staff_portal,Portal Access for Team Staff,model_sports_team_staff,base.group_portal,1,0,0,0
|
||||
|
|
|
|||
|
|
|
@ -26,6 +26,8 @@
|
|||
<field name="date_of_birth"/>
|
||||
<field name="age"/>
|
||||
<field name="team_ids" widget="many2many_tags"/>
|
||||
<field name="match_status"/>
|
||||
<field name="practice_status"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -50,16 +52,33 @@
|
|||
<separator string="Team Information"/>
|
||||
<field name="team_ids"
|
||||
widget="many2many_tags"/>
|
||||
<field name="player_status"/>
|
||||
<field name="match_status"/>
|
||||
<field name="practice_status"/>
|
||||
<field name="predicted_return_date"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Injuries">
|
||||
<field name="injury_ids"/>
|
||||
</page>
|
||||
<page string="Contacts">
|
||||
<field name="contact_ids">
|
||||
<tree string="Patient's Contacts"
|
||||
multi_edit="1" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="contact_type"/>
|
||||
<field name="phone" widget="phone"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="activity_ids" widget="mail_activity"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -80,9 +99,14 @@
|
|||
<field name="diagnosis"/>
|
||||
<field name="treatment_professional_ids"/>
|
||||
<field name="internal_notes"/>
|
||||
<field name="predicted_return_date"/>
|
||||
<field name="predicted_resolution_date"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="activity_ids" widget="mail_activity"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -93,7 +117,7 @@
|
|||
<tree string="Patient Injury History">
|
||||
<field name="injury_date_time" widget="datetime"/>
|
||||
<field name="diagnosis"/>
|
||||
<field name="predicted_return_date" widget="date"/>
|
||||
<field name="predicted_resolution_date" widget="date"/>
|
||||
<field name="treatment_professional_ids"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="teams_view_search" model="ir.ui.view">
|
||||
<field name="name">teams.view.search</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="parent_id" string="Parent Organization"/>
|
||||
<field name="staff_partner_ids"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="res_partner_view_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.partner.view.form.inherit</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='contact_addresses']" position="after">
|
||||
<field name="player_count" invisible="1"/>
|
||||
<page string="Players" name="team_players"
|
||||
attrs="{'invisible': [('player_count', '=', 0)]}">
|
||||
<field name="patient_ids" editable="bottom" nolabel="1">
|
||||
<tree>
|
||||
<field name="first_name"/>
|
||||
<field name="last_name"/>
|
||||
<field name="player_status"/>
|
||||
<field name="is_injured"/>
|
||||
<field name="injured_since" widget="date"/>
|
||||
<field name="predicted_return_date" widget="date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -3,21 +3,38 @@
|
|||
<data>
|
||||
<record id="action_view_team" model="ir.actions.act_window">
|
||||
<field name="name">Sports Teams</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="domain">[('type', '=', 'team')]</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="res_model">sports.team</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="search_view_id" ref="teams_view_search"/>
|
||||
</record>
|
||||
<record id="action_view_team_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="act_window_id" ref="action_view_team"/>
|
||||
<field name="view_id" ref="sports_team_view_kanban"/>
|
||||
</record>
|
||||
<record id="action_view_team_list" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="act_window_id" ref="action_view_team"/>
|
||||
<field name="view_id" ref="sports_team_view_list"/>
|
||||
</record>
|
||||
<record id="action_view_team_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="3"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="act_window_id" ref="action_view_team"/>
|
||||
<field name="view_id" ref="sports_team_view_form"/>
|
||||
</record>
|
||||
<record id="action_view_organization" model="ir.actions.act_window">
|
||||
<field name="name">Organizations</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_mode">list,kanban,form</field>
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
<field name="domain">[('is_company','=', True)]</field>
|
||||
</record>
|
||||
<record id="action_view_patient" model="ir.actions.act_window">
|
||||
<field name="name">Patients</field>
|
||||
<field name="res_model">sports.patient</field>
|
||||
<field name="view_mode">list,kanban,form</field>
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
</record>
|
||||
<menuitem id="sports_clinic_root"
|
||||
web_icon="bemade_sports_clinic,static/description/icon.png"
|
||||
|
|
|
|||
121
bemade_sports_clinic/views/sports_team_views.xml
Normal file
121
bemade_sports_clinic/views/sports_team_views.xml
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="teams_view_search" model="ir.ui.view">
|
||||
<field name="name">teams.view.search</field>
|
||||
<field name="model">sports.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="parent_id" string="Parent Organization"/>
|
||||
<field name="head_coach_id"/>
|
||||
<field name="head_trainer_id"/>
|
||||
<filter name="groupby_parent_id"
|
||||
context="{'group_by': 'parent_id'}"/>
|
||||
<filter name="groupby_head_coach_id"
|
||||
context="{'group_by': 'head_coach_id'}"/>
|
||||
<filter name="groupby_head_trainer_id"
|
||||
context="{'group_by': 'head_trainer_id'}"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="sports_team_view_kanban" model="ir.ui.view">
|
||||
<field name="name">sports.team.view.kanban</field>
|
||||
<field name="model">sports.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="parent_id" default_order="name"
|
||||
group_create="false" group_delete="false" archivable="false">
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="head_coach_name"/>
|
||||
<field name="head_trainer_name"/>
|
||||
<field name="injured_count"/>
|
||||
<field name="healthy_count"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_content oe_kanban_global_click">
|
||||
<div>
|
||||
<strong class="o_kanban_record_title">
|
||||
<span><field name="name"/></span>
|
||||
</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span class="o_kanban_record_subtitle">
|
||||
<field name="parent_id"/>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Head coach: <field
|
||||
name="head_coach_name"/></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Head trainer: <field
|
||||
name="head_trainer_name"/></span>
|
||||
</div>
|
||||
<div class="o_kanban_record_bottom">
|
||||
<div class="oe_kanban_bottom_left">
|
||||
<span class="text-success">Healthy:
|
||||
<field name="healthy_count"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<span t-attf-class="{{record.injured_count.value != 0 ? 'text-danger' : ''}}">
|
||||
Injured:
|
||||
<field name="injured_count"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
<record id="sports_team_view_list" model="ir.ui.view">
|
||||
<field name="name">sports.team.view.list</field>
|
||||
<field name="model">sports.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Sports Teams">
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="head_coach_id"/>
|
||||
<field name="head_trainer_id"/>
|
||||
<field name="player_count"/>
|
||||
<field name="injured_count"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="sports_team_view_form" model="ir.ui.view">
|
||||
<field name="name">sports.team.view.form</field>
|
||||
<field name="model">sports.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header></header>
|
||||
<sheet>
|
||||
<div class="oe_button_box"></div>
|
||||
<div class="oe_title"><h1><field name="name"/></h1></div>
|
||||
<group string="Team Information">
|
||||
<group>
|
||||
<field name="parent_id"/>
|
||||
<field name="player_count"/>
|
||||
<field name="injured_count"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="staff_ids">
|
||||
<tree>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="role"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Players"/>
|
||||
<field name="patient_ids" editable="bottom" nolabel="1"/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in a new issue