From bb8871141f3fa5d2e5fdd0120f7e1476aa36ebfc Mon Sep 17 00:00:00 2001 From: gzbender Date: Tue, 11 Jun 2019 18:55:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BD=D0=B5=D1=81=D0=BE=D0=BB=D1=8C=D0=BA?= =?UTF-8?q?=D0=BE=20=D0=B4=D0=B5=D1=82=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/user/forms.py | 20 +-- apps/user/migrations/0032_child.py | 26 ++++ apps/user/migrations/0033_add_childs.py | 21 ++++ apps/user/models.py | 31 ++++- apps/user/templates/user/bonus-history.html | 2 +- .../user/templates/user/profile-settings.html | 99 ++++----------- apps/user/templates/user/profile.html | 2 +- apps/user/views.py | 74 +++++++++-- project/tests/test_features.py | 3 +- web/src/components/Childs.vue | 119 ++++++++++++++++++ web/src/js/pages/profile.js | 4 + web/src/sass/_common.sass | 4 + 12 files changed, 296 insertions(+), 109 deletions(-) create mode 100644 apps/user/migrations/0032_child.py create mode 100644 apps/user/migrations/0033_add_childs.py create mode 100644 web/src/components/Childs.vue diff --git a/apps/user/forms.py b/apps/user/forms.py index 9a9e68d5..b0f6d51d 100644 --- a/apps/user/forms.py +++ b/apps/user/forms.py @@ -2,7 +2,8 @@ from django import forms from django.contrib.auth import get_user_model from phonenumber_field.formfields import PhoneNumberField -from .fields import CreditCardField +from apps.user.fields import CreditCardField +from apps.user.models import Child User = get_user_model() @@ -31,11 +32,6 @@ class UserEditForm(forms.ModelForm): site = forms.URLField(required=False) photo = forms.ImageField(required=False) - child_gender = forms.CharField(required=False) - child_birthday = forms.DateField(input_formats=['%d/%m/%Y'], required=False) - child_first_name = forms.CharField(required=False) - child_last_name = forms.CharField(required=False) - class Meta: model = User fields = ( @@ -61,10 +57,6 @@ class UserEditForm(forms.ModelForm): 'vkontakte', 'site', 'photo', - 'child_gender', - 'child_birthday', - 'child_first_name', - 'child_last_name', ) @@ -79,3 +71,11 @@ class AuthorRequesForm(forms.Form): email = forms.CharField() about = forms.CharField() facebook = forms.URLField(required=False) + + +class ChildForm(forms.ModelForm): + birthday = forms.DateField(input_formats=['%d/%m/%Y'], required=False) + + class Meta: + model = Child + fields = '__all__' diff --git a/apps/user/migrations/0032_child.py b/apps/user/migrations/0032_child.py new file mode 100644 index 00000000..95c2921c --- /dev/null +++ b/apps/user/migrations/0032_child.py @@ -0,0 +1,26 @@ +# Generated by Django 2.0.7 on 2019-06-06 21:05 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0031_user_review_url'), + ] + + operations = [ + migrations.CreateModel( + name='Child', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=30, verbose_name='Имя ребенка')), + ('last_name', models.CharField(blank=True, default='', max_length=150, verbose_name='Фамилия ребенка')), + ('gender', models.CharField(choices=[('n', 'не указан'), ('m', 'Мужчина'), ('f', 'Женщина')], default='n', max_length=1, verbose_name='Пол ребенка')), + ('birthday', models.DateField(blank=True, null=True, verbose_name='День рождения ребенка')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='childs', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/apps/user/migrations/0033_add_childs.py b/apps/user/migrations/0033_add_childs.py new file mode 100644 index 00000000..a3cc360e --- /dev/null +++ b/apps/user/migrations/0033_add_childs.py @@ -0,0 +1,21 @@ +# Generated by Django 2.0.7 on 2019-06-07 20:48 + +from django.db import migrations + + +def add_childs(apps, schema_editor): + User = apps.get_model('user', 'User') + Child = apps.get_model('user', 'Child') + for user in User.objects.exclude(child_first_name=''): + Child.objects.get_or_create(user=user, first_name=user.child_first_name, last_name=user.child_last_name, + gender=user.child_gender, birthday=user.child_birthday) + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0032_child'), + ] + + operations = [ + migrations.RunPython(add_childs), + ] diff --git a/apps/user/models.py b/apps/user/models.py index aca57b23..854c03ea 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -88,12 +88,6 @@ class User(AbstractUser): 'content.Gallery', on_delete=models.CASCADE, verbose_name='Галерея', null=True, blank=True, ) - - child_first_name = models.CharField('Имя ребенка', max_length=30, blank=True) - child_last_name = models.CharField('Фамилия ребенка', max_length=150, blank=True) - child_gender = models.CharField( - 'Пол ребенка', max_length=1, default='n', choices=GENDER_CHOICES) - child_birthday = models.DateField('День рождения ребенка', null=True, blank=True) review_url = models.URLField('Ссылка на видеоотзыв', blank=True, default='') objects = UserManager() @@ -104,6 +98,14 @@ class User(AbstractUser): class Meta(AbstractUser.Meta): ordering = ('-date_joined',) + @cached_property + def has_child(self): + return self.childs.all().count() > 0 + + def child_filled(self): + child = self.childs.all().first() + return child and child.first_name and child.last_name and child.birthday + @property def url(self): return reverse('user', args=[self.slug or self.id]) @@ -338,3 +340,20 @@ class EmailLog(models.Model): email = models.EmailField(_('email address')) created_at = models.DateTimeField(auto_now_add=True) source = models.PositiveSmallIntegerField(choices=SOURCE_CHOICES) + + +class Child(models.Model): + NOT_DEFINED = 'n' + MALE = 'm' + FEMALE = 'f' + GENDER_CHOICES = ( + (NOT_DEFINED, 'не указан'), + (MALE, 'Мужчина'), + (FEMALE, 'Женщина'), + ) + user = models.ForeignKey(User, related_name='childs', on_delete=models.CASCADE) + first_name = models.CharField('Имя ребенка', max_length=30) + last_name = models.CharField('Фамилия ребенка', max_length=150, blank=True, default='') + gender = models.CharField( + 'Пол ребенка', max_length=1, default='n', choices=GENDER_CHOICES) + birthday = models.DateField('День рождения ребенка', null=True, blank=True) diff --git a/apps/user/templates/user/bonus-history.html b/apps/user/templates/user/bonus-history.html index 0170f356..2edff50a 100644 --- a/apps/user/templates/user/bonus-history.html +++ b/apps/user/templates/user/bonus-history.html @@ -83,7 +83,7 @@
+{{ amount_child_birthday }} LIL
ЗАПОЛНИТЬ КАРТОЧКУ РЕБЕНКА
-
{% if request.user.child_first_name and request.user.child_last_name and request.user.child_birthday %} +
{% if request.user.child_filled %} {% endif %}
diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 3d382497..5e3af1c7 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -67,101 +67,41 @@ {% endfor %} -
-
Почта
-
- -
- {% for error in form.email.errors %} -
{{ error }}
- {% endfor %} -
-
-
Ссылка
-
-
{% setting 'MAIN_HOST' %}/user/
- -
- {% for error in form.slug.errors %} -
{{ error }}
- {% endfor %} -
- - -
-
Карточка ребёнка
-
- Вся информация конфиденциальна и не передается третьим лицам. Необходима только для персонализации наград, - поздравлений с Днем Рождения и других персонализированных акций. -
-
-
-
ИМЯ РЕБЕНКА
-
- -
- {% for error in form.child_first_name.errors %} -
{{ error }}
- {% endfor %} -
-
-
ФАМИЛИЯ РЕБЕНКА
-
- -
- {% for error in form.child_last_name.errors %} -
{{ error }}
- {% endfor %} -
-
-
-
ДАТА РОЖДЕНИЯ
+
+
Почта
- +
- {% for error in form.child_birthday.errors %} + {% for error in form.email.errors %}
{{ error }}
{% endfor %}
-
-
ПОЛ
+
+
НОМЕР ТЕЛЕФОНА
-
-
- {% if user.child_gender == 'f' %}Ж{% elif user.child_gender == 'm' %}M{% else %}М / Ж{% endif %} -
-
-
-
М
-
-
-
Ж
-
-
- -
+
- {% for error in form.child_gender.errors %} + {% for error in form.phone.errors %}
{{ error }}
{% endfor %}
-
-
НОМЕР ТЕЛЕФОНА РОДИТЕЛЯ
-
- +
+
Ссылка
+
+
{% setting 'MAIN_HOST' %}/user/
+
- {% for error in form.phone.errors %} + {% for error in form.slug.errors %}
{{ error }}
{% endfor %}
- + + +
@@ -393,5 +333,8 @@ {% endblock foot %} {% block pre_app_js %} + {% endblock pre_app_js %} diff --git a/apps/user/templates/user/profile.html b/apps/user/templates/user/profile.html index 074bf1d3..a1885b8a 100644 --- a/apps/user/templates/user/profile.html +++ b/apps/user/templates/user/profile.html @@ -1,6 +1,6 @@ {% extends "templates/lilcity/index.html" %} {% load static %} {% load thumbnail %} {% block content %} -{% if not user.child_first_name or not user.child_birthday %} +{% if not user.has_child %}
diff --git a/apps/user/views.py b/apps/user/views.py index 3399cf95..f43a13f5 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -26,9 +26,9 @@ from apps.notification.utils import send_email from apps.school.models import SchoolSchedule from apps.payment.models import AuthorBalance, CoursePayment, SchoolPayment, Payment, UserGiftCertificate, UserBonus, \ DrawingCampPayment -from apps.user.models import AuthorRequest, EmailSubscription, SubscriptionCategory +from apps.user.models import AuthorRequest, EmailSubscription, SubscriptionCategory, Child -from .forms import AuthorRequesForm, UserEditForm, WithdrawalForm +from .forms import AuthorRequesForm, UserEditForm, WithdrawalForm, ChildForm User = get_user_model() @@ -217,6 +217,26 @@ class ProfileEditView(UpdateView): context['is_teacher'] = self.object.role == User.TEACHER_ROLE return context + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + if self.object.childs.all().count(): + context['childs'] = [{ + 'id': c.id, + 'first_name': c.first_name, + 'last_name': c.last_name, + 'gender': c.gender or 'n', + 'birthday': c.birthday.strftime('%Y-%m-%d') if c.birthday else '', + } for c in self.object.childs.all()] + else: + context['childs'] = [{ + 'id': '', + 'first_name': '', + 'last_name': '', + 'gender': 'n', + 'birthday': '', + }] + return self.render_to_response(context) + def post(self, request, *args, **kwargs): # it's magic *-*-*-*-* if 'photo' in request.FILES: @@ -256,15 +276,47 @@ class ProfileEditView(UpdateView): login(request, request.user) else: messages.error(request, 'Неверный пароль.') - messages.info(request, 'Данные сохранены.') - response = super().post(request, *args, **kwargs) - user = User.objects.get(pk=request.user.id) - # начисляемм бонусы, если заполнил профиль - if user.phone and user.first_name and user.last_name and not user.bonuses.filter( - is_service=True, action_name=UserBonus.ACTION_FILL_PROFILE).count(): - UserBonus.objects.create(user=user, amount=UserBonus.AMOUNT_FILL_PROFILE, is_service=True, - action_name=UserBonus.ACTION_FILL_PROFILE) - return response + + child_ids = request.POST.getlist('child_id') + child_first_names = request.POST.getlist('child_first_name') + child_last_names = request.POST.getlist('child_last_name') + child_genders = request.POST.getlist('child_gender') + child_birthdays = request.POST.getlist('child_birthday') + ziped = zip(child_ids, child_first_names, child_last_names, child_genders, child_birthdays) + childs = [dict(zip(['id', 'first_name', 'last_name', 'gender', 'birthday'], z)) for z in ziped] + childs_saved = [] + child_errors = False + for child in childs: + child_instance = None + if child.get('id'): + child_instance = Child.objects.get(pk=child.get('id')) + child['user'] = request.user.id + child['gender'] = child['gender'] or 'n' + child_form = ChildForm(data=child, instance=child_instance) + if child_form.is_valid(): + childs_saved.append(child_form.save().id) + elif not(len(childs) == 1 and not child.get('id') and not child.get('first_name')): + child_errors = True + child['errors'] = {f: e[0] for f, e in child_form.errors.items()} + if not child_errors: + request.user.childs.exclude(id__in=childs_saved).delete() + + form = self.get_form() + if form.is_valid() and not child_errors: + messages.info(request, 'Данные сохранены.') + response = self.form_valid(form) + # начисляем бонусы, если заполнил профиль + if self.object.phone and self.object.first_name and self.object.last_name and not self.object.bonuses.filter( + is_service=True, action_name=UserBonus.ACTION_FILL_PROFILE).count(): + UserBonus.objects.create(user=self.object, amount=UserBonus.AMOUNT_FILL_PROFILE, is_service=True, + action_name=UserBonus.ACTION_FILL_PROFILE) + return response + + else: + context = self.get_context_data(**kwargs) + context['childs'] = childs + return self.render_to_response(context) + def get_success_url(self): return reverse('user-edit-profile') diff --git a/project/tests/test_features.py b/project/tests/test_features.py index dba636a6..88f52095 100644 --- a/project/tests/test_features.py +++ b/project/tests/test_features.py @@ -59,8 +59,7 @@ class AutoAddingUserBonusTestCase(TestCase): user = UserFactory.create(role=User.USER_ROLE, first_name='', last_name='', phone='') self.assertEqual(user.bonus, 0, 'При создании есть бонусы') self.client.force_login(user) - data = {k: user.__dict__[k] for k in ['email', 'slug', 'child_first_name', - 'child_last_name', 'child_birthday', 'child_gender', 'city', + data = {k: user.__dict__[k] for k in ['email', 'slug', 'city', 'country', 'birthday', 'gender', 'about', 'instagram', 'facebook', 'twitter', 'pinterest', 'youtube', 'vkontakte', 'site']} diff --git a/web/src/components/Childs.vue b/web/src/components/Childs.vue new file mode 100644 index 00000000..af4bfb1d --- /dev/null +++ b/web/src/components/Childs.vue @@ -0,0 +1,119 @@ + + + diff --git a/web/src/js/pages/profile.js b/web/src/js/pages/profile.js index 3156c84b..81e9a0b7 100644 --- a/web/src/js/pages/profile.js +++ b/web/src/js/pages/profile.js @@ -2,6 +2,10 @@ import $ from 'jquery'; import slugify from 'slugify'; import ClipboardJS from 'clipboard'; import {showNotification} from '../modules/notification'; +import Childs from '../../components/Childs.vue'; + + +window.LIL_STORE.components['childs'] = Childs; $(document).ready(function () { if(window.LIL_STORE.urlIs('userBonuses')){ diff --git a/web/src/sass/_common.sass b/web/src/sass/_common.sass index 9b5e744b..1761c6c6 100755 --- a/web/src/sass/_common.sass +++ b/web/src/sass/_common.sass @@ -4711,6 +4711,10 @@ a color: #333333 font-size: 12px + &__tabs + justify-content: left + overflow-x: auto + overflow-y: hidden .bonuses-table margin-left: -120px