Compare View
Commits (3)
Showing
8 changed files
Show diff stats
src/core/pyros_django/majordome/agent/Agent.py
@@ -154,7 +154,7 @@ import config.old_config as config_old | @@ -154,7 +154,7 @@ import config.old_config as config_old | ||
154 | #from config import * | 154 | #from config import * |
155 | 155 | ||
156 | from majordome.models import AgentSurvey, AgentCmd, AgentLogs | 156 | from majordome.models import AgentSurvey, AgentCmd, AgentLogs |
157 | -from user_mgmt.models import Period | 157 | +from user_mgmt.models import Period, Quota |
158 | 158 | ||
159 | from vendor.guitastro.src.guitastro import Ephemeris | 159 | from vendor.guitastro.src.guitastro import Ephemeris |
160 | import pickle | 160 | import pickle |
@@ -3592,7 +3592,17 @@ class Agent: | @@ -3592,7 +3592,17 @@ class Agent: | ||
3592 | val[0] = d_total | 3592 | val[0] = d_total |
3593 | val[-1] = d_total - val[-2] | 3593 | val[-1] = d_total - val[-2] |
3594 | # --- update db TODO | 3594 | # --- update db TODO |
3595 | - | 3595 | + quota = Quota() |
3596 | + quota_attributes = {} | ||
3597 | + quota_attributes["id_period"] = operiod.id | ||
3598 | + quota_attributes["night_id"] = night | ||
3599 | + quota_attributes["d_previousq"] = d_prev | ||
3600 | + quota_attributes["d_currentq"] = d_cur | ||
3601 | + quota_attributes["d_totalq"] = d_total | ||
3602 | + quota_attributes["d_nextq"] = d_total - d_cur | ||
3603 | + quota.set_attributes_and_save(quota_attributes) | ||
3604 | + operiod.quota = quota | ||
3605 | + operiod.save() | ||
3596 | #log.info(f"Write {filename=}") | 3606 | #log.info(f"Write {filename=}") |
3597 | #pickle.dump(night_info, open(filename, "wb")) | 3607 | #pickle.dump(night_info, open(filename, "wb")) |
3598 | return night_info | 3608 | return night_info |
src/core/pyros_django/misc/fixtures/initial_fixture_dev_TZ.json
@@ -287,8 +287,7 @@ | @@ -287,8 +287,7 @@ | ||
287 | "fields": { | 287 | "fields": { |
288 | "name": "Admin", | 288 | "name": "Admin", |
289 | "desc": "", | 289 | "desc": "", |
290 | - "priority": 8, | ||
291 | - "quota": 9999.0 | 290 | + "priority": 8 |
292 | } | 291 | } |
293 | }, | 292 | }, |
294 | { | 293 | { |
@@ -297,8 +296,7 @@ | @@ -297,8 +296,7 @@ | ||
297 | "fields": { | 296 | "fields": { |
298 | "name": "Observer", | 297 | "name": "Observer", |
299 | "desc": "", | 298 | "desc": "", |
300 | - "priority": 2, | ||
301 | - "quota": 9999.0 | 299 | + "priority": 2 |
302 | } | 300 | } |
303 | }, | 301 | }, |
304 | { | 302 | { |
@@ -307,8 +305,7 @@ | @@ -307,8 +305,7 @@ | ||
307 | "fields": { | 305 | "fields": { |
308 | "name": "TAC", | 306 | "name": "TAC", |
309 | "desc": "", | 307 | "desc": "", |
310 | - "priority": 1, | ||
311 | - "quota": 9999.0 | 308 | + "priority": 1 |
312 | } | 309 | } |
313 | }, | 310 | }, |
314 | { | 311 | { |
@@ -317,8 +314,7 @@ | @@ -317,8 +314,7 @@ | ||
317 | "fields": { | 314 | "fields": { |
318 | "name": "Management board member", | 315 | "name": "Management board member", |
319 | "desc": "", | 316 | "desc": "", |
320 | - "priority": 3, | ||
321 | - "quota": 9999.0 | 317 | + "priority": 3 |
322 | } | 318 | } |
323 | }, | 319 | }, |
324 | { | 320 | { |
@@ -327,8 +323,7 @@ | @@ -327,8 +323,7 @@ | ||
327 | "fields": { | 323 | "fields": { |
328 | "name": "Operator", | 324 | "name": "Operator", |
329 | "desc": "", | 325 | "desc": "", |
330 | - "priority": 4, | ||
331 | - "quota": 9999.0 | 326 | + "priority": 4 |
332 | } | 327 | } |
333 | }, | 328 | }, |
334 | { | 329 | { |
@@ -337,8 +332,7 @@ | @@ -337,8 +332,7 @@ | ||
337 | "fields": { | 332 | "fields": { |
338 | "name": "Unit-PI", | 333 | "name": "Unit-PI", |
339 | "desc": "", | 334 | "desc": "", |
340 | - "priority": 7, | ||
341 | - "quota": 9999.0 | 335 | + "priority": 7 |
342 | } | 336 | } |
343 | }, | 337 | }, |
344 | { | 338 | { |
@@ -347,8 +341,7 @@ | @@ -347,8 +341,7 @@ | ||
347 | "fields": { | 341 | "fields": { |
348 | "name": "Unit-board", | 342 | "name": "Unit-board", |
349 | "desc": "", | 343 | "desc": "", |
350 | - "priority": 6, | ||
351 | - "quota": 9999.0 | 344 | + "priority": 6 |
352 | } | 345 | } |
353 | }, | 346 | }, |
354 | { | 347 | { |
@@ -357,8 +350,7 @@ | @@ -357,8 +350,7 @@ | ||
357 | "fields": { | 350 | "fields": { |
358 | "name": "Visitor", | 351 | "name": "Visitor", |
359 | "desc": "Account without any privilege", | 352 | "desc": "Account without any privilege", |
360 | - "priority": 0, | ||
361 | - "quota": 0.0 | 353 | + "priority": 0 |
362 | } | 354 | } |
363 | }, | 355 | }, |
364 | { | 356 | { |
@@ -366,7 +358,7 @@ | @@ -366,7 +358,7 @@ | ||
366 | "pk": 2, | 358 | "pk": 2, |
367 | "fields": { | 359 | "fields": { |
368 | "name": "CNRS", | 360 | "name": "CNRS", |
369 | - "quota": 20 | 361 | + "f_quota": 0.2 |
370 | } | 362 | } |
371 | }, | 363 | }, |
372 | { | 364 | { |
@@ -374,7 +366,7 @@ | @@ -374,7 +366,7 @@ | ||
374 | "pk": 1, | 366 | "pk": 1, |
375 | "fields": { | 367 | "fields": { |
376 | "name": "CNES", | 368 | "name": "CNES", |
377 | - "quota": 80 | 369 | + "f_quota": 0.8 |
378 | } | 370 | } |
379 | }, | 371 | }, |
380 | { | 372 | { |
src/core/pyros_django/scheduling/A_Scheduler.py
@@ -222,6 +222,12 @@ class A_Scheduler(Agent): | @@ -222,6 +222,12 @@ class A_Scheduler(Agent): | ||
222 | # 'vote_referee2' | 222 | # 'vote_referee2' |
223 | """ | 223 | """ |
224 | 224 | ||
225 | + | ||
226 | + def update_db_quota_sequence(sequence, quota_attributes, id_period, night_id, d_total=sequence_info['duration']): | ||
227 | + sequence_quota = sequence.quota | ||
228 | + sp_quota = sequence.scientific_program | ||
229 | + institute_quota = | ||
230 | + | ||
225 | def _compute_schedule_1(self): | 231 | def _compute_schedule_1(self): |
226 | """Simple scheduler based on selection-insertion one state algorithm. | 232 | """Simple scheduler based on selection-insertion one state algorithm. |
227 | 233 |
src/core/pyros_django/scp_mgmt/A_SCP_Manager.py
@@ -17,7 +17,7 @@ for short_path in short_paths: | @@ -17,7 +17,7 @@ for short_path in short_paths: | ||
17 | 17 | ||
18 | # Project imports | 18 | # Project imports |
19 | from majordome.agent.Agent import Agent, build_agent | 19 | from majordome.agent.Agent import Agent, build_agent |
20 | -from user_mgmt.models import PyrosUser, SP_Period, Period, SP_Period, SP_Period_Guest, SP_PeriodWorkflow | 20 | +from user_mgmt.models import PyrosUser, Institute, SP_Period, Period, SP_Period, SP_Period_Guest, SP_PeriodWorkflow |
21 | import vendor.guitastro.src.guitastro as guitastro | 21 | import vendor.guitastro.src.guitastro as guitastro |
22 | 22 | ||
23 | # Django imports | 23 | # Django imports |
@@ -229,6 +229,9 @@ class A_SCP_Manager(Agent): | @@ -229,6 +229,9 @@ class A_SCP_Manager(Agent): | ||
229 | next_sp_to_be_notified = next_sp.filter(status=SP_Period.STATUSES_ACCEPTED,is_valid = True) | 229 | next_sp_to_be_notified = next_sp.filter(status=SP_Period.STATUSES_ACCEPTED,is_valid = True) |
230 | self.send_mail_to_observers_for_notification(next_sp_to_be_notified) | 230 | self.send_mail_to_observers_for_notification(next_sp_to_be_notified) |
231 | SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.NOTIFICATION) | 231 | SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.NOTIFICATION) |
232 | + self.update_sun_moon_ephems() | ||
233 | + self.set_quota_for_institutes(self.period.id) | ||
234 | + self.set_quota_for_sp(self.period.id) | ||
232 | 235 | ||
233 | def routine_process_body(self): | 236 | def routine_process_body(self): |
234 | print("routine automatic period workflow") | 237 | print("routine automatic period workflow") |
@@ -243,66 +246,27 @@ class A_SCP_Manager(Agent): | @@ -243,66 +246,27 @@ class A_SCP_Manager(Agent): | ||
243 | for n in range(int((end_date - start_date).days)): | 246 | for n in range(int((end_date - start_date).days)): |
244 | yield start_date + timedelta(n) | 247 | yield start_date + timedelta(n) |
245 | 248 | ||
246 | - def do_generate_ephem_moon_and_sun_for_period(self, period_id:int): | ||
247 | - # Obsolete TODO | ||
248 | - period = Period.objects.get(id=period_id) | ||
249 | - period_start_date = period.start_date | ||
250 | - period_end_date = period.end_date | ||
251 | - | ||
252 | - root_path = os.environ.get("PROJECT_ROOT_PATH") | ||
253 | - os.chdir(root_path) | ||
254 | - | ||
255 | - home = guitastro.Home(self._oc["config"].getHome()) | ||
256 | - self._fn.longitude(home.longitude) | ||
257 | - | ||
258 | - ephem_data_night_folder = self._fn.rootdir | ||
259 | - if os.path.exists(ephem_data_night_folder): | ||
260 | - period_id = str(period.id) | ||
261 | - # form correct period string | ||
262 | - if len(str(period.id)) < 3: | ||
263 | - while len(period_id) < 3: | ||
264 | - period_id = "0" + period_id | ||
265 | - period_id = "P" + period_id | ||
266 | - ephem_data_night_folder = os.path.join(ephem_data_night_folder, period_id) | ||
267 | - if not os.path.exists(ephem_data_night_folder): | ||
268 | - os.makedirs(ephem_data_night_folder, exist_ok=True) | ||
269 | - for single_date in self.daterange(period_start_date, period_end_date): | ||
270 | - current_date = single_date.strftime("%Y%m%d") | ||
271 | - | ||
272 | - eph = guitastro.Ephemeris() | ||
273 | - target_sun = "sun" | ||
274 | - ephem_sun = eph.target2night(target_sun, current_date, None, None) | ||
275 | - | ||
276 | - self._fn.fcontext_create("pyros_eph", "Ephemeris PyROS") | ||
277 | - self._fn.fcontext = "pyros_eph" | ||
278 | - self._fn.pathnaming("PyROS.eph.1") | ||
279 | - self._fn.rootdir = "/tmp/eph" | ||
280 | - self._fn.extension = ".f" | ||
281 | - param = {} | ||
282 | - param['period'] = period_id | ||
283 | - param['date'] = current_date | ||
284 | - param['unit'] = self.pconfig.unit_name | ||
285 | - param['version'] = 1 | ||
286 | - param['target'] = "sun" | ||
287 | - fname = self._fn.naming_set(param) | ||
288 | - file_name_sun = self._fn.join(fname) | ||
289 | - | ||
290 | - # moon parameters | ||
291 | - param['target'] = "moon" | ||
292 | - fname = self._fn.naming_set(param) | ||
293 | - file_name_moon = self._fn.join(fname) | ||
294 | - os.chdir(ephem_data_night_folder) | ||
295 | - pickle.dump(ephem_sun, open(f"{file_name_sun}.f","wb")) | ||
296 | - target_moon = "moon" | ||
297 | - ephem_moon = eph.target2night(target_moon, current_date, None, None) | ||
298 | - pickle.dump(ephem_moon, open(f"{file_name_moon}.f","wb")) | ||
299 | - | ||
300 | - | ||
301 | - | ||
302 | - | ||
303 | - # lire tous les fichiers sun de la period et appliquer le sky_elev pour déterminer le quota total de période | ||
304 | - # prendre le champ alt & | ||
305 | - # -> prendre tous les éléments en dessous de duskelev (cf l412 d'A_Sheduler, exemple 14 des éphémérides pour trier ces éléménts) et faire un sum | 249 | + def set_quota_for_institutes(self, id_period): |
250 | + for institute in Institute.objects.all(): | ||
251 | + f_quota = institute.f_quota | ||
252 | + # the lowest id of quota table for this period should be the first night of the period | ||
253 | + period_quota = Period.objects.get(id=id_period).quota | ||
254 | + institute_quota = period_quota.convert_to_quota(f_quota) | ||
255 | + new_quota = Quota() | ||
256 | + new_quota.set_attributes_and_save(institute_quota) | ||
257 | + institute.quota = new_quota | ||
258 | + institute.save() | ||
259 | + | ||
260 | + def set_quota_for_SP(self, id_period): | ||
261 | + period = Period.objects.get(id=id_period) | ||
262 | + for sp_period in SP_Period.objects.filter(period=period) | ||
263 | + sp = sp_period.scientific_program | ||
264 | + institute = sp.institute | ||
265 | + institute_quota = institute.quota | ||
266 | + new_quota = Quota() | ||
267 | + quota_attributes = institute_quota.convert_to_quota(sp.f_quota) | ||
268 | + new_quota.set_attributes_and_save(quota_attributes) | ||
269 | + | ||
306 | 270 | ||
307 | if __name__ == "__main__": | 271 | if __name__ == "__main__": |
308 | 272 |
src/core/pyros_django/scp_mgmt/forms.py
@@ -39,13 +39,13 @@ class SP_PeriodForm(forms.ModelForm): | @@ -39,13 +39,13 @@ class SP_PeriodForm(forms.ModelForm): | ||
39 | fields = ( | 39 | fields = ( |
40 | #"period", | 40 | #"period", |
41 | "public_visibility", | 41 | "public_visibility", |
42 | - "quota_minimal", | ||
43 | - "quota_nominal", | ||
44 | - "quota_allocated", | ||
45 | - "over_quota_duration", | ||
46 | - "over_quota_duration_allocated", | ||
47 | - "token", | ||
48 | - "token_allocated", | 42 | + # "quota_minimal", |
43 | + # "quota_nominal", | ||
44 | + # "quota_allocated", | ||
45 | + # "over_quota_duration", | ||
46 | + # "over_quota_duration_allocated", | ||
47 | + # "token", | ||
48 | + # "token_allocated", | ||
49 | "vote_referee1", | 49 | "vote_referee1", |
50 | "reason_referee1", | 50 | "reason_referee1", |
51 | "vote_referee2", | 51 | "vote_referee2", |
src/core/pyros_django/scp_mgmt/models.py
1 | -#from django.db import models | 1 | +from django.db import models |
2 | + | ||
3 | + | ||
4 | +class Quota(models.Model): | ||
5 | + id_period = models.BigIntegerField(blank=True, null=True) | ||
6 | + night_id = models.CharField(max_length=8, null=True, blank=True, db_index=True) | ||
7 | + d_totalq = models.BigIntegerField(default=0, blank=True, null=True) | ||
8 | + d_totalx = models.BigIntegerField(default=0, blank=True, null=True) | ||
9 | + | ||
10 | + d_previousq = models.BigIntegerField(default=0, blank=True, null=True) | ||
11 | + d_previousx = models.BigIntegerField(default=0, blank=True, null=True) | ||
12 | + | ||
13 | + d_currentq = models.BigIntegerField(default=0, blank=True, null=True) | ||
14 | + d_currentx = models.BigIntegerField(default=0, blank=True, null=True) | ||
15 | + | ||
16 | + d_passedq = models.BigIntegerField(default=0, blank=True, null=True) | ||
17 | + d_passedx = models.BigIntegerField(default=0, blank=True, null=True) | ||
18 | + | ||
19 | + d_scheduleq = models.BigIntegerField(default=0, blank=True, null=True) | ||
20 | + d_schedulex = models.BigIntegerField(default=0, blank=True, null=True) | ||
21 | + | ||
22 | + d_nextq = models.BigIntegerField(default=0, blank=True, null=True) | ||
23 | + d_nextx = models.BigIntegerField(default=0, blank=True, null=True) | ||
24 | + | ||
25 | + @property | ||
26 | + def d_total(self): | ||
27 | + return self.d_totalq + self.d_totalx | ||
28 | + | ||
29 | + @property | ||
30 | + def d_previous(self): | ||
31 | + return self.d_previousq + self.d_previousx | ||
32 | + | ||
33 | + @property | ||
34 | + def d_current(self): | ||
35 | + return self.d_currentq + self.d_currentx | ||
36 | + | ||
37 | + @property | ||
38 | + def d_passed(self): | ||
39 | + return self.d_passedq + self.d_passedx | ||
40 | + | ||
41 | + @property | ||
42 | + def d_schedule(self): | ||
43 | + return self.d_scheduleq + self.d_schedulex | ||
44 | + | ||
45 | + @property | ||
46 | + def d_next(self): | ||
47 | + return self.d_nextq + self.d_nextx | ||
48 | + | ||
49 | + def set_attributes_and_save(self, quota_attributes:dict): | ||
50 | + | ||
51 | + if quota_attributes.get("id_period") != None: | ||
52 | + self.id_period = quota_attributes["id_period"] | ||
53 | + if quota_attributes.get("night_id") != None: | ||
54 | + self.night_id = quota_attributes["night_id"] | ||
55 | + if quota_attributes.get("d_totalq") != None: | ||
56 | + self.d_totalq = quota_attributes["d_totalq"] | ||
57 | + if quota_attributes.get("d_totalx") != None: | ||
58 | + self.d_totalx = quota_attributes["d_totalx"] | ||
59 | + if quota_attributes.get("d_previousq") != None: | ||
60 | + self.d_previousq = quota_attributes["d_previousq"] | ||
61 | + if quota_attributes.get("d_previousx") != None: | ||
62 | + self.d_previousx = quota_attributes["d_previousx"] | ||
63 | + if quota_attributes.get("d_currentq") != None: | ||
64 | + self.d_currentq = quota_attributes["d_currentq"] | ||
65 | + if quota_attributes.get("d_currentx") != None: | ||
66 | + self.d_currentx = quota_attributes["d_currentx"] | ||
67 | + if quota_attributes.get("d_scheduleq") != None: | ||
68 | + self.d_scheduleq = quota_attributes["d_scheduleq"] | ||
69 | + if quota_attributes.get("d_schedulex") != None: | ||
70 | + self.d_schedule = quota_attributes["d_schedulex"] | ||
71 | + if quota_attributes.get("d_nextq") != None: | ||
72 | + self.d_nextq = quota_attributes["d_nextq"] | ||
73 | + if quota_attributes.get("d_nextx") != None: | ||
74 | + self.d_nextx = quota_attributes["d_nextx"] | ||
75 | + self.save() | ||
76 | + | ||
77 | + def convert_to_quota(self, f_quota): | ||
78 | + quota_institute = {} | ||
79 | + | ||
80 | + quota_institute["d_totalq"] = self.d_totalq * f_quota | ||
81 | + quota_institute["d_totalx"] = self.d_totalx * f_quota | ||
82 | + quota_institute["d_previousq"] = self.d_previousq * f_quota | ||
83 | + quota_institute["d_previousx"] = self.d_previousx * f_quota | ||
84 | + quota_institute["d_currentq"] = self.d_currentq * f_quota | ||
85 | + quota_institute["d_currentx"] = self.d_currentx * f_quota | ||
86 | + quota_institute["d_passedq"] = self.d_passedq * f_quota | ||
87 | + quota_institute["d_passedx"] = self.d_passedx * f_quota | ||
88 | + quota_institute["d_scheduleq"] = self.d_scheduleq * f_quota | ||
89 | + quota_institute["d_schedulex"] = self.d_schedulex * f_quota | ||
90 | + quota_institute["d_nextq"] = self.d_nextq * f_quota | ||
91 | + quota_institute["d_nextx"] = self.d_nextx * f_quota | ||
92 | + | ||
93 | + return quota_institute |
src/core/pyros_django/seq_submit/models.py
@@ -34,6 +34,7 @@ from django.db.models import Q | @@ -34,6 +34,7 @@ from django.db.models import Q | ||
34 | 34 | ||
35 | # Project imports | 35 | # Project imports |
36 | from user_mgmt.models import PyrosUser, ScientificProgram, Period | 36 | from user_mgmt.models import PyrosUser, ScientificProgram, Period |
37 | +from scp_mgmt.models import Quota | ||
37 | # DeviceCommand is used by class Command | 38 | # DeviceCommand is used by class Command |
38 | sys.path.append("../../..") | 39 | sys.path.append("../../..") |
39 | from vendor.guitastro.src.guitastro import FileNames, Ima | 40 | from vendor.guitastro.src.guitastro import FileNames, Ima |
@@ -349,8 +350,9 @@ class Sequence(models.Model): | @@ -349,8 +350,9 @@ class Sequence(models.Model): | ||
349 | obsolete = models.BooleanField(default=False) | 350 | obsolete = models.BooleanField(default=False) |
350 | processing = models.BooleanField(default=False) | 351 | processing = models.BooleanField(default=False) |
351 | flag = models.CharField(max_length=45, blank=True, null=True) | 352 | flag = models.CharField(max_length=45, blank=True, null=True) |
352 | - period = models.ForeignKey(Period, on_delete=models.DO_NOTHING, related_name="sequences", blank=True, null=True) | 353 | + period = models.ForeignKey(Period, on_delete=models.DO_NOTHING, related_name="sequence_period", blank=True, null=True) |
353 | #period = models.ForeignKey("Period", on_delete=models.DO_NOTHING, related_name="sequences", blank=True, null=True) | 354 | #period = models.ForeignKey("Period", on_delete=models.DO_NOTHING, related_name="sequences", blank=True, null=True) |
355 | + quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="sequence_quotas", blank=True, null=True) | ||
354 | 356 | ||
355 | start_date = models.DateTimeField( | 357 | start_date = models.DateTimeField( |
356 | blank=True, null=True, default=timezone.now, editable=True) | 358 | blank=True, null=True, default=timezone.now, editable=True) |
src/core/pyros_django/user_mgmt/models.py
@@ -37,6 +37,11 @@ from django.db.models.query import QuerySet | @@ -37,6 +37,11 @@ from django.db.models.query import QuerySet | ||
37 | from django.utils import timezone | 37 | from django.utils import timezone |
38 | 38 | ||
39 | 39 | ||
40 | +# Pyros import | ||
41 | + | ||
42 | +from scp_mgmt.models import Quota | ||
43 | + | ||
44 | + | ||
40 | 45 | ||
41 | 46 | ||
42 | # Project imports | 47 | # Project imports |
@@ -52,7 +57,6 @@ class UserLevel(models.Model): | @@ -52,7 +57,6 @@ class UserLevel(models.Model): | ||
52 | name = models.CharField(max_length=45, blank=True, null=True) | 57 | name = models.CharField(max_length=45, blank=True, null=True) |
53 | desc = models.TextField(blank=True, null=True) | 58 | desc = models.TextField(blank=True, null=True) |
54 | priority = models.IntegerField(blank=True, null=True) | 59 | priority = models.IntegerField(blank=True, null=True) |
55 | - quota = models.FloatField(blank=True, null=True) | ||
56 | 60 | ||
57 | class Meta: | 61 | class Meta: |
58 | managed = True | 62 | managed = True |
@@ -79,9 +83,11 @@ class Country(models.Model): | @@ -79,9 +83,11 @@ class Country(models.Model): | ||
79 | class Institute(models.Model): | 83 | class Institute(models.Model): |
80 | name = models.CharField(max_length=100, blank=False, | 84 | name = models.CharField(max_length=100, blank=False, |
81 | null=False, unique=True) | 85 | null=False, unique=True) |
82 | - # quota % | ||
83 | - quota = models.IntegerField( | ||
84 | - validators=[MinValueValidator(0), MaxValueValidator(100)]) | 86 | + # fraction quota |
87 | + f_quota = models.FloatField( | ||
88 | + validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True) | ||
89 | + | ||
90 | + quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="institute_quotas", blank=True, null=True) | ||
85 | #representative_user = models.ForeignKey("PyrosUser", on_delete=models.DO_NOTHING,related_name="institutes",default=1) | 91 | #representative_user = models.ForeignKey("PyrosUser", on_delete=models.DO_NOTHING,related_name="institutes",default=1) |
86 | 92 | ||
87 | def __str__(self) -> str: | 93 | def __str__(self) -> str: |
@@ -90,6 +96,8 @@ class Institute(models.Model): | @@ -90,6 +96,8 @@ class Institute(models.Model): | ||
90 | class Meta: | 96 | class Meta: |
91 | db_table = "institute" | 97 | db_table = "institute" |
92 | 98 | ||
99 | + | ||
100 | + | ||
93 | class ScienceTheme(models.Model): | 101 | class ScienceTheme(models.Model): |
94 | name = models.CharField(max_length=120, blank=False, null=False, default="", unique=True) | 102 | name = models.CharField(max_length=120, blank=False, null=False, default="", unique=True) |
95 | def __str__(self) -> str: | 103 | def __str__(self) -> str: |
@@ -367,6 +375,8 @@ class Period(models.Model): | @@ -367,6 +375,8 @@ class Period(models.Model): | ||
367 | data_accessibility_duration = models.PositiveIntegerField( | 375 | data_accessibility_duration = models.PositiveIntegerField( |
368 | blank=True, null=True, default=365*10, editable=True) | 376 | blank=True, null=True, default=365*10, editable=True) |
369 | 377 | ||
378 | + quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="period_quotas", blank=True, null=True) | ||
379 | + | ||
370 | @property | 380 | @property |
371 | def end_date(self): | 381 | def end_date(self): |
372 | return self.start_date + relativedelta(days=self.exploitation_duration) | 382 | return self.start_date + relativedelta(days=self.exploitation_duration) |
@@ -461,11 +471,11 @@ class ScientificProgram(models.Model): | @@ -461,11 +471,11 @@ class ScientificProgram(models.Model): | ||
461 | description_short = models.TextField(default="", max_length=320) | 471 | description_short = models.TextField(default="", max_length=320) |
462 | description_long = models.TextField(default="") | 472 | description_long = models.TextField(default="") |
463 | institute = models.ForeignKey('Institute', on_delete=models.DO_NOTHING, related_name="scientific_programs") | 473 | institute = models.ForeignKey('Institute', on_delete=models.DO_NOTHING, related_name="scientific_programs") |
464 | - sp_pi = models.ForeignKey('PyrosUser', on_delete=models.DO_NOTHING, related_name="Scientific_Program_Users") | 474 | + sp_pi = models.ForeignKey('PyrosUser', on_delete=models.DO_NOTHING, related_name="scientific_Program_Users") |
465 | science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1) | 475 | science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1) |
466 | is_auto_validated = models.BooleanField(default=False) | 476 | is_auto_validated = models.BooleanField(default=False) |
467 | objects = ScientificProgramManager() | 477 | objects = ScientificProgramManager() |
468 | - | 478 | + quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="scientific_program_quotas", blank=True, null=True) |
469 | class Meta: | 479 | class Meta: |
470 | managed = True | 480 | managed = True |
471 | db_table = 'scientific_program' | 481 | db_table = 'scientific_program' |
@@ -525,14 +535,6 @@ class SP_Period(models.Model): | @@ -525,14 +535,6 @@ class SP_Period(models.Model): | ||
525 | is_valid = models.TextField( | 535 | is_valid = models.TextField( |
526 | choices=IS_VALID, default=IS_VALID_REJECTED, blank=True) | 536 | choices=IS_VALID, default=IS_VALID_REJECTED, blank=True) |
527 | status = models.TextField(choices=STATUSES, default=STATUSES_DRAFT) | 537 | status = models.TextField(choices=STATUSES, default=STATUSES_DRAFT) |
528 | - quota_minimal = models.PositiveIntegerField(default=0) | ||
529 | - quota_nominal = models.PositiveIntegerField(default=0) | ||
530 | - quota_allocated = models.PositiveIntegerField(default=0, blank=True) | ||
531 | - quota_remaining = models.PositiveIntegerField(default=0, blank=True) | ||
532 | - over_quota_duration = models.PositiveIntegerField(default=0) | ||
533 | - over_quota_duration_allocated = models.PositiveIntegerField( | ||
534 | - default=0, blank=True) | ||
535 | - over_quota_duration_remaining = models.PositiveIntegerField(default=0) | ||
536 | token = models.PositiveIntegerField(default=0) | 538 | token = models.PositiveIntegerField(default=0) |
537 | token_allocated = models.PositiveIntegerField(default=0, blank=True) | 539 | token_allocated = models.PositiveIntegerField(default=0, blank=True) |
538 | token_remaining = models.PositiveIntegerField(default=0, blank=True) | 540 | token_remaining = models.PositiveIntegerField(default=0, blank=True) |