Add login happy paths

This commit is contained in:
Christian Cueni 2020-01-28 08:35:45 +01:00
parent 87ceb5fc0e
commit bc997bbeea
18 changed files with 390 additions and 85 deletions

View File

@ -53,6 +53,7 @@ class UserFactory(factory.django.DjangoModelFactory):
first_name = factory.LazyAttribute(lambda x: fake.first_name()) first_name = factory.LazyAttribute(lambda x: fake.first_name())
last_name = factory.LazyAttribute(lambda x: fake.last_name()) last_name = factory.LazyAttribute(lambda x: fake.last_name())
email = factory.LazyAttribute(lambda x: fake.ascii_safe_email()) email = factory.LazyAttribute(lambda x: fake.ascii_safe_email())
hep_id = factory.Sequence(lambda n: n)
@factory.post_generation @factory.post_generation
def post(self, create, extracted, **kwargs): def post(self, create, extracted, **kwargs):

View File

@ -7,12 +7,16 @@
# #
# Created on 23.01.20 # Created on 23.01.20
# @author: chrigu <christian.cueni@iterativ.ch> # @author: chrigu <christian.cueni@iterativ.ch>
from datetime import datetime
from django.conf import settings from django.conf import settings
import logging import logging
import requests import requests
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MYSKILLBOX_TEACHER_EDITION_ISBN = "000-4-5678-9012-3"
MYSKILLBOX_STUDENT_EDITION_ISBN = "123-4-5678-9012-3"
class HepClientException(Exception): class HepClientException(Exception):
pass pass
@ -44,6 +48,7 @@ class HepClient:
else: else:
response = requests.get(request_url, headers=headers) response = requests.get(request_url, headers=headers)
# Todo handle 401 and most important network errors
if response.status_code != 200: if response.status_code != 200:
raise HepClientException(response.status_code, response.json()) raise HepClientException(response.status_code, response.json())
@ -87,7 +92,7 @@ class HepClient:
response = self._call('/rest/V1/customers/me', additional_headers={'authorization': 'Bearer {}'.format(token)}) response = self._call('/rest/V1/customers/me', additional_headers={'authorization': 'Bearer {}'.format(token)})
return response.json() return response.json()
def customer_orders(self, admin_token, customer_id): def _customer_orders(self, admin_token, customer_id):
url = ("/rest/V1/orders/?searchCriteria[filterGroups][0][filters][0][" url = ("/rest/V1/orders/?searchCriteria[filterGroups][0][filters][0]["
"field]=customer_id&searchCriteria[filterGroups][0][filters][0][value]={}".format(customer_id)) "field]=customer_id&searchCriteria[filterGroups][0][filters][0][value]={}".format(customer_id))
@ -97,3 +102,34 @@ class HepClient:
def coupon_redeem(self, coupon, customer_id): def coupon_redeem(self, coupon, customer_id):
response = self._call('/rest/deutsch/V1/coupon/{}/customer/{}'.format(coupon, customer_id), method='put') response = self._call('/rest/deutsch/V1/coupon/{}/customer/{}'.format(coupon, customer_id), method='put')
return response return response
def myskillbox_product_for_customer(self, admin_token, customer_id):
orders = self._customer_orders(admin_token, customer_id)
# Todo return only relevant product
return self._extract_myskillbox_products(orders)
def _extract_myskillbox_products(self, orders):
# Todo retun all products
product = None
for order_item in orders['items']:
for item in order_item['items']:
if item['sku'] == MYSKILLBOX_TEACHER_EDITION_ISBN:
product = {
'edition': 'teacher',
'raw': item,
'activated': self._get_item_activation(order_item)
}
elif not product and item['sku'] == MYSKILLBOX_STUDENT_EDITION_ISBN:
product = {
'edition': 'student',
'raw': item,
'activated': self._get_item_activation(order_item)
}
return product
def _get_item_activation(self, item):
for history in item['status_histories']:
if history['comment'] == 'payed by couponcode':
return datetime.strptime(history['created_at'], '%Y-%m-%d %H:%M:%S')

View File

