ositah 25.6.dev1__py3-none-any.whl → 25.9.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ositah might be problematic. Click here for more details.

Files changed (42) hide show
  1. ositah/app.py +17 -17
  2. ositah/apps/analysis.py +785 -785
  3. ositah/apps/configuration/callbacks.py +916 -916
  4. ositah/apps/configuration/main.py +546 -546
  5. ositah/apps/configuration/parameters.py +74 -74
  6. ositah/apps/configuration/tools.py +112 -112
  7. ositah/apps/export.py +1208 -1191
  8. ositah/apps/validation/callbacks.py +240 -240
  9. ositah/apps/validation/main.py +89 -89
  10. ositah/apps/validation/parameters.py +25 -25
  11. ositah/apps/validation/tables.py +646 -646
  12. ositah/apps/validation/tools.py +552 -552
  13. ositah/assets/arrow_down_up.svg +3 -3
  14. ositah/assets/ositah.css +53 -53
  15. ositah/assets/sort_ascending.svg +4 -4
  16. ositah/assets/sort_descending.svg +5 -5
  17. ositah/assets/sorttable.js +499 -499
  18. ositah/main.py +449 -449
  19. ositah/ositah.example.cfg +229 -229
  20. ositah/static/style.css +53 -53
  21. ositah/templates/base.html +22 -22
  22. ositah/templates/bootstrap_login.html +38 -38
  23. ositah/templates/login_form.html +26 -26
  24. ositah/utils/agents.py +124 -124
  25. ositah/utils/authentication.py +287 -287
  26. ositah/utils/cache.py +19 -19
  27. ositah/utils/core.py +13 -13
  28. ositah/utils/exceptions.py +64 -64
  29. ositah/utils/hito_db.py +51 -51
  30. ositah/utils/hito_db_model.py +253 -253
  31. ositah/utils/menus.py +339 -339
  32. ositah/utils/period.py +139 -139
  33. ositah/utils/projects.py +1178 -1178
  34. ositah/utils/teams.py +42 -42
  35. ositah/utils/utils.py +474 -474
  36. {ositah-25.6.dev1.dist-info → ositah-25.9.dev1.dist-info}/METADATA +149 -150
  37. ositah-25.9.dev1.dist-info/RECORD +46 -0
  38. {ositah-25.6.dev1.dist-info → ositah-25.9.dev1.dist-info}/licenses/LICENSE +29 -29
  39. ositah-25.6.dev1.dist-info/RECORD +0 -46
  40. {ositah-25.6.dev1.dist-info → ositah-25.9.dev1.dist-info}/WHEEL +0 -0
  41. {ositah-25.6.dev1.dist-info → ositah-25.9.dev1.dist-info}/entry_points.txt +0 -0
  42. {ositah-25.6.dev1.dist-info → ositah-25.9.dev1.dist-info}/top_level.txt +0 -0
