235 lines
9.5 KiB
Python
235 lines
9.5 KiB
Python
from django.core.exceptions import *
|
||
from django.core.validators import RegexValidator
|
||
from django.db import models
|
||
from django.db.models import Q
|
||
|
||
from account.models import SiteUser
|
||
from datetime import datetime
|
||
|
||
|
||
class City(models.Model):
|
||
code = models.CharField(primary_key=True, max_length=20, verbose_name="Код города", validators=[
|
||
RegexValidator(regex="^[0-9a-zA-Z_]*$"),
|
||
])
|
||
name = models.CharField(unique=True, max_length=50, verbose_name="Название города")
|
||
|
||
def __str__(self):
|
||
return f"{self.name} ({self.code})"
|
||
|
||
@staticmethod
|
||
def to_choices():
|
||
return City.objects.order_by('name').values_list('code', 'name')
|
||
|
||
|
||
def _phone_validate(phone, order=None):
|
||
if phone is not None:
|
||
err_obj = {"phone": f'Телефон {phone} уже используется другим аккаунтом'}
|
||
if SiteUser.objects.filter(phone=phone).count() > 0:
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
if order is None:
|
||
if Order.objects.filter(phone=phone).count() > 0:
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
else:
|
||
if Order.objects.filter(~Q(id=order.id), phone=phone).count() > 0:
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
|
||
|
||
def _email_validate(email, order=None):
|
||
if email is not None:
|
||
err_obj = {'email': f'Почта {email} уже используется другим аккаунтом'}
|
||
if SiteUser.objects.filter(email=email).count():
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
if order is None:
|
||
if Order.objects.filter(email=email).count() > 0:
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
else:
|
||
if Order.objects.filter(~Q(id=order.id), email=email).count() > 0:
|
||
raise ValidationError(
|
||
err_obj,
|
||
code='permission'
|
||
)
|
||
|
||
|
||
class Order(models.Model):
|
||
# основные поля: название и описание
|
||
name = models.CharField(max_length=200, verbose_name="Название заказа")
|
||
description = models.TextField(blank=True, verbose_name="Описание")
|
||
|
||
# площадь в квадратных метрах
|
||
square = models.DecimalField(max_digits=7, decimal_places=2, blank=False, verbose_name="Площадь в м²")
|
||
|
||
work_time = models.CharField(max_length=100, blank=True, verbose_name="Рабочее время")
|
||
|
||
# дальше вид дома, тип ремонта, тип квартиры, требуется дизайн проект, закуп материала, тип исполнителя
|
||
|
||
CHOICE_UNDEFINED = ''
|
||
|
||
# тип ремонта
|
||
TYPE_OF_RENOVATION_OVERHAUL = 'overhaul'
|
||
TYPE_OF_RENOVATION_PARTIAL = 'partial'
|
||
TYPE_OF_RENOVATION_REDECOR = 'redecor'
|
||
TYPE_OF_RENOVATION_PREMIUM = 'premium'
|
||
TYPE_OF_RENOVATION_DESIGN = 'design'
|
||
|
||
TYPE_OF_RENOVATION_CHOICES = [
|
||
(TYPE_OF_RENOVATION_OVERHAUL, 'Капитальный'),
|
||
(TYPE_OF_RENOVATION_PARTIAL, 'Частичный'),
|
||
(TYPE_OF_RENOVATION_REDECOR, 'Косметический'),
|
||
(TYPE_OF_RENOVATION_PREMIUM, 'Премиальный'),
|
||
(TYPE_OF_RENOVATION_DESIGN, 'Дизайнерский'),
|
||
]
|
||
type_of_renovation = models.CharField(max_length=10, choices=TYPE_OF_RENOVATION_CHOICES, default=CHOICE_UNDEFINED,
|
||
blank=True, verbose_name="Тип ремонта")
|
||
|
||
# тип дома
|
||
TYPE_OF_HOUSE_BLOCK = 'block'
|
||
TYPE_OF_HOUSE_BRICK = 'brick'
|
||
TYPE_OF_HOUSE_MONOLITH = 'monolith'
|
||
TYPE_OF_HOUSE_PANEL = 'panel'
|
||
|
||
TYPE_OF_HOUSE_CHOICES = [
|
||
(TYPE_OF_HOUSE_BLOCK, 'Блочный'),
|
||
(TYPE_OF_HOUSE_BRICK, 'Кирпичный'),
|
||
(TYPE_OF_HOUSE_MONOLITH, 'Монолит'),
|
||
(TYPE_OF_HOUSE_PANEL, 'Панельный'),
|
||
]
|
||
type_of_house = models.CharField(max_length=10, choices=TYPE_OF_HOUSE_CHOICES, blank=True, default=CHOICE_UNDEFINED,
|
||
verbose_name="Тип дома")
|
||
|
||
# тип квартиры
|
||
TYPE_OF_ROOM_PRIMARY = 'primary'
|
||
TYPE_OF_ROOM_SECONDARY = 'secondary'
|
||
|
||
TYPE_OF_ROOM_CHOICES = [
|
||
(TYPE_OF_ROOM_PRIMARY, 'Первичка'),
|
||
(TYPE_OF_ROOM_SECONDARY, 'Вторичка')
|
||
]
|
||
type_of_room = models.CharField(max_length=10, choices=TYPE_OF_ROOM_CHOICES, blank=True, default=CHOICE_UNDEFINED,
|
||
verbose_name="Тип квартиры")
|
||
|
||
# требуется дизайн проект
|
||
REQUIRED_DESIGN_CHOICES = ((True, 'Да'), (False, 'Нет'))
|
||
is_require_design = models.BooleanField(default=None, blank=True, null=True, choices=REQUIRED_DESIGN_CHOICES,
|
||
verbose_name="Требуется дизайн проект")
|
||
|
||
# закуп материала
|
||
PURCHASE_OF_MATERIAL_EXECUTOR = 'executor'
|
||
PURCHASE_OF_MATERIAL_CUSTOMER = 'customer'
|
||
|
||
PURCHASE_OF_MATERIAL_CHOICES = [
|
||
(PURCHASE_OF_MATERIAL_EXECUTOR, 'Исполнитель'),
|
||
(PURCHASE_OF_MATERIAL_CUSTOMER, 'Заказчик')
|
||
]
|
||
purchase_of_material = models.CharField(max_length=10, choices=PURCHASE_OF_MATERIAL_CHOICES,
|
||
blank=True, default=CHOICE_UNDEFINED, verbose_name="Закуп материала")
|
||
|
||
# тип исполнителя
|
||
TYPE_OF_EXECUTOR_INDIVIDUAL = 'individual'
|
||
TYPE_OF_EXECUTOR_COMPANY = 'company'
|
||
|
||
TYPE_OF_EXECUTOR_CHOICES = [
|
||
(TYPE_OF_EXECUTOR_INDIVIDUAL, 'Самозанятый/бригада'),
|
||
(TYPE_OF_EXECUTOR_COMPANY, 'Компания')
|
||
]
|
||
type_of_executor = models.CharField(max_length=10, choices=TYPE_OF_EXECUTOR_CHOICES,
|
||
blank=True, default=CHOICE_UNDEFINED, verbose_name="Тип исполнителя")
|
||
|
||
# дальше отдельные параметры
|
||
is_with_warranty = models.BooleanField(default=True, verbose_name="С гарантией")
|
||
is_with_contract = models.BooleanField(default=False, verbose_name="Работа по договору")
|
||
is_with_trade = models.BooleanField(default=False, verbose_name="Возможен торг")
|
||
is_with_cleaning = models.BooleanField(default=False, verbose_name="С уборкой")
|
||
is_with_garbage_removal = models.BooleanField(default=False, verbose_name="С вывозом мусора")
|
||
|
||
# примерная цена
|
||
approximate_price = models.DecimalField(max_digits=12, decimal_places=2, blank=False, verbose_name="Цена")
|
||
|
||
date_start = models.DateField(null=True, blank=True, default=None, verbose_name="Дата начала")
|
||
date_end = models.DateField(null=True, blank=True, default=None, verbose_name="Дата окончания")
|
||
|
||
address_city = models.ForeignKey(City, on_delete=models.CASCADE, blank=False, related_name="address_city",
|
||
verbose_name="Город")
|
||
address_text = models.CharField(max_length=70, blank=True, verbose_name="Улица, дом")
|
||
|
||
owner = models.ForeignKey(SiteUser, on_delete=models.CASCADE, blank=True, null=True, related_name="owner",
|
||
verbose_name="Владелец")
|
||
|
||
email = models.EmailField(null=True, blank=True, verbose_name="Email")
|
||
phone = models.CharField(null=True, blank=True, max_length=16, verbose_name="Телефон", validators=[
|
||
RegexValidator(regex="^\\+7[0-9]{10}$")
|
||
])
|
||
|
||
create_time = models.DateTimeField(default=datetime.now, editable=False, verbose_name="Время создания")
|
||
|
||
moderated = models.BooleanField(default=True, verbose_name="Модерирован")
|
||
published = models.BooleanField(default=False, verbose_name="Опубликован")
|
||
|
||
def clean(self):
|
||
errors = {}
|
||
try:
|
||
if self.pk is None:
|
||
_phone_validate(self.phone)
|
||
else:
|
||
_phone_validate(self.phone, self)
|
||
except ValidationError as e:
|
||
errors["phone"] = [e]
|
||
|
||
try:
|
||
if self.pk is None:
|
||
_email_validate(self.email)
|
||
else:
|
||
_email_validate(self.email, self)
|
||
except ValidationError as e:
|
||
errors["email"] = [e]
|
||
|
||
if len(errors) > 0:
|
||
raise ValidationError(errors)
|
||
|
||
def save(self, *args, **kwargs):
|
||
if self.pk is None:
|
||
if self.owner is None:
|
||
if self.phone is None or self.email is None:
|
||
raise Exception("Could not save: need contact information")
|
||
|
||
if self.owner is not None:
|
||
self.phone = None
|
||
self.email = None
|
||
|
||
self.full_clean()
|
||
|
||
super().save(*args, **kwargs)
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
@staticmethod
|
||
def get_all_for_user(user):
|
||
if user.is_staff:
|
||
return Order.objects.filter().order_by('create_time')
|
||
else:
|
||
return Order.objects.filter(published=True, moderated=True).order_by('create_time')
|
||
|
||
@staticmethod
|
||
def get_for_user_by_id(user, order_id):
|
||
q = Order.get_all_for_user(user).filter(id=order_id)
|
||
if len(q) == 0:
|
||
return None
|
||
else:
|
||
return q[0]
|
||
|