import re import semver from django.db import models from django.core.validators import RegexValidator from membershipworks.models import Member, Flag as MembershipWorksFlag VALID_SEMVER_PATTERN = re.compile( r"(?P\d+\.\d+\.\d+) - (?P\d{4}-\d{2}-\d{2})" ) class CmsRedRiverVeteransScholarship(models.Model): serial = models.AutoField(primary_key=True) program_name = models.CharField(db_column="Program Name", max_length=255) member_name = models.CharField( db_column="Member Name", max_length=255, blank=True, null=True ) discount_percent = models.DecimalField( db_column="Discount Percent", max_digits=16, decimal_places=0, blank=True, null=True, ) discount_code = models.CharField( db_column="Discount Code", max_length=255, blank=True, null=True ) membership_code = models.CharField( db_column="Membership Code", max_length=255, blank=True, null=True ) start_date = models.DateField(db_column="Start Date", blank=True, null=True) end_date = models.DateField(db_column="End Date", blank=True, null=True) program_amount = models.DecimalField( db_column="Program Amount", max_digits=16, decimal_places=0, blank=True, null=True, ) program_status = models.CharField( db_column="Program Status", max_length=16, blank=True, null=True ) def __str__(self): return f"{self.program_name} {self.member_name}" class Meta: db_table = "CMS Red River Veterans Scholarship" class Department(models.Model): name = models.CharField( max_length=64, validators=[RegexValidator("^[-_ A-Za-z0-9]*$")], help_text="This will also be used to generate the mailing list name", ) parent = models.ForeignKey( "self", on_delete=models.PROTECT, related_name="children", blank=True, null=True ) has_mailing_list = models.BooleanField(default=False) list_moderator_flag = models.ForeignKey( MembershipWorksFlag, on_delete=models.PROTECT, blank=True, null=True, db_constraint=False, ) list_reply_to_address = models.EmailField(max_length=254, blank=True) def __str__(self): return self.name @property def list_name(self): return self.name.replace(" ", "_") + "-info" class CertificationDefinition(models.Model): certification_identifier = models.AutoField( db_column="Certification Identifier", primary_key=True ) certification_name = models.CharField( db_column="Certification Name", max_length=255, blank=True, null=True ) department = models.ForeignKey(Department, models.PROTECT) def __str__(self): return f"{self.certification_name} <{self.department}>" class Meta: db_table = "Certification Definitions" ordering = ("certification_name", "department") def latest_version(self) -> "CertificationVersion": all_versions = CertificationVersion.objects.filter(definition=self) return max(all_versions, key=lambda version: version.semantic_version()) class CertificationVersion(models.Model): definition = models.ForeignKey( CertificationDefinition, on_delete=models.PROTECT, db_column="Certification" ) version = models.CharField( db_column="Version", max_length=255, blank=True, null=True ) def __str__(self): return f"{self.definition} [{self.version}]" class Meta: constraints = [ models.UniqueConstraint( fields=["definition", "version"], name="unique_certification_version" ) ] def semantic_version(self) -> semver.VersionInfo: if self.version is None: return "0.0.0-none" elif self.version == "MembershipWorks Label": return semver.parse_version_info("0.0.1-mw-label") elif match := VALID_SEMVER_PATTERN.match(self.version): return semver.parse_version_info( f'{match["semver"]}+{match["approvaldate"]}' ) else: return semver.parse_version_info( "0.0.1-" + re.sub(r"[^.a-zA-Z0-9]", "-", self.version) ) def is_latest(self) -> bool: return self.definition.latest_version() == self is_latest.boolean = True def is_current(self) -> bool: """Returns true if this version compatible with the latest version""" # TODO: should do a more correct comparison than just major version return ( self.definition.latest_version().semantic_version().major == self.semantic_version().major ) is_current.boolean = True class Certification(models.Model): number = models.AutoField(db_column="Number", primary_key=True) certification_version = models.ForeignKey( CertificationVersion, on_delete=models.PROTECT ) name = models.CharField(db_column="Name", max_length=255) member = models.ForeignKey( Member, on_delete=models.PROTECT, to_field="uid", db_column="uid", blank=True, null=True, db_constraint=False, ) certified_by = models.CharField( db_column="Certified_By", max_length=255, blank=True, null=True ) date = models.DateField(db_column="Date", blank=True, null=True) shop_lead_notified = models.DateTimeField( db_column="Shop Lead Notified", blank=True, null=True ) notes = models.CharField(db_column="Notes", max_length=255, blank=True, null=True) def __str__(self): return f"{self.name} - {self.certification_version}" class Meta: db_table = "Certifications" permissions = [ ( "receive_certification_emails", "Receives notifications of all new certifications", ), ] class InstructorOrVendor(models.Model): serial = models.AutoField(primary_key=True) name = models.CharField(db_column="Name", max_length=255) instructor_agreement_date = models.DateField( db_column="Instructor Agreement Date", blank=True, null=True ) w9_date = models.DateField(db_column="W9 date", blank=True, null=True) phone = models.CharField(max_length=255, blank=True, null=True) email_address = models.CharField( db_column="email address", max_length=255, blank=True, null=True ) def __str__(self): return f"{self.name}" class Meta: db_table = "Instructors and Vendors" class SpecialProgram(models.Model): program_name = models.CharField( db_column="Program Name", primary_key=True, max_length=255 ) discount_percent = models.DecimalField( db_column="Discount Percent", max_digits=16, decimal_places=0, blank=True, null=True, ) discount_code = models.CharField( db_column="Discount Code", max_length=255, blank=True, null=True ) membership_code = models.CharField( db_column="Membership Code", max_length=255, blank=True, null=True ) start_date = models.DateField(db_column="Start Date", blank=True, null=True) end_date = models.DateField(db_column="End Date", blank=True, null=True) program_amount = models.DecimalField( db_column="Program Amount", max_digits=16, decimal_places=0, blank=True, null=True, ) program_status = models.CharField( db_column="Program Status", max_length=16, blank=True, null=True ) def __str__(self): return self.program_name class Meta: db_table = "Special_Programs" class Waiver(models.Model): number = models.AutoField(db_column="Number", primary_key=True) name = models.CharField(db_column="Name", max_length=255) date = models.DateField(db_column="Date") emergency_contact_name = models.CharField( db_column="Emergency Contact Name", max_length=255, blank=True, null=True ) emergency_contact_number = models.CharField( db_column="Emergency Contact Number", max_length=25, blank=True, null=True ) waiver_version = models.CharField(db_column="Waiver version", max_length=64) guardian_name = models.CharField( db_column="Guardian Name", max_length=255, blank=True, null=True ) guardian_relation = models.CharField( db_column="Guardian Relation", max_length=255, blank=True, null=True ) guardian_date = models.DateField(db_column="Guardian Date", blank=True, null=True) def __str__(self): return f"{self.name} {self.date}" class Meta: db_table = "Waivers"