@ -371,3 +371,6 @@ TASKBASE_BASEURL = os.environ.get("TASKBASE_BASEURL")
USE_LOCAL_REGISTRATION = False USE_LOCAL_REGISTRATION = False
# HEP
HEP_ADMIN_TOKEN = "asdf"

View File

@ -15,3 +15,5 @@ MIGRATION_MODULES = DisableMigrations()
SENDGRID_API_KEY = "" SENDGRID_API_KEY = ""
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
LOGIN_REDIRECT_URL = '/accounts/login/' LOGIN_REDIRECT_URL = '/accounts/login/'
USE_LOCAL_REGISTRATION = False

View File

@ -9,17 +9,11 @@
# @author: chrigu <christian.cueni@iterativ.ch> # @author: chrigu <christian.cueni@iterativ.ch>
from django.contrib import admin from django.contrib import admin
from registration.models import LicenseType, License from registration.models import License
@admin.register(LicenseType)
class LicenseTypeAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'key', 'for_role', 'active')
list_filter = ('for_role', 'active')
@admin.register(License) @admin.register(License)
class LicenseAdmin(admin.ModelAdmin): class LicenseAdmin(admin.ModelAdmin):
list_display = ('license_type', 'licensee') list_display = ('licensee',)
list_filter = ('license_type', 'licensee') list_filter = ('licensee',)
raw_id_fields = ('licensee',) raw_id_fields = ('licensee',)

View File

@ -11,17 +11,7 @@ import random
import factory import factory
from registration.models import LicenseType, License from registration.models import License
class LicenseTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = LicenseType
name = factory.Sequence(lambda n: 'license-{}'.format(n))
active = True
key = factory.Sequence(lambda n: "license-key-%03d" % n)
description = factory.Sequence(lambda n: "Some description %03d" % n)
class LicenseFactory(factory.django.DjangoModelFactory): class LicenseFactory(factory.django.DjangoModelFactory):

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
#
# ITerativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2020 ITerativ GmbH. All rights reserved.
#
# Created on 27.01.20
# @author: chrigu <christian.cueni@iterativ.ch>
from datetime import timedelta
from django.db import models
from users.models import Role
TEACHER_EDITION_DURATION = 365
STUDENT_EDITION_DURATION = 4*365
class LicenseManager(models.Manager):
def create_license_for_role(self, licensee, activation_date, raw, role):
if role == 'teacher':
user_role = Role.objects.get_default_teacher_role()
expiry_date = activation_date + timedelta(TEACHER_EDITION_DURATION)
else:
user_role = Role.objects.get_default_student_role()
expiry_date = activation_date + timedelta(STUDENT_EDITION_DURATION)
return self._create_license_for_role(licensee, expiry_date, raw, user_role)
def _create_license_for_role(self, licensee, expiry_date, raw, role):
return self.create(licensee=licensee, expire_date=expiry_date, raw=raw, for_role=role)

View File

@ -0,0 +1,41 @@
# Generated by Django 2.0.6 on 2020-01-27 09:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0010_magentotoken'),
('registration', '0002_auto_20191010_0905'),
]
operations = [
migrations.RemoveField(
model_name='licensetype',
name='for_role',
),
migrations.RemoveField(
model_name='license',
name='license_type',
),
migrations.AddField(
model_name='license',
name='expire_date',
field=models.DateField(null=True),
),
migrations.AddField(
model_name='license',
name='for_role',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.Role'),
),
migrations.AddField(
model_name='license',
name='raw',
field=models.TextField(default=''),
),
migrations.DeleteModel(
name='LicenseType',
),
]

View File

