Commit 5c92c456 by zubair-arbi

Merge branch 'zub/ENT-1052-apply-enterprise-offer-by-catalog-id' into business/fontina

parents d2efc15e 64d8a379
1. Record Architecture Decisions
--------------------------------
Status
------
Accepted
Context
-------
We would like to keep a historical record on the architectural
decisions we make with this app as it evolves over time.
Decision
--------
We will use Architecture Decision Records, as described by
Michael Nygard in `Documenting Architecture Decisions`_
.. _Documenting Architecture Decisions: http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions
Consequences
------------
See Michael Nygard's article, linked above.
References
----------
* https://resources.sei.cmu.edu/asset_files/Presentation/2017_017_001_497746.pdf
* https://github.com/npryce/adr-tools/tree/master/doc/adr
2. No synchronous server-to-server calls within transactions
------------------------------------------------------------
Status
------
Accepted
Context
-------
The ecommerce service currently makes various synchronous server-to-server calls within transactions. This has led to
both instability of the overall service and performance issues. The stability issues come in part related to the default
atomic transactions and resulting DB Lock Wait Timeout errors that occur.
Decision
--------
We will add no new synchronous server-to-server calls. Unless special permission is granted by `the Elder`_, these issues must be resolved in some other way.
.. _the Elder: https://openedx.atlassian.net/wiki/spaces/ENG/pages/761200984/Ecommerce+Guild+Homepage
Consequences
------------
Additionally, there will need to be an ongoing effort to transition existing synchronous server-to-server calls to the appropriate future design for each case.
Some possible alternative solutions include:
* Moving calls to be asynchronously made from the ecommerce workers
* Passing more required data to an endpoint
* Making multiple calls from the front-end
* Moving data that should belong to ecommerce
* Data redundancy
* Caching data in the JWT
* Other
References
----------
* https://www.reactivemanifesto.org/
......@@ -12,7 +12,7 @@ from factory.fuzzy import FuzzyText
from oscar.core.loading import get_class, get_model
from oscar.test.factories import OrderFactory, OrderLineFactory, RangeFactory, VoucherFactory
from ecommerce.core.url_utils import get_lms_url
from ecommerce.core.url_utils import get_lms_dashboard_url, get_lms_url
from ecommerce.coupons.tests.mixins import CouponMixin, DiscoveryMockMixin
from ecommerce.coupons.views import voucher_is_valid
from ecommerce.enterprise.tests.mixins import EnterpriseServiceMockMixin
......@@ -430,12 +430,15 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
@httpretty.activate
def test_basket_redirect_enrollment_code(self):
""" Verify the view redirects to the receipt page when an enrollment code is provided. """
""" Verify the view redirects to the LMS dashboard when an enrollment code is provided. """
code = self.create_coupon_and_get_code(benefit_value=100, code='', catalog=self.catalog)
self.mock_account_api(self.request, self.user.username, data={'is_active': True})
self.mock_access_token_response()
self.assert_redirects_to_receipt_page(code=code)
self.assert_redemption_page_redirects(
get_lms_dashboard_url(),
code=code,
)
@httpretty.activate
@mock.patch.object(EdxOrderPlacementMixin, 'place_free_order')
......@@ -444,7 +447,7 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
code = self.create_coupon_and_get_code(benefit_value=100, code='', catalog=self.catalog)
self.mock_account_api(self.request, self.user.username, data={'is_active': True})
self.mock_access_token_response()
place_free_order.return_value = Exception
place_free_order.side_effect = Exception
with mock.patch('ecommerce.coupons.views.logger.exception') as mock_logger:
self.assert_redemption_page_redirects(
......@@ -528,7 +531,7 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
@httpretty.activate
def test_enterprise_customer_successful_redemption(self):
""" Verify the view redirects to LMS when valid consent is provided. """
""" Verify the view redirects to the LMS dashboard when valid consent is provided. """
code = self.prepare_enterprise_data(catalog=self.catalog)
self.mock_enterprise_learner_api_for_learner_with_no_enterprise()
self.mock_enterprise_learner_post_api()
......@@ -539,9 +542,10 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
ENTERPRISE_CUSTOMER
)
self.assert_redirects_to_receipt_page(
self.assert_redemption_page_redirects(
get_lms_dashboard_url(),
code=code,
consent_token=consent_token
consent_token=consent_token,
)
last_request = httpretty.last_request()
self.assertEqual(last_request.path, '/api/enrollment/v1/enrollment')
......@@ -595,7 +599,7 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
@httpretty.activate
def test_multiple_vouchers(self):
""" Verify a redirect to LMS happens when a basket with already existing vouchers is used. """
""" Verify a redirect to LMS dashboard happens when a basket with already existing vouchers is used. """
code = self.create_coupon_and_get_code(benefit_value=100, code='', catalog=self.catalog)
basket = Basket.get_basket(self.user, self.site)
basket.vouchers.add(Voucher.objects.get(code=code))
......@@ -603,7 +607,10 @@ class CouponRedeemViewTests(CouponMixin, DiscoveryTestMixin, LmsApiMockMixin, En
self.mock_account_api(self.request, self.user.username, data={'is_active': True})
self.mock_access_token_response()
self.assert_redirects_to_receipt_page(code=code)
self.assert_redemption_page_redirects(
get_lms_dashboard_url(),
code=code,
)
@httpretty.activate
def test_already_enrolled_rejection(self):
......
......@@ -16,7 +16,7 @@ from django.utils.translation import ugettext as _
from django.views.generic import TemplateView, View
from oscar.core.loading import get_class, get_model
from ecommerce.core.url_utils import get_ecommerce_url
from ecommerce.core.url_utils import get_ecommerce_url, get_lms_dashboard_url
from ecommerce.core.views import StaffOnlyMixin
from ecommerce.coupons.decorators import login_required_for_credit
from ecommerce.coupons.utils import is_voucher_applied
......@@ -32,7 +32,6 @@ from ecommerce.enterprise.utils import (
from ecommerce.extensions.api import exceptions
from ecommerce.extensions.basket.utils import prepare_basket
from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin
from ecommerce.extensions.checkout.utils import get_receipt_page_url
from ecommerce.extensions.offer.utils import render_email_confirmation_if_required
from ecommerce.extensions.order.exceptions import AlreadyPlacedOrderException
from ecommerce.extensions.voucher.utils import get_voucher_and_products_from_code
......@@ -154,7 +153,6 @@ class CouponRedeemView(EdxOrderPlacementMixin, View):
code = request.GET.get('code')
sku = request.GET.get('sku')
failure_url = request.GET.get('failure_url')
site_configuration = request.site.siteconfiguration
if not code:
return render(request, template_name, {'error': _('Code not provided.')})
......@@ -238,12 +236,7 @@ class CouponRedeemView(EdxOrderPlacementMixin, View):
return render(request, template_name, {'error': msg})
if basket.total_excl_tax == 0:
try:
order = self.place_free_order(basket)
return HttpResponseRedirect(get_receipt_page_url(site_configuration, order.number))
except: # pylint: disable=bare-except
logger.exception('Failed to create a free order for basket [%d]', basket.id)
return HttpResponseRedirect(reverse('checkout:error'))
return self._handle_free_order(basket)
if enterprise_customer:
if is_voucher_applied(basket, voucher):
......@@ -260,6 +253,14 @@ class CouponRedeemView(EdxOrderPlacementMixin, View):
return HttpResponseRedirect(reverse('basket:summary'))
def _handle_free_order(self, basket):
try:
self.place_free_order(basket)
return HttpResponseRedirect(get_lms_dashboard_url())
except: # pylint: disable=bare-except
logger.exception('Failed to create a free order for basket [%d]', basket.id)
return HttpResponseRedirect(reverse('checkout:error'))
class EnrollmentCodeCsvView(View):
""" Download enrollment code CSV file view. """
......
import datetime
import json
from uuid import uuid4
import ddt
import httpretty
......@@ -16,6 +17,7 @@ from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.entitlements.utils import create_or_update_course_entitlement
from ecommerce.extensions.basket.tests.mixins import BasketMixin
from ecommerce.extensions.basket.utils import (
ENTERPRISE_CATALOG_ATTRIBUTE_TYPE,
add_utm_params_to_url,
attribute_cookie_data,
get_basket_switch_data,
......@@ -417,6 +419,37 @@ class BasketUtilsTests(DiscoveryTestMixin, BasketMixin, TestCase):
# Verify that no exception is raised when no basket attribute exists fitting the delete statement parameters
prepare_basket(request, [product])
def test_prepare_basket_with_enterprise_catalog(self):
"""
Test `prepare_basket` with enterprise catalog.
"""
product = ProductFactory()
request = self.request
expected_enterprise_catalog_uuid = str(uuid4())
request.GET = {'catalog': expected_enterprise_catalog_uuid}
basket = prepare_basket(request, [product])
# Verify that the enterprise catalog attribute exists for the basket
# when basket is prepared with the value of provide catalog UUID
enterprise_catalog_uuid = BasketAttribute.objects.get(
basket=basket,
attribute_type__name=ENTERPRISE_CATALOG_ATTRIBUTE_TYPE
).value_text
assert expected_enterprise_catalog_uuid == enterprise_catalog_uuid
# Now verify that `prepare_basket` method removes the enterprise
# catalog attribute if there is not catalog in url
request.GET = {}
basket = prepare_basket(request, [product])
# Verify that the enterprise catalog attribute exists for the basket
# when basket is prepared with the value of provide catalog UUID
with self.assertRaises(BasketAttribute.DoesNotExist):
BasketAttribute.objects.get(
basket=basket,
attribute_type__name=ENTERPRISE_CATALOG_ATTRIBUTE_TYPE
)
def test_basket_switch_data(self):
"""Verify the correct basket switch data (single vs. multi quantity) is retrieved."""
__, seat, enrollment_code = self.prepare_course_seat_and_enrollment_code()
......
......@@ -23,6 +23,7 @@ BasketAttribute = get_model('basket', 'BasketAttribute')
BasketAttributeType = get_model('basket', 'BasketAttributeType')
BUNDLE = 'bundle_identifier'
ORGANIZATION_ATTRIBUTE_TYPE = 'organization'
ENTERPRISE_CATALOG_ATTRIBUTE_TYPE = 'enterprise_catalog_uuid'
StockRecord = get_model('partner', 'StockRecord')
OrderLine = get_model('order', 'Line')
Refund = get_model('refund', 'Refund')
......@@ -60,6 +61,7 @@ def prepare_basket(request, products, voucher=None):
basket (Basket): Contains the product to be redeemed and the Voucher applied.
"""
basket = Basket.get_basket(request.user, request.site)
basket_add_enterprise_catalog_attribute(basket, request.GET)
basket.flush()
basket.save()
basket_addition = get_class('basket.signals', 'basket_addition')
......@@ -268,6 +270,35 @@ def basket_add_organization_attribute(basket, request_data):
)
@newrelic.agent.function_trace()
def basket_add_enterprise_catalog_attribute(basket, request_data):
"""
Add enterprise catalog UUID attribute on basket, if the catalog UUID value
is provided in the request.
Arguments:
basket(Basket): order basket
request_data (dict): HttpRequest data
"""
# Value of enterprise catalog UUID is being passed as `catalog` from
# basket page
enterprise_catalog_uuid = request_data.get('catalog') if request_data else None
enterprise_catalog_attribute, __ = BasketAttributeType.objects.get_or_create(
name=ENTERPRISE_CATALOG_ATTRIBUTE_TYPE
)
if enterprise_catalog_uuid:
BasketAttribute.objects.update_or_create(
basket=basket,
attribute_type=enterprise_catalog_attribute,
defaults={
'value_text': enterprise_catalog_uuid.strip()}
)
else:
# Remove the enterprise catalog attribute for future update in basket
BasketAttribute.objects.filter(basket=basket, attribute_type=enterprise_catalog_attribute).delete()
def _set_basket_bundle_status(bundle, basket):
"""
Sets the basket's bundle status
......
......@@ -8,11 +8,10 @@ from django.urls import reverse
from oscar.core.loading import get_model
from oscar.test import factories
from ecommerce.core.url_utils import get_lms_courseware_url, get_lms_program_dashboard_url
from ecommerce.core.url_utils import get_lms_courseware_url, get_lms_dashboard_url, get_lms_program_dashboard_url
from ecommerce.coupons.tests.mixins import DiscoveryMockMixin
from ecommerce.enterprise.tests.mixins import EnterpriseServiceMockMixin
from ecommerce.extensions.checkout.exceptions import BasketNotFreeError
from ecommerce.extensions.checkout.utils import get_receipt_page_url
from ecommerce.extensions.checkout.views import ReceiptResponseView
from ecommerce.extensions.refund.tests.mixins import RefundTestMixin
from ecommerce.tests.mixins import LmsApiMockMixin
......@@ -87,19 +86,14 @@ class FreeCheckoutViewTests(EnterpriseServiceMockMixin, TestCase):
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
@httpretty.activate
def test_successful_redirect(self):
""" Verify redirect to the receipt page. """
def test_successful_redirect_dashboard(self):
""" Verify redirect to the dashboard page. """
self.prepare_basket(0)
self.assertEqual(Order.objects.count(), 0)
response = self.client.get(self.path)
self.assertEqual(Order.objects.count(), 1)
order = Order.objects.first()
expected_url = get_receipt_page_url(
order_number=order.number,
site_configuration=order.site.siteconfiguration
)
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
self.assertRedirects(response, get_lms_dashboard_url(), fetch_redirect_response=False)
class CancelCheckoutViewTests(TestCase):
......
......@@ -21,7 +21,6 @@ from ecommerce.core.url_utils import (
from ecommerce.enterprise.utils import has_enterprise_offer
from ecommerce.extensions.checkout.exceptions import BasketNotFreeError
from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin
from ecommerce.extensions.checkout.utils import get_receipt_page_url
Applicator = get_class('offer.applicator', 'Applicator')
Basket = get_model('basket', 'Basket')
......@@ -52,7 +51,7 @@ class FreeCheckoutView(EdxOrderPlacementMixin, RedirectView):
""" View to handle free checkouts.
Retrieves the user's basket and checks to see if the basket is free in which case
the user is redirected to the receipt page. Otherwise the user is redirected back
the user is redirected to the LMS dashboard. Otherwise the user is redirected back
to the basket summary page.
"""
......@@ -90,11 +89,7 @@ class FreeCheckoutView(EdxOrderPlacementMixin, RedirectView):
course_run_id = order.lines.all()[:1].get().product.course.id
url = get_lms_courseware_url(course_run_id)
else:
receipt_path = get_receipt_page_url(
order_number=order.number,
site_configuration=order.site.siteconfiguration
)
url = site.siteconfiguration.build_lms_url(receipt_path)
url = get_lms_dashboard_url()
else:
# If a user's basket is empty redirect the user to the basket summary
# page which displays the appropriate message for empty baskets.
......
......@@ -55,3 +55,5 @@ APPLE_PAY_CYBERSOURCE_CARD_TYPE_MAP = {
STRIPE_CARD_TYPE_MAP = {
value['stripe_brand']: key for key, value in six.iteritems(CARD_TYPES) if 'stripe_brand' in value
}
VOUCHER_VALIDATION_BEFORE_PAYMENT = 'voucher_validation_before_payment'
""" Tests of the Payment Views. """
from __future__ import unicode_literals
import datetime
import json
import ddt
......@@ -8,10 +9,12 @@ import mock
import responses
from django.conf import settings
from django.urls import reverse
from django.utils.timezone import now
from freezegun import freeze_time
from oscar.apps.payment.exceptions import TransactionDeclined
from oscar.core.loading import get_class, get_model
from oscar.test import factories
from waffle.testutils import override_switch
from ecommerce.core.constants import ENROLLMENT_CODE_PRODUCT_CLASS_NAME, ENROLLMENT_CODE_SWITCH
from ecommerce.core.models import BusinessClient
......@@ -21,11 +24,12 @@ from ecommerce.courses.tests.factories import CourseFactory
from ecommerce.extensions.api.serializers import OrderSerializer
from ecommerce.extensions.basket.utils import basket_add_organization_attribute
from ecommerce.extensions.order.constants import PaymentEventTypeName
from ecommerce.extensions.payment.constants import VOUCHER_VALIDATION_BEFORE_PAYMENT
from ecommerce.extensions.payment.exceptions import InvalidBasketError, InvalidSignatureError
from ecommerce.extensions.payment.processors.cybersource import Cybersource
from ecommerce.extensions.payment.tests.mixins import CybersourceMixin, CybersourceNotificationTestsMixin
from ecommerce.extensions.payment.views.cybersource import CybersourceInterstitialView
from ecommerce.extensions.test.factories import create_basket
from ecommerce.extensions.test.factories import create_basket, prepare_voucher
from ecommerce.invoice.models import Invoice
from ecommerce.tests.testcases import TestCase
......@@ -36,9 +40,10 @@ Order = get_model('order', 'Order')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentProcessorResponse = get_model('payment', 'PaymentProcessorResponse')
Product = get_model('catalogue', 'Product')
Selector = get_class('partner.strategy', 'Selector')
Source = get_model('payment', 'Source')
Product = get_model('catalogue', 'Product')
Voucher = get_model('voucher', 'Voucher')
post_checkout = get_class('checkout.signals', 'post_checkout')
......@@ -79,6 +84,16 @@ class CybersourceSubmitViewTests(CybersourceMixin, TestCase):
basket.thaw()
return basket
def _prepare_basket_for_voucher_validation_tests(self, voucher_start_date, voucher_end_date):
""" Prepares basket for voucher validation """
basket = Basket.objects.create(site=self.site, owner=self.user)
voucher, product = prepare_voucher(start_datetime=voucher_start_date, end_datetime=voucher_end_date)
basket.strategy = Selector().strategy()
basket.add_product(product)
basket.vouchers.add(voucher)
basket.thaw()
return basket
def assert_basket_retrieval_error(self, basket_id):
error_msg = 'There was a problem retrieving your basket. Refresh the page to try again.'
return self._assert_basket_error(basket_id, error_msg)
......@@ -179,6 +194,59 @@ class CybersourceSubmitViewTests(CybersourceMixin, TestCase):
errors = json.loads(response.content)['field_errors']
self.assertIn(field, errors)
@override_switch(VOUCHER_VALIDATION_BEFORE_PAYMENT, active=True)
@ddt.data(
(now() - datetime.timedelta(days=3), 400),
(now() + datetime.timedelta(days=3), 200))
@ddt.unpack
def test_submit_view_fails_for_invalid_voucher(self, voucher_end_time, status_code):
""" Verify SubmitPaymentView fails if basket invalid voucher"""
# Create Basket and payment data
voucher_start_time = now() - datetime.timedelta(days=5)
basket = self._prepare_basket_for_voucher_validation_tests(voucher_start_time, voucher_end_time)
data = self._generate_data(basket.id)
response = self.client.post(self.path, data)
self.assertEqual(response.status_code, status_code)
self.assertEqual(response['content-type'], JSON)
@override_switch(VOUCHER_VALIDATION_BEFORE_PAYMENT, active=True)
@mock.patch(
'ecommerce.extensions.voucher.models.Voucher.is_available_to_user',
return_value=(False, None)
)
def test_submit_view_fails_if_voucher_not_available(self, mock_is_available_to_user):
""" Verify SubmitPaymentView fails if basket voucher not available to student"""
# Create Basket and payment data
voucher_start_time = now() - datetime.timedelta(days=1)
voucher_end_time = now() + datetime.timedelta(days=3)
basket = self._prepare_basket_for_voucher_validation_tests(voucher_start_time, voucher_end_time)
data = self._generate_data(basket.id)
response = self.client.post(self.path, data)
self.assertEqual(response.status_code, 400)
self.assertEqual(response['content-type'], JSON)
self.assertEqual(mock_is_available_to_user.call_count, 3)
@override_switch(VOUCHER_VALIDATION_BEFORE_PAYMENT, active=False)
def test_successful_submit_view_with_voucher_switch_disabled(self):
"""
Temporary test to confirm the problem with SubmitPaymentView
Accepting an invalid voucher when the waffle switch is False.
This will be cleaned up in LEARNER-5719.
"""
voucher_start_time = now() - datetime.timedelta(days=5)
voucher_end_time = now() - datetime.timedelta(days=3)
basket = self._prepare_basket_for_voucher_validation_tests(voucher_start_time, voucher_end_time)
data = self._generate_data(basket.id)
response = self.client.post(self.path, data)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['content-type'], JSON)
@ddt.ddt
class CybersourceInterstitialViewTests(CybersourceNotificationTestsMixin, TestCase):
......
......@@ -32,9 +32,11 @@ Order = get_model('order', 'Order')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentEventType = get_model('order', 'PaymentEventType')
PaymentProcessorResponse = get_model('payment', 'PaymentProcessorResponse')
Product = get_model('catalogue', 'Product')
Selector = get_class('partner.strategy', 'Selector')
SourceType = get_model('payment', 'SourceType')
Product = get_model('catalogue', 'Product')
Voucher = get_model('voucher', 'Voucher')
post_checkout = get_class('checkout.signals', 'post_checkout')
......
......@@ -2,6 +2,7 @@ import abc
import logging
import six
import waffle
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.utils.decorators import method_decorator
......@@ -10,6 +11,7 @@ from django.views.generic import TemplateView, View
from oscar.core.loading import get_class, get_model
from ecommerce.core.url_utils import get_lms_url
from ecommerce.extensions.payment.constants import VOUCHER_VALIDATION_BEFORE_PAYMENT
from ecommerce.extensions.payment.forms import PaymentForm
logger = logging.getLogger(__name__)
......@@ -65,7 +67,7 @@ class BasePaymentSubmitView(View):
form_kwargs = self.get_form_kwargs()
form = self.form_class(**form_kwargs)
if form.is_valid():
if form.is_valid() and self.check_valid_voucher():
return self.form_valid(form)
else:
return self.form_invalid(form)
......@@ -77,6 +79,27 @@ class BasePaymentSubmitView(View):
'request': self.request,
}
def check_valid_voucher(self):
"""
LEARNER-5603 Hot fix
Learners are able to bypass the basket views and pay using the
expired vouchers. This will disable students from doing so.
(https://github.com/django-oscar/django-oscar/blob/master/src/oscar/apps/order/utils.py#L68-L70)
# TODO: LEARNER-5719: Clean-up validation code as needed after further investigation.
"""
if waffle.switch_is_active(VOUCHER_VALIDATION_BEFORE_PAYMENT):
basket = self.request.basket
for voucher in basket.vouchers.select_for_update():
available_to_user, __ = voucher.is_available_to_user(user=self.request.user)
if not available_to_user or not voucher.is_active():
logger.info(
'[%s] basket was checked out with invalid voucher [%s]',
basket.id,
voucher.code,
)
return False
return True
@abc.abstractmethod
def form_valid(self, form):
""" Perform payment processing after validating the form submission. """
......
......@@ -145,13 +145,13 @@ define([
var applePayBtn = document.getElementById('applePayBtn');
if (canMakePayments) {
console.log('Learner is eligible for Apple Pay');
console.log('Learner is eligible for Apple Pay'); // eslint-disable-line no-console
// Display the button
applePayBtn.style.display = 'inline-flex';
applePayBtn.addEventListener('click', self.onApplePayButtonClicked.bind(self));
} else {
console.log('Apple Pay not setup.');
console.log('Apple Pay not setup.'); // eslint-disable-line no-console
}
}
);
......@@ -198,7 +198,7 @@ define([
onApplePayValidateMerchant: function(event) {
var self = this;
console.log('Validating merchant...');
console.log('Validating merchant...'); // eslint-disable-line no-console
$.ajax({
method: 'POST',
......@@ -209,17 +209,17 @@ define([
data: JSON.stringify({url: event.validationURL}),
contentType: 'application/json',
success: function(data) {
console.log('Merchant validation succeeded.');
console.log(data);
console.log('Merchant validation succeeded.'); // eslint-disable-line no-console
console.log(data); // eslint-disable-line no-console
self.applePaySession.completeMerchantValidation(data);
},
error: function(jqXHR, textStatus, errorThrown) {
// Translators: Do not translate "Apple Pay".
var msg = gettext('Apple Pay is not available at this time. Please try another payment method.');
console.log('Merchant validation failed!');
console.log(textStatus);
console.log(errorThrown);
console.log('Merchant validation failed!'); // eslint-disable-line no-console
console.log(textStatus); // eslint-disable-line no-console
console.log(errorThrown); // eslint-disable-line no-console
self.applePaySession.abort();
self.displayErrorMessage(msg);
......@@ -229,7 +229,7 @@ define([
onApplePayPaymentAuthorized: function(event) {
var self = this;
console.log('Submitting Apple Pay payment to CyberSource...');
console.log('Submitting Apple Pay payment to CyberSource...'); // eslint-disable-line no-console
$.ajax({
method: 'POST',
......@@ -240,8 +240,7 @@ define([
data: JSON.stringify(event.payment),
contentType: 'application/json',
success: function(data) {
console.log('Successfully submitted Apple Pay payment to CyberSource.');
console.log(data);
console.log(data); // eslint-disable-line no-console
self.applePaySession.completePayment(ApplePaySession.STATUS_SUCCESS);
self.redirectToReceipt(data.number);
},
......@@ -249,9 +248,8 @@ define([
var msg = gettext('An error occurred while processing your payment. You have NOT been charged. ' +
'Please try again, or select another payment method.');
console.log('Failed to submit Apple Pay payment to CyberSource!');
console.log(textStatus);
console.log(errorThrown);
console.log(textStatus); // eslint-disable-line no-console
console.log(errorThrown); // eslint-disable-line no-console
self.applePaySession.completePayment(ApplePaySession.STATUS_FAILURE);
self.displayErrorMessage(msg);
}
......
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