Commit d040ce6e by Matthew Piatetsky

Add site to coupons and respect site when applying coupon

LEARNER-2447
parent 3fa58d2e
...@@ -396,6 +396,7 @@ class CouponMixin(object): ...@@ -396,6 +396,7 @@ class CouponMixin(object):
title=title, title=title,
voucher_type=voucher_type, voucher_type=voucher_type,
program_uuid=program_uuid, program_uuid=program_uuid,
site=self.site
) )
request = RequestFactory() request = RequestFactory()
......
...@@ -113,6 +113,7 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet): ...@@ -113,6 +113,7 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
title=cleaned_voucher_data['title'], title=cleaned_voucher_data['title'],
voucher_type=cleaned_voucher_data['voucher_type'], voucher_type=cleaned_voucher_data['voucher_type'],
program_uuid=cleaned_voucher_data['program_uuid'], program_uuid=cleaned_voucher_data['program_uuid'],
site=self.request.site
) )
except (KeyError, IntegrityError) as error: except (KeyError, IntegrityError) as error:
logger.exception('Coupon creation failed!') logger.exception('Coupon creation failed!')
......
...@@ -37,7 +37,7 @@ from ecommerce.extensions.payment.constants import CLIENT_SIDE_CHECKOUT_FLAG_NAM ...@@ -37,7 +37,7 @@ from ecommerce.extensions.payment.constants import CLIENT_SIDE_CHECKOUT_FLAG_NAM
from ecommerce.extensions.payment.forms import PaymentForm from ecommerce.extensions.payment.forms import PaymentForm
from ecommerce.extensions.payment.tests.processors import DummyProcessor from ecommerce.extensions.payment.tests.processors import DummyProcessor
from ecommerce.extensions.test.factories import create_order, prepare_voucher from ecommerce.extensions.test.factories import create_order, prepare_voucher
from ecommerce.tests.factories import ProductFactory, StockRecordFactory from ecommerce.tests.factories import ProductFactory, SiteFactory, StockRecordFactory
from ecommerce.tests.mixins import ApiMockMixin, LmsApiMockMixin from ecommerce.tests.mixins import ApiMockMixin, LmsApiMockMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
...@@ -814,6 +814,23 @@ class VoucherAddViewTests(LmsApiMockMixin, TestCase): ...@@ -814,6 +814,23 @@ class VoucherAddViewTests(LmsApiMockMixin, TestCase):
VoucherApplication.objects.create(voucher=voucher, user=self.user, order=order) VoucherApplication.objects.create(voucher=voucher, user=self.user, order=order)
self.assert_form_valid_message("Coupon code '{code}' has already been redeemed.".format(code=COUPON_CODE)) self.assert_form_valid_message("Coupon code '{code}' has already been redeemed.".format(code=COUPON_CODE))
def test_voucher_valid_without_site(self):
""" Verify coupon works when the sites on the coupon and request are the same. """
self.mock_access_token_response()
self.mock_account_api(self.request, self.user.username, data={'is_active': True})
__, product = prepare_voucher(code=COUPON_CODE, site=self.request.site)
self.basket.add_product(product)
self.assert_form_valid_message("Coupon code '{code}' added to basket.".format(code=COUPON_CODE))
def test_voucher_not_valid_for_other_site(self):
""" Verify correct error message is returned when coupon is applied against on the wrong site. """
site2 = SiteFactory()
self.mock_access_token_response()
self.mock_account_api(self.request, self.user.username, data={'is_active': True})
voucher, product = prepare_voucher(code=COUPON_CODE, site=site2)
self.basket.add_product(product)
self.assert_form_valid_message("Coupon code '{code}' is not valid for this basket.".format(code=voucher.code))
def test_voucher_not_valid_for_bundle(self): def test_voucher_not_valid_for_bundle(self):
""" Verify correct error message is returned when voucher is used against a bundle. """ """ Verify correct error message is returned when voucher is used against a bundle. """
self.mock_access_token_response() self.mock_access_token_response()
......
...@@ -417,6 +417,15 @@ class VoucherAddView(BaseVoucherAddView): # pylint: disable=function-redefined ...@@ -417,6 +417,15 @@ class VoucherAddView(BaseVoucherAddView): # pylint: disable=function-redefined
messages.error(self.request, message) messages.error(self.request, message)
return return
# Do not allow coupons for one site to be used on another site
request_site = self.request.site
voucher_site = voucher.offers.first().site
if request_site and voucher_site and request_site != voucher_site:
messages.error(
self.request,
_("Coupon code '{code}' is not valid for this basket.").format(code=code))
return
# Do not allow single course run coupons used on bundles. # Do not allow single course run coupons used on bundles.
if self.request.basket.num_lines > 1 and not voucher.offers.first().condition.program_uuid: if self.request.basket.num_lines > 1 and not voucher.offers.first().condition.program_uuid:
messages.error( messages.error(
......
...@@ -134,6 +134,7 @@ class CouponCreationTests(CouponMixin, TestCase): ...@@ -134,6 +134,7 @@ class CouponCreationTests(CouponMixin, TestCase):
title=title, title=title,
voucher_type=Voucher.ONCE_PER_CUSTOMER, voucher_type=Voucher.ONCE_PER_CUSTOMER,
program_uuid=None, program_uuid=None,
site=self.site
) )
def test_custom_code_integrity_error(self): def test_custom_code_integrity_error(self):
......
...@@ -40,6 +40,7 @@ def create_coupon_product( ...@@ -40,6 +40,7 @@ def create_coupon_product(
voucher_type, voucher_type,
course_catalog, course_catalog,
program_uuid, program_uuid,
site
): ):
""" """
Creates a coupon product and a stock record for it. Creates a coupon product and a stock record for it.
...@@ -65,6 +66,7 @@ def create_coupon_product( ...@@ -65,6 +66,7 @@ def create_coupon_product(
title (str): The name of the coupon. title (str): The name of the coupon.
voucher_type (str): Voucher type voucher_type (str): Voucher type
program_uuid (str): Program UUID for the Coupon program_uuid (str): Program UUID for the Coupon
site (site): Site for which the Coupon is created.
Returns: Returns:
A coupon Product object. A coupon Product object.
...@@ -100,6 +102,7 @@ def create_coupon_product( ...@@ -100,6 +102,7 @@ def create_coupon_product(
start_datetime=start_datetime, start_datetime=start_datetime,
voucher_type=voucher_type, voucher_type=voucher_type,
program_uuid=program_uuid, program_uuid=program_uuid,
site=site
) )
except IntegrityError: 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)
......
...@@ -69,7 +69,7 @@ def create_order(number=None, basket=None, user=None, shipping_address=None, # ...@@ -69,7 +69,7 @@ def create_order(number=None, basket=None, user=None, shipping_address=None, #
def prepare_voucher(code='COUPONTEST', _range=None, start_datetime=None, end_datetime=None, benefit_value=100, def prepare_voucher(code='COUPONTEST', _range=None, start_datetime=None, end_datetime=None, benefit_value=100,
benefit_type=Benefit.PERCENTAGE, usage=Voucher.SINGLE_USE, max_usage=None, email_domains=None, benefit_type=Benefit.PERCENTAGE, usage=Voucher.SINGLE_USE, max_usage=None, email_domains=None,
enterprise_customer=None): enterprise_customer=None, site=None):
""" Helper function to create a voucher and add an offer to it that contains a product. """ """ Helper function to create a voucher and add an offer to it that contains a product. """
# NOTE (CCB): We use empty categories here to avoid unique-constraint issues that occur when we use # NOTE (CCB): We use empty categories here to avoid unique-constraint issues that occur when we use
...@@ -109,7 +109,8 @@ def prepare_voucher(code='COUPONTEST', _range=None, start_datetime=None, end_dat ...@@ -109,7 +109,8 @@ def prepare_voucher(code='COUPONTEST', _range=None, start_datetime=None, end_dat
offer_type=ConditionalOffer.VOUCHER, offer_type=ConditionalOffer.VOUCHER,
benefit=benefit, benefit=benefit,
condition=condition, condition=condition,
email_domains=email_domains email_domains=email_domains,
site=site
) )
voucher.offers.add(offer) voucher.offers.add(offer)
return voucher, product return voucher, product
......
...@@ -300,7 +300,7 @@ def generate_coupon_report(coupon_vouchers): ...@@ -300,7 +300,7 @@ def generate_coupon_report(coupon_vouchers):
def _get_or_create_offer( def _get_or_create_offer(
product_range, benefit_type, benefit_value, coupon_id=None, product_range, benefit_type, benefit_value, coupon_id=None,
max_uses=None, offer_number=None, email_domains=None, program_uuid=None max_uses=None, offer_number=None, email_domains=None, program_uuid=None, site=None
): ):
""" """
Return an offer for a catalog with condition and benefit. Return an offer for a catalog with condition and benefit.
...@@ -320,6 +320,7 @@ def _get_or_create_offer( ...@@ -320,6 +320,7 @@ def _get_or_create_offer(
email_domains (str): a comma-separated string of email domains allowed to apply email_domains (str): a comma-separated string of email domains allowed to apply
this offer this offer
program_uuid (str): the Program UUID program_uuid (str): the Program UUID
site (site): Site for which the Coupon is created. Defaults to None.
Returns: Returns:
Offer Offer
...@@ -371,7 +372,8 @@ def _get_or_create_offer( ...@@ -371,7 +372,8 @@ def _get_or_create_offer(
condition=offer_condition, condition=offer_condition,
benefit=offer_benefit, benefit=offer_benefit,
max_global_applications=max_uses, max_global_applications=max_uses,
email_domains=email_domains email_domains=email_domains,
site=site
) )
return offer return offer
...@@ -474,6 +476,7 @@ def create_vouchers( ...@@ -474,6 +476,7 @@ def create_vouchers(
email_domains=None, email_domains=None,
course_catalog=None, course_catalog=None,
program_uuid=None, program_uuid=None,
site=None,
): ):
""" """
Create vouchers. Create vouchers.
...@@ -498,6 +501,7 @@ def create_vouchers( ...@@ -498,6 +501,7 @@ def create_vouchers(
voucher_type (str): Type of voucher. voucher_type (str): Type of voucher.
_range (Range): Product range. Defaults to None. _range (Range): Product range. Defaults to None.
program_uuid (str): Program UUID. Defaults to None. program_uuid (str): Program UUID. Defaults to None.
site (site): Site for which the Coupon is created. Defaults to None.
Returns: Returns:
List[Voucher] List[Voucher]
...@@ -563,7 +567,8 @@ def create_vouchers( ...@@ -563,7 +567,8 @@ def create_vouchers(
coupon_id=coupon.id, coupon_id=coupon.id,
offer_number=num, offer_number=num,
email_domains=email_domains, email_domains=email_domains,
program_uuid=program_uuid program_uuid=program_uuid,
site=site
) )
offers.append(offer) offers.append(offer)
......
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