Commit babdb457 by McKenzie Welter

cache basket_switch_data as product model property

parent 8e27e72a
...@@ -32,7 +32,6 @@ from ecommerce.courses.tests.factories import CourseFactory ...@@ -32,7 +32,6 @@ from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.enterprise.tests.mixins import EnterpriseServiceMockMixin from ecommerce.enterprise.tests.mixins import EnterpriseServiceMockMixin
from ecommerce.entitlements.utils import create_or_update_course_entitlement from ecommerce.entitlements.utils import create_or_update_course_entitlement
from ecommerce.extensions.analytics.utils import translate_basket_line_for_segment from ecommerce.extensions.analytics.utils import translate_basket_line_for_segment
from ecommerce.extensions.basket.utils import get_basket_switch_data
from ecommerce.extensions.catalogue.tests.mixins import DiscoveryTestMixin from ecommerce.extensions.catalogue.tests.mixins import DiscoveryTestMixin
from ecommerce.extensions.offer.utils import format_benefit_value from ecommerce.extensions.offer.utils import format_benefit_value
from ecommerce.extensions.order.utils import UserAlreadyPlacedOrder from ecommerce.extensions.order.utils import UserAlreadyPlacedOrder
...@@ -372,9 +371,9 @@ class BasketSummaryViewTests(EnterpriseServiceMockMixin, DiscoveryTestMixin, Dis ...@@ -372,9 +371,9 @@ class BasketSummaryViewTests(EnterpriseServiceMockMixin, DiscoveryTestMixin, Dis
seat_sku = StockRecord.objects.get(product=seat).partner_sku seat_sku = StockRecord.objects.get(product=seat).partner_sku
ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku
__, partner_sku = get_basket_switch_data(seat) __, partner_sku = seat.basket_switch_data
self.assertEqual(partner_sku, ec_sku) self.assertEqual(partner_sku, ec_sku)
__, partner_sku = get_basket_switch_data(enrollment_code) __, partner_sku = enrollment_code.basket_switch_data
self.assertEqual(partner_sku, seat_sku) self.assertEqual(partner_sku, seat_sku)
@ddt.data( @ddt.data(
......
...@@ -119,42 +119,6 @@ def prepare_basket(request, products, voucher=None): ...@@ -119,42 +119,6 @@ def prepare_basket(request, products, voucher=None):
return basket return basket
def get_basket_switch_data(product):
structure = product.structure
switch_link_text = None
if product.is_enrollment_code_product:
switch_link_text = _('Click here to just purchase an enrollment for yourself')
structure = 'child'
elif product.is_seat_product:
switch_link_text = _('Click here to purchase multiple seats in this course')
structure = 'standalone'
stock_records = StockRecord.objects.filter(
product__course_id=product.course_id,
product__structure=structure
)
# Determine the proper partner SKU to embed in the single/multiple basket switch link
# The logic here is a little confusing. "Seat" products have "certificate_type" attributes, and
# "Enrollment Code" products have "seat_type" attributes. If the basket is in single-purchase
# mode, we are working with a Seat product and must present the 'buy multiple' switch link and
# SKU from the corresponding Enrollment Code product. If the basket is in multi-purchase mode,
# we are working with an Enrollment Code product and must present the 'buy single' switch link
# and SKU from the corresponding Seat product.
partner_sku = None
product_cert_type = getattr(product.attr, 'certificate_type', None)
product_seat_type = getattr(product.attr, 'seat_type', None)
for stock_record in stock_records:
stock_record_cert_type = getattr(stock_record.product.attr, 'certificate_type', None)
stock_record_seat_type = getattr(stock_record.product.attr, 'seat_type', None)
if (product_seat_type and product_seat_type == stock_record_cert_type) or \
(product_cert_type and product_cert_type == stock_record_seat_type):
partner_sku = stock_record.partner_sku
break
return switch_link_text, partner_sku
def attribute_cookie_data(basket, request): def attribute_cookie_data(basket, request):
try: try:
with transaction.atomic(): with transaction.atomic():
......
...@@ -27,7 +27,7 @@ from ecommerce.extensions.analytics.utils import ( ...@@ -27,7 +27,7 @@ from ecommerce.extensions.analytics.utils import (
track_segment_event, track_segment_event,
translate_basket_line_for_segment translate_basket_line_for_segment
) )
from ecommerce.extensions.basket.utils import add_utm_params_to_url, get_basket_switch_data, prepare_basket from ecommerce.extensions.basket.utils import add_utm_params_to_url, prepare_basket
from ecommerce.extensions.offer.utils import format_benefit_value, render_email_confirmation_if_required from ecommerce.extensions.offer.utils import format_benefit_value, render_email_confirmation_if_required
from ecommerce.extensions.order.exceptions import AlreadyPlacedOrderException from ecommerce.extensions.order.exceptions import AlreadyPlacedOrderException
from ecommerce.extensions.partner.shortcuts import get_partner_for_site from ecommerce.extensions.partner.shortcuts import get_partner_for_site
...@@ -270,7 +270,7 @@ class BasketSummaryView(BasketView): ...@@ -270,7 +270,7 @@ class BasketSummaryView(BasketView):
} }
# Get variables for the switch link that toggles from enrollment codes and seat. # Get variables for the switch link that toggles from enrollment codes and seat.
switch_link_text, partner_sku = get_basket_switch_data(line.product) switch_link_text, partner_sku = line.product.basket_switch_data
if line.has_discount: if line.has_discount:
benefit = self.request.basket.applied_offers().values()[0].benefit benefit = self.request.basket.applied_offers().values()[0].benefit
......
import waffle
from django.conf import settings
from django.core.cache import cache
from django.db import models from django.db import models
from django.db.models.signals import post_init, post_save from django.db.models.signals import post_init, post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from oscar.apps.catalogue.abstract_models import AbstractProduct from oscar.apps.catalogue.abstract_models import AbstractProduct
from oscar.core.loading import get_model
from ecommerce.core.cache_utils import CACHE_MISS, safe_cache_get
from ecommerce.core.constants import ( from ecommerce.core.constants import (
COUPON_PRODUCT_CLASS_NAME, COUPON_PRODUCT_CLASS_NAME,
COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME, COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME,
ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_PRODUCT_CLASS_NAME,
SEAT_PRODUCT_CLASS_NAME SEAT_PRODUCT_CLASS_NAME
) )
from ecommerce.core.utils import log_message_and_raise_validation_error from ecommerce.core.utils import get_cache_key, log_message_and_raise_validation_error
StockRecord = get_model('partner', 'StockRecord')
class Product(AbstractProduct): class Product(AbstractProduct):
...@@ -37,6 +45,55 @@ class Product(AbstractProduct): ...@@ -37,6 +45,55 @@ class Product(AbstractProduct):
def is_coupon_product(self): def is_coupon_product(self):
return self.get_product_class().name == COUPON_PRODUCT_CLASS_NAME return self.get_product_class().name == COUPON_PRODUCT_CLASS_NAME
@cached_property
def basket_switch_data(self):
if waffle.switch_is_active("CACHE_BASKET_SWITCH_DATA_FOR_PRODUCT"):
cache_key = get_cache_key(
resource='basket_switch_data',
product_id=self.id,
)
switch_data = safe_cache_get(cache_key)
if switch_data is CACHE_MISS:
switch_data = self._get_basket_switch_data()
cache.set(cache_key, switch_data, settings.BASKET_SWTICH_DATA_CACHE_TIMEOUT)
return switch_data
else:
return self._get_basket_switch_data()
def _get_basket_switch_data(self):
structure = str(self.structure)
switch_link_text = None
if self.is_enrollment_code_product:
switch_link_text = _('Click here to just purchase an enrollment for yourself')
structure = 'child'
elif self.is_seat_product:
switch_link_text = _('Click here to purchase multiple seats in this course')
structure = 'standalone'
stock_records = StockRecord.objects.filter(
product__course_id=self.course_id,
product__structure=structure
)
# Determine the proper partner SKU to embed in the single/multiple basket switch link
# The logic here is a little confusing. "Seat" products have "certificate_type" attributes, and
# "Enrollment Code" products have "seat_type" attributes. If the basket is in single-purchase
# mode, we are working with a Seat product and must present the 'buy multiple' switch link and
# SKU from the corresponding Enrollment Code product. If the basket is in multi-purchase mode,
# we are working with an Enrollment Code product and must present the 'buy single' switch link
# and SKU from the corresponding Seat product.
partner_sku = None
product_cert_type = getattr(self.attr, 'certificate_type', None)
product_seat_type = getattr(self.attr, 'seat_type', None)
for stock_record in stock_records:
stock_record_cert_type = getattr(stock_record.product.attr, 'certificate_type', None)
stock_record_seat_type = getattr(stock_record.product.attr, 'seat_type', None)
if (product_seat_type and product_seat_type == stock_record_cert_type) or \
(product_cert_type and product_cert_type == stock_record_seat_type):
partner_sku = stock_record.partner_sku
break
return switch_link_text, partner_sku
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
try: try:
if not isinstance(self.attr.note, basestring) and self.attr.note is not None: if not isinstance(self.attr.note, basestring) and self.attr.note is not None:
......
...@@ -253,6 +253,9 @@ CREDIT_PROVIDER_CACHE_TIMEOUT = 600 ...@@ -253,6 +253,9 @@ CREDIT_PROVIDER_CACHE_TIMEOUT = 600
# Anonymous User Calculate Cache timeout # Anonymous User Calculate Cache timeout
ANONYMOUS_BASKET_CALCULATE_CACHE_TIMEOUT = 3600 # Value is in seconds. ANONYMOUS_BASKET_CALCULATE_CACHE_TIMEOUT = 3600 # Value is in seconds.
#
BASKET_SWTICH_DATA_CACHE_TIMEOUT = 3600
# LMS API settings used for fetching information from LMS # LMS API settings used for fetching information from LMS
LMS_API_CACHE_TIMEOUT = 30 # Value is in seconds. LMS_API_CACHE_TIMEOUT = 30 # Value is in seconds.
# END URL CONFIGURATION # END URL CONFIGURATION
......
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