from django.db import models from django.db.models import Model, CharField, EmailField, \ DateTimeField, DecimalField, ForeignKey, ManyToManyField, \ IntegerField, ImageField, BooleanField, \ CASCADE, SET_NULL, PROTECT from django_countries.fields import CountryField from phonenumber_field.modelfields import PhoneNumberField from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ # MODELS # Warning : # If you modify a Model sub-class attribute, you # should then run : # ./manage.py makemigrations # ./manage.py migrate def validate_positive(value): if value < 0: raise ValidationError( _('%(value)s is not a positive number'), params={'value': value}, ) class Address(Model): address = CharField(max_length=200,default='miss_add') zip_code = CharField(max_length=10,default='miss_zip') city = CharField(max_length=200,default='miss_city') country = CountryField() # Methods def __str__(self): return '{}, {} - {}, {}'.format(self.address, self.zip_code, self.city, self.country) class Person(Model): name = CharField(max_length=50,blank=True,null=True) surname = CharField(max_length=50,blank=True,null=True) nationality = CountryField(blank=True,null=True) email = EmailField(max_length=254,blank=True,null=True) # phone number has to be in international format # i.e : for 0102030405 in france => +33102030405 # (the number is written WITHOUT the leading 0) phone = PhoneNumberField(blank=True,null=True) # Foreign keys address = ForeignKey(Address,on_delete=SET_NULL,blank=True,null=True) # Methods def __str__(self): return '{} {}'.format(self.name, self.surname) class Company(Model): name = CharField(max_length=50,blank=True) email = EmailField(max_length=200,blank=True,null=True) phone = PhoneNumberField(blank=True,null=True) registration_num = CharField(max_length=50,blank=True,null=True) # Foreign keys address = ForeignKey(Address,on_delete=SET_NULL,blank=True,null=True) # Methods def __str__(self): return '{}'.format(self.name) class Insurance(Company): pass class Boat(Model): name = CharField(max_length=50) registration_num = CharField('Registration number', max_length=20, blank=True, null=True) length = DecimalField('Length', max_digits=7, decimal_places=2, blank=True,null=True, validators=[validate_positive]) beam = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) water_draught = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) tonnage = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) water_tank = DecimalField('Water tank capacity', max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) model = CharField(max_length=50,blank=True,null=True) heating = CharField(max_length=50,blank=True,null=True) passenger_capacity = IntegerField(blank=True,null=True) picture = ImageField(upload_to='uploads/', height_field=None, width_field=None, max_length=100, blank=True, null=True) # Foreign keys company = ForeignKey(Company, on_delete=SET_NULL, blank=True, null=True, related_name='+') boat_insurance = ManyToManyField( Insurance, through='BoatInsurance', through_fields=('boat', 'insurance'), blank=True ) persons = ManyToManyField( Person, through='SailsOn', through_fields=('boat', 'person') ) # Methods def __str__(self): return '{}'.format(self.name) def getInsurance(self, date=None): try: return self.insured \ .order_by('-date')[0].insurance \ if date is None \ else self.insured.filter(date__lte=date) \ .order_by('-date')[0].insurance except IndexError: return None class SailsOn(Model): boat = ForeignKey( Boat, on_delete=PROTECT, related_name='sailors' ) person = ForeignKey(Person,on_delete=PROTECT) is_captain = BooleanField() is_crew = BooleanField() is_owner = BooleanField() is_guest = BooleanField() is_pet = BooleanField() present = BooleanField(default=True) def update(self, sailson): self.is_captain = sailson.is_captain self.is_crew = sailson.is_crew self.is_owner = sailson.is_owner self.is_guest = sailson.is_guest self.is_pet = sailson.is_pet self.present = sailson.present class BoatInsurance(Model): contract = IntegerField(blank=True,null=True) date = DateTimeField(auto_now_add=True) # Foreign keys insurance = ForeignKey(Insurance,on_delete=PROTECT) boat = ForeignKey( Boat, on_delete=PROTECT, related_name='insured' ) class Port(Model): name = CharField(max_length=50) # Foreign keys address = ForeignKey(Address,on_delete=PROTECT) company = ForeignKey(Company,on_delete=PROTECT) employees = ManyToManyField( Person, through='Employee', through_fields=('port', 'person')) # Methods def __str__(self): return '{}'.format(self.name) class Employee(Model): position = CharField('Job',max_length=20,blank=True,null=True) # Foreign keys port = ForeignKey(Port,on_delete=PROTECT,blank=True) person = ForeignKey(Person,on_delete=PROTECT) # Methods def __str__(self): return '{}, {} at {}'.format(str(self.person), self.position, str(self.port)) class Dock(Model): name = CharField(max_length=10) length = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) width = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) depth_min = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) depth_max = DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, validators=[validate_positive]) # Foreign keys port = ForeignKey(Port,on_delete=PROTECT) # Methods def __str__(self): return '{} : {}'.format(str(self.port), self.num) class Plug(Model): name = CharField(max_length=10) amperage = DecimalField(max_digits=7, decimal_places=2, validators=[validate_positive]) voltage = DecimalField(max_digits=7, decimal_places=2, validators=[validate_positive]) # Foreign keys port = ForeignKey(Port,on_delete=PROTECT) # Methods def __str__(self): return '{} : {}'.format(str(self.port), self.num) class Tap(Model): name = CharField(max_length=10) # Foreign keys port = ForeignKey(Port,on_delete=PROTECT) # Methods def __str__(self): return '{} : {}'.format(str(self.port), self.num) class Payment(Model): num = CharField(max_length=40) date = DateTimeField() amount = DecimalField(max_digits=7, decimal_places=2) pay_type = CharField( max_length=3, choices=[ ('CSH', 'Cash'), ('CHK', 'Check'), ('TSF', 'Transfer'), ('CRD', 'Credit Card') ], default='CSH' ) # Methods def __str__(self): return '{} at {}'.format(self.num, str(self.date)) class Service(Model): name = CharField(max_length=50) # Methods def __str__(self): return '{}'.format(self.name) class Bill(Model): num = IntegerField() date = DateTimeField() total = DecimalField(max_digits=7, decimal_places=2) # Foreign keys payments = ManyToManyField( Payment, through='BillPayment', through_fields=('bill', 'payment') ) # Methods def __str__(self): return '{} at {}'.format(self.num, str(self.date)) class BillLine(Model): quantity = DecimalField(max_digits=7, decimal_places=2) value = DecimalField(max_digits=7, decimal_places=2, default=0.) # Foreign keyks service = ForeignKey(Service,on_delete=PROTECT) bill = ForeignKey(Bill,on_delete=PROTECT) # Methods def __str__(self): return '{}x {} - {}'.format(self.quantity, str(self.service), str(self.value)) class BillPayment(Model): amount = DecimalField(max_digits=7, decimal_places=2) # Foreign keys bill = ForeignKey(Bill,on_delete=PROTECT) payment = ForeignKey(Payment,on_delete=PROTECT) class Stay(Model): arrival = DateTimeField() departure = DateTimeField(blank=True,null=True) coming_from = CharField(max_length=200,blank=True,null=True) going_to = CharField(max_length=200,blank=True,null=True) no_mooring = BooleanField('Set moorings later',default=False,blank=True) # Foreign keys boat = ForeignKey(Boat,on_delete=PROTECT) bill = ForeignKey(Bill,on_delete=PROTECT,blank=True,null=True) # Methods def __str__(self): return '{} - {} : {}'.format(self.arrival, self.departure, str(self.boat)) class Mooring(Model): date = DateTimeField() # Foreign keys stay = ForeignKey(Stay,on_delete=CASCADE) dock = ForeignKey(Dock,on_delete=PROTECT) tap = ForeignKey(Tap,on_delete=PROTECT,blank=True,null=True) plug = ForeignKey(Plug,on_delete=PROTECT,blank=True,null=True) # Methods def __str__(self): return '{} - {} at {}'.format(str(self.date), str(self.stay.boat), str(self.dock))