parent
0547ed23ba
commit
4f26a4b7c3
20 changed files with 1142 additions and 351 deletions
@ -1,3 +1,143 @@ |
||||
import csv |
||||
import datetime |
||||
import pytils |
||||
import weasyprint |
||||
from decimal import Decimal |
||||
|
||||
from django.conf import settings |
||||
from django.contrib import admin |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
from django.http import HttpResponse |
||||
from django.template.loader import render_to_string |
||||
|
||||
from jet.admin import CompactInline |
||||
from jet.filters import DateRangeFilter |
||||
from rangefilter.filter import DateTimeRangeFilter |
||||
|
||||
from core.admin import SafeModelAdmin |
||||
from core.models import Certificate |
||||
from eshop_project.settings.base import PAY_REQUISITES |
||||
from .models import ( |
||||
Offer, SupplyType, |
||||
Currency, Buying, |
||||
SupplyTarget, |
||||
Order, Discount, |
||||
Client) |
||||
|
||||
|
||||
class ProductOfferInlineAdmin(CompactInline): |
||||
model = Offer |
||||
exclude = ('status',) |
||||
extra = 1 |
||||
show_change_link = 1 |
||||
max_num = 1 |
||||
|
||||
# Supply admins |
||||
|
||||
@admin.register(SupplyType) |
||||
class SupplyTypeAdmin(admin.ModelAdmin): |
||||
list_display = ('name', 'min_term', 'max_term') |
||||
search_fields = ('name', 'min_term', 'max_term') |
||||
|
||||
|
||||
@admin.register(SupplyTarget) |
||||
class SupplyTargetAdmin(admin.ModelAdmin): |
||||
list_display = ('name', 'slug') |
||||
search_fields = ('name', 'slug',) |
||||
|
||||
|
||||
@admin.register(Discount) |
||||
class DiscountAdmin(admin.ModelAdmin): |
||||
list_display = ['code', 'valid_from', 'valid_to', 'value', 'active'] |
||||
list_filter = ['valid_from', 'valid_to', 'active'] |
||||
search_field = ['code'] |
||||
|
||||
|
||||
# Offer admins |
||||
@admin.register(Offer) |
||||
class ProductOfferAdmin(SafeModelAdmin): |
||||
list_display = ('product', 'price', 'amount', 'currency') |
||||
search_fields = ('product__name',) |
||||
list_filter = ('currency',) |
||||
|
||||
|
||||
@admin.register(Buying) |
||||
class BuyingAdmin(SafeModelAdmin): |
||||
def export_buyings_to_csv(self, buying, queryset): |
||||
opts = buying._meta |
||||
response = HttpResponse(content_type='text/csv') |
||||
response['Content-Disposition'] = 'attachment; filename=Orders-{}.csv'.format( |
||||
datetime.datetime.now().strftime("%d/%m/%Y")) |
||||
writer = csv.writer(response) |
||||
|
||||
fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many] |
||||
|
||||
writer.writerow([field.verbose_name for field in fields]) |
||||
|
||||
for obj in queryset: |
||||
data_row = [] |
||||
for field in fields: |
||||
value = getattr(obj, field.name) |
||||
if isinstance(value, datetime.datetime): |
||||
value = value.strftime('%d/%m/%Y') |
||||
|
||||
data_row.append(value) |
||||
writer.writerow(data_row) |
||||
return response |
||||
export_buyings_to_csv.short_description = _('экспортировать CSV') |
||||
|
||||
def print_order_in_pdf(self,buyings): |
||||
verb_price = pytils.numeral.in_words(round(buyings.total_price)) |
||||
verb_cur = pytils.numeral.choose_plural(round(buyings.total_price), ("рубль", "рубля", "рублей")) |
||||
html = render_to_string('bootstrap/pdf/buyings.html', { |
||||
**PAY_REQUISITES, 'order': buyings, 'verb_cur': verb_cur, 'verb_price': verb_price |
||||
}) |
||||
rendered_html = html.encode(encoding="UTF-8") |
||||
response = HttpResponse(content_type='application/pdf') |
||||
response['Content-Disposition'] = 'filename=order_{}.pdf'.format(buyings.id) |
||||
|
||||
|
||||
weasyprint.HTML( |
||||
string=rendered_html, |
||||
base_url=self.request.build_absolute_uri() |
||||
).write_pdf( |
||||
response, |
||||
stylesheets = [ |
||||
weasyprint.CSS(settings.STATIC_ROOT + '/css/bootstrap.min.css') |
||||
] |
||||
) |
||||
return response |
||||
print_order_in_pdf.short_description = _('Распечатать заказ в pdf') |
||||
|
||||
def mark_buyings_as_paid(self, request, queryset): |
||||
for buying in queryset: |
||||
user_profile = buying.user.profile |
||||
if user_profile.parent: |
||||
parent_profile = user_profile.parent.profile |
||||
parent_profile.user_points += round(buying.total_price * Decimal(0.01)) |
||||
parent_profile.save() |
||||
buying.status = BUYING_STATUS_PAID |
||||
buying.save() |
||||
mark_buyings_as_paid.short_description = _('Отметить как оплаченные') |
||||
|
||||
|
||||
inlines = () |
||||
list_display = ('user', 'offer', 'status', 'amount', 'total_price') |
||||
search_fields = ('user', 'offer',) |
||||
list_filter = ( |
||||
('create_at', DateRangeFilter), ('updated_at', DateTimeRangeFilter) |
||||
) |
||||
|
||||
actions = (export_buyings_to_csv, print_order_in_pdf, mark_buyings_as_paid) |
||||
|
||||
|
||||
@admin.register(Order) |
||||
class OrderAdmin(SafeModelAdmin): |
||||
list_display = ('order_code', 'customer_user', 'customer_name', 'customer_email','phone') |
||||
|
||||
|
||||
# Register your models here. |
||||
@admin.register(Client) |
||||
class ClientAdmin(SafeModelAdmin): |
||||
list_display = ('name','image','status',) |
||||
search_fields = ('name',) |
||||
list_filter = ('status',) |
||||
|
||||
@ -1,87 +0,0 @@ |
||||
from decimal import Decimal |
||||
from django.conf import settings |
||||
from django.contrib import auth |
||||
from products.models import Product |
||||
# from discount.models import Discount |
||||
|
||||
class Cart(object): |
||||
def __init__(self, request): |
||||
self.session = request.session |
||||
# self.discount_id = self.session.get('discount_id') |
||||
if request.user.is_authenticated(): |
||||
# self.points = self.session.get('points') |
||||
self.points_quant = auth.get_user(request).profile.user_points |
||||
cart = self.session.get(settings.CART_SESSION_ID) |
||||
if not cart: |
||||
request.session['points'] = False |
||||
cart = self.session[settings.CART_SESSION_ID] = {} |
||||
self.cart = cart |
||||
|
||||
def add(self, offer, price_per_itom, quantity=1, update_quantity=False): |
||||
offer_slug = offer.slug |
||||
if offer_slug not in self.cart: |
||||
self.cart[offer_slug] = {'quantity': 0, |
||||
'price': str(price_per_itom)} |
||||
if update_quantity: |
||||
self.cart[offer_slug]['quantity'] = int(quantity) |
||||
else: |
||||
self.cart[offer_slug]['quantity'] += int(quantity) |
||||
self.save() |
||||
|
||||
def save(self): |
||||
self.session[settings.CART_SESSION_ID] = self.cart |
||||
self.session.modified = True |
||||
|
||||
def remove(self, offer_slug): |
||||
# product_id = str(products.id) |
||||
if offer_slug in self.cart: |
||||
del self.cart[offer_slug] |
||||
self.save() |
||||
|
||||
def __iter__(self): |
||||
offers_ids = self.cart.keys() |
||||
offers = Offer.objects.filter(slug__in=offers_ids) |
||||
|
||||
for offer in offers: |
||||
self.cart[str(offer.slug)]['offer'] = offer |
||||
|
||||
for item in self.cart.values(): |
||||
item['price'] = Decimal(item['price']) |
||||
item['total_price'] = item['price'] * item['quantity'] |
||||
yield item |
||||
|
||||
def __len__(self): |
||||
return sum(item['quantity'] for item in self.cart.values()) |
||||
|
||||
def get_total_price(self): |
||||
return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values()) |
||||
|
||||
def get_max(self): |
||||
return min(self.points_quant, self.get_total_price() - 1) |
||||
|
||||
def clear(self): |
||||
del self.session[settings.CART_SESSION_ID] |
||||
self.session.modified = True |
||||
|
||||
# @property |
||||
# def discount(self): |
||||
# if self.discount_id: |
||||
# return Discount.objects.get(id=self.discount_id) |
||||
# return None |
||||
|
||||
# def get_discount(self): |
||||
# if self.discount: |
||||
# return (self.discount.discount / Decimal('100')) * self.get_total_price() |
||||
# return Decimal('0') |
||||
|
||||
# def get_total_price_after_discount(self): |
||||
# return self.get_total_price() - self.get_discount() |
||||
|
||||
def get_total_deduct_points(self): |
||||
total_price = self.get_total_price() |
||||
if total_price <= self.points_quant: |
||||
# self.points_quant = self.points_quant - total_price + 1 |
||||
# self.save() |
||||
return 1 |
||||
return total_price - self.points_quant |
||||
|
||||
@ -1,6 +1,6 @@ |
||||
from .cart import Cart |
||||
from cart.utils import Cart |
||||
|
||||
|
||||
def cart(request): |
||||
def cart_basket(request): |
||||
return {'cart': Cart(request) } |
||||
|
||||
|
||||
@ -0,0 +1 @@ |
||||
[{"model": "cart.supplytarget", "pk": 1, "fields": {"create_at": "2018-08-12T20:48:30.165Z", "updated_at": "2018-08-12T20:48:30.165Z", "name": "\u0414\u043e\u043c\u0430\u0448\u043d\u044f\u044f", "slug": "domashnyaya", "status": 25}}, {"model": "cart.supplytarget", "pk": 2, "fields": {"create_at": "2018-08-12T20:48:38.954Z", "updated_at": "2018-08-12T20:49:01.074Z", "name": "\u0413\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f", "slug": "gosudarstvennaya", "status": 75}}, {"model": "cart.supplytarget", "pk": 3, "fields": {"create_at": "2018-08-12T20:48:49.758Z", "updated_at": "2018-08-12T20:48:49.758Z", "name": "\u041a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f", "slug": "korporativnaya", "status": 50}}, {"model": "cart.supplytarget", "pk": 4, "fields": {"create_at": "2018-08-12T20:49:11.950Z", "updated_at": "2018-08-12T20:49:11.950Z", "name": "\u0410\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u0435\u0441\u043a\u0430\u044f", "slug": "akademicheskaya", "status": 100}}] |
||||
@ -0,0 +1 @@ |
||||
[] |
||||
@ -1,21 +1,257 @@ |
||||
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 |
||||
|
||||
class CartAddProductForm(forms.Form): |
||||
quantity = forms.CharField(widget=forms.TextInput(attrs={ |
||||
'id': 'quantity', |
||||
'name': 'quantity', |
||||
'type': 'number', |
||||
'min': '1', |
||||
'max': '1000', |
||||
'value': '1', |
||||
'onchange': 'calculate()'})) |
||||
product_slug = forms.CharField(widget=forms.TextInput(attrs={ |
||||
'id': 'product_slug', |
||||
'name': 'product_slug', |
||||
'type': 'hidden'})) |
||||
price_per_itom = forms.IntegerField(widget=forms.TextInput(attrs={ |
||||
'id': 'price_per_itom', |
||||
'name': 'price_per_itom', |
||||
'type': 'hidden'})) |
||||
update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput) |
||||
from cart.models import ( |
||||
Buying, BUYING_STATUS_IN_CART, Offer, SupplyType, SupplyTarget, Discount, Order |
||||
) |
||||
from core.forms import QueryFormBase |
||||
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('Купить',value='submit'), |
||||
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('Убрать'), |
||||
css_class='catalog__btn' |
||||
) |
||||
) |
||||
|
||||
super().__init__(*args, **kwargs) |
||||
|
||||
class Meta: |
||||
model = Buying |
||||
fields = ('offer',) |
||||
widgets = { |
||||
'offer': forms.HiddenInput() |
||||
} |
||||
|
||||
|
||||
CartRemoveBuyingFormset = formset_factory(CartRemoveBuyingForm) |
||||
|
||||
|
||||
class CartCheckoutForm(forms.ModelForm): |
||||
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'), |
||||
Field('customer_email'), |
||||
Field('customer_user'), |
||||
Field('phone'), |
||||
Field('customer_address'), |
||||
Field('city'), |
||||
Field('buyings'), |
||||
Field('comment'), |
||||
Div( |
||||
Submit('Подвердить'), |
||||
css_class='catalog__btn' |
||||
) |
||||
) |
||||
|
||||
super().__init__(*args, **kwargs) |
||||
|
||||
class Model: |
||||
model = Order |
||||
fields = ( |
||||
'customer_name', 'customer_email', 'customer_user', |
||||
'phone', 'customer_address', 'city', 'buyings', |
||||
'comment' |
||||
) |
||||
|
||||
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',) |
||||
|
||||
@ -0,0 +1,13 @@ |
||||
from cart.utils import Cart |
||||
|
||||
|
||||
class CartMonkeyPatchingMiddleware: |
||||
def __init__(self, get_response): |
||||
self.get_response = get_response |
||||
|
||||
def __call__(self, request): |
||||
request.cart = Cart(request) |
||||
|
||||
response = self.get_response(request) |
||||
|
||||
return response |
||||
@ -0,0 +1,45 @@ |
||||
import celery |
||||
from django.conf import settings |
||||
from celery import task |
||||
from django.template.loader import render_to_string |
||||
from django.core.mail import send_mail, EmailMessage |
||||
from io import BytesIO |
||||
import weasyprint |
||||
import pytils |
||||
|
||||
from cart.models import Order |
||||
|
||||
SUPPLIER_INFO = '''ООО "Русские Программы", ИНН 7713409230, КПП 771301001, |
||||
127411, Москва г, Дмитровское ш., дом № 157, корпус 7, тел.: +74957258950''' |
||||
|
||||
requisites = {'name': 'ООО "Русские Программы"', 'bank': 'АО "СМП БАНК" Г. МОСКВА', 'INN': '7713409230', |
||||
'KPP': '771301001', 'BIK': '44525503', 'bank_acc': '30101810545250000503', 'acc': '40702810300750000177', |
||||
'sup_info': SUPPLIER_INFO} |
||||
|
||||
@celery.task |
||||
def send_user_order_notification(order_id): |
||||
""" |
||||
Sending Email of order creating |
||||
""" |
||||
order = Order.objects.get(id=order_id) |
||||
verb_price = pytils.numeral.in_words(round(order.total_price)) |
||||
verb_cur = pytils.numeral.choose_plural(round(order.total_price), ("рубль", "рубля", "рублей")) |
||||
subject = 'Заказ № {}'.format(order.id) |
||||
message = 'Уважаемый, {}, номер Вашего заказа {}. \ |
||||
Пожалуйста, совершите платеж по поручению в приложении к этому письму в течение 14 дней.'.format(order.customer_name, order.id) |
||||
mail_send = EmailMessage(subject, message, 'admin@myshop.ru', [order.customer_email]) |
||||
|
||||
# html = render_to_string('orders:AdminOrderPDF', args=[order_id]) |
||||
|
||||
html = render_to_string('orders/pdf.html', {**requisites, 'order': order, |
||||
'verb_cur': verb_cur, 'verb_price': verb_price}) |
||||
rendered_html = html.encode(encoding="UTF-8") |
||||
out = BytesIO() |
||||
weasyprint.HTML(string=rendered_html).write_pdf(out, |
||||
stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + 'css/bootstrap.min.css')]) |
||||
|
||||
# weasyprint.HTML(string=rendered_html, base_url=request.build_absolute_uri()).write_pdf(response, |
||||
# stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + '/css/bootstrap.min.css')]) |
||||
mail_send.attach('order_{}.pdf'.format(order_id), out.getvalue(), 'application/pdf') |
||||
mail_send.send() |
||||
return mail_send |
||||
@ -0,0 +1,18 @@ |
||||
from django.template import Library |
||||
|
||||
register = Library() |
||||
|
||||
|
||||
@register.filter |
||||
def calculate_price(cart, offer): |
||||
# @TODO: BUG!!! MAKE TYPE CASTING OF CART KEYS |
||||
if offer.product_id in cart: |
||||
return offer.price * cart[offer.product_id]['quantity'] |
||||
return offer.price |
||||
|
||||
|
||||
@register.filter |
||||
def get_cart_offer_amount(cart, offer): |
||||
if offer.product_id in cart: |
||||
return cart[offer.product_id]['quantity'] if offer.product_id in cart else 0 |
||||
return 0 |
||||
@ -0,0 +1,124 @@ |
||||
from django import template |
||||
from django.template import loader, Node, Variable |
||||
from django.utils.encoding import smart_str, smart_bytes |
||||
from django.template.defaulttags import url |
||||
from django.template import VariableDoesNotExist |
||||
from mptt.templatetags.mptt_tags import recursetree |
||||
|
||||
register = template.Library() |
||||
|
||||
@register.tag |
||||
def breadcrumb(parser, token): |
||||
""" |
||||
Renders the breadcrumb. |
||||
Examples: |
||||
{% breadcrumb "Title of breadcrumb" url_var %} |
||||
{% breadcrumb context_var url_var %} |
||||
{% breadcrumb "Just the title" %} |
||||
{% breadcrumb just_context_var %} |
||||
|
||||
Parameters: |
||||
-First parameter is the title of the crumb, |
||||
-Second (optional) parameter is the url variable to link to, produced by url tag, i.e.: |
||||
{% url person_detail object.id as person_url %} |
||||
then: |
||||
{% breadcrumb person.name person_url %} |
||||
|
||||
@author Andriy Drozdyuk |
||||
""" |
||||
return BreadcrumbNode(token.split_contents()[1:]) |
||||
|
||||
|
||||
@register.tag |
||||
def breadcrumb_url(parser, token): |
||||
""" |
||||
Same as breadcrumb |
||||
but instead of url context variable takes in all the |
||||
arguments URL tag takes. |
||||
{% breadcrumb "Title of breadcrumb" person_detail person.id %} |
||||
{% breadcrumb person.name person_detail person.id %} |
||||
""" |
||||
|
||||
bits = token.split_contents() |
||||
if len(bits)==2: |
||||
return breadcrumb(parser, token) |
||||
|
||||
# Extract our extra title parameter |
||||
title = bits.pop(1) |
||||
token.contents = ' '.join(bits) |
||||
|
||||
url_node = url(parser, token) |
||||
|
||||
return UrlBreadcrumbNode(title, url_node) |
||||
|
||||
@register.tag |
||||
def breadcrumb_mptt_url(parser, token): |
||||
return recursetree(parser, token) |
||||
|
||||
class BreadcrumbNode(Node): |
||||
def __init__(self, vars): |
||||
""" |
||||
First var is title, second var is url context variable |
||||
""" |
||||
self.vars = map(Variable,vars) |
||||
|
||||
def render(self, context): |
||||
title = self.vars[0].var |
||||
|
||||
if title.find("'")==-1 and title.find('"')==-1: |
||||
try: |
||||
val = self.vars[0] |
||||
title = val.resolve(context) |
||||
except: |
||||
title = '' |
||||
|
||||
else: |
||||
title=title.strip("'").strip('"') |
||||
title=smart_bytes(title) |
||||
|
||||
url = None |
||||
|
||||
if len(self.vars)>1: |
||||
val = self.vars[1] |
||||
try: |
||||
url = val.resolve(context) |
||||
except VariableDoesNotExist: |
||||
print('URL does not exist', val) |
||||
url = None |
||||
|
||||
return create_crumb(title, url) |
||||
|
||||
|
||||
class UrlBreadcrumbNode(Node): |
||||
def __init__(self, title, url_node): |
||||
self.title = Variable(title) |
||||
self.url_node = url_node |
||||
|
||||
def render(self, context): |
||||
title = self.title.var |
||||
|
||||
if title.find("'")==-1 and title.find('"')==-1: |
||||
try: |
||||
val = self.title |
||||
title = val.resolve(context) |
||||
except: |
||||
title = '' |
||||
else: |
||||
title=title.strip("'").strip('"') |
||||
title=smart_bytes(title) |
||||
|
||||
url = self.url_node.render(context) |
||||
return create_crumb(title, url) |
||||
|
||||
|
||||
def create_crumb(title, url=None): |
||||
""" |
||||
Helper function |
||||
""" |
||||
crumb = """<li><a href='%s'>%s</a></span>""" |
||||
if url: |
||||
crumb = crumb.format(url, title) |
||||
else: |
||||
crumb = crumb.format('#', title) |
||||
|
||||
return crumb |
||||
@ -0,0 +1,65 @@ |
||||
from decimal import Decimal |
||||
from django.conf import settings |
||||
from django.contrib import auth |
||||
|
||||
from cart.models import Offer |
||||
from products.models import Product |
||||
|
||||
|
||||
# from discount.models import Discount |
||||
|
||||
class Cart(object): |
||||
def __init__(self, request): |
||||
self.store = request.session |
||||
cart = self.store.get(settings.CART_SESSION_ID) |
||||
if not cart: |
||||
cart = self.store[settings.CART_SESSION_ID] = {} |
||||
self.cart = cart |
||||
|
||||
def add(self, offer_id, quantity=1): |
||||
offer_id = str(offer_id) |
||||
if offer_id in self.cart: |
||||
self.cart[offer_id]['quantity'] += int(quantity) |
||||
else: |
||||
self.cart[offer_id] = {'quantity': quantity} |
||||
self.save() |
||||
|
||||
def save(self): |
||||
self.store[settings.CART_SESSION_ID] = self.cart |
||||
self.store.modified = True |
||||
|
||||
def remove(self, offer_id): |
||||
if offer_id in self.cart: |
||||
del self.cart[offer_id] |
||||
self.save() |
||||
|
||||
def clear(self): |
||||
del self.store[settings.CART_SESSION_ID] |
||||
self.store.modified = True |
||||
|
||||
def keys(self): |
||||
return self.cart.keys() |
||||
|
||||
def __iter__(self): |
||||
return iter(self.cart.keys()) |
||||
|
||||
def __setitem__(self, key, value): |
||||
try: |
||||
self.cart[str(key)] = value |
||||
except KeyError: |
||||
return setattr(self, key, value) |
||||
|
||||
def __getitem__(self, key): |
||||
try: |
||||
return self.cart[str(key)] |
||||
except KeyError: |
||||
return getattr(self, key) |
||||
|
||||
def __contains__(self, item): |
||||
return str(item) in self.cart |
||||
|
||||
def __next__(self): |
||||
return self.cart.__next__() |
||||
|
||||
def __len__(self): |
||||
return self.cart.__len__() |
||||
@ -1,4 +0,0 @@ |
||||
{% extends 'base.html' %} |
||||
{% block content %} |
||||
Missing buying history |
||||
{% endblock %} |
||||
@ -0,0 +1 @@ |
||||
{% extends 'base.html' %} |
||||
@ -0,0 +1 @@ |
||||
{% extends 'base.html' %} |
||||
Loading…
Reference in new issue