Compare commits

..

1 Commits

Author SHA1 Message Date
Max Yakovenko aace6dd8df break project)) 7 years ago
  1. 0
      .env.sample
  2. 11
      .gitignore
  3. 54
      README.md
  4. 0
      accounts_ext/__init__.py
  5. 7
      accounts_ext/admin.py
  6. 0
      accounts_ext/apps.py
  7. 1
      accounts_ext/fixtures/accounts.json
  8. 15
      accounts_ext/forms.py
  9. 5
      accounts_ext/models.py
  10. 0
      accounts_ext/templatetags/__init__.py
  11. 3
      accounts_ext/templatetags/accounts_ext_filters.py
  12. 0
      accounts_ext/tests.py
  13. 5
      accounts_ext/urls.py
  14. 0
      accounts_ext/utils.py
  15. 19
      accounts_ext/views.py
  16. 0
      blog_ext/__init__.py
  17. 6
      blog_ext/admin.py
  18. 0
      blog_ext/apps.py
  19. 1
      blog_ext/forms.py
  20. 7
      blog_ext/models.py
  21. 0
      blog_ext/tests.py
  22. 2
      blog_ext/urls.py
  23. 1
      blog_ext/views.py
  24. 0
      cabinet/__init__.py
  25. 0
      cabinet/admin.py
  26. 0
      cabinet/apps.py
  27. 0
      cabinet/models.py
  28. 0
      cabinet/tests.py
  29. 0
      cabinet/urls.py
  30. 45
      cabinet/views.py
  31. 0
      cart/__init__.py
  32. 26
      cart/admin.py
  33. 0
      cart/apps.py
  34. 3
      cart/context_processors.py
  35. 0
      cart/fixtures/supply_targets.json
  36. 0
      cart/fixtures/supply_types.json
  37. 11
      cart/forms.py
  38. 0
      cart/middleware.py
  39. 11
      cart/models.py
  40. 0
      cart/signals.py
  41. 15
      cart/tasks.py
  42. 0
      cart/templatetags/__init__.py
  43. 0
      cart/templatetags/cart_filters.py
  44. 27
      cart/templatetags/cart_tags.py
  45. 0
      cart/tests.py
  46. 1
      cart/urls.py
  47. 0
      cart/utils.py
  48. 0
      cart/views.py
  49. 8197
      client/asserts/css/bootstrap.css
  50. 93
      client/asserts/css/jquery.rating.css
  51. 16
      client/index.js
  52. 29
      client/package.json
  53. 48
      client/webpack.config.js
  54. 0
      contact_us/__init__.py
  55. 5
      contact_us/admin.py
  56. 0
      contact_us/apps.py
  57. 4
      contact_us/context_processors.py
  58. 26
      contact_us/forms.py
  59. 4
      contact_us/mixins.py
  60. 6
      contact_us/models.py
  61. 0
      contact_us/templatetags/__init__.py
  62. 0
      contact_us/templatetags/custom_admin_modify.py
  63. 1
      contact_us/tests.py
  64. 0
      contact_us/urls.py
  65. 11
      contact_us/views.py
  66. 0
      core/__init__.py
  67. 3
      core/admin.py
  68. 0
      core/apps.py
  69. 1
      core/context_processors.py
  70. 0
      core/fixtures/cities.json
  71. 0
      core/fixtures/currencies.json
  72. 0
      core/fixtures/sites.json
  73. 0
      core/forms.py
  74. 0
      core/management/__init__.py
  75. 0
      core/management/commands/__init__.py
  76. 4
      core/management/commands/clean_deleted.py
  77. 1
      core/management/commands/clearcache.py
  78. 0
      core/middlewares.py
  79. 5
      core/models.py
  80. 0
      core/templatetags/__init__.py
  81. 1
      core/templatetags/core_filters.py
  82. 0
      core/templatetags/core_tags.py
  83. 0
      core/tests.py
  84. 0
      core/utils.py
  85. 4
      core/views.py
  86. 11
      deployment/eshop.conf
  87. 20
      eshop/accounts_ext/fixtures/accounts.json
  88. 110
      eshop/accounts_ext/migrations/0001_initial.py
  89. 93
      eshop/blog_ext/migrations/0001_initial.py
  90. 195
      eshop/cart/migrations/0001_initial.py
  91. 25
      eshop/cart/migrations/0002_auto_20181027_1653.py
  92. 33
      eshop/contact_us/migrations/0001_initial.py
  93. 60
      eshop/core/migrations/0001_initial.py
  94. 5
      eshop/core/tests.py
  95. 18
      eshop/eshop_project/settings/development.py.template
  96. 47
      eshop/eshop_project/urls.py
  97. 44
      eshop/flatpages_ext/migrations/0001_initial.py
  98. 0
      eshop/flatpages_ext/migrations/__init__.py
  99. 0
      eshop/index/__init__.py
  100. 0
      eshop/index/migrations/__init__.py
  101. Some files were not shown because too many files have changed in this diff Show More

11
.gitignore vendored

