from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Field, Div, HTML, Hidden, Fieldset, Submit from django import forms from django.conf import settings from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.forms import ALL_FIELDS, formset_factory from django.urls import reverse_lazy from cart.models import ( Buying, BUYING_STATUS_IN_CART, Offer, SupplyType, SupplyTarget, Discount, Order ) from cart.tasks import send_user_order_notification, send_admin_order_notification from contact_us.mixins import RequestNotifiable from core.forms import QueryFormBase from core.models import City from core.utils import parse_path from django.utils.translation import ugettext_lazy as _ from products.models import Product class CartAddInlineForm(forms.ModelForm): form_action = {'viewname': 'cart:add', 'kwargs': {}} def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'post' self.helper.form_action = reverse_lazy(**self.form_action) self.helper.layout = Layout( Field('offer'), Field('amount'), Div( Submit('add', value=_('Купить')), css_class='catalog__btn' ) ) super().__init__(*args, **kwargs) def clean_amount(self): amount = self.cleaned_data['amount'] offer = self.cleaned_data['offer'] if amount > offer.amount: raise ValidationError('Колличество товара указано больше доступного') elif amount <= 0: raise ValidationError('Укажите колличество товара больше 0') return amount def save(self, cart, user, commit=True): offer = Offer.active.get(self.offer) self.instance.user = user self.instance.offer = offer self.instance.amount = self.cart[offer.product.id]['quantity'] self.instance.total_price = offer.product * self.cart[offer.product.id]['quantity'] return super().save(commit) class Meta: model = Buying fields = ('offer', 'amount',) widgets = { 'offer': forms.HiddenInput(), 'amount': forms.HiddenInput() } class CartRemoveBuyingForm(forms.ModelForm): form_action = {'viewname': 'cart:remove', 'kwargs': {}} def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'post' self.helper.form_action = reverse_lazy(**self.form_action) self.helper.layout = Layout( Field('offer'), Div( Submit('cancel', value=_('Убрать')), css_class='catalog__btn' ) ) super().__init__(*args, **kwargs) class Meta: model = Buying fields = ('offer',) widgets = { 'offer': forms.HiddenInput() } class CartCheckoutBuyingForm(forms.Form): order = forms.Field() offer = forms.Field() amount = forms.IntegerField() bonus_points = forms.IntegerField() def get_initial_for_field(self, field, field_name): if field_name == 'offer': field = Offer.active.get(product_id=self.initia[field_name]) elif field_name == 'order': field = Order.objects.get(order_code=self.initial[field_name]) elif field_name == 'amount' or field_name == 'bonus_points': field.value = self.initial[field_name] return super().get_initial_for_field(field, field_name) def save(self, user): buying = Buying() buying.user = user buying.offer = self.offer buying.order = self.order buying.bonus_points = self.bonus_points buying.amount = self.amount buying.total_price = self.offer.get_price_with_discount * self.amount buying.save() return buying class CartCheckoutForm(RequestNotifiable, forms.ModelForm): form_action = {'viewname': 'cart:confirm', 'kwargs': {}} field_template = 'bootstrap/forms/cart_checkout.html' def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'post' self.helper.form_action = reverse_lazy(**self.form_action) self.helper.layout = Layout( Field('customer_name', css_class="order__input", template=self.field_template), Field('customer_email', css_class="order__input", template=self.field_template), Field('customer_user', css_class="order__input", template=self.field_template), Field('phone', css_class="order__input", template=self.field_template), Field('customer_address', css_class="order__input", template=self.field_template), Field('city', css_class="order__input", template=self.field_template), Field('comment', css_class="order__input", template=self.field_template), Div( Submit('checkout', value=_('Подтвердить'), style="margin: 0 auto;"), css_class='catalog__btn' ) ) super().__init__(*args, **kwargs) def save(self, commit=True): if not City.objects.filter(name=self.cleaned_data['city']).exists(): city = City() city.name = self.cleaned_data['city'] city.save() self.instance.city = city return super().save(commit) def send_order_invoice(self, request): return send_user_order_notification.delay(self.instance.id, request) def send_order_request(self, request): context = { 'from_email': settings.DEFAULT_FROM_EMAIL, 'recipients': (settings.DEFAULT_FROM_EMAIL,), 'email': { 'subject': _('У вас новый заказ'), 'order': self.instance, }, 'send_at_date': self.instance.create_at, } return send_admin_order_notification.delay(context) class Meta: model = Order fields = ( 'customer_name', 'customer_email', 'phone', 'customer_address', 'city', 'comment' ) widgets = { 'city': forms.TextInput() } class ProductOfferPriceFilterForm(QueryFormBase): min_price = 0 max_price = 9999 price = forms.IntegerField(min_value=0, max_value=0) field_template = 'bootstrap/forms/product_filter.html' title = _('Цена') def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'get' self.helper.layout = Layout( Div(HTML(self.title), css_class='category__title left-menu__price-item'), Field('price', template=self.field_template) ) super().__init__(*args, **kwargs) self.helper.form_action = reverse_lazy(**self.form_action) self.init_price_bounders() self.init_field_params() def init_price_bounders(self): if Offer.active.exists(): off_qs = Offer.active category_instance = '' if self.form_action.get('kwargs', None): category_instance = parse_path(self.form_action.get('kwargs').get('path', '')) off_qs = Offer.active.filter(product__parent__name=category_instance, product__name__icontains=self.query_params.get('name', '')) if off_qs.exists(): self.min_price = round(off_qs.order_by('price').only('price').first().price, 0) self.max_price = round(off_qs.order_by('-price').only('price').first().price, 0) def init_field_params(self): for field in self.fields: if field == 'price': self.fields[field].validators = [ MaxValueValidator(self.max_price), MinValueValidator(self.min_price) ] def get_initial_for_field(self, field, field_name): return super().get_initial_for_field(field, field_name) class ProductOfferSupplyTypeFilterForm(QueryFormBase): supply_type = forms.ChoiceField() field_template = 'bootstrap/forms/product_filter.html' title = _('Тип поставки') def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'get' self.helper.layout = Layout( Div(HTML(self.title), css_class='category__title'), Field('supply_type', template=self.field_template) ) super().__init__(*args, **kwargs) self.helper.form_action = reverse_lazy(**self.form_action) def get_initial_for_field(self, field, field_name): if field_name == 'supply_type': sup_typ_qs = SupplyType.objects category_instance = '' if self.form_action.get('kwargs', None): category_instance = parse_path(self.form_action.get('kwargs').get('path', '')) off_qs = Offer.active.filter(product__parent__name=category_instance, product__name__icontains=self.query_params.get('name', '')) if off_qs.count(): sup_typ_qs = sup_typ_qs.filter(offer__pk__in=off_qs.all()) return sup_typ_qs.distinct('name').only('name', 'slug') return super().get_initial_for_field(field, field_name) class ProductOfferSupplyTargetFilterForm(QueryFormBase): supply_target = forms.ChoiceField() field_template = 'bootstrap/forms/product_filter.html' title = _('Назначение') def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'get' self.helper.layout = Layout( Div(HTML(self.title), css_class='category__title'), Field('supply_target', template=self.field_template) ) super().__init__(*args, **kwargs) self.helper.form_action = reverse_lazy(**self.form_action) def get_initial_for_field(self, field, field_name): if field_name == 'supply_target': sup_tar_qs = SupplyTarget.objects category_instance = '' if self.form_action.get('kwargs', None): category_instance = parse_path(self.form_action.get('kwargs').get('path', '')) off_qs = Offer.active.filter(product__parent__name=category_instance, product__name__icontains=self.query_params.get('name', '')) if off_qs.count(): sup_tar_qs = sup_tar_qs.filter(product__pk__in=off_qs.all()) return sup_tar_qs.distinct('name').only('name', 'slug') return super().get_initial_for_field(field, field_name) # @TODO: NOT IMPLEMENTED ON THE FRONT END. TEST BEFORE PRODUCTION class DiscountForm(forms.ModelForm): class Meta: model = Discount fields = ('code',) class OrderCreateForm(forms.ModelForm): customer_name = forms.CharField(max_length=100, required=True, label='Customer_name', widget=forms.TextInput(attrs={'placeholder': 'Ф.И.О.'})) customer_phone = forms.CharField(required=True, label='Customer_phone', widget=forms.TextInput(attrs={'placeholder': 'номер телефона'})) customer_email = forms.EmailField(required=True, label='Customer_email', widget=forms.TextInput(attrs={'placeholder': 'e-mail'})) city = forms.CharField(max_length=100, label='City', widget=forms.TextInput(attrs={'placeholder': 'город'})) class Meta: model = Order exclude = ('status',)