@ -7,28 +7,29 @@
# #
# Created on 2019-10-08 # Created on 2019-10-08
# @author: chrigu <christian.cueni@iterativ.ch> # @author: chrigu <christian.cueni@iterativ.ch>
from datetime import datetime
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db import models from django.db import models
from registration.managers import LicenseManager
from users.managers import RoleManager from users.managers import RoleManager
from users.models import Role, User from users.models import Role, User
class LicenseType(models.Model): class License(models.Model):
for_role = models.ForeignKey(Role, blank=False, null=True, on_delete=models.CASCADE)
licensee = models.ForeignKey(User, blank=False, null=True, on_delete=models.CASCADE)
expire_date = models.DateField(blank=False, null=True,)
raw = models.TextField(default="")
name = models.CharField(_('License name'), max_length=255, blank=False, null=False) objects = LicenseManager()
for_role = models.ForeignKey(Role, blank=False, null=False, on_delete=models.CASCADE)
key = models.CharField(max_length=128, blank=False, null=False, unique=True)
active = models.BooleanField(_('License active'), default=False)
description = models.TextField(_('Description'), default="")
def is_teacher_license(self): def is_teacher_license(self):
return self.for_role.key == RoleManager.TEACHER_KEY return self.for_role.key == RoleManager.TEACHER_KEY
def is_valid(self):
return datetime(self.expire_date.year, self.expire_date.month, self.expire_date.day) <= datetime.now()
def __str__(self): def __str__(self):
return '%s - role: %s' % (self.name, self.for_role) return 'License for role: %s' % self.for_role
class License(models.Model):
license_type = models.ForeignKey(LicenseType, blank=False, null=False, on_delete=models.CASCADE)
licensee = models.ForeignKey(User, blank=False, null=True, on_delete=models.CASCADE)

View File

@ -12,7 +12,7 @@ from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import CharField, EmailField from rest_framework.fields import CharField, EmailField
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from registration.models import License, LicenseType from registration.models import License
class RegistrationSerializer(serializers.Serializer): class RegistrationSerializer(serializers.Serializer):
@ -38,9 +38,4 @@ class RegistrationSerializer(serializers.Serializer):
return lower_email return lower_email
def validate_license_key(self, value): def validate_license_key(self, value):
license_types = LicenseType.objects.filter(key=value, active=True)
if len(license_types) == 0:
raise serializers.ValidationError(_(u'Die Lizenznummer ist ungültig'))
self.context['license_type'] = license_types[0] # Assuming there is just ONE license per key
return value return value

View File

@ -4,6 +4,8 @@ from django.utils.translation import ugettext_lazy as _
from django.db import models from django.db import models
from django.contrib.auth.models import UserManager as DjangoUserManager from django.contrib.auth.models import UserManager as DjangoUserManager
from core.hep_client import HepClient
class RoleManager(models.Manager): class RoleManager(models.Manager):
use_in_migrations = True use_in_migrations = True
@ -82,12 +84,27 @@ class UserRoleManager(models.Manager):
class UserManager(DjangoUserManager): class UserManager(DjangoUserManager):
def create_user_with_random_password(self, first_name, last_name, email):
def _create_user_with_random_password_no_save(self, first_name, last_name, email):
user, created = self.model.objects.get_or_create(email=email, username=email) user, created = self.model.objects.get_or_create(email=email, username=email)
user.first_name = first_name user.first_name = first_name
user.last_name = last_name user.last_name = last_name
# Todo: remove if not used # Todo: remove if not used
# user.set_password(self.model.objects.make_random_password()) # user.set_password(self.model.objects.make_random_password())
user.set_unusable_password() user.set_unusable_password()
return user
def create_user_with_random_password(self, first_name, last_name, email):
user = self._create_user_with_random_password_no_save()
user.save()
return user
def create_user_from_hep(self, token):
hep_client = HepClient()
me_data = hep_client.customer_me(token)
user = self.user = self._create_user_with_random_password_no_save(
me_data['firstname'], me_data['lastname'], me_data['email'])
user.hep_id = me_data['id']
user.save() user.save()
return user return user

View File

