This repository has been archived on 2024-01-13. You can view files and clone it, but cannot push or open issues or pull requests.
arka-mvp/order/models.py

279 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from hashlib import sha256
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
import os
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]
def _upload_image_filename(instance, filename):
name, ext = os.path.splitext(filename)
fn = sha256((str(datetime.now()) + name).encode('utf-8')).hexdigest() + ext
return "order-images/" + fn
class OrderImage(models.Model):
MAX_IMAGES = 10
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="order", verbose_name="Заказ")
image = models.ImageField(upload_to=_upload_image_filename, verbose_name="Картинка",
width_field=None, height_field=None)
def __str__(self):
return f"{self.id}: {self.order}"
class OrderRespond(models.Model):
create_time = models.DateTimeField(default=datetime.now, editable=False, verbose_name="Время отклика")
user = models.ForeignKey(SiteUser, on_delete=models.CASCADE, related_name="respond_user", verbose_name="Пользователь")
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="respond_order", verbose_name="Заказ")
class Meta:
constraints = [
models.UniqueConstraint(
fields=['user', 'order'], name='unique_order_respond_user_order'
)
]
def __str__(self):
return f"{self.order}: {self.user}"
def save(self, *args, **kwargs):
if Order.objects.get(id=self.order.id) == self.user.id:
raise Exception("User can't respond to self order")
self.full_clean()
super().save(*args, **kwargs)