@@ -1,253 +1,253 @@
1
- """
2
- Module defining the DB SQLAlchemy model.
3
- This is done by using the class provided by Flask-sqlalchemy that requires the DB connection
4
- to be initialized before. Thus this module must not be imported before it is done.
5
- """
6
-
7
- from hito_tools.utils import sql_longtext_to_list
8
-
9
- from ositah.utils.hito_db import new_uuid
10
- from ositah.utils.utils import GlobalParams
11
-
12
- global_params = GlobalParams()
13
- db = global_params.hito_db
14
-
15
- team_mgrs = db.Table(
16
- "team_agent",
17
- db.Column("team_id", db.String, db.ForeignKey("team.id")),
18
- db.Column("agent_id", db.String, db.ForeignKey("agent.id")),
19
- )
20
-
21
- children_team_mgrs = db.Table(
22
- "agent_team_parent_responsable",
23
- db.Column("team_id", db.String, db.ForeignKey("team.id")),
24
- db.Column("agent_id", db.String, db.ForeignKey("agent.id")),
25
- )
26
-
27
- activity_teams = db.Table(
28
- "activite_team",
29
- db.Column("activite_id", db.String, db.ForeignKey("activite.id")),
30
- db.Column("team_id", db.String, db.ForeignKey("team.id")),
31
- )
32
-
33
- project_teams = db.Table(
34
- "projet_team",
35
- db.Column("projet_id", db.String, db.ForeignKey("projet.id")),
36
- db.Column("team_id", db.String, db.ForeignKey("team.id")),
37
- )
38
-
39
-
40
- class Agent(db.Model):
41
- id = db.Column(db.String, primary_key=True)
42
- nom = db.Column(db.String)
43
- prenom = db.Column(db.String)
44
- email = db.Column(db.String)
45
- email_auth = db.Column(db.String)
46
- roles = db.Column(db.Text)
47
- statut = db.Column(db.String)
48
- team_id = db.Column(db.String)
49
-
50
- # Teams an agent is directly managing
51
- teams = db.relationship("Team", secondary=team_mgrs, backref=db.backref("managers"))
52
-
53
- # Children teams of the teams an agent is managing
54
- children_teams = db.relationship(
55
- "Team", secondary=children_team_mgrs, backref=db.backref("children_managers")
56
- )
57
-
58
- def __repr__(self):
59
- if self.email_auth is None or len(self.email_auth) == 0:
60
- connexion_email = self.email
61
- else:
62
- connexion_email = self.email_auth
63
- return (
64
- f"<Agent(nom={self.nom}, email={self.email}, roles={sql_longtext_to_list(self.roles)}"
65
- f" (email connexion={connexion_email}))>"
66
- )
67
-
68
-
69
- class Carriere(db.Model):
70
- id = db.Column(db.String, primary_key=True)
71
- date_debut = db.Column(db.DateTime)
72
- date_fin = db.Column(db.DateTime)
73
- type = db.Column(db.String)
74
- agent_id = db.Column(db.String(36), db.ForeignKey("agent.id"), nullable=False)
75
-
76
- def __repr__(self):
77
- date = ""
78
- if self.date_debut:
79
- date += f" date_debut={self.date_debut}"
80
- if self.date_fin:
81
- date += f" date_debut={self.date_fin}"
82
- return f"<Carriere(id={self.id}, type={self.type}{date})>"
83
-
84
-
85
- class Team(db.Model):
86
- id = db.Column(db.String, primary_key=True)
87
- nom = db.Column(db.String)
88
- description = db.Column(db.String)
89
- parent_team_id = db.Column(db.String)
90
-
91
- def __repr__(self):
92
- if not self.description or len(self.description) == 0:
93
- description = self.nom
94
- else:
95
- description = self.description
96
- return f"<Team(nom={self.nom}, description={description})>"
97
-
98
-
99
- class Referentiel(db.Model):
100
- id = db.Column(db.Integer, primary_key=True)
101
- libelle = db.Column(db.String)
102
- ordre = db.Column(db.Integer)
103
- object_class = db.Column("class", db.String)
104
-
105
- def __repr__(self):
106
- return f"Referentiel<id={self.id}, libelle={self.libelle}, class={self.object_class}>"
107
-
108
-
109
- class Activite(db.Model):
110
- id = db.Column(db.String, primary_key=True, default=new_uuid)
111
- libelle = db.Column(db.String)
112
- description = db.Column(db.String)
113
- ordre = db.Column(db.Integer)
114
-
115
- activite_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
116
- projet_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
117
-
118
- referentiel_nsip_project = db.relationship(
119
- "Referentiel",
120
- backref=db.backref("activite_project", lazy=True),
121
- foreign_keys=[projet_nsip_referentiel_id],
122
- )
123
- referentiel_nsip_activity = db.relationship(
124
- "Referentiel",
125
- backref=db.backref("activite_activity", lazy=True),
126
- foreign_keys=[activite_nsip_referentiel_id],
127
- )
128
-
129
- # Teams associated with an activity
130
- teams = db.relationship(
131
- "Team",
132
- secondary=activity_teams,
133
- lazy="subquery",
134
- backref=db.backref("activity_teams", lazy=True),
135
- )
136
-
137
- def __repr__(self):
138
- return f"<Activite(libelle={self.libelle}, id={id})>"
139
-
140
-
141
- class Projet(db.Model):
142
- id = db.Column(db.String, primary_key=True, default=new_uuid)
143
- libelle = db.Column(db.String)
144
- description = db.Column(db.String)
145
- ordre = db.Column(db.Integer)
146
-
147
- activite_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
148
- projet_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
149
-
150
- referentiel_nsip_project = db.relationship(
151
- "Referentiel",
152
- backref=db.backref("projet_project", lazy=True),
153
- foreign_keys=[projet_nsip_referentiel_id],
154
- )
155
- referentiel_nsip_activity = db.relationship(
156
- "Referentiel",
157
- backref=db.backref("projet_activity", lazy=True),
158
- foreign_keys=[activite_nsip_referentiel_id],
159
- )
160
-
161
- # Teams associated with a project
162
- teams = db.relationship(
163
- "Team",
164
- secondary=project_teams,
165
- lazy="subquery",
166
- backref=db.backref("project_teams", lazy=True),
167
- )
168
-
169
- def __repr__(self):
170
- return f"<Projet(libelle={self.libelle}, id={id})>"
171
-
172
-
173
- class ActiviteDetail(db.Model):
174
- id = db.Column(db.Integer, primary_key=True)
175
- activite_id = db.Column(db.String, db.ForeignKey("activite.id"))
176
- projet_id = db.Column(db.String, db.ForeignKey("projet.id"))
177
- agent_id = db.Column(db.String, db.ForeignKey("agent.id"))
178
- team_id = db.Column(db.String, db.ForeignKey("team.id"))
179
- type = db.Column(db.Integer)
180
- date = db.Column(db.DateTime)
181
- pourcent = db.Column(db.Float)
182
- nbHeures = db.Column(db.Float)
183
-
184
- project = db.relationship("Projet", backref=db.backref("activity_detail", lazy=True))
185
- agent = db.relationship(
186
- "Agent",
187
- backref=db.backref("activity_detail", lazy=True),
188
- foreign_keys=[agent_id],
189
- )
190
- team = db.relationship(
191
- "Team", backref=db.backref("activity_detail", lazy=True), foreign_keys=[team_id]
192
- )
193
-
194
- def __repr__(self):
195
- return (
196
- f"<ActiviteDetail(id={self.id}, date={self.date}, pourcent={self.pourcent},"
197
- f" nbHeures={self.nbHeures})>"
198
- )
199
-
200
-
201
- class OSITAHSession(db.Model):
202
- __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
203
-
204
- id = db.Column(db.String(36), primary_key=True)
205
- email = db.Column(db.String(255), nullable=False)
206
- last_use = db.Column(db.DateTime, nullable=False)
207
-
208
-
209
- class OSITAHValidation(db.Model):
210
- __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
211
-
212
- id = db.Column(db.String(36), primary_key=True, default=new_uuid)
213
- validated = db.Column(db.Boolean, nullable=False)
214
- timestamp = db.Column(db.DateTime, nullable=False)
215
- initial_timestamp = db.Column(db.DateTime, nullable=True)
216
- agent_id = db.Column(db.String(36), db.ForeignKey("agent.id"), nullable=False)
217
- period_id = db.Column(
218
- db.String(36), db.ForeignKey("ositah_validation_period.id"), nullable=False
219
- )
220
-
221
- agent = db.relationship("Agent", backref=db.backref("validation", lazy=True))
222
- period = db.relationship(
223
- "OSITAHValidationPeriod", backref=db.backref("validation_data", lazy=True)
224
- )
225
-
226
-
227
- class OSITAHValidationPeriod(db.Model):
228
- __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
229
-
230
- id = db.Column(db.String(36), primary_key=True, default=new_uuid)
231
- name = db.Column(db.String(255), unique=True, nullable=False)
232
- start_date = db.Column(db.DateTime, nullable=False)
233
- end_date = db.Column(db.DateTime, nullable=False)
234
- validation_date = db.Column(db.DateTime, nullable=False)
235
-
236
-
237
- class OSITAHProjectDeclaration(db.Model):
238
- __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
239
-
240
- id = db.Column(db.String(36), primary_key=True, default=new_uuid)
241
- projet = db.Column(db.String(255), nullable=False)
242
- masterprojet = db.Column(db.String(255), nullable=False)
243
- category = db.Column(db.String(255), nullable=False)
244
- hours = db.Column(db.Float, nullable=False)
245
- # quotite is the fraction of FTE declared by the agent (1=full time)
246
- quotite = db.Column(db.Float, nullable=False)
247
- validation_id = db.Column(db.String(36), db.ForeignKey("ositah_validation.id"), nullable=False)
248
- # Allow foreign key to Hito projet table to be null so that a Hito project can be delete
249
- # without deleting the declaration
250
- hito_project_id = db.Column(db.String(36), db.ForeignKey("projet.id"), nullable=True)
251
-
252
- validation = db.relationship("OSITAHValidation", backref=db.backref("project", lazy=True))
253
- project = db.relationship("Projet", backref=db.backref("validation_project", lazy=True))
1
+ """
2
+ Module defining the DB SQLAlchemy model.
3
+ This is done by using the class provided by Flask-sqlalchemy that requires the DB connection
4
+ to be initialized before. Thus this module must not be imported before it is done.
5
+ """
6
+
7
+ from hito_tools.utils import sql_longtext_to_list
8
+
9
+ from ositah.utils.hito_db import new_uuid
10
+ from ositah.utils.utils import GlobalParams
11
+
12
+ global_params = GlobalParams()
13
+ db = global_params.hito_db
14
+
15
+ team_mgrs = db.Table(
16
+ "team_agent",
17
+ db.Column("team_id", db.String, db.ForeignKey("team.id")),
18
+ db.Column("agent_id", db.String, db.ForeignKey("agent.id")),
19
+ )
20
+
21
+ children_team_mgrs = db.Table(
22
+ "agent_team_parent_responsable",
23
+ db.Column("team_id", db.String, db.ForeignKey("team.id")),
24
+ db.Column("agent_id", db.String, db.ForeignKey("agent.id")),
25
+ )
26
+
27
+ activity_teams = db.Table(
28
+ "activite_team",
29
+ db.Column("activite_id", db.String, db.ForeignKey("activite.id")),
30
+ db.Column("team_id", db.String, db.ForeignKey("team.id")),
31
+ )
32
+
33
+ project_teams = db.Table(
34
+ "projet_team",
35
+ db.Column("projet_id", db.String, db.ForeignKey("projet.id")),
36
+ db.Column("team_id", db.String, db.ForeignKey("team.id")),
37
+ )
38
+
39
+
40
+ class Agent(db.Model):
41
+ id = db.Column(db.String, primary_key=True)
42
+ nom = db.Column(db.String)
43
+ prenom = db.Column(db.String)
44
+ email = db.Column(db.String)
45
+ email_auth = db.Column(db.String)
46
+ roles = db.Column(db.Text)
47
+ statut = db.Column(db.String)
48
+ team_id = db.Column(db.String)
49
+
50
+ # Teams an agent is directly managing
51
+ teams = db.relationship("Team", secondary=team_mgrs, backref=db.backref("managers"))
52
+
53
+ # Children teams of the teams an agent is managing
54
+ children_teams = db.relationship(
55
+ "Team", secondary=children_team_mgrs, backref=db.backref("children_managers")
56
+ )
57
+
58
+ def __repr__(self):
59
+ if self.email_auth is None or len(self.email_auth) == 0:
60
+ connexion_email = self.email
61
+ else:
62
+ connexion_email = self.email_auth
63
+ return (
64
+ f"<Agent(nom={self.nom}, email={self.email}, roles={sql_longtext_to_list(self.roles)}"
65
+ f" (email connexion={connexion_email}))>"
66
+ )
67
+
68
+
69
+ class Carriere(db.Model):
70
+ id = db.Column(db.String, primary_key=True)
71
+ date_debut = db.Column(db.DateTime)
72
+ date_fin = db.Column(db.DateTime)
73
+ type = db.Column(db.String)
74
+ agent_id = db.Column(db.String(36), db.ForeignKey("agent.id"), nullable=False)
75
+
76
+ def __repr__(self):
77
+ date = ""
78
+ if self.date_debut:
79
+ date += f" date_debut={self.date_debut}"
80
+ if self.date_fin:
81
+ date += f" date_debut={self.date_fin}"
82
+ return f"<Carriere(id={self.id}, type={self.type}{date})>"
83
+
84
+
85
+ class Team(db.Model):
86
+ id = db.Column(db.String, primary_key=True)
87
+ nom = db.Column(db.String)
88
+ description = db.Column(db.String)
89
+ parent_team_id = db.Column(db.String)
90
+
91
+ def __repr__(self):
92
+ if not self.description or len(self.description) == 0:
93
+ description = self.nom
94
+ else:
95
+ description = self.description
96
+ return f"<Team(nom={self.nom}, description={description})>"
97
+
98
+
99
+ class Referentiel(db.Model):
100
+ id = db.Column(db.Integer, primary_key=True)
101
+ libelle = db.Column(db.String)
102
+ ordre = db.Column(db.Integer)
103
+ object_class = db.Column("class", db.String)
104
+
105
+ def __repr__(self):
106
+ return f"Referentiel<id={self.id}, libelle={self.libelle}, class={self.object_class}>"
107
+
108
+
109
+ class Activite(db.Model):
110
+ id = db.Column(db.String, primary_key=True, default=new_uuid)
111
+ libelle = db.Column(db.String)
112
+ description = db.Column(db.String)
113
+ ordre = db.Column(db.Integer)
114
+
115
+ activite_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
116
+ projet_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
117
+
118
+ referentiel_nsip_project = db.relationship(
119
+ "Referentiel",
120
+ backref=db.backref("activite_project", lazy=True),
121
+ foreign_keys=[projet_nsip_referentiel_id],
122
+ )
123
+ referentiel_nsip_activity = db.relationship(
124
+ "Referentiel",
125
+ backref=db.backref("activite_activity", lazy=True),
126
+ foreign_keys=[activite_nsip_referentiel_id],
127
+ )
128
+
129
+ # Teams associated with an activity
130
+ teams = db.relationship(
131
+ "Team",
132
+ secondary=activity_teams,
133
+ lazy="subquery",
134
+ backref=db.backref("activity_teams", lazy=True),
135
+ )
136
+
137
+ def __repr__(self):
138
+ return f"<Activite(libelle={self.libelle}, id={id})>"
139
+
140
+
141
+ class Projet(db.Model):
142
+ id = db.Column(db.String, primary_key=True, default=new_uuid)
143
+ libelle = db.Column(db.String)
144
+ description = db.Column(db.String)
145
+ ordre = db.Column(db.Integer)
146
+
147
+ activite_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
148
+ projet_nsip_referentiel_id = db.Column(db.String, db.ForeignKey("referentiel.id"))
149
+
150
+ referentiel_nsip_project = db.relationship(
151
+ "Referentiel",
152
+ backref=db.backref("projet_project", lazy=True),
153
+ foreign_keys=[projet_nsip_referentiel_id],
154
+ )
155
+ referentiel_nsip_activity = db.relationship(
156
+ "Referentiel",
157
+ backref=db.backref("projet_activity", lazy=True),
158
+ foreign_keys=[activite_nsip_referentiel_id],
159
+ )
160
+
161
+ # Teams associated with a project
162
+ teams = db.relationship(
163
+ "Team",
164
+ secondary=project_teams,
165
+ lazy="subquery",
166
+ backref=db.backref("project_teams", lazy=True),
167
+ )
168
+
169
+ def __repr__(self):
170
+ return f"<Projet(libelle={self.libelle}, id={id})>"
171
+
172
+
173
+ class ActiviteDetail(db.Model):
174
+ id = db.Column(db.Integer, primary_key=True)
175
+ activite_id = db.Column(db.String, db.ForeignKey("activite.id"))
176
+ projet_id = db.Column(db.String, db.ForeignKey("projet.id"))
177
+ agent_id = db.Column(db.String, db.ForeignKey("agent.id"))
178
+ team_id = db.Column(db.String, db.ForeignKey("team.id"))
179
+ type = db.Column(db.Integer)
180
+ date = db.Column(db.DateTime)
181
+ pourcent = db.Column(db.Float)
182
+ nbHeures = db.Column(db.Float)
183
+
184
+ project = db.relationship("Projet", backref=db.backref("activity_detail", lazy=True))
185
+ agent = db.relationship(
186
+ "Agent",
187
+ backref=db.backref("activity_detail", lazy=True),
188
+ foreign_keys=[agent_id],
189
+ )
190
+ team = db.relationship(
191
+ "Team", backref=db.backref("activity_detail", lazy=True), foreign_keys=[team_id]
192
+ )
193
+
194
+ def __repr__(self):
195
+ return (
196
+ f"<ActiviteDetail(id={self.id}, date={self.date}, pourcent={self.pourcent},"
197
+ f" nbHeures={self.nbHeures})>"
198
+ )
199
+
200
+
201
+ class OSITAHSession(db.Model):
202
+ __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
203
+
204
+ id = db.Column(db.String(36), primary_key=True)
205
+ email = db.Column(db.String(255), nullable=False)
206
+ last_use = db.Column(db.DateTime, nullable=False)
207
+
208
+
209
+ class OSITAHValidation(db.Model):
210
+ __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
211
+
212
+ id = db.Column(db.String(36), primary_key=True, default=new_uuid)
213
+ validated = db.Column(db.Boolean, nullable=False)
214
+ timestamp = db.Column(db.DateTime, nullable=False)
215
+ initial_timestamp = db.Column(db.DateTime, nullable=True)
216
+ agent_id = db.Column(db.String(36), db.ForeignKey("agent.id"), nullable=False)
217
+ period_id = db.Column(
218
+ db.String(36), db.ForeignKey("ositah_validation_period.id"), nullable=False
219
+ )
220
+
221
+ agent = db.relationship("Agent", backref=db.backref("validation", lazy=True))
222
+ period = db.relationship(
223
+ "OSITAHValidationPeriod", backref=db.backref("validation_data", lazy=True)
224
+ )
225
+
226
+
227
+ class OSITAHValidationPeriod(db.Model):
228
+ __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
229
+
230
+ id = db.Column(db.String(36), primary_key=True, default=new_uuid)
231
+ name = db.Column(db.String(255), unique=True, nullable=False)
232
+ start_date = db.Column(db.DateTime, nullable=False)
233
+ end_date = db.Column(db.DateTime, nullable=False)
234
+ validation_date = db.Column(db.DateTime, nullable=False)
235
+
236
+
237
+ class OSITAHProjectDeclaration(db.Model):
238
+ __table_args__ = {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
239
+
240
+ id = db.Column(db.String(36), primary_key=True, default=new_uuid)
241
+ projet = db.Column(db.String(255), nullable=False)
242
+ masterprojet = db.Column(db.String(255), nullable=False)
243
+ category = db.Column(db.String(255), nullable=False)
244
+ hours = db.Column(db.Float, nullable=False)
245
+ # quotite is the fraction of FTE declared by the agent (1=full time)
246
+ quotite = db.Column(db.Float, nullable=False)
247
+ validation_id = db.Column(db.String(36), db.ForeignKey("ositah_validation.id"), nullable=False)
248
+ # Allow foreign key to Hito projet table to be null so that a Hito project can be delete
249
+ # without deleting the declaration
250
+ hito_project_id = db.Column(db.String(36), db.ForeignKey("projet.id"), nullable=True)
251
+
252
+ validation = db.relationship("OSITAHValidation", backref=db.backref("project", lazy=True))
253
+ project = db.relationship("Projet", backref=db.backref("validation_project", lazy=True))