@ -0,0 +1,24 @@
# Generated by Django 2.0.6 on 2020-01-27 09:32
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0009_auto_20191009_0905'),
]
operations = [
migrations.CreateModel(
name='MagentoToken',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.CharField(blank=True, max_length=64, null=True)),
('created_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_token', to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.0.6 on 2020-01-27 13:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0010_magentotoken'),
]
operations = [
migrations.AddField(
model_name='user',
name='hep_id',
field=models.PositiveIntegerField(null=True),
),
]

View File

@ -15,6 +15,7 @@ class User(AbstractUser):
last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True) last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True)
avatar_url = models.CharField(max_length=254, blank=True, default='') avatar_url = models.CharField(max_length=254, blank=True, default='')
email = models.EmailField(_('email address'), unique=True) email = models.EmailField(_('email address'), unique=True)
hep_id = models.PositiveIntegerField(null=True, blank=False)
objects = UserManager() objects = UserManager()
@ -166,3 +167,8 @@ class UserSetting(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name='user_setting') user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name='user_setting')
selected_class = models.ForeignKey(SchoolClass, blank=True, null=True, on_delete=models.CASCADE) selected_class = models.ForeignKey(SchoolClass, blank=True, null=True, on_delete=models.CASCADE)
class MagentoToken(models.Model):
token = models.CharField(blank=True, null=True, max_length=64)
created_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE, related_name='user_token')

View File

@ -15,6 +15,8 @@ from graphene import relay
from core.hep_client import HepClient from core.hep_client import HepClient
from registration.models import License from registration.models import License
from users.managers import UserRoleManager
from users.models import MagentoToken, User, Role, UserRole, SchoolClass
class LoginError(graphene.ObjectType): class LoginError(graphene.ObjectType):
@ -32,6 +34,9 @@ class Login(relay.ClientIDMutation):
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **kwargs): def mutate_and_get_payload(cls, root, info, **kwargs):
username = kwargs.get('username_input')
password = kwargs.get('password_input')
# get token # get token
# wrong password # wrong password
# #
@ -44,8 +49,8 @@ class Login(relay.ClientIDMutation):
# save role information # save role information
# login # login
if not settings.USE_LOCAL_REGISTRATION: if settings.USE_LOCAL_REGISTRATION:
user = authenticate(username=kwargs.get('username_input'), password=kwargs.get('password_input')) user = authenticate(username=username, password=password)
if user is None: if user is None:
error = LoginError(field='invalid_credentials') error = LoginError(field='invalid_credentials')
return cls(success=False, errors=[error]) return cls(success=False, errors=[error])
@ -53,24 +58,72 @@ class Login(relay.ClientIDMutation):
else: else:
hep_client = HepClient() hep_client = HepClient()
# Todo catch error # Todo network error catch error
token = hep_client.customer_token(kwargs.get('username_input'), kwargs.get('password_input')) token = hep_client.customer_token(username, password)
# Todo save token try:
#verify email user = User.objects.get(email=username)
except User.DoesNotExist:
user = User.objects.create_user_from_hep(token)
# ISBN "123-4-5678-9012-3"
magento_token, created = MagentoToken.objects.get_or_create(user=user)
magento_token.token = token['token']
magento_token.save()
if not hep_client.is_email_verified(username):
# Todo handle unverifed emails
pass
try:
license = License.objects.get(licensee=user)
except License.DoesNotExist:
product = hep_client.myskillbox_product_for_customer(settings.HEP_ADMIN_TOKEN, user.hep_id)
if product:
license = License.objects.create_license_for_role(user, product['activated'],
product['raw'], product['edition'])
else:
# todo go to shop
pass
UserRole.objects.create_role_for_user(user, license.for_role.key)
default_class_name = SchoolClass.generate_default_group_name()
default_class = SchoolClass.objects.create(name=default_class_name)
user.school_classes.add(default_class)
# if teacher create class
# if student add to class if exists???
# no orders
# network errors
# Todo get orders from magento
# check items
# show buy or create license
user_license = None # check items
# show buy page
try: if not license.is_valid():
user_license = License.objects.get(licensee=user) pass
except License.DoesNotExist:
# current users have no license, allow them to login
pass
if user_license is not None and not user_license.license_type.active:
error = LoginError(field='license_inactive') # show page
return cls(success=False, errors=[error])
#
# user_license = None
#
# try:
# user_license = License.objects.get(licensee=user)
# except License.DoesNotExist:
# # current users have no license, allow them to login
# pass
#
# if user_license is not None and not user_license.license_type.active:
# error = LoginError(field='license_inactive')
# return cls(success=False, errors=[error])
login(info.context, user) login(info.context, user)
return cls(success=True, errors=[]) return cls(success=True, errors=[])

