gault-millau/apps/establishment/models.py

232 lines
9.1 KiB
Python

"""Establishment models."""
from functools import reduce
from django.contrib.contenttypes import fields as generic
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from location.models import Address
from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField,
TraslatedFieldsMixin, BaseAttributes)
# todo: establishment type&subtypes check
class EstablishmentType(ProjectBaseMixin, TraslatedFieldsMixin):
"""Establishment type model."""
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'),
help_text='{"en":"some text"}')
use_subtypes = models.BooleanField(_('Use subtypes'), default=True)
class Meta:
"""Meta class."""
verbose_name = _('Establishment type')
verbose_name_plural = _('Establishment types')
class EstablishmentSubTypeManager(models.Manager):
"""Extended manager for establishment subtype."""
def make(self, name, establishment_type):
obj = self.model(name=name, establishment_type=establishment_type)
obj.full_clean()
obj.save()
return obj
class EstablishmentSubType(ProjectBaseMixin, TraslatedFieldsMixin):
"""Establishment type model."""
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'),
help_text='{"en":"some text"}')
establishment_type = models.ForeignKey(EstablishmentType,
on_delete=models.CASCADE,
verbose_name=_('Type'))
objects = EstablishmentSubTypeManager()
class Meta:
"""Meta class."""
verbose_name = _('Establishment subtype')
verbose_name_plural = _('Establishment subtypes')
def clean_fields(self, exclude=None):
if not self.establishment_type.use_subtypes:
raise ValidationError(_('Establishment type is not use subtypes.'))
class EstablishmentQuerySet(models.QuerySet):
"""Extended queryset for Establishment model."""
def search(self, value, locale=None):
"""Search text in JSON fields."""
if locale is not None:
filters = [
{f'name__{locale}__icontains': value},
{f'description__{locale}__icontains': value}
]
return self.filter(reduce(lambda x, y: x | y, [models.Q(**i) for i in filters]))
else:
return self.none()
def prefetch_actual_employees(self):
"""Prefetch actual employees."""
return self.prefetch_related(
models.Prefetch('establishmentemployee_set',
queryset=EstablishmentEmployee.objects.actual().select_related(
'position'),
to_attr='actual_establishment_employees'))
class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
"""Establishment model."""
name = TJSONField(blank=True, null=True, default=None,
verbose_name=_('Name'), help_text='{"en":"some text"}')
description = TJSONField(blank=True, null=True, default=None,
verbose_name=_('Description'),
help_text='{"en":"some text"}')
public_mark = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('Public mark'),)
toque_number = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('Toque number'),)
establishment_type = models.ForeignKey(EstablishmentType,
related_name='establishment',
on_delete=models.PROTECT,
verbose_name=_('Type'))
establishment_subtypes = models.ManyToManyField(EstablishmentSubType,
related_name='subtype_establishment',
verbose_name=_('Subtype'))
address = models.ForeignKey(Address, blank=True, null=True, default=None,
on_delete=models.PROTECT,
verbose_name=_('Address'))
price_level = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('Price level'))
awards = generic.GenericRelation(to='main.Award')
tags = generic.GenericRelation(to='main.MetaDataContent')
objects = EstablishmentQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name = _('Establishment')
verbose_name_plural = _('Establishments')
# todo: recalculate toque_number
def recalculate_toque_number(self):
self.toque_number = 4
def recalculate_price_level(self, low_price=None, high_price=None):
if low_price is None or high_price is None:
low_price, high_price = self.get_price_level()
# todo: calculate price level
self.price_level = 3
def get_price_level(self):
country = self.address.city.country
return country.low_price, country.high_price
# todo: make via prefetch
@property
def subtypes(self):
return EstablishmentSubType.objects.filter(
subtype_establishment=self,
establishment_type=self.establishment_type,
establishment_type__use_subtypes=True)
def set_establishment_type(self, establishment_type):
self.establishment_type = establishment_type
self.establishment_subtypes.exclude(
establishement_type=establishment_type).delete()
def add_establishment_subtype(self, establishment_subtype):
if establishment_subtype.establishment_type != self.establishment_type:
raise ValidationError('Establishment type of subtype does not match')
self.establishment_subtypes.add(establishment_subtype)
class Position(BaseAttributes, TraslatedFieldsMixin):
"""Position model."""
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'),
help_text='{"en":"some text"}')
class Meta:
"""Meta class."""
verbose_name = _('Position')
verbose_name_plural = _('Positions')
class EstablishmentEmployeeQuerySet(models.QuerySet):
"""Extended queryset for EstablishmEntemployee model."""
def actual(self):
"""Actual objects.."""
now = timezone.now()
return self.filter(models.Q(from_date__lte=now),
(models.Q(to_date__gte=now) |
models.Q(to_date__isnull=True)))
class EstablishmentEmployee(BaseAttributes):
"""EstablishmentEmployee model."""
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT,
verbose_name=_('Establishment'))
employee = models.ForeignKey('establishment.Employee', on_delete=models.PROTECT,
verbose_name=_('Employee'))
from_date = models.DateTimeField(default=timezone.now, verbose_name=_('From date'))
to_date = models.DateTimeField(blank=True, null=True, default=None,
verbose_name=_('To date'))
position = models.ForeignKey(Position, on_delete=models.PROTECT,
verbose_name=_('Position'))
objects = EstablishmentEmployeeQuerySet.as_manager()
class Employee(BaseAttributes):
"""Employee model."""
user = models.OneToOneField('account.User', on_delete=models.PROTECT,
null=True, blank=True, default=None,
verbose_name=_('User'))
name = models.CharField(max_length=255, verbose_name=_('Last name'))
establishments = models.ManyToManyField(Establishment, related_name='employees',
through=EstablishmentEmployee)
awards = generic.GenericRelation(to='main.Award')
tags = generic.GenericRelation(to='main.MetaDataContent')
class Meta:
"""Meta class."""
verbose_name = _('Employee')
verbose_name_plural = _('Employees')
class EstablishmentScheduleQuerySet(models.QuerySet):
"""QuerySet for model EstablishmentSchedule"""
class EstablishmentSchedule(BaseAttributes):
"""Establishment schedule model."""
establishment = models.OneToOneField(Establishment,
related_name='schedule',
on_delete=models.CASCADE,
verbose_name=_('Establishment'))
schedule = models.ManyToManyField(to='timetable.Timetable',
verbose_name=_('Establishment schedule'))
objects = EstablishmentScheduleQuerySet.as_manager()
class Meta:
"""Meta class"""
verbose_name = _('Establishment schedule')
verbose_name_plural = _('Establishment schedules')