Commit 9fd6f149 by Clinton Blackburn

Moved coupons-related mixins to appropriate module (#764)

parent 79ad83c9
import datetime
import json
import httpretty
from django.conf import settings
from django.test import RequestFactory
from oscar.test import factories
from ecommerce.core.models import BusinessClient
from ecommerce.extensions.api.v2.views.coupons import CouponViewSet
from ecommerce.extensions.basket.utils import prepare_basket
from ecommerce.tests.factories import PartnerFactory
from ecommerce.tests.mixins import ProductClass, Catalog, Benefit, Voucher, Applicator
class CatalogPreviewMockMixin(object):
""" Mocks for the Course Discovery responses. """
def setUp(self):
super(CatalogPreviewMockMixin, self).setUp()
def mock_dynamic_catalog_course_runs_api(self, course_run=None, query=None):
""" Helper function to register a dynamic course catalog API endpoint for the course run information. """
course_run_info = {
'count': 1,
'results': [{
'key': course_run.id,
'title': course_run.name,
}] if course_run else [{
'key': 'test',
'title': 'Test course',
}],
}
course_run_info_json = json.dumps(course_run_info)
course_run_url = '{}course_runs/?q={}'.format(
settings.COURSE_CATALOG_API_URL,
query if query else 'id:course*'
)
httpretty.register_uri(
httpretty.GET, course_run_url,
body=course_run_info_json,
content_type='application/json'
)
def mock_dynamic_catalog_contains_api(self, course_run_ids, query):
""" Helper function to register a dynamic course catalog API endpoint for the contains information. """
course_contains_info = {
'course_runs': {}
}
for course_run_id in course_run_ids:
course_contains_info['course_runs'][course_run_id] = True
course_run_info_json = json.dumps(course_contains_info)
course_run_url = '{}course_runs/contains/?course_run_ids={}&query={}'.format(
settings.COURSE_CATALOG_API_URL,
(course_run_id for course_run_id in course_run_ids),
query if query else 'id:course*'
)
httpretty.register_uri(
httpretty.GET, course_run_url,
body=course_run_info_json,
content_type='application/json'
)
class CouponMixin(object):
""" Mixin for preparing data for coupons and creating coupons. """
REDEMPTION_URL = "/coupons/offer/?code={}"
def setUp(self):
super(CouponMixin, self).setUp()
self.category = factories.CategoryFactory()
# Force the creation of a coupon ProductClass
self.coupon_product_class # pylint: disable=pointless-statement
@property
def coupon_product_class(self):
defaults = {'requires_shipping': False, 'track_stock': False, 'name': 'Coupon'}
pc, created = ProductClass.objects.get_or_create(name='Coupon', slug='coupon', defaults=defaults)
if created:
factories.ProductAttributeFactory(
code='coupon_vouchers',
name='Coupon vouchers',
product_class=pc,
type='entity'
)
factories.ProductAttributeFactory(
code='note',
name='Note',
product_class=pc,
type='text'
)
return pc
def create_coupon(self, title='Test coupon', price=100, client=None, partner=None, catalog=None, code='',
benefit_value=100, note=None, max_uses=None, quantity=5, catalog_query=None,
course_seat_types=None):
"""Helper method for creating a coupon.
Arguments:
title(str): Title of the coupon
price(int): Price of the coupon
partner(Partner): Partner used for creating a catalog
catalog(Catalog): Catalog of courses for which the coupon applies
code(str): Custom coupon code
benefit_value(int): The voucher benefit value
catalog_query(str): course query string
course_seat_types(JSONField): List of seat types
Returns:
coupon (Coupon)
"""
if partner is None:
partner = PartnerFactory(name='Tester')
if client is None:
client, __ = BusinessClient.objects.get_or_create(name='Test Client')
if catalog is None and not (catalog_query and course_seat_types):
catalog = Catalog.objects.create(partner=partner)
if code is not '':
quantity = 1
data = {
'partner': partner,
'benefit_type': Benefit.PERCENTAGE,
'benefit_value': benefit_value,
'catalog': catalog,
'end_date': datetime.date(2020, 1, 1),
'code': code,
'quantity': quantity,
'start_date': datetime.date(2015, 1, 1),
'voucher_type': Voucher.SINGLE_USE,
'categories': [self.category],
'note': note,
'max_uses': max_uses,
'catalog_query': catalog_query,
'course_seat_types': course_seat_types,
}
coupon = CouponViewSet().create_coupon_product(
title=title,
price=price,
data=data
)
request = RequestFactory()
request.site = self.site
request.user = factories.UserFactory()
request.COOKIES = {}
self.basket = prepare_basket(request, coupon)
self.response_data = CouponViewSet().create_order_for_invoice(self.basket, coupon_id=coupon.id, client=client)
coupon.client = client
return coupon
def apply_voucher(self, user, site, voucher):
""" Apply the voucher to a basket. """
basket = factories.BasketFactory(owner=user, site=site)
product = voucher.offers.first().benefit.range.all_products()[0]
basket.add_product(product)
basket.vouchers.add(voucher)
Applicator().apply(basket, self.user)
return basket
import httpretty
import mock import mock
from django.conf import settings from django.conf import settings
from edx_rest_api_client.client import EdxRestApiClient from edx_rest_api_client.client import EdxRestApiClient
import httpretty
from ecommerce.coupons.tests.mixins import CatalogPreviewMockMixin, CouponMixin
from ecommerce.coupons.utils import get_seats_from_query from ecommerce.coupons.utils import get_seats_from_query
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.tests.mixins import CouponMixin, CatalogPreviewMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
...@@ -19,7 +18,6 @@ from ecommerce.tests.testcases import TestCase ...@@ -19,7 +18,6 @@ from ecommerce.tests.testcases import TestCase
)) ))
) )
class CouponUtilsTests(CouponMixin, CourseCatalogTestMixin, CatalogPreviewMockMixin, TestCase): class CouponUtilsTests(CouponMixin, CourseCatalogTestMixin, CatalogPreviewMockMixin, TestCase):
def setUp(self): def setUp(self):
super(CouponUtilsTests, self).setUp() super(CouponUtilsTests, self).setUp()
self.query = 'key:*' self.query = 'key:*'
......
import datetime import datetime
import ddt import ddt
import httpretty
import pytz
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import httpretty
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test.factories import ( from oscar.test.factories import (
ConditionalOfferFactory, OrderFactory, OrderLineFactory, RangeFactory, VoucherFactory ConditionalOfferFactory, OrderFactory, OrderLineFactory, RangeFactory, VoucherFactory
) )
from oscar.test.utils import RequestFactory from oscar.test.utils import RequestFactory
import pytz
from ecommerce.core.url_utils import get_lms_url, get_lms_enrollment_api_url from ecommerce.core.url_utils import get_lms_url, get_lms_enrollment_api_url
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.coupons.views import get_voucher_from_code, voucher_is_valid from ecommerce.coupons.views import get_voucher_from_code, voucher_is_valid
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.api import exceptions from ecommerce.extensions.api import exceptions
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.test.factories import prepare_voucher from ecommerce.extensions.test.factories import prepare_voucher
from ecommerce.tests.mixins import CouponMixin, LmsApiMockMixin from ecommerce.tests.mixins import LmsApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Applicator = get_class('offer.utils', 'Applicator') Applicator = get_class('offer.utils', 'Applicator')
...@@ -64,7 +65,6 @@ class CouponAppViewTests(TestCase): ...@@ -64,7 +65,6 @@ class CouponAppViewTests(TestCase):
class GetVoucherTests(TestCase): class GetVoucherTests(TestCase):
def test_get_voucher_from_code(self): def test_get_voucher_from_code(self):
""" Verify that get_voucher_from_code() returns product and voucher. """ """ Verify that get_voucher_from_code() returns product and voucher. """
original_voucher, original_product = prepare_voucher(code=COUPON_CODE) original_voucher, original_product = prepare_voucher(code=COUPON_CODE)
......
import json import json
import mock
import ddt import ddt
import httpretty
import mock
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import RequestFactory from django.test import RequestFactory
from edx_rest_api_client.client import EdxRestApiClient from edx_rest_api_client.client import EdxRestApiClient
import httpretty
from requests.exceptions import ConnectionError, Timeout
from oscar.core.loading import get_model from oscar.core.loading import get_model
from requests.exceptions import ConnectionError, Timeout
from slumber.exceptions import SlumberBaseException from slumber.exceptions import SlumberBaseException
from ecommerce.coupons.tests.mixins import CatalogPreviewMockMixin
from ecommerce.extensions.api.serializers import ProductSerializer from ecommerce.extensions.api.serializers import ProductSerializer
from ecommerce.extensions.api.v2.views.catalog import CatalogViewSet
from ecommerce.extensions.api.v2.tests.views.mixins import CatalogMixin from ecommerce.extensions.api.v2.tests.views.mixins import CatalogMixin
from ecommerce.tests.mixins import ApiMockMixin, CatalogPreviewMockMixin from ecommerce.extensions.api.v2.views.catalog import CatalogViewSet
from ecommerce.tests.mixins import ApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Catalog = get_model('catalogue', 'Catalog') Catalog = get_model('catalogue', 'Catalog')
StockRecord = get_model('partner', 'StockRecord') StockRecord = get_model('partner', 'StockRecord')
...@@ -144,7 +144,6 @@ class CatalogViewSetTest(CatalogMixin, CatalogPreviewMockMixin, ApiMockMixin, Te ...@@ -144,7 +144,6 @@ class CatalogViewSetTest(CatalogMixin, CatalogPreviewMockMixin, ApiMockMixin, Te
class PartnerCatalogViewSetTest(CatalogMixin, TestCase): class PartnerCatalogViewSetTest(CatalogMixin, TestCase):
def setUp(self): def setUp(self):
super(PartnerCatalogViewSetTest, self).setUp() super(PartnerCatalogViewSetTest, self).setUp()
......
...@@ -34,9 +34,9 @@ class CheckoutViewTests(TestCase): ...@@ -34,9 +34,9 @@ class CheckoutViewTests(TestCase):
super(CheckoutViewTests, self).setUp() super(CheckoutViewTests, self).setUp()
self.user = self.create_user() self.user = self.create_user()
self.client.login(username=self.user.username, password=self.password) self.client.login(username=self.user.username, password=self.password)
Basket.objects.create(owner=self.user) self.basket = Basket.objects.create(owner=self.user)
self.data = { self.data = {
'basket_id': 1, 'basket_id': self.basket.id,
'payment_processor': DummyProcessorWithUrl.NAME 'payment_processor': DummyProcessorWithUrl.NAME
} }
...@@ -70,7 +70,7 @@ class CheckoutViewTests(TestCase): ...@@ -70,7 +70,7 @@ class CheckoutViewTests(TestCase):
response = self.client.post(self.path, data=self.data) response = self.client.post(self.path, data=self.data)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
basket = Basket.objects.get(id=1) basket = Basket.objects.get(id=self.basket.id)
self.assertEqual(basket.status, Basket.FROZEN) self.assertEqual(basket.status, Basket.FROZEN)
response_data = json.loads(response.content) response_data = json.loads(response.content)
self.assertEqual(response_data['payment_form_data']['transaction_param'], 'test_trans_param') self.assertEqual(response_data['payment_form_data']['transaction_param'], 'test_trans_param')
......
...@@ -3,20 +3,21 @@ from __future__ import unicode_literals ...@@ -3,20 +3,21 @@ from __future__ import unicode_literals
import json import json
from decimal import Decimal from decimal import Decimal
import mock
import ddt import ddt
import httpretty
import mock
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
from django.test import RequestFactory from django.test import RequestFactory
from edx_rest_api_client.client import EdxRestApiClient from edx_rest_api_client.client import EdxRestApiClient
import httpretty
from oscar.apps.catalogue.categories import create_from_breadcrumbs from oscar.apps.catalogue.categories import create_from_breadcrumbs
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import factories from oscar.test import factories
from rest_framework import status from rest_framework import status
from ecommerce.coupons.tests.mixins import CatalogPreviewMockMixin, CouponMixin
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.api.constants import APIConstants as AC from ecommerce.extensions.api.constants import APIConstants as AC
from ecommerce.extensions.api.v2.views.coupons import CouponViewSet from ecommerce.extensions.api.v2.views.coupons import CouponViewSet
...@@ -24,7 +25,7 @@ from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin ...@@ -24,7 +25,7 @@ from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.voucher.models import CouponVouchers from ecommerce.extensions.voucher.models import CouponVouchers
from ecommerce.invoice.models import Invoice from ecommerce.invoice.models import Invoice
from ecommerce.tests.factories import ProductFactory, SiteConfigurationFactory, SiteFactory from ecommerce.tests.factories import ProductFactory, SiteConfigurationFactory, SiteFactory
from ecommerce.tests.mixins import CouponMixin, CatalogPreviewMockMixin, ThrottlingMixin from ecommerce.tests.mixins import ThrottlingMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Applicator = get_class('offer.utils', 'Applicator') Applicator = get_class('offer.utils', 'Applicator')
...@@ -46,18 +47,15 @@ COUPONS_LINK = reverse('api:v2:coupons-list') ...@@ -46,18 +47,15 @@ COUPONS_LINK = reverse('api:v2:coupons-list')
@httpretty.activate @httpretty.activate
@ddt.ddt @ddt.ddt
class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
"""Unit tests for creating coupon order."""
def setUp(self): def setUp(self):
super(CouponViewSetTest, self).setUp() super(CouponViewSetTest, self).setUp()
self.user = self.create_user(is_staff=True) self.user = self.create_user(is_staff=True)
self.client.login(username=self.user.username, password=self.password) self.client.login(username=self.user.username, password=self.password)
course = CourseFactory(id='edx/Demo_Course/DemoX') course = CourseFactory(id='edx/Demo_Course/DemoX')
course.create_or_update_seat('verified', True, 50, self.partner) self.seat = course.create_or_update_seat('verified', True, 50, self.partner)
self.catalog = Catalog.objects.create(partner=self.partner) self.catalog = Catalog.objects.create(partner=self.partner)
self.product_class, __ = ProductClass.objects.get_or_create(name='Coupon')
self.coupon_data = { self.coupon_data = {
'title': 'Test Coupon', 'title': 'Test Coupon',
'partner': self.partner, 'partner': self.partner,
...@@ -90,10 +88,11 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -90,10 +88,11 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
def test_create(self, voucher_type, max_uses, expected_max_uses): def test_create(self, voucher_type, max_uses, expected_max_uses):
"""Test the create method.""" """Test the create method."""
title = 'Test coupon' title = 'Test coupon'
stock_record = self.seat.stockrecords.first()
self.coupon_data.update({ self.coupon_data.update({
'title': title, 'title': title,
'client_username': 'Client', 'client_username': 'Client',
'stock_record_ids': [1], 'stock_record_ids': [stock_record.id],
'voucher_type': voucher_type, 'voucher_type': voucher_type,
'price': 100, 'price': 100,
'category_ids': [self.category.id], 'category_ids': [self.category.id],
...@@ -122,7 +121,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -122,7 +121,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
def test_create_coupon_product(self): def test_create_coupon_product(self):
"""Test the created coupon data.""" """Test the created coupon data."""
coupon = self.create_coupon() coupon = self.create_coupon()
self.assertEqual(Product.objects.filter(product_class=self.product_class).count(), 1) self.assertEqual(Product.objects.filter(product_class=self.coupon_product_class).count(), 1)
self.assertIsInstance(coupon, Product) self.assertIsInstance(coupon, Product)
self.assertEqual(coupon.title, 'Test coupon') self.assertEqual(coupon.title, 'Test coupon')
...@@ -239,7 +238,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -239,7 +238,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
def test_delete_coupon(self): def test_delete_coupon(self):
"""Test the coupon deletion.""" """Test the coupon deletion."""
coupon = self.create_coupon(partner=self.partner) coupon = self.create_coupon(partner=self.partner)
self.assertEqual(Product.objects.filter(product_class=self.product_class).count(), 1) self.assertEqual(Product.objects.filter(product_class=self.coupon_product_class).count(), 1)
self.assertEqual(StockRecord.objects.filter(product=coupon).count(), 1) self.assertEqual(StockRecord.objects.filter(product=coupon).count(), 1)
coupon_voucher_qs = CouponVouchers.objects.filter(coupon=coupon) coupon_voucher_qs = CouponVouchers.objects.filter(coupon=coupon)
self.assertEqual(coupon_voucher_qs.count(), 1) self.assertEqual(coupon_voucher_qs.count(), 1)
...@@ -249,7 +248,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -249,7 +248,7 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
request.site = self.setup_site_configuration() request.site = self.setup_site_configuration()
response = CouponViewSet().destroy(request, coupon.id) response = CouponViewSet().destroy(request, coupon.id)
self.assertEqual(Product.objects.filter(product_class=self.product_class).count(), 0) self.assertEqual(Product.objects.filter(product_class=self.coupon_product_class).count(), 0)
self.assertEqual(StockRecord.objects.filter(product=coupon).count(), 0) self.assertEqual(StockRecord.objects.filter(product=coupon).count(), 0)
coupon_voucher_qs = CouponVouchers.objects.filter(coupon=coupon) coupon_voucher_qs = CouponVouchers.objects.filter(coupon=coupon)
self.assertEqual(coupon_voucher_qs.count(), 0) self.assertEqual(coupon_voucher_qs.count(), 0)
...@@ -261,13 +260,8 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -261,13 +260,8 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
@ddt.ddt @ddt.ddt
class CouponViewSetFunctionalTest( class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CatalogPreviewMockMixin, ThrottlingMixin,
CouponMixin, TestCase):
CourseCatalogTestMixin,
CatalogPreviewMockMixin,
ThrottlingMixin,
TestCase
):
"""Test the coupon order creation functionality.""" """Test the coupon order creation functionality."""
def setUp(self): def setUp(self):
...@@ -509,7 +503,7 @@ class CouponViewSetFunctionalTest( ...@@ -509,7 +503,7 @@ class CouponViewSetFunctionalTest(
# Seats derived from a migrated "audit" mode do not have a certificate_type attribute. # Seats derived from a migrated "audit" mode do not have a certificate_type attribute.
if mode == 'audit': if mode == 'audit':
seat = ProductFactory() seat = ProductFactory()
self.data.update({'stock_record_ids': [StockRecord.objects.get(product=seat).id], }) self.data.update({'stock_record_ids': [StockRecord.objects.get(product=seat).id]})
response = self.client.post(COUPONS_LINK, data=self.data, format='json') response = self.client.post(COUPONS_LINK, data=self.data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
......
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
import json import json
import pytz
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import RequestFactory
from oscar.core.loading import get_model from oscar.core.loading import get_model
import pytz
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.courses.models import Course from ecommerce.courses.models import Course
from ecommerce.extensions.api.serializers import ProductSerializer
from ecommerce.extensions.api.v2.tests.views import JSON_CONTENT_TYPE, ProductSerializerMixin from ecommerce.extensions.api.v2.tests.views import JSON_CONTENT_TYPE, ProductSerializerMixin
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.tests.mixins import CouponMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Benefit = get_model('offer', 'Benefit') Benefit = get_model('offer', 'Benefit')
...@@ -20,7 +23,6 @@ Voucher = get_model('voucher', 'Voucher') ...@@ -20,7 +23,6 @@ Voucher = get_model('voucher', 'Voucher')
class ProductViewSetBase(ProductSerializerMixin, CourseCatalogTestMixin, TestCase): class ProductViewSetBase(ProductSerializerMixin, CourseCatalogTestMixin, TestCase):
def setUp(self): def setUp(self):
super(ProductViewSetBase, self).setUp() super(ProductViewSetBase, self).setUp()
self.user = self.create_user(is_staff=True) self.user = self.create_user(is_staff=True)
...@@ -33,7 +35,6 @@ class ProductViewSetBase(ProductSerializerMixin, CourseCatalogTestMixin, TestCas ...@@ -33,7 +35,6 @@ class ProductViewSetBase(ProductSerializerMixin, CourseCatalogTestMixin, TestCas
class ProductViewSetTests(ProductViewSetBase): class ProductViewSetTests(ProductViewSetBase):
def test_list(self): def test_list(self):
""" Verify a list of products is returned. """ """ Verify a list of products is returned. """
path = reverse('api:v2:product-list') path = reverse('api:v2:product-list')
...@@ -129,7 +130,6 @@ class ProductViewSetTests(ProductViewSetBase): ...@@ -129,7 +130,6 @@ class ProductViewSetTests(ProductViewSetBase):
class ProductViewSetCouponTests(CouponMixin, ProductViewSetBase): class ProductViewSetCouponTests(CouponMixin, ProductViewSetBase):
def test_coupon_product_details(self): def test_coupon_product_details(self):
"""Verify the endpoint returns all coupon information.""" """Verify the endpoint returns all coupon information."""
coupon = self.create_coupon() coupon = self.create_coupon()
...@@ -137,12 +137,11 @@ class ProductViewSetCouponTests(CouponMixin, ProductViewSetBase): ...@@ -137,12 +137,11 @@ class ProductViewSetCouponTests(CouponMixin, ProductViewSetBase):
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content) request = RequestFactory(SERVER_NAME=self.site.domain).get('/')
self.assertEqual(response_data['id'], 3) request.user = self.user
self.assertEqual(response_data['title'], 'Test coupon') request.site = self.site
self.assertEqual(response_data['price'], '100.00') expected = ProductSerializer(coupon, context={'request': request}).data
self.assertEqual(response_data['attribute_values'][0]['name'], 'Coupon vouchers') self.assertDictEqual(response.data, expected)
self.assertEqual(len(response_data['attribute_values'][0]['value']), 5)
def test_coupon_voucher_serializer(self): def test_coupon_voucher_serializer(self):
"""Verify that the vouchers of a coupon are properly serialized.""" """Verify that the vouchers of a coupon are properly serialized."""
......
...@@ -4,7 +4,6 @@ import logging ...@@ -4,7 +4,6 @@ import logging
from decimal import Decimal from decimal import Decimal
import dateutil.parser import dateutil.parser
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
...@@ -209,9 +208,9 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet): ...@@ -209,9 +208,9 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
catalog_query=data['catalog_query'], catalog_query=data['catalog_query'],
course_seat_types=data['course_seat_types'] course_seat_types=data['course_seat_types']
) )
except IntegrityError as ex: except IntegrityError:
logger.exception('Failed to create vouchers for [%s] coupon.', coupon_product.title) logger.exception('Failed to create vouchers for [%s] coupon.', coupon_product.title)
raise IntegrityError(ex) # pylint: disable=nonstandard-exception raise
coupon_vouchers = CouponVouchers.objects.get(coupon=coupon_product) coupon_vouchers = CouponVouchers.objects.get(coupon=coupon_product)
...@@ -219,28 +218,26 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet): ...@@ -219,28 +218,26 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
coupon_product.attr.note = data['note'] coupon_product.attr.note = data['note']
coupon_product.save() coupon_product.save()
sku = generate_sku( sku = generate_sku(product=coupon_product, partner=data['partner'])
StockRecord.objects.update_or_create(
product=coupon_product, product=coupon_product,
partner=data['partner'], partner=data['partner'],
partner_sku=sku,
defaults={
'price_currency': 'USD',
'price_excl_tax': price
}
) )
stock_record, __ = StockRecord.objects.get_or_create(
product=coupon_product,
partner=data['partner'],
partner_sku=sku
)
stock_record.price_currency = 'USD'
stock_record.price_excl_tax = price
stock_record.save()
return coupon_product return coupon_product
def assign_categories_to_coupon(self, coupon, categories): def assign_categories_to_coupon(self, coupon, categories):
""" """
Assign categories to a coupon. If a category is already assigned, it will be fetch instead. Assigns categories to a coupon.
Arguments: Arguments:
coupon (Product): Coupon product coupon (Product): Coupon product
categories (List): List of categories to be assigned to a coupon categories (list): List of Category instances
""" """
for category in categories: for category in categories:
ProductCategory.objects.get_or_create(product=coupon, category=category) ProductCategory.objects.get_or_create(product=coupon, category=category)
......
...@@ -3,31 +3,32 @@ import hashlib ...@@ -3,31 +3,32 @@ import hashlib
import json import json
import ddt import ddt
import httpretty
import pytz
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import override_settings from django.test import override_settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import httpretty
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import newfactories as factories from oscar.test import newfactories as factories
import pytz
from requests.exceptions import ConnectionError, Timeout from requests.exceptions import ConnectionError, Timeout
from slumber.exceptions import SlumberBaseException from slumber.exceptions import SlumberBaseException
from testfixtures import LogCapture from testfixtures import LogCapture
from ecommerce.core.constants import ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_SWITCH from ecommerce.core.constants import ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_SWITCH
from ecommerce.core.url_utils import get_lms_enrollment_api_url
from ecommerce.core.models import SiteConfiguration from ecommerce.core.models import SiteConfiguration
from ecommerce.core.tests import toggle_switch from ecommerce.core.tests import toggle_switch
from ecommerce.core.url_utils import get_lms_enrollment_api_url
from ecommerce.core.url_utils import get_lms_url from ecommerce.core.url_utils import get_lms_url
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.offer.utils import format_benefit_value from ecommerce.extensions.offer.utils import format_benefit_value
from ecommerce.extensions.payment.tests.processors import DummyProcessor from ecommerce.extensions.payment.tests.processors import DummyProcessor
from ecommerce.extensions.test.factories import prepare_voucher from ecommerce.extensions.test.factories import prepare_voucher
from ecommerce.tests.factories import StockRecordFactory from ecommerce.tests.factories import StockRecordFactory
from ecommerce.tests.mixins import ApiMockMixin, CouponMixin, LmsApiMockMixin from ecommerce.tests.mixins import ApiMockMixin, LmsApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Applicator = get_class('offer.utils', 'Applicator') Applicator = get_class('offer.utils', 'Applicator')
...@@ -90,6 +91,7 @@ class BasketSingleItemViewTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockM ...@@ -90,6 +91,7 @@ class BasketSingleItemViewTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockM
def callback(request, uri, headers): # pylint: disable=unused-argument def callback(request, uri, headers): # pylint: disable=unused-argument
raise error raise error
url = '{host}/{username},{course_id}'.format( url = '{host}/{username},{course_id}'.format(
host=get_lms_enrollment_api_url(), host=get_lms_enrollment_api_url(),
username=self.user.username, username=self.user.username,
......
...@@ -4,10 +4,10 @@ from hashlib import md5 ...@@ -4,10 +4,10 @@ from hashlib import md5
from oscar.core.loading import get_model from oscar.core.loading import get_model
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.catalogue.utils import generate_sku, get_or_create_catalog from ecommerce.extensions.catalogue.utils import generate_sku, get_or_create_catalog
from ecommerce.tests.factories import ProductFactory from ecommerce.tests.factories import ProductFactory
from ecommerce.tests.mixins import CouponMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Benefit = get_model('offer', 'Benefit') Benefit = get_model('offer', 'Benefit')
...@@ -26,7 +26,7 @@ class UtilsTests(CourseCatalogTestMixin, TestCase): ...@@ -26,7 +26,7 @@ class UtilsTests(CourseCatalogTestMixin, TestCase):
def setUp(self): def setUp(self):
super(UtilsTests, self).setUp() super(UtilsTests, self).setUp()
self.course = Course.objects.create(id=COURSE_ID, name='Test Course') self.course = Course.objects.create(id=COURSE_ID, name='Test Course')
self.course.create_or_update_seat('verified', False, 0, self.partner) self.seat = self.course.create_or_update_seat('verified', False, 0, self.partner)
self.catalog = Catalog.objects.create(name='Test', partner_id=self.partner.id) self.catalog = Catalog.objects.create(name='Test', partner_id=self.partner.id)
def test_generate_sku_with_missing_product_class(self): def test_generate_sku_with_missing_product_class(self):
...@@ -56,14 +56,15 @@ class UtilsTests(CourseCatalogTestMixin, TestCase): ...@@ -56,14 +56,15 @@ class UtilsTests(CourseCatalogTestMixin, TestCase):
def test_get_or_create_catalog(self): def test_get_or_create_catalog(self):
"""Verify that the proper catalog is fetched.""" """Verify that the proper catalog is fetched."""
self.catalog.stock_records.add(StockRecord.objects.first()) stock_record = self.seat.stockrecords.first()
self.catalog.stock_records.add(stock_record)
self.assertEqual(self.catalog.id, 1) self.assertEqual(self.catalog.id, 1)
existing_catalog, created = get_or_create_catalog( existing_catalog, created = get_or_create_catalog(
name='Test', name='Test',
partner=self.partner, partner=self.partner,
stock_record_ids=[1] stock_record_ids=[stock_record.id]
) )
self.assertFalse(created) self.assertFalse(created)
self.assertEqual(self.catalog, existing_catalog) self.assertEqual(self.catalog, existing_catalog)
...@@ -71,12 +72,13 @@ class UtilsTests(CourseCatalogTestMixin, TestCase): ...@@ -71,12 +72,13 @@ class UtilsTests(CourseCatalogTestMixin, TestCase):
course_id = 'sku/test2/course' course_id = 'sku/test2/course'
course = Course.objects.create(id=course_id, name='Test Course 2') course = Course.objects.create(id=course_id, name='Test Course 2')
course.create_or_update_seat('verified', False, 0, self.partner) seat_2 = course.create_or_update_seat('verified', False, 0, self.partner)
stock_record_2 = seat_2.stockrecords.first()
new_catalog, created = get_or_create_catalog( new_catalog, created = get_or_create_catalog(
name='Test', name='Test',
partner=self.partner, partner=self.partner,
stock_record_ids=[1, 2] stock_record_ids=[stock_record.id, stock_record_2.id]
) )
self.assertTrue(created) self.assertTrue(created)
self.assertNotEqual(self.catalog, new_catalog) self.assertNotEqual(self.catalog, new_catalog)
...@@ -84,7 +86,6 @@ class UtilsTests(CourseCatalogTestMixin, TestCase): ...@@ -84,7 +86,6 @@ class UtilsTests(CourseCatalogTestMixin, TestCase):
class CouponUtilsTests(CouponMixin, CourseCatalogTestMixin, TestCase): class CouponUtilsTests(CouponMixin, CourseCatalogTestMixin, TestCase):
def setUp(self): def setUp(self):
super(CouponUtilsTests, self).setUp() super(CouponUtilsTests, self).setUp()
self.course = Course.objects.create(id=COURSE_ID, name='Test Course') self.course = Course.objects.create(id=COURSE_ID, name='Test Course')
......
"""Tests of the Fulfillment API's fulfillment modules.""" """Tests of the Fulfillment API's fulfillment modules."""
import datetime import datetime
import json import json
import ddt import ddt
import httpretty import httpretty
import mock import mock
from django.test import override_settings from django.test import override_settings
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import factories from oscar.test import factories
...@@ -15,9 +15,10 @@ from testfixtures import LogCapture ...@@ -15,9 +15,10 @@ from testfixtures import LogCapture
from ecommerce.core.constants import ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_SWITCH from ecommerce.core.constants import ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_SWITCH
from ecommerce.core.tests import toggle_switch from ecommerce.core.tests import toggle_switch
from ecommerce.core.url_utils import get_lms_enrollment_api_url from ecommerce.core.url_utils import get_lms_enrollment_api_url
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.courses.models import Course from ecommerce.courses.models import Course
from ecommerce.courses.utils import mode_for_seat
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.courses.utils import mode_for_seat
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.fulfillment.modules import ( from ecommerce.extensions.fulfillment.modules import (
CouponFulfillmentModule, EnrollmentCodeFulfillmentModule, EnrollmentFulfillmentModule CouponFulfillmentModule, EnrollmentCodeFulfillmentModule, EnrollmentFulfillmentModule
...@@ -26,7 +27,6 @@ from ecommerce.extensions.fulfillment.status import LINE ...@@ -26,7 +27,6 @@ from ecommerce.extensions.fulfillment.status import LINE
from ecommerce.extensions.fulfillment.tests.mixins import FulfillmentTestMixin from ecommerce.extensions.fulfillment.tests.mixins import FulfillmentTestMixin
from ecommerce.extensions.voucher.models import OrderLineVouchers from ecommerce.extensions.voucher.models import OrderLineVouchers
from ecommerce.extensions.voucher.utils import create_vouchers from ecommerce.extensions.voucher.utils import create_vouchers
from ecommerce.tests.mixins import CouponMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
JSON = 'application/json' JSON = 'application/json'
......
import httpretty
import mock import mock
from django.conf import settings from django.conf import settings
from django.test import RequestFactory from django.test import RequestFactory
from edx_rest_api_client.client import EdxRestApiClient from edx_rest_api_client.client import EdxRestApiClient
import httpretty
from oscar.core.loading import get_model from oscar.core.loading import get_model
from oscar.test import factories from oscar.test import factories
from ecommerce.coupons.tests.mixins import CatalogPreviewMockMixin, CouponMixin
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.tests.mixins import CouponMixin, CatalogPreviewMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Catalog = get_model('catalogue', 'Catalog') Catalog = get_model('catalogue', 'Catalog')
......
import httpretty
from django.db import IntegrityError from django.db import IntegrityError
from django.test import override_settings from django.test import override_settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import httpretty
from oscar.templatetags.currency_filters import currency from oscar.templatetags.currency_filters import currency
from oscar.test.factories import * # pylint:disable=wildcard-import,unused-wildcard-import from oscar.test.factories import * # pylint:disable=wildcard-import,unused-wildcard-import
from ecommerce.core.url_utils import get_ecommerce_url from ecommerce.core.url_utils import get_ecommerce_url
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.fulfillment.modules import CouponFulfillmentModule from ecommerce.extensions.fulfillment.modules import CouponFulfillmentModule
...@@ -13,10 +14,9 @@ from ecommerce.extensions.fulfillment.status import LINE ...@@ -13,10 +14,9 @@ from ecommerce.extensions.fulfillment.status import LINE
from ecommerce.extensions.voucher.utils import ( from ecommerce.extensions.voucher.utils import (
create_vouchers, generate_coupon_report, get_voucher_discount_info, update_voucher_offer create_vouchers, generate_coupon_report, get_voucher_discount_info, update_voucher_offer
) )
from ecommerce.tests.mixins import CouponMixin, LmsApiMockMixin from ecommerce.tests.mixins import LmsApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Basket = get_model('basket', 'Basket') Basket = get_model('basket', 'Basket')
Benefit = get_model('offer', 'Benefit') Benefit = get_model('offer', 'Benefit')
Catalog = get_model('catalogue', 'Catalog') Catalog = get_model('catalogue', 'Catalog')
...@@ -33,7 +33,6 @@ VOUCHER_CODE_LENGTH = 1 ...@@ -33,7 +33,6 @@ VOUCHER_CODE_LENGTH = 1
class UtilTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockMixin, TestCase): class UtilTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockMixin, TestCase):
course_id = 'edX/DemoX/Demo_Course' course_id = 'edX/DemoX/Demo_Course'
certificate_type = 'test-certificate-type' certificate_type = 'test-certificate-type'
provider = None provider = None
...@@ -382,10 +381,8 @@ class UtilTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockMixin, TestCase): ...@@ -382,10 +381,8 @@ class UtilTests(CouponMixin, CourseCatalogTestMixin, LmsApiMockMixin, TestCase):
for benefit in benefits: for benefit in benefits:
discount_info = get_voucher_discount_info(benefit, self.seat_price) discount_info = get_voucher_discount_info(benefit, self.seat_price)
if ( if (benefit.type == "Percentage" and benefit.value == 100.00) or \
benefit.type == "Percentage" and benefit.value == 100.00 or (benefit.type == "Absolute" and benefit.value == self.seat_price):
benefit.type == "Absolute" and benefit.value == self.seat_price
):
self.assertEqual(discount_info['discount_percentage'], 100.00) self.assertEqual(discount_info['discount_percentage'], 100.00)
self.assertEqual(discount_info['discount_value'], 100.00) self.assertEqual(discount_info['discount_value'], 100.00)
self.assertFalse(discount_info['is_discounted']) self.assertFalse(discount_info['is_discounted'])
......
...@@ -3,11 +3,12 @@ from django.test import RequestFactory ...@@ -3,11 +3,12 @@ from django.test import RequestFactory
from oscar.core.loading import get_model from oscar.core.loading import get_model
from oscar.test import factories from oscar.test import factories
from ecommerce.coupons.tests.mixins import CouponMixin
from ecommerce.courses.tests.factories import CourseFactory from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin from ecommerce.extensions.catalogue.tests.mixins import CourseCatalogTestMixin
from ecommerce.extensions.voucher.views import CouponReportCSVView from ecommerce.extensions.voucher.views import CouponReportCSVView
from ecommerce.tests.factories import PartnerFactory from ecommerce.tests.factories import PartnerFactory
from ecommerce.tests.mixins import CouponMixin, LmsApiMockMixin from ecommerce.tests.mixins import LmsApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Basket = get_model('basket', 'Basket') Basket = get_model('basket', 'Basket')
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Broadly-useful mixins for use in automated tests.""" """Broadly-useful mixins for use in automated tests."""
import datetime
from decimal import Decimal
import json import json
from decimal import Decimal
import httpretty
import jwt
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.cache import cache from django.core.cache import cache
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.client import RequestFactory from django.test.client import RequestFactory
import httpretty
import jwt
from mock import patch from mock import patch
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import factories from oscar.test import factories
from threadlocals.threadlocals import set_thread_variable
from social.apps.django_app.default.models import UserSocialAuth from social.apps.django_app.default.models import UserSocialAuth
from threadlocals.threadlocals import set_thread_variable
from ecommerce.core.models import BusinessClient
from ecommerce.core.url_utils import get_lms_url from ecommerce.core.url_utils import get_lms_url
from ecommerce.courses.utils import mode_for_seat from ecommerce.courses.utils import mode_for_seat
from ecommerce.extensions.api.constants import APIConstants as AC from ecommerce.extensions.api.constants import APIConstants as AC
from ecommerce.extensions.api.v2.views.coupons import CouponViewSet
from ecommerce.extensions.basket.utils import prepare_basket
from ecommerce.extensions.fulfillment.signals import SHIPPING_EVENT_NAME from ecommerce.extensions.fulfillment.signals import SHIPPING_EVENT_NAME
from ecommerce.tests.factories import PartnerFactory, SiteConfigurationFactory from ecommerce.tests.factories import SiteConfigurationFactory
Applicator = get_class('offer.utils', 'Applicator') Applicator = get_class('offer.utils', 'Applicator')
Basket = get_model('basket', 'Basket') Basket = get_model('basket', 'Basket')
...@@ -252,7 +248,7 @@ class SiteMixin(object): ...@@ -252,7 +248,7 @@ class SiteMixin(object):
domain = 'testserver.fake' domain = 'testserver.fake'
self.client = self.client_class(SERVER_NAME=domain) self.client = self.client_class(SERVER_NAME=domain)
Site.objects.get_current().delete() Site.objects.all().delete()
site_configuration = SiteConfigurationFactory( site_configuration = SiteConfigurationFactory(
partner__name='edX', partner__name='edX',
site__id=settings.SITE_ID, site__id=settings.SITE_ID,
...@@ -313,170 +309,3 @@ class LmsApiMockMixin(object): ...@@ -313,170 +309,3 @@ class LmsApiMockMixin(object):
course_id = course.id if course else 'course-v1:test+test+test' course_id = course.id if course else 'course-v1:test+test+test'
course_url = get_lms_url('api/courses/v1/courses/{}/'.format(course_id)) course_url = get_lms_url('api/courses/v1/courses/{}/'.format(course_id))
httpretty.register_uri(httpretty.GET, course_url, body=course_info_json, content_type='application/json') httpretty.register_uri(httpretty.GET, course_url, body=course_info_json, content_type='application/json')
class CatalogPreviewMockMixin(object):
""" Mocks for the Course Discovery responses. """
def setUp(self):
super(CatalogPreviewMockMixin, self).setUp()
def mock_dynamic_catalog_course_runs_api(self, course_run=None, query=None):
""" Helper function to register a dynamic course catalog API endpoint for the course run information. """
course_run_info = {
'count': 1,
'results': [{
'key': course_run.id,
'title': course_run.name,
}] if course_run else [{
'key': 'test',
'title': 'Test course',
}],
}
course_run_info_json = json.dumps(course_run_info)
course_run_url = '{}course_runs/?q={}'.format(
settings.COURSE_CATALOG_API_URL,
query if query else 'id:course*'
)
httpretty.register_uri(
httpretty.GET, course_run_url,
body=course_run_info_json,
content_type='application/json'
)
def mock_dynamic_catalog_contains_api(self, course_run_ids, query):
""" Helper function to register a dynamic course catalog API endpoint for the contains information. """
course_contains_info = {
'course_runs': {}
}
for course_run_id in course_run_ids:
course_contains_info['course_runs'][course_run_id] = True
course_run_info_json = json.dumps(course_contains_info)
course_run_url = '{}course_runs/contains/?course_run_ids={}&query={}'.format(
settings.COURSE_CATALOG_API_URL,
(course_run_id for course_run_id in course_run_ids),
query if query else 'id:course*'
)
httpretty.register_uri(
httpretty.GET, course_run_url,
body=course_run_info_json,
content_type='application/json'
)
class CouponMixin(object):
""" Mixin for preparing data for coupons and creating coupons. """
REDEMPTION_URL = "/coupons/offer/?code={}"
def setUp(self):
super(CouponMixin, self).setUp()
self.category = factories.CategoryFactory()
# Force the creation of a coupon ProductClass
self.coupon_product_class # pylint: disable=pointless-statement
@property
def coupon_product_class(self):
defaults = {'requires_shipping': False, 'track_stock': False, 'name': 'Coupon'}
pc, created = ProductClass.objects.get_or_create(slug='coupon', defaults=defaults)
if created:
factories.ProductAttributeFactory(
code='coupon_vouchers',
name='Coupon vouchers',
product_class=pc,
type='entity'
)
factories.ProductAttributeFactory(
code='note',
name='Note',
product_class=pc,
type='text'
)
return pc
def create_coupon(
self,
title='Test coupon',
price=100,
client=None,
partner=None,
catalog=None,
code='',
benefit_value=100,
note=None,
max_uses=None,
quantity=5,
catalog_query=None,
course_seat_types=None
):
"""Helper method for creating a coupon.
Arguments:
title(str): Title of the coupon
price(int): Price of the coupon
partner(Partner): Partner used for creating a catalog
catalog(Catalog): Catalog of courses for which the coupon applies
code(str): Custom coupon code
benefit_value(int): The voucher benefit value
catalog_query(str): course query string
course_seat_types(JSONField): List of seat types
Returns:
coupon (Coupon)
"""
if partner is None:
partner = PartnerFactory(name='Tester')
if client is None:
client, __ = BusinessClient.objects.get_or_create(name='Test Client')
if catalog is None and not (catalog_query and course_seat_types):
catalog = Catalog.objects.create(partner=partner)
if code is not '':
quantity = 1
data = {
'partner': partner,
'benefit_type': Benefit.PERCENTAGE,
'benefit_value': benefit_value,
'catalog': catalog,
'end_date': datetime.date(2020, 1, 1),
'code': code,
'quantity': quantity,
'start_date': datetime.date(2015, 1, 1),
'voucher_type': Voucher.SINGLE_USE,
'categories': [self.category],
'note': note,
'max_uses': max_uses,
'catalog_query': catalog_query,
'course_seat_types': course_seat_types,
}
coupon = CouponViewSet().create_coupon_product(
title=title,
price=price,
data=data
)
request = RequestFactory()
request.site = self.site
request.user = factories.UserFactory()
request.COOKIES = {}
self.basket = prepare_basket(request, coupon)
self.response_data = CouponViewSet().create_order_for_invoice(self.basket, coupon_id=coupon.id, client=client)
coupon.client = client
return coupon
def apply_voucher(self, user, site, voucher):
""" Apply the voucher to a basket. """
basket = factories.BasketFactory(owner=user, site=site)
product = voucher.offers.first().benefit.range.all_products()[0]
basket.add_product(product)
basket.vouchers.add(voucher)
Applicator().apply(basket, self.user)
return basket
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment