remotes/origin/feature/test_courses
parent
3679d31293
commit
1ae3ac332d
20 changed files with 509 additions and 54 deletions
@ -0,0 +1,25 @@ |
|||||||
|
ADMIN = 1 |
||||||
|
STUDENTS = 2 |
||||||
|
TEACHERS = 3 |
||||||
|
MANAGERS = 4 |
||||||
|
FINANCE_MANAGERS = 5 |
||||||
|
LEAD_MANAGERS = 6 |
||||||
|
CURATORS = 7 |
||||||
|
PARTNERS = 8 |
||||||
|
SUPPORTS = 9 |
||||||
|
FINANCE = 10 |
||||||
|
PROJECT_MANAGERS = 11 |
||||||
|
|
||||||
|
STATUS_CHOICES = ( |
||||||
|
(ADMIN, 'admin'), |
||||||
|
(STUDENTS, 'students'), |
||||||
|
(TEACHERS, 'teachers'), |
||||||
|
(MANAGERS, 'managers'), |
||||||
|
(FINANCE_MANAGERS, 'finance_managers'), |
||||||
|
(LEAD_MANAGERS, 'lead_managers'), |
||||||
|
(CURATORS, 'curators'), |
||||||
|
(PARTNERS, 'partners'), |
||||||
|
(SUPPORTS, 'supports'), |
||||||
|
(FINANCE, 'finance'), |
||||||
|
(PROJECT_MANAGERS, 'project_managers'), |
||||||
|
) |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
import uuid |
||||||
|
|
||||||
|
import factory |
||||||
|
import factory.fuzzy |
||||||
|
|
||||||
|
from functools import partial |
||||||
|
|
||||||
|
from factories.users import UserFactory |
||||||
|
|
||||||
|
from access import groups |
||||||
|
|
||||||
|
IMAGE_URL = 'https://dummyimage.com/240x240/000/fff.png' |
||||||
|
BIG_IMAGE_URL = 'https://dummyimage.com/1200x800/000/fff.png' |
||||||
|
BIG_MOBILE_IMAGE_URL = 'https://dummyimage.com/600x400/000/fff.png' |
||||||
|
|
||||||
|
Faker = partial(factory.Faker, locale='ru_RU') |
||||||
|
|
||||||
|
|
||||||
|
class CourseFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'courses.Course' |
||||||
|
|
||||||
|
token = factory.LazyFunction(uuid.uuid4) |
||||||
|
slug = factory.LazyAttribute(lambda x: factory.Faker('sentence'). |
||||||
|
generate({'nb_words': 3}).replace(' ', '-').replace('.', '')) |
||||||
|
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4})) |
||||||
|
description = factory.LazyAttribute( |
||||||
|
lambda x: '\n'.join(Faker('paragraphs').generate({'nb': 15})) |
||||||
|
) |
||||||
|
direction = factory.fuzzy.FuzzyChoice(range(1, 5)) |
||||||
|
public = True |
||||||
|
image = IMAGE_URL |
||||||
|
big_image = BIG_IMAGE_URL |
||||||
|
big_mobile_image = BIG_MOBILE_IMAGE_URL |
||||||
|
|
||||||
|
@factory.lazy_attribute |
||||||
|
def teacher_tokens(self): |
||||||
|
teacher = UserFactory(groups=(groups.TEACHERS,)) |
||||||
|
return [teacher.out_key] |
||||||
|
|
||||||
|
|
||||||
|
class TopicFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'courses.Topic' |
||||||
|
|
||||||
|
course = factory.SubFactory(CourseFactory) |
||||||
|
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4})) |
||||||
|
description = factory.LazyAttribute( |
||||||
|
lambda x: '\n'.join(Faker('paragraphs').generate({'nb': 15})) |
||||||
|
) |
||||||
|
sort = 0 |
||||||
|
|
||||||
|
|
||||||
|
class LessonFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'courses.Lesson' |
||||||
|
|
||||||
|
token = factory.LazyFunction(uuid.uuid4) |
||||||
|
key = factory.LazyFunction(uuid.uuid4) |
||||||
|
topic = factory.SubFactory(TopicFactory) |
||||||
|
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4})) |
||||||
|
sort = 0 |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
import uuid |
||||||
|
|
||||||
|
import factory |
||||||
|
import factory.fuzzy |
||||||
|
|
||||||
|
from functools import partial |
||||||
|
|
||||||
|
from django.utils import timezone |
||||||
|
from yandex_money.models import Payment |
||||||
|
|
||||||
|
from factories.courses import CourseFactory, TopicFactory, LessonFactory |
||||||
|
from factories.users import UserFactory |
||||||
|
from finance.models import Invoice |
||||||
|
|
||||||
|
Faker = partial(factory.Faker, locale='ru_RU') |
||||||
|
|
||||||
|
|
||||||
|
class BillFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'finance.Bill' |
||||||
|
|
||||||
|
user = factory.SubFactory(UserFactory) |
||||||
|
opener = factory.SubFactory(UserFactory) |
||||||
|
description = Faker('text') |
||||||
|
|
||||||
|
@factory.lazy_attribute |
||||||
|
def course_token(self): |
||||||
|
course = CourseFactory() |
||||||
|
topic = TopicFactory( |
||||||
|
course=course |
||||||
|
) |
||||||
|
LessonFactory( |
||||||
|
topic=topic |
||||||
|
) |
||||||
|
return course.token |
||||||
|
|
||||||
|
|
||||||
|
class InvoiceFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'finance.Invoice' |
||||||
|
|
||||||
|
status = factory.fuzzy.FuzzyChoice( |
||||||
|
(choice[0] for choice in Invoice.BILL_STATUSES) |
||||||
|
) |
||||||
|
price = factory.fuzzy.FuzzyDecimal(1000) |
||||||
|
real_price = factory.fuzzy.FuzzyDecimal(1000) |
||||||
|
method = factory.fuzzy.FuzzyChoice( |
||||||
|
(choice[0] for choice in Invoice.BILL_METHOD) |
||||||
|
) |
||||||
|
key = factory.Faker('pyint') |
||||||
|
yandex_pay = factory.SubFactory('factories.finance.PaymentFactory') |
||||||
|
comment = Faker('word') |
||||||
|
bill = factory.SubFactory(BillFactory) |
||||||
|
|
||||||
|
|
||||||
|
class PaymentFactory(factory.django.DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = 'yandex_money.Payment' |
||||||
|
|
||||||
|
user = factory.SubFactory(UserFactory) |
||||||
|
pub_date = timezone.now() |
||||||
|
order_amount = factory.fuzzy.FuzzyDecimal(1000) |
||||||
|
payment_type = factory.fuzzy.FuzzyChoice( |
||||||
|
(choice[0] for choice in Payment.PAYMENT_TYPE.CHOICES) |
||||||
|
) |
||||||
|
order_number = factory.LazyFunction(uuid.uuid4) |
||||||
|
status = factory.fuzzy.FuzzyChoice( |
||||||
|
(choice[0] for choice in Payment.STATUS.CHOICES) |
||||||
|
) |
||||||
|
invoice_id = factory.Faker('pyint') |
||||||
|
shop_amount = factory.fuzzy.FuzzyDecimal(1000) |
||||||
|
performed_datetime = timezone.now() |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
import logging |
||||||
|
from .settings import * # noqa |
||||||
|
|
||||||
|
DEBUG = True |
||||||
|
EMAIL_DEBUG = True |
||||||
|
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa |
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media_qa') # noqa |
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
||||||
|
PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher', ) |
||||||
|
|
||||||
|
CELERY_TASK_ALWAYS_EAGER = True |
||||||
|
|
||||||
|
# Disable cache during testing |
||||||
|
CACHE_DISABLED = True |
||||||
|
|
||||||
|
LOGGING = {} |
||||||
|
LOCAL_APPS_LOGGERS = {} |
||||||
|
# Disable all logging calls with levels less severe than or equal to CRITICAL |
||||||
|
logging.disable(logging.CRITICAL) |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
import pytest |
||||||
|
|
||||||
|
from factories.courses import CourseFactory, LessonFactory, TopicFactory |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def course(): |
||||||
|
""" |
||||||
|
Create course |
||||||
|
""" |
||||||
|
_course = CourseFactory() |
||||||
|
topic = TopicFactory( |
||||||
|
course=_course |
||||||
|
) |
||||||
|
LessonFactory( |
||||||
|
topic=topic |
||||||
|
) |
||||||
|
return _course |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
import pytest |
||||||
|
|
||||||
|
from factories.finance import BillFactory, InvoiceFactory |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def bill_cash(student, manager): |
||||||
|
""" |
||||||
|
Create bill for the student |
||||||
|
""" |
||||||
|
_bill = BillFactory( |
||||||
|
user=student, |
||||||
|
opener=manager, |
||||||
|
) |
||||||
|
InvoiceFactory( |
||||||
|
status='P', |
||||||
|
method='C', |
||||||
|
yandex_pay=None, |
||||||
|
bill=_bill |
||||||
|
) |
||||||
|
return _bill |
||||||
@ -0,0 +1,134 @@ |
|||||||
|
import json |
||||||
|
|
||||||
|
import mock |
||||||
|
import pytest |
||||||
|
|
||||||
|
from django.urls import reverse |
||||||
|
|
||||||
|
from rest_framework import status |
||||||
|
|
||||||
|
from finance import models |
||||||
|
from progress.models import Progress, ProgressLesson |
||||||
|
|
||||||
|
PRICE = 1000.00 |
||||||
|
METHOD_CASH = 'C' |
||||||
|
STATUS_WAIT = 'W' |
||||||
|
STATUS_PAID = 'F' |
||||||
|
DUMMY_COMMENT = 'test comment' |
||||||
|
DUMMY_DESCRIPTION = 'test description' |
||||||
|
|
||||||
|
mock.patch('lms.global_decorators.transaction_decorator', lambda x: x).start() |
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db |
||||||
|
def test_list_bills(api_client, student_client, student, manager, admin_client, |
||||||
|
manager_client, lead_manager_client, bill_cash): |
||||||
|
""" |
||||||
|
Test for get list of bills |
||||||
|
""" |
||||||
|
assert api_client.get( |
||||||
|
reverse('finance:bills'), |
||||||
|
status=status.HTTP_403_FORBIDDEN |
||||||
|
) |
||||||
|
response = student_client.get( |
||||||
|
reverse('finance:bills'), |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results_student = json.loads(response.content) |
||||||
|
assert len(results_student) is 1 |
||||||
|
assert results_student[0]['opener'] == manager.email |
||||||
|
assert results_student[0]['user'] == student.email |
||||||
|
response_admin = admin_client.get( |
||||||
|
reverse('finance:bills'), |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results_admin = json.loads(response_admin.content) |
||||||
|
assert len(results_admin) is 0 |
||||||
|
response_manager = manager_client.get( |
||||||
|
reverse('finance:bills'), |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results_manager = json.loads(response_manager.content) |
||||||
|
assert results_manager[0]['opener'] == manager.email |
||||||
|
assert results_manager[0]['user'] == student.email |
||||||
|
response_lead_manager = lead_manager_client.get( |
||||||
|
reverse('finance:bills'), |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results_lead_manager = json.loads(response_lead_manager.content) |
||||||
|
assert len(results_lead_manager) is 0 |
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db |
||||||
|
def test_create_bill(api_client, student_client, manager_client, |
||||||
|
manager, student, course): |
||||||
|
""" |
||||||
|
Test create bill |
||||||
|
""" |
||||||
|
data = { |
||||||
|
'bill': { |
||||||
|
'course_token': course.token.hex, |
||||||
|
'opener': manager.email, |
||||||
|
'user': student.email, |
||||||
|
'comment': DUMMY_COMMENT, |
||||||
|
'description': DUMMY_DESCRIPTION |
||||||
|
}, |
||||||
|
'children': [{ |
||||||
|
'status': STATUS_WAIT, |
||||||
|
'method': METHOD_CASH, |
||||||
|
'price': PRICE, |
||||||
|
'real_price': PRICE, |
||||||
|
}] |
||||||
|
} |
||||||
|
response = manager_client.post( |
||||||
|
reverse('finance:bills'), |
||||||
|
data=data, |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results = json.loads(response.content) |
||||||
|
assert models.Bill.objects.get(user=student).id == results['bill']['id'] |
||||||
|
assert models.Invoice.objects.get( |
||||||
|
bill=results['bill']['id']).id == results['children'][0]['id'] |
||||||
|
assert api_client.post( |
||||||
|
reverse('finance:bills'), |
||||||
|
data=data, |
||||||
|
status=status.HTTP_403_FORBIDDEN |
||||||
|
) |
||||||
|
assert student_client.post( |
||||||
|
reverse('finance:bills'), |
||||||
|
data=data, |
||||||
|
status=status.HTTP_403_FORBIDDEN |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db |
||||||
|
def test_confirm_pay_manager(manager_client, bill_cash, student): |
||||||
|
assert Progress.objects.count() is 0 |
||||||
|
assert ProgressLesson.objects.count() is 0 |
||||||
|
data = { |
||||||
|
'bill': { |
||||||
|
'course_token': bill_cash.course_token.hex, |
||||||
|
'opener': bill_cash.opener.email, |
||||||
|
'user': bill_cash.user.email, |
||||||
|
'comment': bill_cash.comment, |
||||||
|
'description': bill_cash.description |
||||||
|
}, |
||||||
|
'children': [{ |
||||||
|
'status': STATUS_PAID, |
||||||
|
'method': METHOD_CASH, |
||||||
|
'price': PRICE, |
||||||
|
'real_price': PRICE, |
||||||
|
}] |
||||||
|
} |
||||||
|
response = manager_client.post( |
||||||
|
reverse('finance:bills'), |
||||||
|
data=data, |
||||||
|
status=status.HTTP_200_OK |
||||||
|
) |
||||||
|
results = json.loads(response.content) |
||||||
|
assert models.Bill.objects.get(user=student).id == results['bill']['id'] |
||||||
|
assert Progress.objects.count() is 1 |
||||||
|
assert ProgressLesson.objects.count() is 1 |
||||||
|
progress = Progress.objects.filter(user=bill_cash.user).first() |
||||||
|
assert Progress.objects.filter(user=bill_cash.user).exists() is True |
||||||
|
assert ProgressLesson.objects.filter(progress=progress).exists() is True |
||||||
Loading…
Reference in new issue