class Project(models.Model): """Project entity representing a paid project for a customer.""" name = models.CharField(max_length=200, db_index=True) customer = models.ForeignKey(Customer, on_delete=models.PROTECT) active = models.BooleanField(default=True) code = models.CharField(max_length=200, db_index=True, blank=True, null=False, editable=False) created_on = models.DateTimeField(auto_now_add=True) updated_on = models.DateTimeField(auto_now=True) def get_code_default(self) -> str: return f"P{self.customer.id}-{self.id}" # Override save function to populate self.code # We need to double save, because code is derived from pk but pk is None until object is saved def save(self, *args, **kwargs): created = not self.pk if created: # if initial creation, save instance to generate pk super().save(*args, **kwargs) # if instance doesn't have `code` generate it if not self.code: self.code = self.get_code_default() # save, saved in any case return super().save(*args, **kwargs) def __str__(self): return f"{self.customer.name} - {self.name} ({self.code})" class ProjectCode(models.Model): name = models.CharField(max_length=200, db_index=True) code = models.CharField(max_length=200, unique=True, db_index=True, blank=True, null=False, editable=False) project = models.ForeignKey(Project, on_delete=models.PROTECT) active = models.BooleanField(default=True) rate = models.DecimalField(blank=True, null=True, max_digits=10, decimal_places=2) max_hours = models.IntegerField(blank=True, null=True) date_start = models.DateField(blank=True, null=True) date_end = models.DateField(blank=True, null=True) created_on = models.DateTimeField(auto_now_add=True) updated_on = models.DateTimeField(auto_now=True) def get_code_default(self) -> str: return f"PC-{self.project.customer.id}-{self.project.id}-{self.id}" # Override save function to populate self.code # We need to double save, because code is derived from pk but pk is None until object is saved def save(self, *args, **kwargs): created = not self.pk if created: # if initial creation, save instance to generate pk super().save(*args, **kwargs) # if instance doesn't have `code` generate it if not self.code: self.code = self.get_code_default() # save, saved in any case return super().save(*args, **kwargs)