View File

@ -0,0 +1,41 @@
{
"id": 49124,
"group_id": 1,
"default_billing": "47579",
"default_shipping": "47579",
"confirmation": "41b58ba6598a618095e8c70625d7f052",
"created_at": "2018-07-19 15:05:27",
"updated_at": "2019-11-26 17:04:29",
"created_in": "hep verlag",
"email": "1heptest19072018@mailinator.com",
"firstname": "Test",
"lastname": "Test",
"prefix": "Frau",
"gender": 2,
"store_id": 1,
"website_id": 1,
"addresses": [
{
"id": 47579,
"customer_id": 49124,
"region": {
"region_code": null,
"region": null,
"region_id": 0
},
"region_id": 0,
"country_id": "CH",
"street": [
"Test"
],
"telephone": "",
"postcode": "0000",
"city": "Test",
"firstname": "Test",
"lastname": "Test",
"prefix": "Frau",
"default_shipping": true,
"default_billing": true
}
]
}

View File

@ -8,30 +8,42 @@
# Created on 2019-10-02 # Created on 2019-10-02
# @author: chrigu <christian.cueni@iterativ.ch> # @author: chrigu <christian.cueni@iterativ.ch>
import json import json
import os
from datetime import timedelta
from unittest.mock import patch from unittest.mock import patch
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from django.utils import timezone
from graphene.test import Client from graphene.test import Client
from api.schema_public import schema from api.schema_public import schema
from core.factories import UserFactory from core.factories import UserFactory
from core.hep_client import HepClient from core.hep_client import HepClient
from registration.factories import LicenseTypeFactory, LicenseFactory from registration.factories import LicenseFactory
from users.models import Role from registration.models import License
from users.models import Role, MagentoToken, User
FAKE_TOKEN = 'abcd12345!' FAKE_TOKEN = 'abcd12345!'
with open('orders.json', 'r') as file:
dir_path = os.path.dirname(os.path.realpath(__file__))
with open('{}/valid_teacher_orders.json'.format(dir_path), 'r') as file:
order_data = file.read() order_data = file.read()
ORDERS = json.loads(order_data) ORDERS = json.loads(order_data)
with open('{}/me_data.json'.format(dir_path), 'r') as file:
me_data = file.read()
ME_DATA = json.loads(me_data)
class PasswordResetTests(TestCase): class PasswordResetTests(TestCase):
def setUp(self): def setUp(self):
self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch') self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch')
self.teacher_role = Role.objects.create(key=Role.objects.TEACHER_KEY, name="Teacher Role") Role.objects.create_default_roles()
self.teacher_license_type = LicenseTypeFactory(for_role=self.teacher_role) self.teacher_role = Role.objects.get_default_teacher_role()
request = RequestFactory().post('/') request = RequestFactory().post('/')
@ -61,38 +73,77 @@ class PasswordResetTests(TestCase):
}) })
@patch.object(HepClient, 'customer_token', return_value={'token': FAKE_TOKEN}) @patch.object(HepClient, 'customer_token', return_value={'token': FAKE_TOKEN})
@patch.object(HepClient, 'customer_orders', return_value=ORDERS) def test_user_can_login_with_local_user_and_valid_local_license(self, token_mock):
def test_user_can_login(self, orders_mock, token_mock):
now = timezone.now()
expiry_date = now + timedelta(365)
LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save()
result = self.make_login_mutation(self.user.email, 'test123') result = self.make_login_mutation(self.user.email, 'test123')
token = MagentoToken.objects.get(user=self.user)
self.assertEqual(token.token, FAKE_TOKEN)
self.assertTrue(result.get('data').get('login').get('success')) self.assertTrue(result.get('data').get('login').get('success'))
self.assertTrue(self.user.is_authenticated) self.assertTrue(self.user.is_authenticated)
def test_user_cannot_login_with_invalid_password(self): @patch.object(HepClient, 'customer_token', return_value={'token': FAKE_TOKEN})
password = 'test123' @patch.object(HepClient, '_customer_orders', return_value=ORDERS)
self.user.set_password(password) @patch.object(HepClient, 'customer_me', return_value=ME_DATA)
self.user.save() def test_user_can_login_with_local_user_and_remote_license(self, order_mock, token_mock, me_token):
result = self.make_login_mutation(ME_DATA['email'], 'test123')
result = self.make_login_mutation(self.user.email, 'test1234') user = User.objects.get(email=ME_DATA['email'])
self.assertFalse(result.get('data').get('login').get('success')) token = MagentoToken.objects.get(user=user)
self.assertEqual(token.token, FAKE_TOKEN)
def test_user_with_active_license_can_login(self): user_role_key = user.user_roles.get(user=user).role.key
password = 'test123' self.assertEqual(user_role_key, Role.objects.TEACHER_KEY)
self.user.set_password(password)
self.user.save()
LicenseFactory(license_type=self.teacher_license_type, licensee=self.user) license = License.objects.get(licensee=user)
self.assertEqual(license.for_role.key, Role.objects.TEACHER_KEY)
result = self.make_login_mutation(self.user.email, password)
self.assertTrue(result.get('data').get('login').get('success')) self.assertTrue(result.get('data').get('login').get('success'))
self.assertTrue(self.user.is_authenticated)
def test_user_with_inactive_license_cannot_login(self): ## can login with license and user
password = 'test123' # can login with no user and license
self.user.set_password(password) # can login with no user and local license
self.user.save() # cannot login without user
# cannot login with user and not verfied
# cannot login with user and no license
# cannot login with user and expired license
# non 200 error
# if more than one valid license take correct
# if mulitple licenses and one correct take one test in own class
self.teacher_license_type.active = False
self.teacher_license_type.save()
LicenseFactory(license_type=self.teacher_license_type, licensee=self.user)
result = self.make_login_mutation(self.user.email, password) # def test_user_cannot_login_with_invalid_password(self):
self.assertFalse(result.get('data').get('login').get('success')) # password = 'test123'
# self.user.set_password(password)
# self.user.save()
#
# result = self.make_login_mutation(self.user.email, 'test1234')
# self.assertFalse(result.get('data').get('login').get('success'))
#
# def test_user_with_active_license_can_login(self):
# password = 'test123'
# self.user.set_password(password)
# self.user.save()
#
# LicenseFactory(license_type=self.teacher_license_type, licensee=self.user)
#
# result = self.make_login_mutation(self.user.email, password)
# self.assertTrue(result.get('data').get('login').get('success'))
#
# def test_user_with_inactive_license_cannot_login(self):
# password = 'test123'
# self.user.set_password(password)
# self.user.save()
#
# self.teacher_license_type.active = False
# self.teacher_license_type.save()
# LicenseFactory(license_type=self.teacher_license_type, licensee=self.user)
#
# result = self.make_login_mutation(self.user.email, password)
# self.assertFalse(result.get('data').get('login').get('success'))

View File

@ -82,7 +82,7 @@
"is_qty_decimal": 0, "is_qty_decimal": 0,
"is_virtual": 1, "is_virtual": 1,
"item_id": 80317, "item_id": 80317,
"name": "Gesellschaft Ausgabe A (eLehrmittel, Neuauflage)", "name": "Myskillbox Lehreredition",
"no_discount": 0, "no_discount": 0,
"order_id": 57612, "order_id": 57612,
"original_price": 46, "original_price": 46,
@ -99,7 +99,7 @@
"row_invoiced": 0, "row_invoiced": 0,
"row_total": 44.88, "row_total": 44.88,
"row_total_incl_tax": 46, "row_total_incl_tax": 46,
"sku": "978-3-0355-1082-9", "sku": "000-4-5678-9012-3",
"store_id": 1, "store_id": 1,
"tax_amount": 1.12, "tax_amount": 1.12,
"tax_invoiced": 0, "tax_invoiced": 0,