diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py
index 2feb05776..b7c506a08 100644
--- a/app/comp/bonus_spo.py
+++ b/app/comp/bonus_spo.py
@@ -862,6 +862,51 @@ class BonusStDenis(BonusSportAdditif):
bonus_max = 0.5
+class BonusTarbes(BonusSportAdditif):
+ """Calcul bonus optionnels (sport, culture), règle IUT de Tarbes.
+
+
+ - Les étudiants opeuvent suivre un ou plusieurs activités optionnelles notées.
+ La meilleure des notes obtenue est prise en compte, si elle est supérieure à 10/20.
+
+ - Le trentième des points au dessus de 10 est ajouté à la moyenne des UE.
+
+ - Exemple: un étudiant ayant 16/20 bénéficiera d'un bonus de (16-10)/30 = 0,2 points
+ sur chaque UE.
+
+
+ """
+
+ name = "bonus_tarbes"
+ displayed_name = "IUT de Tazrbes"
+ seuil_moy_gen = 10.0
+ proportion_point = 1 / 30.0
+ classic_use_bonus_ues = True
+
+ def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
+ """calcul du bonus"""
+ # Prend la note de chaque modimpl, sans considération d'UE
+ if len(sem_modimpl_moys_inscrits.shape) > 2: # apc
+ sem_modimpl_moys_inscrits = sem_modimpl_moys_inscrits[:, :, 0]
+ # ici sem_modimpl_moys_inscrits est nb_etuds x nb_mods_bonus, en APC et en classic
+ note_bonus_max = np.max(sem_modimpl_moys_inscrits, axis=1) # 1d, nb_etuds
+ ues = self.formsemestre.query_ues(with_sport=False).all()
+ ues_idx = [ue.id for ue in ues]
+
+ if self.formsemestre.formation.is_apc(): # --- BUT
+ bonus_moy_arr = np.where(
+ note_bonus_max > self.seuil_moy_gen,
+ (note_bonus_max - self.seuil_moy_gen) * self.proportion_point,
+ 0.0,
+ )
+ self.bonus_ues = pd.DataFrame(
+ np.stack([bonus_moy_arr] * len(ues)).T,
+ index=self.etuds_idx,
+ columns=ues_idx,
+ dtype=float,
+ )
+
+
class BonusTours(BonusDirect):
"""Calcul bonus sport & culture IUT Tours.