class RoomSafetyItem(models.Model): """ Allow each unit to manage the categories which are now included in a visit. """ unit = models.ForeignKey(Unit, null=False, blank=False, on_delete=models.PROTECT) label = models.CharField(null=False, blank=False, max_length=50) description = models.CharField(null=True, blank=True, max_length=500) hidden = models.BooleanField(null=False, blank=False, default=False, editable=False) config = JSONField(null=False, blank=False, default=dict, editable=False) # addition configuration stuff: def autoslug(self): return make_slug(self.unit.slug + '-' + self.label) slug = AutoSlugField(populate_from='autoslug', null=False, editable=False, unique=True) def __str__(self): return self.label objects = RoomSafetyItemQuerySet.as_manager() def delete(self): # As usual, only hide stuff, don't delete it. self.hidden = True self.save()
class SessionalContract(models.Model): """ Similar to TA or RA contract, but we need to be able to use them with people who aren't in the system yet. """ sessional = models.ForeignKey(AnyPerson, null=False, blank=False, on_delete=models.PROTECT) account = models.ForeignKey(SessionalAccount, null=False, blank=False, on_delete=models.PROTECT) unit = models.ForeignKey(Unit, null=False, blank=False, on_delete=models.PROTECT) sin = models.CharField(max_length=30, verbose_name="SIN", help_text="Social Insurance Number - 000000000 if unknown") # We want do add some sort of accountability for checking visas. Don't # allow printing of the contract if this box hasn't been checked. visa_verified = models.BooleanField(default=False, help_text="I have verified this sessional's visa information") appointment_start = models.DateField(null=False, blank=False) appointment_end = models.DateField(null=False, blank=False) pay_start = models.DateField(null=False, blank=False) pay_end = models.DateField(null=False, blank=False) # Was going to add a Semester, but since the offering itself has a semester, no need for it. offering = models.ForeignKey(CourseOffering, null=False, blank=False, on_delete=models.PROTECT) course_hours_breakdown = models.CharField(null=True, blank=True, max_length=100, help_text="e.g. 1x2HR Lecture, etc. This will show up in the form in " "the column after the course department and number.") appt_guarantee = models.CharField("Appoinment Guarantee", max_length=4, choices=GUARANTEE_CHOICES, null=False, blank=False, default='GUAR') appt_type = models.CharField("Appointment Type", max_length=4, choices=TYPE_CHOICES, null=False, blank=False, default='INIT') contact_hours = models.DecimalField("Weekly Contact Hours", max_digits=6, decimal_places=2, null=False, blank=False) total_salary = models.DecimalField(max_digits=8, decimal_places=2, null=False, blank=False) notes = models.CharField(max_length=400, null=True, blank=True) created = models.DateTimeField(auto_now_add=True, editable=False) created_by = models.CharField(max_length=20, null=False, blank=False, editable=False) hidden = models.BooleanField(null=False, default=False, editable=False) config = JSONField(null=False, blank=False, editable=False, default=dict) objects = SessionalContractQuerySet.as_manager() def autoslug(self): """As usual, create a unique slug for each object""" return make_slug(str(self.sessional) + "-" + str(self.offering)) slug = AutoSlugField(populate_from='autoslug', null=False, editable=False, unique=True) def __str__(self): return "%s - %s" % (str(self.sessional), str(self.offering)) def delete(self): """Like most of our objects, we don't want to ever really delete it.""" self.hidden = True self.save() def has_attachments(self): return self.attachments.visible().count() > 0 class Meta: # Presumably, you can only have one contract for the same person, offering, and account/position. unique_together = (('sessional', 'account', 'offering'),)
class BookingRecord(models.Model): location = models.ForeignKey(Location, related_name='bookings', on_delete=models.PROTECT) person = models.ForeignKey(Person, related_name='+', on_delete=models.PROTECT) start_time = models.DateTimeField("Start date/time", default=timezone_today) end_time = models.DateTimeField("End date/time", null=True, blank=True) form_submission_URL = models.CharField(null=True, blank=True, max_length=1000, help_text="If the user filled in a form to get this booking created, put " "its URL here.") notes = models.CharField(null=True, blank=True, max_length=1000) hidden = models.BooleanField(default=False, null=False, blank=False, editable=False) config = JSONField(null=False, blank=False, editable=False, default=dict) last_modified = models.DateTimeField(blank=False, null=False, editable=False) last_modified_by = models.ForeignKey(Person, null=True, blank=True, editable=False, related_name='+', on_delete=models.PROTECT) objects = BookingRecordManager.as_manager() # A property to mark if this booking conflicts with any others. conflict = config_property('conflict', False) def autoslug(self): return make_slug(self.location.slug + '-' + self.person.userid_or_emplid() + '-' + str(self.start_time.date())) slug = AutoSlugField(populate_from='autoslug', null=False, editable=False, unique=True) def __str__(self): return "%s - %s" % (self.person.name(), self.start_time) def save(self, editor=None, *args, **kwargs): # Only note the last modified things if we have an editor. Otherwise, the object is being changed # by the conflict checking code or the code end-dating it automagically. if editor: self.last_modified = timezone_today() self.last_modified_by = editor # In remote cases, we could have created the object without an editor automagically, like when creating # the fixtures. In that case, only if we don't have a previous last_modified, create it. elif not self.last_modified: self.last_modified = timezone_today() super(BookingRecord, self).save(*args, **kwargs) def has_attachments(self): return self.attachments.visible().count() > 0 def get_attachments(self): return self.attachments.visible().order_by('created_at') def has_memos(self): return self.memos.count() > 0 def get_memos(self): return self.memos.objects.all().order_by('created_at') def is_current(self): return self.start_time <= timezone_today() and (not self.end_time or self.end_time > timezone_today()) def has_key_request(self): return hasattr(self, 'key_request')
class RoomType(models.Model): unit = models.ForeignKey(Unit, null=False, on_delete=models.PROTECT) long_description = models.CharField(max_length=256, null=False, blank=False, help_text='e.g. "General Store"') code = models.CharField(max_length=50, null=False, blank=False, help_text='e.g. "STOR_GEN"') COU_code_description = models.CharField( max_length=256, null=False, blank=False, help_text='e.g. "Academic Office Support Space"') space_factor = models.DecimalField(max_digits=3, decimal_places=1, blank=True, default=0.0) COU_code_value = models.DecimalField(max_digits=4, decimal_places=1, help_text='e.g. 10.1', blank=True, null=True) hidden = models.BooleanField(default=False, null=False, blank=False, editable=False) config = JSONField(null=False, blank=False, editable=False, default=dict) objects = RoomTypeManager.as_manager() def autoslug(self): return make_slug(self.unit.slug + '-' + self.code + '-' + str(self.COU_code_value)) slug = AutoSlugField(populate_from='autoslug', null=False, editable=False, unique=True) def __str__(self): return "%s-%s-%s" % (self.unit.label, self.code, str(self.COU_code_value))
class Location(models.Model): unit = models.ForeignKey(Unit, null=False, on_delete=models.PROTECT) campus = models.CharField(max_length=5, choices=CAMPUS_CHOICES, null=False, blank=False) building = models.CharField(max_length=5, choices=BUILDING_CHOICES, null=False, blank=False) floor = models.PositiveIntegerField(null=False, blank=False) room_number = models.CharField(max_length=25, null=False, blank=False) square_meters = models.DecimalField(max_digits=8, decimal_places=2) room_type = models.ForeignKey(RoomType, null=False, on_delete=models.PROTECT) infrastructure = models.CharField(max_length=3, choices=INFRASTRUCTURE_CHOICES, null=True, blank=True) room_capacity = models.PositiveIntegerField(null=True, blank=True) category = models.CharField(max_length=5, choices=CATEGORY_CHOICES, null=True, blank=True) occupancy_count = models.PositiveIntegerField(null=True, blank=True) own_or_lease = models.CharField("SFU Owned or Leased", max_length=5, choices=OWN_CHOICES, null=True, blank=True) comments = models.CharField(max_length=400, null=True, blank=True) hidden = models.BooleanField(default=False, null=False, blank=False, editable=False) config = JSONField(null=False, blank=False, editable=False, default=dict) objects = LocationManager.as_manager() def autoslug(self): return make_slug(self.unit.slug + '-' + self.campus + '-' + self.building + '-' + str(self.floor) + '-' + self.room_number) slug = AutoSlugField(populate_from='autoslug', null=False, editable=False, unique=True) def __str__(self): return "%s, %s - %s" % (CAMPUSES_SHORT[self.campus], BUILDINGS[self.building], self.room_number) def get_current_bookings(self): visible_bookings = self.bookings.visible().filter( start_time__lte=timezone_today()).order_by('start_time') return [b for b in visible_bookings if b.is_current()] def get_current_bookings_str(self): return "; ".join( [b.person.name() for b in self.get_current_bookings()]) def has_bookings(self): return self.bookings.filter(hidden=False).count() > 0 def get_bookings(self): return self.bookings.filter(hidden=False) def mark_conflicts(self): # A stupid nested loop to see if there are any conflicts within the bookings for this location self.conflicts = False for a in self.get_bookings(): a.conflict = False for b in self.get_bookings().exclude(id=a.id): if a.end_time is None and b.end_time is None: a.conflict = True break if a.end_time is None and a.start_time < b.end_time: a.conflict = True break if b.end_time is None and ((a.start_time > b.start_time) or (a.end_time > b.start_time)): a.conflict = True break if a.end_time is not None and b.end_time is not None and a.start_time < b.end_time \ and a.end_time > b.start_time: a.conflict = True a.save()