@ -33,7 +33,6 @@ __pycache__/
# Distribution / packaging
.Python
env/
venv/
build/
develop-eggs/
dist/
@ -78,17 +77,17 @@ docs/_build/
target/
### Project ###
### Django ###
*.log
*.pot
*.pyc
__pycache__/
**/node_modules/**
assets/
node_modules/
package-lock.json
development.py
static/
client/node_modules/*
client/dist/*
*/migrations/*
.env
db.sqlite3

@ -8,58 +8,27 @@
---
### Server configuration
1. Install necessary packages:
```bash
sudo apt-get install -y libpq-dev postgresql nginx virtualenv
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs
```
2. Create database:
```bash
CREATE DATABASE eshop_db;
CREATE USER eshop_admin WITH password '12345678';
GRANT ALL ON DATABASE eshop_db TO eshop_admin;
# Allow user to create db for running django tests
ALTER USER eshop_admin CREATEDB;
```
3. Install virtualenv inside the project directory and activate it:
```bash
virtualenv --python3=$(which python3) venv
source venv/bin/activate
```
4. Use systemd file with name gunicorn-eshop.service to initialize gunicorn server with DJANGO_SETTINGS_MODULE environment var
5. Use systemd file with name celery-eshop.service to initialize celery following with these [instructions](http://docs.celeryproject.org/en/latest/userguide/daemonizing.html#usage-systemd "Celery | Daemonization")
6. Install dependencies from inside the activated virtualenv:
```bash
pip install -r requirements.txt
```
7. Install all packages from package.json in the client/ directory and run webpack
```bash
npm i
npm run dev
```
8. Create empty logs dir in project directory
1. Use systemd file with name gunicorn-eshop.service to initialize gunicorn server with DJANGO_SETTINGS_MODULE environment var
2. Use systemd file with name celery-eshop.service to initialize celery following with these [instructions](http://docs.celeryproject.org/en/latest/userguide/daemonizing.html#usage-systemd "Celery | Daemonization")
2. Install virtualenv inside the project directory in run server
3. Install dependencies from inside the activated virtualenv
4. Create empty logs dir in project directory
5. Install nodejs with npm(nvm preferably)
6. install all packages
###Development
1. Activate eshop environment using virtualenv
1. Activate eshop environment using virtualenvwrapper(workon)
2. Make .env file with the structure described in .env.sample file
3. Make migrations for modules: auth, accounts_ext, etc.
4. Start celery queue for tasks with the command:
`celery -A eshop_project worker -l info --pool=eventlet`
5. Make alias for gulp with alias command and path gulp executable file
6. Run `gulp default`
###Deployment
1. Activate eshop environment using virtualenv
1. Activate eshop environment using virtualenvwrapper(workon)
2. Make pull request from bitbucket repo by ssh using passphrase
3. Make .env file with the structure described in .env.sample file
4. Make migrations for modules
@ -67,5 +36,4 @@ npm run dev
6. Restart gunicorn-eshop and celery-eshop daemons in systemd
7. Load fixture core fixture sites to configure site domain (before the FIRST http request)
8. Add corresponding entry to django_site table

@ -1,7 +1,7 @@
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin, GroupAdmin
from django.contrib.auth.models import Group as GroupBase
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin, GroupAdmin
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from import_export import resources
@ -9,7 +9,8 @@ from jet.filters import DateRangeFilter
from rangefilter.filter import DateTimeRangeFilter
from core.admin import SafeModelAdmin
from referral.admin import ReferralAdminInline
# from referral.admin import ReferralAdminInline
from .forms import UserChangeForm, UserCreationForm
from .models import Profile, Company, Group
@ -26,7 +27,7 @@ class CustomUserResource(resources.ModelResource):
@admin.register(get_user_model())
class UserAdmin(SafeModelAdmin, BaseUserAdmin):
inlines = (
ReferralAdminInline,
# ReferralAdminInline,
)
fieldsets = (

@ -0,0 +1 @@
[{"model": "accounts_ext.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$100000$AAP4DpqYKrFB$mQRKz7qi/1va3Zoh2O3g9j7wYKCBaMLz5LFrbszDNLA=", "last_login": "2018-08-12T20:46:54Z", "create_at": "2018-08-12T20:46:44.961Z", "updated_at": "2018-08-12T20:47:05.733Z", "status": 25, "is_superuser": true, "username": "dimkasp", "email": "dimkasp@mail.ru", "referral_user": null, "confirmed_at": null, "groups": [], "user_permissions": []}}]

@ -1,9 +1,13 @@
import logging
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Div, Submit, HTML
from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model, password_validation
from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django_email_blacklist import DisposableEmailChecker
from registration.forms import RegistrationFormUniqueEmail
from django.contrib.auth.forms import (
AuthenticationForm as AuthenticationFormBase,
PasswordResetForm as PasswordResetFormBase,
@ -12,10 +16,6 @@ from django.contrib.auth.forms import (
UserCreationForm as UserCreationFormBase
)
from django.contrib.auth.forms import UsernameField
from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django_email_blacklist import DisposableEmailChecker
from registration.forms import RegistrationFormUniqueEmail
from snowpenguin.django.recaptcha2.fields import ReCaptchaField
from snowpenguin.django.recaptcha2.widgets import ReCaptchaWidget
@ -56,11 +56,6 @@ class RegistrationForm(RegistrationFormUniqueEmail):
raise forms.ValidationError(_('Введите email с валидными доменом'))
return email
def clean(self):
if not self.cleaned_data['captcha']:
raise forms.ValidationError(_("Проверьте правильности капчи"))
return self.cleaned_data
def save(self, commit=True):
user = super().save(commit)
profile = Profile.objects.filter(user=user).first()

@ -6,8 +6,9 @@ from django.core.validators import RegexValidator
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.timezone import now as datetime_now
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now as datetime_now
from registration.signals import user_activated
from core.models import (
@ -17,6 +18,8 @@ from core.models import (
)
# Create your models here.
class UserManager(ActualOnlyManager, BaseUserManager):
def create_superuser(self, email, password):
user = self.model(

@ -2,7 +2,6 @@ from django.template import Library
register = Library()
@register.simple_tag(name='get')
def get_by_key(dict, key):
return getattr(dict, key)
return getattr(dict,key)

@ -1,7 +1,7 @@
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^login/$', views.LoginView.as_view(), name='login'),
re_path(r'^logout/$', views.LogoutView.as_view(), name='logout'),
@ -9,7 +9,6 @@ urlpatterns = [
re_path(r'^register/done/$', views.RegistrationDoneView.as_view(), name='register_done'),
re_path(r'^password/reset/$', views.ResetPasswordView.as_view(), name='reset_password'),
re_path(r'^password/reset/done/$', views.ResetPasswordDoneView.as_view(), name='reset_password_done'),
re_path(r'^password/reset/change/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
views.ResetPasswordConfirmView.as_view(), name='reset_password_change'),
re_path(r'^password/reset/change/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', views.ResetPasswordConfirmView.as_view(), name='reset_password_change'),
re_path(r'^password/reset/complete/$', views.ResetPasswordCompleteView.as_view(), name='reset_password_complete')
]

@ -1,6 +1,6 @@
import logging
from django.conf import settings
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.views import (
LoginView as LoginViewBase,
LogoutView,
@ -9,26 +9,29 @@ from django.contrib.auth.views import (
PasswordResetConfirmView as PasswordResetConfirmViewBase,
PasswordResetCompleteView as PasswordResetCompleteViewBase,
)
from django.shortcuts import redirect, resolve_url
from django.urls import reverse_lazy
from django.utils.http import is_safe_url, urlencode
from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView
from registration.backends.default.views import (
RegistrationView as RegistrationViewBase,
ResendActivationView as ResendActivationViewBase
)
from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import redirect, resolve_url
from django.urls import reverse_lazy
from django.utils.http import is_safe_url, urlencode
from django.utils.translation import ugettext_lazy as _
from core.views import ProtectedTemplateView
from .forms import (
PasswordResetRequestForm, SetPasswordForm, RegistrationCompanyForm,
AuthenticationForm,
RegistrationForm
)
RegistrationForm)
logger = logging.getLogger(__name__)
# Create your views here.
class LoginView(LoginViewBase):
redirect_field_name = 'next'
form_class = AuthenticationForm
@ -149,7 +152,7 @@ class RegistrationDoneView(TemplateView):
class ResendActivationView(ResendActivationViewBase):
template_name = 'registration/resend_activation.html'
template_name = 'registration/resend_activation.tml'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

@ -1,11 +1,14 @@
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from pinax.blog.admin import (
PostAdmin as BasePostAdmin,
SectionAdmin as BaseSectionAdmin,
PostImageSet as BasePostImageSet
)
from pinax.blog.models import (
Post as PinaxPost,
Section as PinaxSection,
@ -57,6 +60,7 @@ class PostImageSet(ImageSet):
verbose_name_plural = _('Изображения')
admin.site.unregister(BasePostImageSet)
admin.site.register(

@ -1,5 +1,6 @@
from django.forms import forms
from django.utils.translation import ugettext_lazy as _
from pinax.blog.forms import AdminPostForm as BaseAdminPostForm
from blog_ext.models import Post

@ -1,8 +1,11 @@
import uuid
import pytz
from django.conf import settings
from django.db import models
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
# Create your models here.
from pinax.blog.models import (
Post as BasePost,
@ -11,7 +14,9 @@ from pinax.blog.models import (
Section as BaseSection
)
from pinax.images.models import (
ImageSet as BaseImageSet)
ImageSet as BaseImageSet,
Image as BaseImage,
image_upload_to)
from core.models import AbstractStatusModel, AbstractDateTimeModel

@ -1,7 +1,7 @@
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r"^$", views.BlogIndexView.as_view(), name="blog"),

@ -5,7 +5,6 @@ from pinax.blog.views import (
SecretKeyPostDetailView as BaseSecretKeyPostDetailView,
SlugUniquePostDetailView as BaseSlugUniquePostDetailView)
class SlugUniquePostDetailView(BaseSlugUniquePostDetailView):
pass

@ -1,8 +1,9 @@
from django.conf import settings
from django.core.paginator import Paginator
from django.utils.translation import ugettext_lazy as _
# Create your views here.
from cart.models import BUYING_STATUS_PAID
# from cart.models import BUYING_STATUS_PAID
from core.views import ProtectedTemplateView
@ -10,40 +11,40 @@ class IndexTemplateView(ProtectedTemplateView):
template_name = 'cabinet/index.html'
title = _('Личный кабинет')
def get_ref_link(self, user):
return "{path}?ref={ref_link}".format(**{
'path': user.referral.url,
'ref_link': user.referral.code
})
def get_bought_item_list(self, user):
bought_item_queryset = user.buying_set.filter(status=BUYING_STATUS_PAID).order_by('-create_at').all()
paginator = Paginator(
object_list=bought_item_queryset,
per_page=5
)
the_page = 1
return paginator.page(the_page)
def get_full_name(self, user):
# def get_ref_link(self,user):
# return "{path}?ref={ref_link}".format(**{
# 'path': user.referral.url,
# 'ref_link': user.referral.code
# })
# def get_bought_item_list(self,user):
# bought_item_queryset = user.buying_set.filter(status=BUYING_STATUS_PAID).order_by('-create_at').all()
# paginator = Paginator(
# object_list=bought_item_queryset,
# per_page=5
# )
# the_page = 1
# return paginator.page(the_page)
def get_full_name(self,user):
return '{last_name} {first_name} {patronymic}'.format(**{
'last_name': user.profile.last_name or "",
'first_name': user.profile.first_name or "",
'patronymic': user.profile.patronymic or ""
})
def get_user_points(self, user):
return user.referral.referralstats.points
# def get_user_points(self,user):
# return user.referral.referralstats.points
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = self.title
context['ref_link'] = self.get_ref_link(self.request.user)
context['bought_item_list'] = self.get_bought_item_list(self.request.user)
# context['ref_link'] = self.get_ref_link(self.request.user)
# context['bought_item_list'] = self.get_bought_item_list(self.request.user)
context['full_name'] = self.get_full_name(self.request.user)
context['email'] = self.request.user.email
context['phone_number'] = self.request.user.profile.phone
context['company'] = self.request.user.company or None
context['profile'] = self.request.user.profile or None
context['referral_points'] = self.get_user_points(user=self.request.user)
# context['referral_points'] = self.get_user_points(user=self.request.user)
return context

@ -1,23 +1,25 @@
import csv
import datetime
from decimal import Decimal
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 django.utils.translation import ugettext_lazy as _
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,
Buying,
Currency, Buying,
SupplyTarget,
Order, Discount,
Client)
@ -30,7 +32,6 @@ class ProductOfferInlineAdmin(CompactInline):
show_change_link = 1
max_num = 1
# Supply admins
@admin.register(SupplyType)
@ -48,7 +49,7 @@ class SupplyTargetAdmin(admin.ModelAdmin):
@admin.register(Discount)
class DiscountAdmin(admin.ModelAdmin):
list_display = ['code', 'valid_from', 'valid_to', 'value', 'active']
list_filter = ['valid_from', 'valid_to', 'active']
list_filter = ['valid_from', 'valid_to', 'active']
search_field = ['code']
@ -83,10 +84,9 @@ class BuyingAdmin(SafeModelAdmin):
data_row.append(value)
writer.writerow(data_row)
return response
export_buyings_to_csv.short_description = _('экспортировать CSV')
def print_order_in_pdf(self, buyings):
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', {
@ -96,17 +96,17 @@ class BuyingAdmin(SafeModelAdmin):
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=[
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):
@ -118,9 +118,9 @@ class BuyingAdmin(SafeModelAdmin):
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',)
@ -133,11 +133,11 @@ class BuyingAdmin(SafeModelAdmin):
@admin.register(Order)
class OrderAdmin(SafeModelAdmin):
list_display = ('order_code', 'customer_user', 'customer_name', 'customer_email', 'phone')
list_display = ('order_code', 'customer_user', 'customer_name', 'customer_email','phone')
@admin.register(Client)
class ClientAdmin(SafeModelAdmin):
list_display = ('name', 'image', 'status',)
list_display = ('name','image','status',)
search_fields = ('name',)
list_filter = ('status',)

@ -2,4 +2,5 @@ from cart.utils import Cart
def cart_basket(request):
return {'cart': Cart(request)}
return {'cart': Cart(request) }

@ -1,22 +1,25 @@
import uuid
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Div, HTML, Submit
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 django.utils.translation import ugettext_lazy as _
from cart.models import (
Buying, Offer, SupplyType, SupplyTarget, Discount, Order
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):
@ -119,7 +122,7 @@ class CartCheckoutForm(RequestNotifiable, forms.ModelForm):
form_action = {'viewname': 'cart:confirm', 'kwargs': {}}
field_template = 'bootstrap/forms/cart_checkout.html'
city = forms.CharField(label=_('Город'), max_length=255)
city = forms.CharField(label=_('Город'),max_length=255)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()

@ -1,19 +1,24 @@
import uuid
from decimal import Decimal
from decimal import Decimal
from autoslug import AutoSlugField
from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models import Avg
from django.utils.timezone import now, timedelta
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now, timedelta
# Create your models here.
from core.models import (
AbstractStatusModel, AbstractDateTimeModel,
ActiveOnlyManager,
City, Currency)
from products.models import Product

@ -1,15 +1,14 @@
from io import BytesIO
import celery
import pytils
import weasyprint
import pytils
from io import BytesIO
from django.conf import settings
from django.core.mail import EmailMessage, EmailMultiAlternatives
from django.template.loader import render_to_string, get_template
from django.core.mail import EmailMessage, EmailMultiAlternatives
from cart.models import Order
@celery.task()
def send_user_order_notification(context):
"""
@ -27,7 +26,7 @@ def send_user_order_notification(context):
# html = render_to_string('orders:AdminOrderPDF', args=[order_id])
html = render_to_string('cart/order_invoice.html', {**settings.PAY_REQUISITES, 'order': order,
'verb_cur': verb_cur, 'verb_price': verb_price})
'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,
@ -35,8 +34,8 @@ def send_user_order_notification(context):
weasyprint.CSS(settings.STATIC_ROOT + 'css/build.css')])
order_invoice_name = 'Order_' + order.order_code
weasyprint.HTML(string=rendered_html, base_url=context['site_url']).write_pdf(order_invoice_name,
stylesheets=[weasyprint.CSS(
settings.STATIC_ROOT + '/css/build.css')])
stylesheets=[weasyprint.CSS(
settings.STATIC_ROOT + '/css/build.css')])
mail_send.attach('order_{}.pdf'.format(order.id), out.getvalue(), 'application/pdf')
mail_send.send()
return mail_send

@ -1,13 +1,12 @@
from django import template
from django.template import Node, Variable
from django.template import VariableDoesNotExist
from django.template import loader, Node, Variable
from django.utils.encoding import smart_str, smart_bytes
from django.template.defaulttags import url
from django.utils.encoding import smart_bytes
from django.template import VariableDoesNotExist
from mptt.templatetags.mptt_tags import recursetree
register = template.Library()
@register.tag
def breadcrumb(parser, token):
"""
@ -41,7 +40,7 @@ def breadcrumb_url(parser, token):
"""
bits = token.split_contents()
if len(bits) == 2:
if len(bits)==2:
return breadcrumb(parser, token)
# Extract our extra title parameter
@ -52,23 +51,21 @@ def breadcrumb_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)
self.vars = map(Variable,vars)
def render(self, context):
title = self.vars[0].var
if title.find("'") == -1 and title.find('"') == -1:
if title.find("'")==-1 and title.find('"')==-1:
try:
val = self.vars[0]
title = val.resolve(context)
@ -76,12 +73,12 @@ class BreadcrumbNode(Node):
title = ''
else:
title = title.strip("'").strip('"')
title = smart_bytes(title)
title=title.strip("'").strip('"')
title=smart_bytes(title)
url = None
if len(self.vars) > 1:
if len(self.vars)>1:
val = self.vars[1]
try:
url = val.resolve(context)
@ -100,15 +97,15 @@ class UrlBreadcrumbNode(Node):
def render(self, context):
title = self.title.var
if title.find("'") == -1 and title.find('"') == -1:
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)
title=title.strip("'").strip('"')
title=smart_bytes(title)
url = self.url_node.render(context)
return create_crumb(title, url)

@ -1,3 +1,4 @@
from django.conf.urls import url
from django.urls import re_path
from . import views

File diff suppressed because it is too large Load Diff

@ -1,93 +0,0 @@
.br-theme-css-stars .br-widget {
height: 28px;
white-space: nowrap
}
.br-theme-css-stars .br-widget a {
text-decoration: none;
height: 18px;
width: 18px;
float: left;
font-size: 23px;
margin-right: 5px
}
.br-theme-css-stars .br-widget a:after {
content: "\2605";
color: #d2d2d2
}
.br-theme-css-stars .br-widget a.br-active:after {
color: #edb867
}
.br-theme-css-stars .br-widget a.br-selected:after {
color: #edb867
}
.br-theme-css-stars .br-widget .br-current-rating {
display: none
}
.br-theme-css-stars .br-readonly a {
cursor: default
}
@media print {
.br-theme-css-stars .br-widget a:after {
content: "\2606";
color: #000
}
.br-theme-css-stars .br-widget a.br-active:after, .br-theme-css-stars .br-widget a.br-selected:after {
content: "\2605";
color: #000
}
}
.br-theme-fontawesome-stars .br-widget {
height: 28px;
white-space: nowrap
}
.br-theme-fontawesome-stars .br-widget a {
font: normal normal normal 20px/1 FontAwesome;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
text-decoration: none;
margin-right: 2px
}
.br-theme-fontawesome-stars .br-widget a:after {
content: '\f005';
color: #d2d2d2
}
.br-theme-fontawesome-stars .br-widget a.br-active:after {
color: #edb867
}
.br-theme-fontawesome-stars .br-widget a.br-selected:after {
color: #edb867
}
.br-theme-fontawesome-stars .br-widget .br-current-rating {
display: none
}
.br-theme-fontawesome-stars .br-readonly a {
cursor: default
}
@media print {
.br-theme-fontawesome-stars .br-widget a:after {
content: '\f006';
color: #000
}
.br-theme-fontawesome-stars .br-widget a.br-active:after, .br-theme-fontawesome-stars .br-widget a.br-selected:after {
content: '\f005';
color: #000
}
}

@ -1,16 +0,0 @@
import "./asserts/css/main.css";
import './node_modules/jquery-ui-dist/jquery-ui.min.css';
import "./node_modules/bootstrap/dist/css/bootstrap.min.css";
import './node_modules/jquery/dist/jquery.js';
import './node_modules/jquery-ui-dist/jquery-ui.js';
import './node_modules/magnific-popup/dist/jquery.magnific-popup.js';
import './node_modules/jquery-bar-rating/dist/jquery.barrating.min.js';
import './node_modules/bootstrap/dist/js/bootstrap.js';
import './node_modules/jquery-autocomplete/jquery.autocomplete.js';
import "./asserts/js/ajax.js";
import "./asserts/js/basket.tools.js";
import "./asserts/js/common.js";
import "./asserts/js/our_search_code.js";

@ -1,29 +0,0 @@
{
"name": "eshop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode=development --watch",
"build": "webpack --mode=production"
},
"author": "FUNNYDMAN",
"license": "ISC",
"devDependencies": {
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2",
"css-loader": "^1.0.1",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^2.0.0",
"style-loader": "^0.23.1"
},
"dependencies": {
"bootstrap": "3.3.7",
"jquery": "^3.3.1",
"jquery-autocomplete": "^1.2.8",
"jquery-bar-rating": "^1.2.2",
"jquery-ui-dist": "1.12.1",
"magnific-popup": "^1.1.0"
}
}

@ -1,48 +0,0 @@
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: './index.js',
output: {
filename: './js/build-min.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(css)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader']
})
},
{
test: /\.(png|svg|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {outputPath: 'img/'}
}
]
}, {
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
]
},
plugins: [
new ExtractTextPlugin("css/build.css"),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
};

@ -6,7 +6,6 @@ from core import admin as CoreAdmin
from .models import Request
@admin.register(Request)
class ContactUsAdmin(CoreAdmin.SafeModelAdmin):
list_filter = (
@ -14,5 +13,5 @@ class ContactUsAdmin(CoreAdmin.SafeModelAdmin):
('create_at', DateRangeFilter),
('updated_at', DateTimeRangeFilter),
)
search_fields = ('email', 'subject', 'phone')
list_display = ('email', 'subject', 'phone', 'status')
search_fields = ('email','subject','phone')
list_display = ('email','subject','phone', 'status')

@ -15,12 +15,12 @@ def contact_us_form(request):
'left_contact_us_form': ContactUsForm(
next=request.resolver_match.view_name,
kwargs=request.resolver_match.kwargs,
field_css_class_base='left-menu'
field_css_base_class='left-menu'
),
'content_contact_us_form': ContactUsForm(
next=request.resolver_match.view_name,
kwargs=request.resolver_match.kwargs,
field_css_class_base='contact'
field_css_base_class='contact'
),
'contact_us_form_message': message
}

@ -1,5 +1,5 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Submit, Hidden
from crispy_forms.layout import Layout, HTML, Field, Submit, Hidden
from django import forms
from django.conf import settings
@ -11,29 +11,28 @@ from .models import (
Request, STATUS_NEW
)
# -------------------------------- Client-side forms -----------------------------------#
class ContactUsForm(RequestNotifiable, forms.ModelForm):
field_template = 'bootstrap/forms/contact_us.html'
def __init__(self, *args, **kwargs):
self.next = kwargs.pop('next')
# TODO: kwargs don't have the kwargs key. Check it!
self.next_kwargs = kwargs.pop('kwargs', {})
self.field_css = kwargs.pop('field_css_class_base')
self.next_kwargs = kwargs.pop('kwargs')
self.field_css = kwargs.pop('field_css_base_class')
self.helper = FormHelper()
self.helper.form_action = reverse_lazy('contact_us:send')
self.helper.form_method = 'post'
self.helper.layout = Layout(
Hidden('next', reverse_lazy(self.next) if not self.next_kwargs else reverse_lazy(self.next,
kwargs=self.next_kwargs)),
Field('name', css_class=self.field_css + "__text", placeholder=_("Имя"), template=self.field_template),
Field('email', css_class=self.field_css + "__text", placeholder=_("Email"), template=self.field_template),
Field('subject', css_class=self.field_css + "__text", placeholder=_("Название продукта"),
template=self.field_template),
Field('phone', css_class=self.field_css + "__text", placeholder=_("+79781234567"),
template=self.field_template),
Submit('send', _("Отправить"), css_class=self.field_css + "__btn")
Hidden('next', reverse_lazy(self.next) if not self.next_kwargs else reverse_lazy(self.next, kwargs=self.next_kwargs)),
Field('name', css_class=self.field_css+"__text", placeholder=_("Имя"), template=self.field_template),
Field('email', css_class=self.field_css+"__text", placeholder=_("Email"), template=self.field_template),
Field('subject', css_class=self.field_css+"__text", placeholder=_("Название продукта"), template=self.field_template),
Field('phone', css_class=self.field_css+"__text", placeholder=_("+79781234567"), template=self.field_template),
Submit('send', _("Отправить"), css_class=self.field_css+"__btn")
)
super(ContactUsForm, self).__init__(*args, **kwargs)
self.init_fields(self.fields)
@ -67,6 +66,7 @@ class ContactUsForm(RequestNotifiable, forms.ModelForm):
context,
)
class Meta:
model = Request
fields = ('name', 'email', 'subject', 'phone',)

@ -1,11 +1,11 @@
import logging
from django.core.mail import EmailMultiAlternatives
from django.template import Context
from django.template.loader import get_template
logger = logging.Logger(__name__)
class RequestNotifiable(object):
MAIL_CATEGORY = 'Request'
@ -34,7 +34,7 @@ class RequestNotifiable(object):
context['from_email'],
context['recipients']
)
email.attach_alternative(body.render(context['email']), 'text/html')
email.attach_alternative(body.render(context['email']),'text/html')
try:
email.send()
except Exception as e:

@ -1,7 +1,13 @@
import os
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.validators import RegexValidator
from django.db import models
from django.utils.translation import ugettext_lazy as _
# Create your models here.
from core.models import AbstractStatusModel, STATUS_DELETED
# --------------------- REQUEST STATUS LIST --------------------
STATUS_NEW = 0

@ -5,6 +5,7 @@ from core.tests import BehaviourTestCaseMixin
from .models import Request
# Create your tests here.
class SendRequestWithTestCase(BehaviourTestCaseMixin, TestCase):
model = Request

@ -2,15 +2,16 @@ import logging
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponseRedirect, Http404
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponseRedirect, HttpResponseBadRequest, Http404
from django.views.generic import FormView
from django.utils.translation import ugettext_lazy as _
from .forms import ContactUsForm
logger = logging.getLogger(__name__)
# Create your views here.
class ContactUsFormView(SuccessMessageMixin, FormView):
next = None
template_name = None
@ -25,18 +26,18 @@ class ContactUsFormView(SuccessMessageMixin, FormView):
form.send_email(self.request)
except Exception as e:
self.form_invalid(form=form)
messages.add_message(self.request, messages.SUCCESS, self.success_message, extra_tags='contact_us_form_message')
messages.add_message(self.request,messages.SUCCESS,self.success_message,extra_tags='contact_us_form_message')
return HttpResponseRedirect(self.next)
def form_invalid(self, form):
context = self.get_context_data()
if len(form.errors) > 0:
context['form_show_errors'] = True
messages.add_message(self.request, messages.ERROR, self.error_message, extra_tags='contact_us_form_message')
messages.add_message(self.request,messages.ERROR,self.error_message,extra_tags='contact_us_form_message')
return HttpResponseRedirect(self.next)
def dispatch(self, request, *args, **kwargs):
if request.POST.get('next', None) is None:
if request.POST.get('next',None) is None:
raise Http404()
else:
self.next = request.POST.get('next')

@ -117,7 +117,7 @@ class SafeModelAdmin(admin.ModelAdmin):
@admin.register(Certificate)
class CertAdmin(SafeModelAdmin):
list_display = ('name', 'image', 'status')
list_display = ('name','image', 'status')
search_fields = ('name',)
list_filter = ('status',)
@ -135,3 +135,4 @@ class CurrencyAdmin(admin.ModelAdmin):
('create_at', DateRangeFilter), ('updated_at', DateTimeRangeFilter)
)
search_fields = ('name', 'code', 'sign')

@ -31,5 +31,6 @@ def _product_breadcrumbs(request):
return breadcrumb
def _news_breadcrumbs(request):
pass

@ -1,4 +1,4 @@
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
import django.apps
from core.models import AbstractStatusModel
@ -15,4 +15,4 @@ class Command(BaseCommand):
for obj in data:
obj.delete_from_base()
self.stdout.write(self.style.SUCCESS('Successfully deleted %s %s' % (len(data), model)))
self.stdout.write(self.style.SUCCESS('Successfully deleted %s %s' % (len(data), model)))

@ -1,7 +1,6 @@
from django.core.management.base import BaseCommand
from django.core.cache import cache
class Command(BaseCommand):
def handle(self, *args, **kwargs):
cache.clear()

@ -1,4 +1,7 @@
from abc import abstractmethod
from django.conf import settings
from django.contrib.auth.base_user import BaseUserManager
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.db import models
@ -151,7 +154,7 @@ class Certificate(AbstractStatusModel):
})
name = models.CharField(_('Название'), max_length=255)
image = models.FileField(_('Изображение'), upload_to=upload_file_to, blank=True, null=True)
image = models.FileField(_('Изображение'), upload_to=upload_file_to, blank=True,null=True)
preview = models.FileField(_('Миниатюрка'), upload_to=upload_file_to)
class Meta:

@ -2,7 +2,6 @@ from django.template import Library
register = Library()
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)

@ -1,5 +1,6 @@
from django.contrib.auth.mixins import LoginRequiredMixin
# Create your views here.
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView, FormView
from django.views.generic.edit import BaseFormView
@ -24,11 +25,9 @@ class ProtectedDetailView(LoginRequiredMixin, DetailView):
class ProtectedFormView(LoginRequiredMixin, FormView):
pass
class ProtectedBaseFormView(LoginRequiredMixin, BaseFormView):
pass
class Handler404View(TemplateView):
template_name = '404.html'
@ -40,6 +39,5 @@ class Handler500View(TemplateView):
class Handler403View(TemplateView):
template_name = '403.html'
class Handler400View(TemplateView):
template_name = '400.html'

@ -1,11 +0,0 @@
server {
server_name name_or_ip;
listen 80;
location / {
proxy_pass http://localhost:8000;
}
location /static/ {
root path_to_static_files;
}
}

@ -1,20 +0,0 @@
[
{
"model": "accounts_ext.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$100000$AAP4DpqYKrFB$mQRKz7qi/1va3Zoh2O3g9j7wYKCBaMLz5LFrbszDNLA=",
"last_login": "2018-08-12T20:46:54Z",
"create_at": "2018-08-12T20:46:44.961Z",
"updated_at": "2018-08-12T20:47:05.733Z",
"status": 25,
"is_superuser": true,
"username": "dimkasp",
"email": "dimkasp@mail.ru",
"referral_user": null,
"confirmed_at": null,
"groups": [],
"user_permissions": []
}
}
]

@ -1,110 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
from django.conf import settings
import django.contrib.auth.models
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
('core', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(max_length=255, verbose_name='username')),
('email', models.EmailField(error_messages={'unique': 'A user with that email already exists.'}, max_length=254, unique=True, verbose_name='email')),
('confirmed_at', models.DateTimeField(blank=True, null=True, verbose_name='подвтержден в')),
],
options={
'verbose_name': 'пользователь',
'verbose_name_plural': 'пользователи',
},
),
migrations.CreateModel(
name='Company',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('company_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='компания')),
('address', models.TextField(blank=True, null=True, verbose_name='адрес')),
('inn', models.CharField(blank=True, max_length=12, null=True, verbose_name='ИНН')),
('ogrn', models.CharField(blank=True, max_length=13, null=True, verbose_name='ОГРН')),
('type', models.SmallIntegerField(blank=True, choices=[(25, 'Компания'), (50, 'Физ лицо')], default=25, null=True, verbose_name='тип')),
('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.City')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='username')),
],
options={
'verbose_name': 'компания',
'verbose_name_plural': 'компании',
},
),
migrations.CreateModel(
name='Profile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('first_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='last name')),
('patronymic', models.CharField(blank=True, max_length=100, null=True, verbose_name='отчество')),
('birthday', models.DateField(blank=True, null=True, verbose_name='дата рождения')),
('phone', models.CharField(blank=True, max_length=12, null=True, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+99999999999'. Up to 12 digits allowed.", regex='^\\((+7)|8)?\\d{10}$')], verbose_name='телефон')),
('address', models.TextField(verbose_name='aдрес')),
('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.City', verbose_name='город')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='username')),
],
options={
'verbose_name': 'профиль',
'verbose_name_plural': 'профили',
},
),
migrations.CreateModel(
name='Group',
fields=[
],
options={
'verbose_name': 'группа',
'verbose_name_plural': 'группы',
'proxy': True,
'indexes': [],
},
bases=('auth.group',),
managers=[
('objects', django.contrib.auth.models.GroupManager()),
],
),
migrations.AddField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'),
),
migrations.AddField(
model_name='user',
name='referral_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Реферальный пользователь'),
),
migrations.AddField(
model_name='user',
name='user_permissions',
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'),
),
]

@ -1,93 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
import blog_ext.models
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('blog', '0001_initial'),
('pinax_images', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='ImageSet',
fields=[
('imageset_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='pinax_images.ImageSet')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
],
options={
'verbose_name': 'Коллаж',
'verbose_name_plural': 'Коллажи',
},
bases=('pinax_images.imageset', models.Model),
),
migrations.CreateModel(
name='Post',
fields=[
('post_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.Post')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('preview_image', models.FileField(blank=True, null=True, upload_to=blog_ext.models.Post.upload_file_to, verbose_name='Превью изображение')),
],
options={
'verbose_name': 'Пост',
'verbose_name_plural': 'Посты',
},
bases=('blog.post', models.Model),
),
migrations.CreateModel(
name='ReviewComment',
fields=[
('reviewcomment_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.ReviewComment')),
],
options={
'verbose_name': 'Комментарий',
'verbose_name_plural': 'Комментарий',
},
bases=('blog.reviewcomment',),
),
migrations.CreateModel(
name='Revision',
fields=[
('revision_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.Revision')),
],
options={
'verbose_name': 'Ревизия',
'verbose_name_plural': 'Ревизии',
},
bases=('blog.revision',),
),
migrations.CreateModel(
name='Section',
fields=[
('section_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.Section')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
],
options={
'verbose_name': 'Секция',
'verbose_name_plural': 'Секции',
},
bases=('blog.section', models.Model),
),
migrations.CreateModel(
name='PostImageSet',
fields=[
],
options={
'verbose_name': 'Изображение',
'verbose_name_plural': 'Изображения',
'proxy': True,
'indexes': [],
},
bases=('blog_ext.imageset',),
),
]

@ -1,195 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
import autoslug.fields
import cart.models
import datetime
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.manager
from django.utils.timezone import utc
class Migration(migrations.Migration):
initial = True
dependencies = [
('products', '0001_initial'),
('core', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Buying',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('bonus_points', models.IntegerField(validators=[django.core.validators.MinValueValidator(0)], verbose_name='бонусы')),
('status', models.SmallIntegerField(choices=[(25, 'В корзине'), (50, 'Обрабатываеться'), (75, 'Оплаченно')], default=25, verbose_name='статус')),
('amount', models.SmallIntegerField(default=0, verbose_name='колличество')),
('total_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='цена')),
],
options={
'verbose_name': 'Покупка',
'verbose_name_plural': 'Покупки',
},
managers=[
('active', django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name='Cashback',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('cashback', models.DecimalField(decimal_places=2, default=0, max_digits=7, verbose_name='Сумма')),
('status', models.SmallIntegerField(choices=[(0, 'заработанный'), (100, 'потраченный')], default=0, verbose_name='статус')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'cashback',
'verbose_name_plural': 'cashback',
},
),
migrations.CreateModel(
name='Client',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('name', models.CharField(max_length=255, verbose_name='Название')),
('image', models.FileField(upload_to=cart.models.Client.upload_file_to, verbose_name='Изображение')),
('preview', models.FileField(upload_to=cart.models.Client.upload_file_to, verbose_name='Миниатюрка')),
],
options={
'verbose_name': 'Клиент',
'verbose_name_plural': 'Клиенты',
},
),
migrations.CreateModel(
name='Discount',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='Имя')),
('image', models.FileField(blank=True, null=True, upload_to=cart.models.Discount.upload_file_to, verbose_name='Изображение')),
('code', models.CharField(blank=True, default='f09d1c83-a6f8-40b5-a980-c7e69f7f585c', max_length=50, unique=True, verbose_name='Код')),
('valid_from', models.DateTimeField(auto_now_add=True, verbose_name='Начало')),
('valid_to', models.DateTimeField(blank=True, default=datetime.datetime(2018, 11, 1, 15, 27, 27, 195955, tzinfo=utc), verbose_name='Конец')),
('value', models.IntegerField(default=0, help_text='Указываем целым числом. Пример: 30 = 30%', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)], verbose_name='Процент')),
('active', models.BooleanField(default=True, verbose_name='Активная')),
],
options={
'verbose_name': 'Дисконт',
'verbose_name_plural': 'Дисконт',
},
),
migrations.CreateModel(
name='Offer',
fields=[
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('product', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='products.Product', verbose_name='Продукт')),
('vendor_code', models.CharField(help_text='Должен быть уникальным', max_length=255, unique=True, verbose_name='Артикул')),
('price', models.DecimalField(decimal_places=2, help_text='Цена за продукт', max_digits=10, validators=[django.core.validators.MinValueValidator(1.0)], verbose_name='цена')),
('amount', models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)], verbose_name='Колличество')),
('cashback', models.DecimalField(decimal_places=2, default=0, help_text='Указаная сумма будет отображаться в выбранной валюте позиции', max_digits=6, verbose_name='Кешбек')),
('note', models.TextField(blank=True, null=True, verbose_name='Пометка')),
('account_nds', models.BooleanField(default=False, verbose_name='с учетом НДС')),
('currency', models.ForeignKey(help_text='Цена по умолчанию в рублях', on_delete=django.db.models.deletion.PROTECT, to='core.Currency', verbose_name='Валюта')),
('discount', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cart.Discount', verbose_name='Дисконт')),
],
options={
'verbose_name': 'Позиция',
'verbose_name_plural': 'Позиции',
},
),
migrations.CreateModel(
name='Order',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('order_code', models.CharField(max_length=255, verbose_name='код заказа')),
('customer_name', models.CharField(max_length=255, verbose_name='имя')),
('customer_email', models.EmailField(blank=True, default=None, max_length=254, null=True, verbose_name='email')),
('phone', models.CharField(max_length=12, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+99999999999'. Up to 12 digits allowed.", regex='^((\\+7)|8)?\\d{10}$')], verbose_name='телефон')),
('customer_address', models.TextField(verbose_name='адрес')),
('total_price', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='стоимость')),
('comment', models.TextField(blank=True, default=None, null=True, verbose_name='комментарий')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (50, 'Обрабатывается'), (100, 'Оплаченно')], default=0, verbose_name='статус')),
('city', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='core.City', verbose_name='Город')),
('customer_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='пользователь')),
],
options={
'verbose_name': 'Заказ',
'verbose_name_plural': 'Заказы',
'ordering': ('-create_at',),
},
),
migrations.CreateModel(
name='SupplyTarget',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='Назначение')),
('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)),
('status', models.PositiveSmallIntegerField(help_text='Необходимо указать числовой код статус', verbose_name='статус')),
],
options={
'verbose_name': 'Лицензия',
'verbose_name_plural': 'Лицензии',
},
),
migrations.CreateModel(
name='SupplyType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='Тип')),
('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)),
('min_term', models.IntegerField(help_text='Минимальный срок поставки', verbose_name='от')),
('max_term', models.IntegerField(help_text='Максимальный срок поставки', verbose_name='до')),
('term_dimension', models.SmallIntegerField(choices=[(0, 'Час'), (0, 'День'), (0, 'Неделя'), (0, 'Месяц')], default=0, verbose_name='размерность')),
],
options={
'verbose_name': 'Тип поставки',
'verbose_name_plural': 'Тип поставки',
},
),
migrations.AddField(
model_name='offer',
name='supply_target',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cart.SupplyTarget', verbose_name='Лицензия'),
),
migrations.AddField(
model_name='offer',
name='supply_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cart.SupplyType', verbose_name='Поставка'),
),
migrations.AddField(
model_name='buying',
name='offer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cart.Offer', verbose_name='позиция'),
),
migrations.AddField(
model_name='buying',
name='order',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cart.Order', verbose_name='пользователь'),
),
migrations.AddField(
model_name='buying',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='пользователь'),
),
]

@ -1,25 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-27 16:53
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('cart', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='discount',
name='code',
field=models.CharField(blank=True, default='866872fd-bf5a-48bc-8e22-c3581eb7a307', max_length=50, unique=True, verbose_name='Код'),
),
migrations.AlterField(
model_name='discount',
name='valid_to',
field=models.DateTimeField(blank=True, default=datetime.datetime(2018, 11, 3, 16, 53, 38, 906817, tzinfo=utc), verbose_name='Конец'),
),
]

@ -1,33 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Request',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('email', models.EmailField(max_length=254, verbose_name='Email')),
('subject', models.CharField(max_length=500, verbose_name='Subject')),
('message', models.TextField(blank=True, null=True)),
('phone', models.CharField(blank=True, max_length=12, null=True, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+99999999999'. Up to 12 digits allowed.", regex='^((\\+7)|8)?\\d{10}$')])),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (10, 'Обрабатывается'), (20, 'Обработан'), (50, 'Удаленный')], default=0, verbose_name='статус')),
],
options={
'verbose_name': 'Запрос',
'verbose_name_plural': 'Запросы',
},
),
]

@ -1,60 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
import core.models
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Certificate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('status', models.SmallIntegerField(choices=[(0, 'Новый'), (25, 'Активный'), (50, 'Удаленный')], default=0, verbose_name='статус')),
('name', models.CharField(max_length=255, verbose_name='Название')),
('image', models.FileField(blank=True, null=True, upload_to=core.models.Certificate.upload_file_to, verbose_name='Изображение')),
('preview', models.FileField(upload_to=core.models.Certificate.upload_file_to, verbose_name='Миниатюрка')),
],
options={
'verbose_name': 'Сертификат',
'verbose_name_plural': 'Сертификаты',
},
),
migrations.CreateModel(
name='City',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='Город')),
],
options={
'verbose_name': 'Город',
'verbose_name_plural': 'Города',
},
),
migrations.CreateModel(
name='Currency',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_at', models.DateTimeField(auto_now_add=True, verbose_name='создан в')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='обновлен')),
('name', models.CharField(max_length=255, verbose_name='название')),
('code', models.CharField(max_length=64, verbose_name='код валюты')),
('sign', models.CharField(blank=True, max_length=10, null=True, verbose_name='символ валюты')),
('value', models.DecimalField(decimal_places=2, help_text='Указывается в рублях', max_digits=6, verbose_name='Курс')),
],
options={
'verbose_name': 'Валюта',
'verbose_name_plural': 'Валюта',
},
),
]

@ -1,5 +0,0 @@
from django.test import TestCase
class BehaviourTestCaseMixin:
pass

@ -1,18 +0,0 @@
try:
from .base import *
except ImportError:
raise ImportError("Oops,can't find base settings")
# configurations for django debug toolbar
INTERNAL_IPS = ('127.0.0.1',)
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware'
] + MIDDLEWARE
INSTALLED_APPS = INSTALLED_APPS + ['debug_toolbar']
DEBUG_TOOLBAR_CONFIG = {
'RESULTS_CACHE_SIZE': 50
}
DEFAULT_FROM_EMAIL = 'order@russian-programms.ru'
CELERY_ALWAYS_EAGER = True

@ -1,47 +0,0 @@
from django.urls import re_path, path, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from core import views
admin.autodiscover()
urlpatterns = [
re_path(r'^jet/', include('jet.urls', 'jet')),
re_path(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
re_path(r'^admin/', admin.site.urls),
re_path(r'^ckeditor/', include('ckeditor_uploader.urls')),
re_path('pages/', include('django.contrib.flatpages.urls')),
re_path('accounts/', include(('accounts_ext.urls', 'accounts_ext'), namespace='accounts_ext')),
re_path('accounts/', include('registration.backends.default.urls')),
re_path('accounts/',
include(('django.contrib.auth.urls', 'django.contrib.auth'), namespace='accounts')),
re_path(r'', include(('index.urls', 'index'), namespace='index')),
re_path(r'^contact-us/', include(('contact_us.urls', 'contact_us'), namespace='contact_us')),
re_path(r'^products/', include(('products.urls', 'products'), namespace='products')),
re_path(r'^cabinet/', include(('cabinet.urls', 'cabinet'), namespace='cabinet')),
re_path(r'^cart/', include(('cart.urls', 'cart'), namespace='cart')),
re_path(r'^news/', include(('blog_ext.urls', 'blog_ext'), namespace='news')),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
handler404 = views.Handler404View.as_view()
handler500 = views.Handler500View.as_view()
handler403 = views.Handler403View.as_view()
handler400 = views.Handler400View.as_view()

@ -1,44 +0,0 @@
# Generated by Django 2.0.7 on 2018-10-25 15:27
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('flatpages', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CKFlatPage',
fields=[
('flatpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='flatpages.FlatPage')),
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
('is_visible', models.BooleanField(default=True, verbose_name='показывать?')),
('header_class', models.CharField(blank=True, max_length=255, null=True, verbose_name='Header css class')),
('description', models.CharField(blank=True, max_length=255, null=True, verbose_name='Meta описание')),
('keywords', models.CharField(blank=True, max_length=255, null=True, verbose_name='Meta теги')),
],
options={
'verbose_name': 'Простая страница',
'verbose_name_plural': 'Простые страницы',
},
bases=('flatpages.flatpage',),
),
migrations.CreateModel(
name='Subscriber',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('email', models.EmailField(max_length=254, verbose_name='Email')),
('name', models.CharField(max_length=128, verbose_name='Имя')),
],
options={
'verbose_name': 'Подписчик',
'verbose_name_plural': 'Подписчики',
},
),
]

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save