{"version":3,"file":"jwsdw-basket.js","sources":["../../../../../../../webfrontend/assets/vendor/angularjs/angular-touch.js","../../../../../../../temp/ngAnnotate/assets/modules/basket/app.module.js","../../../../../../../temp/ngAnnotate/assets/modules/basket/app.constants.js","../../../../../../../temp/ngAnnotate/assets/modules/basket/app.controller.js","../../../../../../../temp/ngAnnotate/assets/modules/basket/data.service.js","../../../../../../../temp/ngAnnotate/assets/jwsdw-basket.js"],"sourcesContent":["/**\r\n * @license AngularJS v1.8.0\r\n * (c) 2010-2020 Google, Inc. http://angularjs.org\r\n * License: MIT\r\n */\r\n(function(window, angular) {'use strict';\r\n\r\n/**\r\n * @ngdoc module\r\n * @name ngTouch\r\n * @description\r\n *\r\n * The `ngTouch` module provides helpers for touch-enabled devices.\r\n * The implementation is based on jQuery Mobile touch event handling\r\n * ([jquerymobile.com](http://jquerymobile.com/)). *\r\n *\r\n * See {@link ngTouch.$swipe `$swipe`} for usage.\r\n *\r\n * @deprecated\r\n * sinceVersion=\"1.7.0\"\r\n * The ngTouch module with the {@link ngTouch.$swipe `$swipe`} service and\r\n * the {@link ngTouch.ngSwipeLeft} and {@link ngTouch.ngSwipeRight} directives are\r\n * deprecated. Instead, stand-alone libraries for touch handling and gesture interaction\r\n * should be used, for example [HammerJS](https://hammerjs.github.io/) (which is also used by\r\n * Angular).\r\n */\r\n\r\n// define ngTouch module\r\n/* global ngTouch */\r\nvar ngTouch = angular.module('ngTouch', []);\r\n\r\nngTouch.info({ angularVersion: '1.8.0' });\r\n\r\nfunction nodeName_(element) {\r\n return angular.$$lowercase(element.nodeName || (element[0] && element[0].nodeName));\r\n}\r\n\r\n/* global ngTouch: false */\r\n\r\n /**\r\n * @ngdoc service\r\n * @name $swipe\r\n *\r\n * @deprecated\r\n * sinceVersion=\"1.7.0\"\r\n *\r\n * See the {@link ngTouch module} documentation for more information.\r\n *\r\n * @description\r\n * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe\r\n * behavior, to make implementing swipe-related directives more convenient.\r\n *\r\n * Requires the {@link ngTouch `ngTouch`} module to be installed.\r\n *\r\n * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`.\r\n *\r\n * # Usage\r\n * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element\r\n * which is to be watched for swipes, and an object with four handler functions. See the\r\n * documentation for `bind` below.\r\n */\r\n\r\nngTouch.factory('$swipe', [function() {\r\n // The total distance in any direction before we make the call on swipe vs. scroll.\r\n var MOVE_BUFFER_RADIUS = 10;\r\n\r\n var POINTER_EVENTS = {\r\n 'mouse': {\r\n start: 'mousedown',\r\n move: 'mousemove',\r\n end: 'mouseup'\r\n },\r\n 'touch': {\r\n start: 'touchstart',\r\n move: 'touchmove',\r\n end: 'touchend',\r\n cancel: 'touchcancel'\r\n },\r\n 'pointer': {\r\n start: 'pointerdown',\r\n move: 'pointermove',\r\n end: 'pointerup',\r\n cancel: 'pointercancel'\r\n }\r\n };\r\n\r\n function getCoordinates(event) {\r\n var originalEvent = event.originalEvent || event;\r\n var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];\r\n var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0];\r\n\r\n return {\r\n x: e.clientX,\r\n y: e.clientY\r\n };\r\n }\r\n\r\n function getEvents(pointerTypes, eventType) {\r\n var res = [];\r\n angular.forEach(pointerTypes, function(pointerType) {\r\n var eventName = POINTER_EVENTS[pointerType][eventType];\r\n if (eventName) {\r\n res.push(eventName);\r\n }\r\n });\r\n return res.join(' ');\r\n }\r\n\r\n return {\r\n /**\r\n * @ngdoc method\r\n * @name $swipe#bind\r\n *\r\n * @description\r\n * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an\r\n * object containing event handlers.\r\n * The pointer types that should be used can be specified via the optional\r\n * third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default,\r\n * `$swipe` will listen for `mouse`, `touch` and `pointer` events.\r\n *\r\n * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`\r\n * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw\r\n * `event`. `cancel` receives the raw `event` as its single parameter.\r\n *\r\n * `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is\r\n * watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total\r\n * distance moved in either dimension exceeds a small threshold.\r\n *\r\n * Once this threshold is exceeded, either the horizontal or vertical delta is greater.\r\n * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow.\r\n * - If the vertical distance is greater, this is a scroll, and we let the browser take over.\r\n * A `cancel` event is sent.\r\n *\r\n * `move` is called on `mousemove`, `touchmove` and `pointermove` after the above logic has determined that\r\n * a swipe is in progress.\r\n *\r\n * `end` is called when a swipe is successfully completed with a `touchend`, `mouseup` or `pointerup`.\r\n *\r\n * `cancel` is called either on a `touchcancel` or `pointercancel` from the browser, or when we begin scrolling\r\n * as described above.\r\n *\r\n */\r\n bind: function(element, eventHandlers, pointerTypes) {\r\n // Absolute total movement, used to control swipe vs. scroll.\r\n var totalX, totalY;\r\n // Coordinates of the start position.\r\n var startCoords;\r\n // Last event's position.\r\n var lastPos;\r\n // Whether a swipe is active.\r\n var active = false;\r\n\r\n pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer'];\r\n element.on(getEvents(pointerTypes, 'start'), function(event) {\r\n startCoords = getCoordinates(event);\r\n active = true;\r\n totalX = 0;\r\n totalY = 0;\r\n lastPos = startCoords;\r\n if (eventHandlers['start']) {\r\n eventHandlers['start'](startCoords, event);\r\n }\r\n });\r\n var events = getEvents(pointerTypes, 'cancel');\r\n if (events) {\r\n element.on(events, function(event) {\r\n active = false;\r\n if (eventHandlers['cancel']) {\r\n eventHandlers['cancel'](event);\r\n }\r\n });\r\n }\r\n\r\n element.on(getEvents(pointerTypes, 'move'), function(event) {\r\n if (!active) return;\r\n\r\n // Android will send a touchcancel if it thinks we're starting to scroll.\r\n // So when the total distance (+ or - or both) exceeds 10px in either direction,\r\n // we either:\r\n // - On totalX > totalY, we send preventDefault() and treat this as a swipe.\r\n // - On totalY > totalX, we let the browser handle it as a scroll.\r\n\r\n if (!startCoords) return;\r\n var coords = getCoordinates(event);\r\n\r\n totalX += Math.abs(coords.x - lastPos.x);\r\n totalY += Math.abs(coords.y - lastPos.y);\r\n\r\n lastPos = coords;\r\n\r\n if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) {\r\n return;\r\n }\r\n\r\n // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll.\r\n if (totalY > totalX) {\r\n // Allow native scrolling to take over.\r\n active = false;\r\n if (eventHandlers['cancel']) {\r\n eventHandlers['cancel'](event);\r\n }\r\n return;\r\n } else {\r\n // Prevent the browser from scrolling.\r\n event.preventDefault();\r\n if (eventHandlers['move']) {\r\n eventHandlers['move'](coords, event);\r\n }\r\n }\r\n });\r\n\r\n element.on(getEvents(pointerTypes, 'end'), function(event) {\r\n if (!active) return;\r\n active = false;\r\n if (eventHandlers['end']) {\r\n eventHandlers['end'](getCoordinates(event), event);\r\n }\r\n });\r\n }\r\n };\r\n}]);\r\n\r\n/* global ngTouch: false */\r\n\r\n/**\r\n * @ngdoc directive\r\n * @name ngSwipeLeft\r\n *\r\n * @deprecated\r\n * sinceVersion=\"1.7.0\"\r\n *\r\n * See the {@link ngTouch module} documentation for more information.\r\n *\r\n * @description\r\n * Specify custom behavior when an element is swiped to the left on a touchscreen device.\r\n * A leftward swipe is a quick, right-to-left slide of the finger.\r\n * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag\r\n * too.\r\n *\r\n * To disable the mouse click and drag functionality, add `ng-swipe-disable-mouse` to\r\n * the `ng-swipe-left` or `ng-swipe-right` DOM Element.\r\n *\r\n * Requires the {@link ngTouch `ngTouch`} module to be installed.\r\n *\r\n * @element ANY\r\n * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate\r\n * upon left swipe. (Event object is available as `$event`)\r\n *\r\n * @example\r\n \r\n \r\n
\r\n Some list content, like an email in the inbox\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n angular.module('ngSwipeLeftExample', ['ngTouch']);\r\n \r\n
\r\n */\r\n\r\n/**\r\n * @ngdoc directive\r\n * @name ngSwipeRight\r\n *\r\n * @deprecated\r\n * sinceVersion=\"1.7.0\"\r\n *\r\n * See the {@link ngTouch module} documentation for more information.\r\n *\r\n * @description\r\n * Specify custom behavior when an element is swiped to the right on a touchscreen device.\r\n * A rightward swipe is a quick, left-to-right slide of the finger.\r\n * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag\r\n * too.\r\n *\r\n * Requires the {@link ngTouch `ngTouch`} module to be installed.\r\n *\r\n * @element ANY\r\n * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate\r\n * upon right swipe. (Event object is available as `$event`)\r\n *\r\n * @example\r\n \r\n \r\n
\r\n Some list content, like an email in the inbox\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n angular.module('ngSwipeRightExample', ['ngTouch']);\r\n \r\n
\r\n */\r\n\r\nfunction makeSwipeDirective(directiveName, direction, eventName) {\r\n ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) {\r\n // The maximum vertical delta for a swipe should be less than 75px.\r\n var MAX_VERTICAL_DISTANCE = 75;\r\n // Vertical distance should not be more than a fraction of the horizontal distance.\r\n var MAX_VERTICAL_RATIO = 0.3;\r\n // At least a 30px lateral motion is necessary for a swipe.\r\n var MIN_HORIZONTAL_DISTANCE = 30;\r\n\r\n return function(scope, element, attr) {\r\n var swipeHandler = $parse(attr[directiveName]);\r\n\r\n var startCoords, valid;\r\n\r\n function validSwipe(coords) {\r\n // Check that it's within the coordinates.\r\n // Absolute vertical distance must be within tolerances.\r\n // Horizontal distance, we take the current X - the starting X.\r\n // This is negative for leftward swipes and positive for rightward swipes.\r\n // After multiplying by the direction (-1 for left, +1 for right), legal swipes\r\n // (ie. same direction as the directive wants) will have a positive delta and\r\n // illegal ones a negative delta.\r\n // Therefore this delta must be positive, and larger than the minimum.\r\n if (!startCoords) return false;\r\n var deltaY = Math.abs(coords.y - startCoords.y);\r\n var deltaX = (coords.x - startCoords.x) * direction;\r\n return valid && // Short circuit for already-invalidated swipes.\r\n deltaY < MAX_VERTICAL_DISTANCE &&\r\n deltaX > 0 &&\r\n deltaX > MIN_HORIZONTAL_DISTANCE &&\r\n deltaY / deltaX < MAX_VERTICAL_RATIO;\r\n }\r\n\r\n var pointerTypes = ['touch'];\r\n if (!angular.isDefined(attr['ngSwipeDisableMouse'])) {\r\n pointerTypes.push('mouse');\r\n }\r\n $swipe.bind(element, {\r\n 'start': function(coords, event) {\r\n startCoords = coords;\r\n valid = true;\r\n },\r\n 'cancel': function(event) {\r\n valid = false;\r\n },\r\n 'end': function(coords, event) {\r\n if (validSwipe(coords)) {\r\n scope.$apply(function() {\r\n element.triggerHandler(eventName);\r\n swipeHandler(scope, {$event: event});\r\n });\r\n }\r\n }\r\n }, pointerTypes);\r\n };\r\n }]);\r\n}\r\n\r\n// Left is negative X-coordinate, right is positive.\r\nmakeSwipeDirective('ngSwipeLeft', -1, 'swipeleft');\r\nmakeSwipeDirective('ngSwipeRight', 1, 'swiperight');\r\n\r\n\r\n\r\n})(window, window.angular);","/**\r\n * @namespace jwsdwBasket\r\n */\r\n'use strict';\r\n(function (angular) {\r\n\r\n config.$inject = ['$compileProvider'];\r\n angular.module('jwsdw.basket', [\r\n 'jwsdw.services',\r\n 'jwsdw.ocapi',\r\n 'jwsdw.tracking',\r\n 'jwsdw.util',\r\n 'jwsdw.picker',\r\n 'jwsp.picker',\r\n 'jwsp.picture',\r\n 'ngSanitize',\r\n 'ngTouch'\r\n ]).config(config);\r\n\r\n /**\r\n * Config function that specifies configuration for the jwsdw basket module.\r\n * @param {Object} $compileProvider compile provider disables adding of internal debug info.\r\n * @returns {void}\r\n */\r\n function config($compileProvider) {\r\n $compileProvider.debugInfoEnabled(false);\r\n }\r\n}(angular));","'use strict';\r\n\r\n(function (angular, window) {\r\n\r\n angular\r\n .module('jwsdw.basket')\r\n .constant('BASKET_ID', window.jwsdwSettings.basket.id)\r\n .constant('LIST_PRICE_BOOK', window.jwsdwSettings.listPriceBook)\r\n .constant('SALE_PRICE_BOOK', window.jwsdwSettings.salePriceBook)\r\n .constant('IMAGE_BASE_URL', window.jwsdwSettings.productGetImageBaseUrl)\r\n .constant('SETTINGS', window.jwsdwSettings);\r\n}(angular, window));","'use strict';\r\n\r\n(function (angular) {\r\n BasketController.$inject = ['$scope', '$log', '$anchorScroll', '$window', '$location', '$timeout', 'dataService', 'productService', 'basketService', 'contentService', 'BASKET_ID', 'SETTINGS', 'trackAddToBasketService'];\r\n angular\r\n .module('jwsdw.basket')\r\n .config(['$locationProvider', function($locationProvider) {\r\n $locationProvider.html5Mode(true);\r\n // $locationProvider.hashPrefix('?');\r\n }])\r\n .controller('BasketController', BasketController);\r\n\r\n /**\r\n * @class jwsdwBasket.BasketController\r\n * @description Method to initialize the basket page functionality\r\n * @param {Object} $scope current scope\r\n * @param {Object} $log log service that provides logging in angluar\r\n * @param {Object} $anchorScroll service to allow scrolling on the page\r\n * @param {Object} $window browser window object\r\n * @param {Object} $location browser location object\r\n * @param {Object} $timeout angular timeout service\r\n * @param {Object} dataService service to provide access data layer of the basket\r\n * @param {Object} productService service to provide product information (used for creation of variants item)\r\n * @param {Object} basketService service to provide basket information\r\n * @param {Object} contentService service to provide content information via OCAPI\r\n * @param {String} BASKET_ID basket id of the current basket provided through demandware backend (window.jwsdwSettings) and loaded into the module as constant\r\n * @param {String} SETTINGS window jwsdwSettings\r\n * @param {Object} trackAddToBasketService trackAddToBasketService\r\n * @constructor\r\n */\r\n function BasketController($scope, $log, $anchorScroll, $window, $location, $timeout, dataService, productService, basketService, contentService, BASKET_ID, SETTINGS, trackAddToBasketService) { // eslint-disable-line max-len, max-params, max-statements\r\n var vm = this;\r\n\r\n vm.dataService = dataService;\r\n vm.productService = productService;\r\n\r\n vm.proceedingToCheckout = false;\r\n vm.proceedingToDirectCheckout = false;\r\n\r\n vm.openBonusPointsInfoPicker = openBonusPointsInfoPicker;\r\n\r\n vm.updating = false;\r\n vm.sessionError = false;\r\n vm.invalidProductError = false;\r\n vm.quantityError = false;\r\n vm.bonusProductActive = true;\r\n vm.couponCode = '';\r\n vm.gPayLoaded = false;\r\n vm.maxCartQuantityPerItem = SETTINGS.maxCartQuantityPerItem;\r\n vm.quantityOptions = [];\r\n vm.couponInputRevealed = false;\r\n vm.recommendedProductDismissed = false;\r\n vm.recommendedProductObserver = null;\r\n vm.refusalReason = $location.search().reason || undefined;\r\n\r\n /* Wishlist handling */\r\n vm.wishlistCount = SETTINGS.wishlistCount || 0;\r\n vm.maxWishlistItemsForGuest = SETTINGS.maxWishlistItemsForGuest || 0;\r\n vm.wishlist = SETTINGS.wishlist;\r\n\r\n //public methods\r\n vm.removeItem = removeItem;\r\n vm.onRemoveButtonClick = onRemoveButtonClick;\r\n vm.onRemoveCancelButtonClick = onRemoveCancelButtonClick;\r\n vm.updateQuantity = updateQuantity;\r\n vm.updateProduct = updateProduct;\r\n vm.addCoupon = addCoupon;\r\n vm.removeCoupon = removeCoupon;\r\n vm.removeBonusCoupon = removeBonusCoupon;\r\n vm.toggleBonusProduct = toggleBonusProduct;\r\n vm.checkout = checkout;\r\n vm.directCheckout = directCheckout;\r\n vm.onEditButtonClick = onEditButtonClick;\r\n vm.openPriceOverridePicker = openPriceOverridePicker;\r\n vm.openVoucherPicker = openVoucherPicker;\r\n vm.onMoveToWishlistButtonClick = onMoveToWishlistButtonClick;\r\n vm.onMoveToWishlistCancelButtonClick = onMoveToWishlistCancelButtonClick;\r\n vm.moveItemToWishlist = moveItemToWishlist;\r\n vm.toggleCouponInput = toggleCouponInput;\r\n vm.addRecommendedProduct = addRecommendedProduct;\r\n vm.addBonusItem = addBonusItem;\r\n vm.onRemoveRecommButtonClick = onRemoveRecommButtonClick;\r\n\r\n /**\r\n * @description Method to run the initialization of the basket module\r\n * @returns {void}\r\n */\r\n this.$onInit = function () {\r\n dataService.init(function() {\r\n if ($location.search().openPicker === 'bonusPointsInfoPicker') {\r\n openBonusPointsInfoPicker();\r\n\r\n if (_browserSupportsHistoryAPI()) {\r\n $location.search('openPicker', null);\r\n } else {\r\n $window.location.href = $window.location.pathname;\r\n }\r\n }\r\n\r\n vm.errorMessage = dataService.errorMessages();\r\n\r\n // check for invalid products\r\n dataService.productItems().forEach(function(product) {\r\n if (!product.hasOwnProperty('price') || typeof product.price !== 'number') {\r\n removeItem(product);\r\n vm.invalidProductError = true;\r\n\r\n if (product.isBonusProduct) {\r\n // prevent bonusproduct selection picker from reappearing\r\n $window.sessionStorage.setItem('jwsdw-choiceOfBonusProductPicker', 'hide');\r\n }\r\n }\r\n });\r\n\r\n if (dataService.recommendedProductItem() && !vm.recommendedProductObserver) {\r\n _initObserver(dataService.recommendedProductItem());\r\n }\r\n\r\n if (!vm.gPayLoaded && window.googlePay && dataService.applicablePaymentMethods().indexOf('GOOGLE_PAY') > -1) {\r\n $.getScript(\"https://pay.google.com/gp/p/js/pay.js\", function() {\r\n vm.gPayLoaded = true;\r\n window.googlePay.onLoaded();\r\n });\r\n }\r\n\r\n /*\r\n Logic to first show the order limit reached message as a general banner on the basket page when first landing on it,\r\n whether it's due to the reason URL param or from pdict information.\r\n */\r\n if (vm.refusalReason === undefined) {\r\n vm.refusalReason = dataService.refusalReason();\r\n }\r\n\r\n /*\r\n The general banner disappears once the order limit is not an issue anymore.\r\n If the limit is an issue again (eg. if the customer updates a product's quantity), then the order limit message is shown above the 'Checkout' button\r\n */\r\n if (vm.refusalReason === 'orderLimit' && !dataService.orderLimitReached()) {\r\n vm.refusalReason = null;\r\n\r\n if ($location.search().reason) {\r\n $location.search('reason', null).replace();\r\n }\r\n }\r\n\r\n vm.orderLimitMsg = dataService.orderLimitMsg();\r\n vm.showShippingNotification = dataService.showShippingNotification();\r\n\r\n updateProgressBar();\r\n });\r\n\r\n populateCartQuantityOptions();\r\n\r\n // listen to the 'sessionExpired' event broadcasted by the mediator\r\n $window.jwsdwMediator.subscribe('sessionExpired', function() {\r\n $anchorScroll();\r\n vm.sessionError = true;\r\n });\r\n\r\n // listen to the 'updateBasket' event broadcasted by the mediator\r\n $window.jwsdwMediator.subscribe('updateBasket', function() {\r\n dataService.init();\r\n });\r\n\r\n // listen to the 'updateBasket' event broadcasted by the mediator\r\n $window.jwsdwMediator.subscribe('updateBasketProduct', function(data) {\r\n updateProduct(data.itemId, data.initialProductId, data.variantId, data.quantity, data.product);\r\n });\r\n\r\n\r\n // listen to the 'updateBonusProduct' event broadcasted by the mediator\r\n $window.jwsdwMediator.subscribe('updateBonusProduct', function(data) {\r\n updateBonusProduct(data.itemId, data.initialProductId, data.variantId, data.product);\r\n });\r\n\r\n /* Update basket quantity dynamically */\r\n $window.jwsdwMediator.subscribe('setCartCount', function(cartQuantity) {\r\n vm.productCount = cartQuantity;\r\n });\r\n\r\n //if data service publishes a qunatity error the view model parameter is set to true as well\r\n $scope.$watch(function () {\r\n return dataService.quantityError;\r\n }, function () {\r\n vm.quantityError = dataService.quantityError;\r\n });\r\n };\r\n\r\n /**\r\n * Method that is triggered if user clicks edit button for a product.\r\n * It broadcasts the 'openPicker' event for 'variationPicker' with the product as payload.\r\n * The Listener is registered in the variationPicker.controller.js\r\n * @param {Object} product the product which should be edited\r\n * @param {Boolean} isBonus optional parameter, true if current product is of type bonus\r\n * @returns {void}\r\n */\r\n function onEditButtonClick(product, isBonus) {\r\n $window.jwsdwMediator.publish('openPicker', 'variationPicker', {\r\n 'product': product,\r\n 'dataService': dataService,\r\n 'isBonus': isBonus\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to open the product remove overlay.\r\n * @param {Object} product - The product which should be removed.\r\n * @returns {undefined}\r\n */\r\n function onRemoveButtonClick(product) {\r\n product.markedForRemoval = true;\r\n }\r\n\r\n /**\r\n * @description Method to add multiple items to the basket.\r\n * @param {Object} recommendedProduct recommended product object\r\n * @returns {undefined}\r\n */\r\n function _initObserver(recommendedProduct) {\r\n $timeout(() => {\r\n let recommendationBlock;\r\n let observer = new IntersectionObserver(entries => {\r\n entries.forEach(entry => {\r\n if (entry.isIntersecting) {\r\n let sendEvent = trackAddToBasketService.sendRecommendedProductImpressions.bind(this, recommendedProduct, 1);\r\n $window.jwsdwApi.tracking.ensureConsent(sendEvent);\r\n observer.disconnect();\r\n }\r\n });\r\n }, {\r\n 'root': null,\r\n 'rootMargin': '0px',\r\n 'threshold': 1.0\r\n });\r\n\r\n recommendationBlock = document.getElementById('recommendationBlock');\r\n observer.observe(recommendationBlock);\r\n vm.recommendedProductObserver = true;\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to open the product move to wishlist overlay.\r\n * @param {Object} product - The product which should be moved to the wishlist.\r\n * @returns {undefined}\r\n */\r\n function onMoveToWishlistButtonClick(product) {\r\n product.markedForWishlist = true;\r\n }\r\n\r\n /**\r\n * @description Method to close the product remove overlay.\r\n * @param {Object} product - The product whose removal overlay should be closed.\r\n * @returns {undefined}\r\n */\r\n function onRemoveCancelButtonClick(product) {\r\n product.markedForRemoval = false;\r\n }\r\n\r\n /**\r\n * @description Method to close the product move to wishlist overlay.\r\n * @param {Object} product - The product whose move to wishlist overlay should be closed.\r\n * @returns {undefined}\r\n */\r\n function onMoveToWishlistCancelButtonClick(product) {\r\n product.markedForWishlist = false;\r\n }\r\n\r\n /**\r\n * @description Method to trigger removal of a product from the basket. This method triggers the basket service.\r\n * @param {Object} product - The product which should be removed from the basket.\r\n * @param {boolean} markForRemoval - Boolean parameter to determine whether to also mark the product for removal.\r\n * @returns {void}\r\n */\r\n function removeItem(product, markForRemoval) {\r\n if (markForRemoval) {\r\n product.markedForRemoval = true;\r\n }\r\n\r\n product.removing = true;\r\n\r\n basketService.removeItem(product.basketItemId).then((basketData) => {\r\n product.removed = true;\r\n product.removing = false;\r\n $timeout(() => {\r\n product.tileHeight = angular.element(`[data-item-id=${product.basketItemId}]`).outerHeight() + 'px';\r\n product.fadeOut = true;\r\n $timeout(() => {\r\n dataService.basketSuccess(basketData);\r\n }, 1000);\r\n }, 2000);\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to trigger removal of a product from the basket and its addition to the wishlist. This method triggers the basket service.\r\n * @param {Object} product - The product which should be moved to the wishlist.\r\n * @returns {undefined}\r\n */\r\n function moveItemToWishlist(product) {\r\n product.movingToWishlist = true;\r\n\r\n if (!window.jwsdwSettings.customerAuthenticated && vm.wishlistCount === vm.maxWishlistItemsForGuest) {\r\n product.movingToWishlist = false;\r\n window.jwsdwMediator.publish('openPicker', 'loginPicker', {\r\n 'showMaxGuestWishlistMessage': true,\r\n 'callback': function() {\r\n moveItemToWishlist(product);\r\n }\r\n });\r\n return;\r\n }\r\n\r\n productService.addToWishlist(product.id).then(addToWishlistSuccess, addToWishlistError);\r\n\r\n /**\r\n * @description Method on success\r\n * @param {Object} data response data\r\n * @returns {undefined}\r\n */\r\n function addToWishlistSuccess(data) {\r\n vm.wishlist.products.push({\r\n 'id': data.itemId,\r\n 'pid': data.productId,\r\n 'color': data.color\r\n });\r\n\r\n window.jwsdwMediator.publish('setWishlistCount', data.items);\r\n\r\n basketService.removeItem(product.basketItemId).then((basketData) => {\r\n product.movedToWishlist = true;\r\n product.movingToWishlist = false;\r\n $timeout(() => {\r\n product.tileHeight = angular.element(`[data-item-id=${product.basketItemId}]`).outerHeight() + 'px';\r\n product.fadeOut = true;\r\n $timeout(() => {\r\n dataService.basketSuccess(basketData);\r\n }, 1000);\r\n }, 2000);\r\n });\r\n }\r\n\r\n /**\r\n * @description Method on error\r\n * @returns {undefined}\r\n */\r\n function addToWishlistError() {\r\n product.movingToWishlist = false;\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to trigger update of a product quantity in the basket.\r\n * This method checks if the new quantity is valid and then triggers the basket service.\r\n * @param {Object} product - The basket product for which the quantity should be updated.\r\n * @returns {undefined}\r\n */\r\n function updateQuantity(product) {\r\n if (dataService.checkValidQuantity(product.basketItemId, product.quantity, product.stock)) {\r\n _refreshProductView(\r\n product,\r\n basketService\r\n .updateQuantity(product.basketItemId, product.quantity)\r\n .then(dataService.basketSuccess)\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to update a product via the variation picker using the basketService. The method checks if the product changed\r\n * and then adds the new product to the basket and then removes the old one.\r\n * @param {String} itemId itemId\r\n * @param {String} initialProductId initialProductId\r\n * @param {String} variantId Id of the variant that should replace the old product\r\n * @param {Number} quantity quantity for the product. This is the same if enough stock is available for the\r\n * new variant otherwise the maximum stock will be used.\r\n * @param {Object} product the product object of the new variant\r\n * @returns {void}\r\n */\r\n function updateProduct(itemId, initialProductId, variantId, quantity, product) {\r\n if (initialProductId !== variantId) {\r\n basketService.addItem(variantId, quantity, product).then(function() {\r\n _refreshBasketView(\r\n basketService\r\n .removeItem(itemId)\r\n .then(dataService.basketSuccess)\r\n );\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to update a bonus product via the variation picker using the basketService. The method checks if the product changed\r\n * and then adds the new product to the basket and then removes the old one.\r\n * @param {String} itemId itemId\r\n * @param {String} initialProductId initialProductId\r\n * @param {String} variantId Id of the variant that should replace the old product\r\n * @param {Object} product the product object of the new variant\r\n * @returns {void}\r\n */\r\n function updateBonusProduct(itemId, initialProductId, variantId, product) {\r\n if (initialProductId !== variantId) {\r\n basketService.removeItem(itemId).then(function() {\r\n _refreshBasketView(\r\n basketService\r\n .addBonusItem(variantId, product)\r\n .then(dataService.basketSuccess)\r\n );\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to add a recommended product to basket\r\n * @param {String} productID productID\r\n * @param {String} quantity quantity\r\n * @param {Object} product product\r\n * @returns {void}\r\n */\r\n function addRecommendedProduct(productID, quantity, product) {\r\n _refreshBasketView(\r\n basketService\r\n .addItem(productID, quantity, product, true)\r\n .then(dataService.basketSuccess)\r\n );\r\n vm.recommendedProductDismissed = true;\r\n }\r\n\r\n /**\r\n * @description Method to add a bonus product to basket\r\n * @param {String} productID productID\r\n * @param {Object} product product\r\n * @returns {void}\r\n */\r\n function addBonusItem(productID, product) {\r\n _refreshBasketView(\r\n basketService\r\n .addBonusItem(productID, product)\r\n .then(dataService.basketSuccess)\r\n );\r\n vm.isRemovedBonusProduct = false;\r\n }\r\n\r\n /**\r\n * @description Method to remove a recommended product block\r\n * @returns {void}\r\n */\r\n function onRemoveRecommButtonClick() {\r\n vm.recommendedProductDismissed = true;\r\n }\r\n\r\n /**\r\n * @description Method to add a coupon to the basket using the basketService.\r\n * The logic first tries to add the coupon as entered by the user.\r\n * If the request fails it retries with uppercase and lowercase variants of the coupon.\r\n * @returns {void}\r\n */\r\n function addCoupon() {\r\n // logic tries the coupon code as it was entered by the user\r\n // if no matching code can be found tries uppercase and lowercase versions of the code\r\n // if still no code is found an error message is displayed\r\n\r\n // frontend validation\r\n if (!$('.jwsdw-basket-couponArea-form').valid()) {\r\n return;\r\n }\r\n\r\n _refreshBasketView(\r\n basketService\r\n .addCoupon(vm.couponCode)\r\n .then(couponSuccess, couponError)\r\n );\r\n }\r\n\r\n /**\r\n * @description Method to handle successful responses from the add coupon code function.\r\n * It handles if and how coupons are displayed in the basket and shows errors otherwise.\r\n * Cases:\r\n * valid and applied - coupon is displayed as applied\r\n * valid and not applied - coupon is displayed as not applied\r\n * not valid - error no coupon is displayed, error message coupon not found\r\n * @param {Object} basketData current basket data\r\n * @returns {void}\r\n */\r\n function couponSuccess(basketData) {\r\n var couponItem;\r\n\r\n dataService.basketSuccess(basketData);\r\n couponItem = dataService.couponItems()\r\n .concat(dataService.couponGiftCertificateItems())\r\n .find(function(coupon) {\r\n return coupon.code.toUpperCase() === vm.couponCode.toUpperCase();\r\n });\r\n\r\n //check the status of the received coupon\r\n if (couponItem && couponItem.valid) {\r\n vm.couponCode = '';\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to handle unsuccessful responses for coupon code calls.\r\n * @param {Object} errorData current error data\r\n * @returns {void}\r\n */\r\n function couponError(errorData) {\r\n $('.jwsdw-basket-couponArea-form').validate().showErrors({\r\n \"basketCouponCode\": errorData.details.message\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to remove a coupon from the basket using the basketService.\r\n * @param {String} couponId id of the coupon that should be removed\r\n * @returns {void}\r\n */\r\n function removeCoupon(couponId) {\r\n _refreshBasketView(\r\n basketService\r\n .removeCoupon(couponId)\r\n .then(dataService.basketSuccess)\r\n );\r\n }\r\n\r\n /**\r\n * @description Method to remove a coupon from the basket using the basketService.\r\n * @param {String} couponCode coupon code that should be removed\r\n * @returns {void}\r\n */\r\n function removeBonusCoupon(couponCode) {\r\n basketService.removeBonusCoupon(couponCode).then(dataService.basketSuccess);\r\n }\r\n\r\n /**\r\n * @description Method to open the price override picker. It calculates the adjusted product pice without previous manual adjustments.\r\n * @param {Object} product the product which should be edited\r\n * @returns {void}\r\n */\r\n function openPriceOverridePicker(product) {\r\n var regex = new RegExp('\\\\d{5,7}-\\\\d-' + product.id),\r\n adjustmentTotal = 0,\r\n manualAdjustments = product.priceAdjustments.filter(function (priceAdjustment) {\r\n $log.info('regexp: ' + regex.toString());\r\n $log.info('adjustment: ' + priceAdjustment.promotionId);\r\n $log.info('adjustment matches: ' + regex.test(priceAdjustment.promotionId));\r\n return regex.test(priceAdjustment.promotionId);\r\n });\r\n\r\n manualAdjustments.forEach(function (manualAdjustment) {\r\n adjustmentTotal = adjustmentTotal + (manualAdjustment.price * -1);\r\n });\r\n\r\n window.jwsdwMediator.publish('openPicker', 'priceOverridePicker', {\r\n 'productId': product.id,\r\n 'oldPrice': adjustmentTotal > 0 ? product.priceAfterItemDiscount + adjustmentTotal : product.priceAfterItemDiscount\r\n });\r\n }\r\n\r\n\r\n /**\r\n * Method open info picker with Checkout-redeem-coupons content\r\n * @returns {void}\r\n */\r\n function openVoucherPicker() {\r\n contentService.getContent('Checkout-redeem-coupons').then(success, error);\r\n\r\n /**\r\n * Method called on success\r\n * @param {Object} response response object\r\n * @returns {void}\r\n */\r\n function success(response) {\r\n $window.jwsdwMediator.publish('openPicker', 'infoPicker', {\r\n 'width': 1,\r\n 'content': response.content,\r\n 'isVisible': true,\r\n 'level': 2\r\n });\r\n }\r\n\r\n /**\r\n * Method called on error\r\n * @param {Object} err error object\r\n * @returns {void}\r\n */\r\n function error(err) {\r\n $log.error('Could not fetch content asset \"Checkout-redeem-coupons\"', err);\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to toggle the bonus product.\r\n * This method is currently not in use since demandware has no internal logic to remove bonus products from basket.\r\n * @returns {void}\r\n */\r\n function toggleBonusProduct() {\r\n vm.bonusProductActive = !vm.bonusProductActive;\r\n }\r\n\r\n /**\r\n * @description Method to open pawpoint infopicker\r\n * @returns {void}\r\n */\r\n function openBonusPointsInfoPicker() {\r\n $window.jwsdwMediator.publish('openPicker', 'bonusPointsInfoPicker', {\r\n 'bonusPoints': dataService.bonusPoints(),\r\n 'level': 2\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to validate the basket and if validation is successful direct the customer to the checkout.\r\n * @returns {void}\r\n */\r\n function checkout() {\r\n vm.proceedingToCheckout = true;\r\n basketService.prepareCheckout()\r\n .then(function () {\r\n if (!basketService.checkout()) {\r\n vm.proceedingToCheckout = false;\r\n }\r\n\r\n })\r\n .catch(function (validationResult) {\r\n $log.debug('validation error: ', validationResult);\r\n basketService.getBasket(BASKET_ID).then(dataService.basketSuccess);\r\n vm.proceedingToCheckout = false;\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to validate the basket and if validation is successful direct the customer to the direct checkout (PayPal Express).\r\n * @returns {void}\r\n */\r\n function directCheckout() {\r\n vm.proceedingToDirectCheckout = true;\r\n basketService.prepareCheckout().then(function (validationResult) {\r\n if (!validationResult.error) {\r\n basketService.directCheckout();\r\n } else {\r\n $log.debug('validation error: ', validationResult.errorType);\r\n basketService.getBasket(BASKET_ID).then(dataService.basketSuccess);\r\n vm.proceedingToDirectCheckout = false;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to check if the browser supports HTML5 HistoryAPI.\r\n * @returns {Boolean} true if the browser supports the html 5 history API false otherwise\r\n * @memberOf jwsdwStoreDetail.StoreDetailController\r\n */\r\n function _browserSupportsHistoryAPI() {\r\n return $window.history && $window.history.pushState;\r\n }\r\n\r\n /**\r\n * @description Method to refresh a product view that is about to suffer changes.\r\n * @param {Object} product - The current product whose view should be refreshed.\r\n * @param {Promise} promise - A promise returned by a product update function.\r\n * @returns {Promise} a new promise.\r\n */\r\n function _refreshProductView(product, promise) {\r\n return new Promise((resolve) => {\r\n product.updating = true;\r\n promise.then(() => product.updating = false && resolve());\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to refresh certain parts of the basket view that are about to suffer changes.\r\n * @param {Promise} promise - A promise returned by an update function.\r\n * @returns {Promise} a new promise.\r\n */\r\n function _refreshBasketView(promise) {\r\n return new Promise((resolve) => {\r\n vm.updating = true;\r\n promise.then(() => vm.updating = false && resolve());\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to populate the quantity selector options based on site preference.\r\n * @returns {undefined}\r\n */\r\n function populateCartQuantityOptions() {\r\n let i = 1;\r\n\r\n if (vm.maxCartQuantityPerItem <= i) {\r\n vm.quantityOptions = [i];\r\n return;\r\n }\r\n\r\n while (i <= vm.maxCartQuantityPerItem) {\r\n vm.quantityOptions.push(i);\r\n i++;\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to reveal/hide coupon input.\r\n * @returns {undefined}\r\n */\r\n function toggleCouponInput() {\r\n vm.couponInputRevealed = !vm.couponInputRevealed;\r\n }\r\n\r\n /**\r\n * @description Method to update free shipping progress bar\r\n * @returns {undefined}\r\n */\r\n function updateProgressBar() {\r\n $timeout(function() {\r\n $scope.$apply(function() {\r\n $(document).find('.jwsdw-basket-progressBar-content').css('width', (100 - dataService.freeShippingPercentage()) + '%');\r\n });\r\n });\r\n }\r\n }\r\n}(angular));\r\n","'use strict';\r\n\r\n(function (angular) {\r\n dataService.$inject = ['$window', '$q', '$log', '$sce', 'basketService', 'productService', 'promotionService', 'BASKET_ID'];\r\n angular\r\n .module('jwsdw.basket')\r\n .factory('dataService', dataService);\r\n\r\n /**\r\n * @class jwsdwBasket.dataService\r\n * @description Service that provides access to the data layer of the basket\r\n * @param {Object} $window window service that provides access to the window object\r\n * @param {Object} $q promise service that provides promise functionality\r\n * @param {Object} $log log service that provides logging in angluar\r\n * @param {Object} $sce angular santize service\r\n * @param {Object} basketService service to provide basket information\r\n * @param {Object} productService service to provide product information (used for creation of variants item)\r\n * @param {Object} promotionService service to provide promotion information\r\n * @param {String} BASKET_ID basket id of the current basket provided through demandware backend (window.jwsdwSettings) and loaded into the module as constant\r\n * @returns {Object} service object that returns public methods\r\n */\r\n function dataService($window, $q, $log, $sce, basketService, productService, promotionService, BASKET_ID) { // eslint-disable-line max-statements\r\n var service,\r\n _ready = false,\r\n _callback,\r\n _basketData,\r\n _totalOrderPriceAdjustment,\r\n _quantityErrors = {};\r\n\r\n //public methods\r\n service = {\r\n 'quantityError': false,\r\n 'init': init,\r\n 'ready': ready,\r\n 'empty': empty,\r\n 'update': update,\r\n 'basketSuccess': basketSuccess,\r\n 'orderTotal': orderTotal,\r\n 'merchandizeTotalGrossPrice': merchandizeTotalGrossPrice,\r\n 'adjustedMerchandizeTotalPrice': adjustedMerchandizeTotalPrice,\r\n 'shippingTotal': shippingTotal,\r\n 'totalOrderPriceAdjustment': totalOrderPriceAdjustment,\r\n 'productLevelPriceAdjustments': productLevelPriceAdjustments,\r\n 'orderCouponPriceAdjustments': orderCouponPriceAdjustments,\r\n 'orderPriceAdjustments': orderPriceAdjustments,\r\n 'productItems': productItems,\r\n 'couponItems': couponItems,\r\n 'couponGiftCertificateItems': couponGiftCertificateItems,\r\n 'giftCardItems': giftCardItems,\r\n 'isReducedProduct': isReducedProduct,\r\n 'isTaxIncluded': isTaxIncluded,\r\n 'getTaxRate': getTaxRate,\r\n 'isMixedTaxRate': isMixedTaxRate,\r\n 'hasItemDiscount': hasItemDiscount,\r\n 'productQuantity': productQuantity,\r\n 'bonusPoints': bonusPoints,\r\n 'checkValidQuantity': checkValidQuantity,\r\n 'freeShippingAmount': freeShippingAmount,\r\n 'freeShippingPercentage': freeShippingPercentage,\r\n 'isChoiceOfBonusProductLineItem': isChoiceOfBonusProductLineItem,\r\n 'applicablePaymentMethods': applicablePaymentMethods,\r\n 'isLoyaltyCustomer': isLoyaltyCustomer,\r\n 'isEmployeeAccount': isEmployeeAccount,\r\n 'isCallawayAccount': isCallawayAccount,\r\n 'isFranchiseStore': isFranchiseStore,\r\n 'sessionCurrency': sessionCurrency,\r\n 'agent': agent,\r\n 'isCustomerLoggedIn': isCustomerLoggedIn,\r\n 'getOriginalOrderTotal': getOriginalOrderTotal,\r\n 'errorMessages': errorMessages,\r\n 'recommendedProductItem': recommendedProductItem,\r\n 'promotionTotal': promotionTotal,\r\n 'orderLimitReached': orderLimitReached,\r\n 'refusalReason': refusalReason,\r\n 'orderLimitMsg': orderLimitMsg,\r\n 'showShippingNotification': showShippingNotification,\r\n 'selectableBonusProductsList': selectableBonusProducts,\r\n 'allBonusProductVariants': allBonusProductVariants,\r\n 'hasBonusDiscountLineItem': hasBonusDiscountLineItem,\r\n 'hideBonusProductImage': hideBonusProductImage,\r\n 'maxBonusProducts': maxBonusProducts,\r\n 'isRemovedBonusProduct': isRemovedBonusProduct,\r\n 'defaultSelectableBonusProduct': defaultSelectableBonusProduct,\r\n 'selectedBonusProductLineItems': selectedBonusProductLineItems,\r\n 'outOfStockBonus': outOfStockBonus,\r\n 'hasPriceAdjustments': hasPriceAdjustments,\r\n 'approachingDiscounts': approachingDiscounts\r\n };\r\n\r\n // expose selected methods\r\n window.basketService = {\r\n 'init': init,\r\n 'orderTotal': orderTotal,\r\n 'shippingTotal': shippingTotal,\r\n 'taxTotal': taxTotal,\r\n 'applicableCreditCards': applicableCreditCards\r\n };\r\n\r\n return service;\r\n\r\n /**\r\n * @description Method to start initialization process to retrieve basket information\r\n * @param {Function} callback callback function\r\n * @returns {void}\r\n */\r\n function init(callback) {\r\n _ready = false;\r\n _callback = callback;\r\n basketService.getBasket(BASKET_ID).then(basketSuccess, basketError);\r\n }\r\n\r\n /**\r\n * @description Method to handle successful basket response by using product items to retrieve further product information.\r\n * @param {Object} basketData parsed basket data returned by the basket service\r\n * @returns {Promise} a promise to be resolved.\r\n */\r\n function basketSuccess(basketData) {\r\n var defer = $q.defer(),\r\n productIds = basketData.products\r\n .map(function(product) {\r\n return product.id;\r\n })\r\n .filter(window.jwsdwUtil.arrayUtils.unique());\r\n\r\n\r\n _basketData = basketData;\r\n\r\n $window.jwsdwSettings.basket.id = _basketData.id;\r\n\r\n $log.debug('jwsdw.basket.dataService: Using following data to built the page: ', _basketData);\r\n productService.getProducts(productIds).then(_productDataSuccess, _productDataError).then(() => defer.resolve());\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to handle error from basket response by using product items to retrieve further product information.\r\n * @param {Object} error error object\r\n * @returns {void}\r\n */\r\n function basketError(error) {\r\n _basketData = {\r\n 'empty': true\r\n };\r\n $log.debug('jwsdw.basket.dataService: No basket could be loaded: ', BASKET_ID, error);\r\n _ready = true;\r\n if (typeof _callback === 'function') {\r\n _callback();\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to handle successful product request and trigger further update logic.\r\n * @param {Object} productData parsed product data returned by the product service\r\n * @returns {Promise} a promise to be resolved.\r\n * @private\r\n */\r\n function _productDataSuccess(productData) {\r\n var defer = $q.defer();\r\n $log.debug('jwsdw.basket.dataService: Using following product data: ', productData);\r\n update().then(function() {\r\n _checkValidQuantities();\r\n _calculateTotalListPricesForSaleProducts();\r\n _ready = true;\r\n if (typeof _callback === 'function') {\r\n _callback();\r\n }\r\n defer.resolve();\r\n });\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to handle product data errors. This method is triggered if the product data does not\r\n * contain data for all products that were requested. This is used to handle deleted products.\r\n * @param {String[]} unavailableProductIds product ids for which no data was retrieved\r\n * @returns {void}\r\n * @private\r\n */\r\n function _productDataError(unavailableProductIds) {\r\n /*\r\n * this construct allows the sequential processing of promises.\r\n * This is neccessary since products that are not available anymore are deleted from the basket.\r\n * This changes the state of the basket. Asynchronous processing of multiple remove calls creates\r\n * a state problem where operations are done on outdated basket objects.\r\n * The array.reduce function allows to process each product id separately.\r\n * This works by setting the current value which is passed through every reduce callback to promise\r\n * and resolve it inside the callback. This creates a state were the next reduce iteration waits until the previous\r\n * iteration finishes and resolves the current value.\r\n */\r\n unavailableProductIds.reduce(_recheckAndDeleteUnavailableProducts, $q.resolve()).then(init);\r\n }\r\n\r\n /**\r\n * Method that is called with every iteration of the reduce function. It checks if the product is in the basket and then\r\n * rechecks if the product data cannot be retrieved and removes the product from the basket in this case.\r\n * @param {Object} defer promise that is resolve with every successful iteration through the reduce\r\n * function to ensure sequential processing\r\n * @param {String} productId the product id which is rechecked for availability\r\n * @returns {Object} promise that is resolved after successful processing of the function\r\n * @private\r\n */\r\n function _recheckAndDeleteUnavailableProducts(defer, productId) {\r\n var product = productItems().find(function (productItem) {\r\n return productItem.id === productId;\r\n });\r\n if (product) {\r\n return defer.then(function () {\r\n return productService.getProduct(product.id).catch(function () {\r\n return basketService.removeItem(product.basketItemId);\r\n });\r\n });\r\n }\r\n return defer;\r\n }\r\n\r\n /**\r\n * @description Method to update values and broadcast new values for the basket resource.\r\n * @returns {Object} promise that resolves if all update operations were successful\r\n */\r\n function update() {\r\n var defer = $q.defer(),\r\n promises = [];\r\n\r\n _totalOrderPriceAdjustment = _getTotalOrderPriceAdjustment();\r\n $window.jwsdwMediator.publish('setCartCount', _basketData.cartQuantity);\r\n\r\n\r\n promises.push(_extendOrderPriceAdjustmentsWithPromotionData());\r\n promises.push(_extendBasketProductsWithProductData());\r\n promises.push(_updateProductAvailabilityData());\r\n\r\n $q.all(promises).then(function () {\r\n defer.resolve();\r\n });\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to get the ready state of the basket.\r\n * @returns {Boolean} true if basket data is ready false otherwise\r\n */\r\n function ready() {\r\n return _ready;\r\n }\r\n\r\n /**\r\n * @description Method to get the empty state of the basket.\r\n * @returns {Boolean} true if basket is empty false otherwise\r\n */\r\n function empty() {\r\n return _basketData.empty;\r\n }\r\n\r\n /**\r\n * @description Method to get the order total from the basket data.\r\n * @returns {Number} the total order price\r\n */\r\n function orderTotal() {\r\n return _basketData.orderTotal;\r\n }\r\n\r\n /**\r\n * @description Method to get the error messages from the basket data.\r\n * @returns {String} the error message\r\n */\r\n function errorMessages() {\r\n return _basketData.errorMessages;\r\n }\r\n /**\r\n * @description Method to get the order total from the basket data.\r\n * @returns {Number} the total order price\r\n */\r\n function merchandizeTotalGrossPrice() {\r\n return _basketData.merchandizeTotalGrossPrice;\r\n }\r\n\r\n /**\r\n * @description Method to get the adjusted merchandize total from the basket data.\r\n * @returns {Number} the total order price\r\n */\r\n function adjustedMerchandizeTotalPrice() {\r\n return _basketData.adjustedMerchandizeTotalPrice;\r\n }\r\n\r\n /**\r\n * @description Method to get the shipping total from the basket data.\r\n * @returns {Number} the total order shipping price\r\n */\r\n function shippingTotal() {\r\n return _basketData.shippingTotal;\r\n }\r\n\r\n\r\n /**\r\n * @description Method to get coupon-based order price adjustments from the basket data.\r\n * @returns {String[]} array of order price adjustments\r\n */\r\n function orderCouponPriceAdjustments() {\r\n return _basketData.orderCouponPriceAdjustments;\r\n }\r\n\r\n /**\r\n * @description Method to get order non-coupon-based price adjustments from the basket data.\r\n * @returns {String[]} array of order price adjustments\r\n */\r\n function orderPriceAdjustments() {\r\n return _basketData.orderPriceAdjustments;\r\n }\r\n\r\n /**\r\n * @description Method to get the total order price adjustment from the basket data.\r\n * @returns {Number} total order price adjustment\r\n */\r\n function totalOrderPriceAdjustment() {\r\n return _totalOrderPriceAdjustment;\r\n }\r\n\r\n /**\r\n * @description Method to get the total product level price adjustments.\r\n * @returns {Object} a map of total product level price adjustments.\r\n */\r\n function productLevelPriceAdjustments() {\r\n return _basketData.productLevelPriceAdjustments;\r\n }\r\n\r\n /**\r\n * @description Method to get the product items from the basket data.\r\n * @returns {Object[]} array of product items\r\n */\r\n function productItems() {\r\n return _basketData.products;\r\n }\r\n\r\n /**\r\n * @description Method to get the recommended product items from the basket data.\r\n * @returns {Object[]} array of product items\r\n */\r\n function recommendedProductItem() {\r\n return _basketData.recommendedProduct;\r\n }\r\n\r\n /**\r\n * @description Method to get the selectable bonus product items from the basket data.\r\n * @returns {String[]} array of product ids\r\n */\r\n function selectableBonusProducts() {\r\n return _basketData.selectableBonusProducts;\r\n }\r\n\r\n /**\r\n * @description Method to check if the basket has a bonus line item discount.\r\n * @returns {Boolean} true if there is a bonus line item currently in basket\r\n */\r\n function hasBonusDiscountLineItem() {\r\n return _basketData.hasBonusDiscountLineItem;\r\n }\r\n\r\n /**\r\n * @description Method to check whether to hide the product image in the bonus product banner.\r\n * @returns {Boolean} true if the product image in the bonus promo banner should be hidden.\r\n */\r\n function hideBonusProductImage() {\r\n return _basketData.hideBonusProductImage;\r\n }\r\n\r\n /**\r\n * @description Method to get the max number of bonus products from the basket data.\r\n * @returns {Number} maximum number of bonus products that can be added in basket\r\n */\r\n function maxBonusProducts() {\r\n return _basketData.maxBonusProducts;\r\n }\r\n\r\n /**\r\n * @description Method to display banner if all bonus products are out of stock\r\n * @returns {Boolean} true if all bonus product variants are out of stock\r\n */\r\n function outOfStockBonus() {\r\n return _basketData.outOfStockBonus;\r\n }\r\n\r\n /**\r\n * @description Method to get the coupon items from the basket data.\r\n * @returns {Object[]} array of coupon items\r\n */\r\n function couponItems() {\r\n return _basketData.coupons;\r\n }\r\n\r\n /**\r\n * @description Method to get the loyalty coupon items from the basket data.\r\n * @returns {Object[]} array of loyalty coupon items\r\n */\r\n function couponGiftCertificateItems() {\r\n return _basketData.couponGiftCertificates;\r\n }\r\n\r\n /**\r\n * @description Method to get the gift card items from the basket data.\r\n * @returns {Object[]} array of gift card items\r\n */\r\n function giftCardItems() {\r\n return _basketData.giftCards;\r\n }\r\n\r\n /**\r\n * @description Method to get the quantity of a basket product item\r\n * @param {String} basketItemId id of the basket product item (not product id)\r\n * @returns {Number} qunatity of the requested basket item\r\n */\r\n function productQuantity(basketItemId) {\r\n let basketItem = productItems().find(function(product) {\r\n return product.basketItemId === basketItemId;\r\n });\r\n\r\n return basketItem ? basketItem.quantity : 0;\r\n }\r\n\r\n /**\r\n * @description Method to check if a product is reduced through sale price or item price adjustments.\r\n * TODO check if in use\r\n * @param {Object} product product that is checked for reductions\r\n * @param {Boolean} product.isBonusProduct true if product is bonus product\r\n * @param {Number} product.price price\r\n * @param {Number} product.priceAfterItemDiscount price after applied discounts\r\n * @returns {Boolean} true if product is reduced false otherwise\r\n */\r\n function isReducedProduct(product) {\r\n return !product.isBonusProduct && (hasItemDiscount(product) || productService.isSaleProduct(product));\r\n }\r\n\r\n /**\r\n * @description Method to check if tax is included in the total price\r\n * @returns {Boolean} true if tax is included\r\n */\r\n function isTaxIncluded() {\r\n return productItems().some(function(pli) {\r\n return pli.taxRate > 0;\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to get tax rate\r\n * @returns {Number|Null} tax rate of basket or null\r\n */\r\n function getTaxRate() {\r\n if (isTaxIncluded() && !isMixedTaxRate()) {\r\n return productItems()[0].taxRate;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * @description Method to check if tax rates are mixed\r\n * @returns {Boolean} true if tax is mixed\r\n */\r\n function isMixedTaxRate() {\r\n return productItems().filter(window.jwsdwUtil.arrayUtils.unique('taxRate')).length > 1;\r\n }\r\n\r\n /**\r\n * @description Method to check if tax is included in the total price\r\n * @returns {Boolean} true if tax is included\r\n */\r\n function taxTotal() {\r\n return _basketData.taxTotal;\r\n }\r\n\r\n /**\r\n * @description Method to check if the bonus product has been removed from basket\r\n * @returns {Boolean} true if bonus product was removed\r\n */\r\n function isRemovedBonusProduct() {\r\n return _basketData.isRemovedBonusProduct;\r\n }\r\n\r\n /**\r\n * @description Method to return default bonus product to be displayed in basket\r\n * @returns {Object} default selectable bonus product\r\n */\r\n function defaultSelectableBonusProduct() {\r\n return _basketData.defaultSelectableBonusProduct;\r\n }\r\n\r\n /**\r\n * @description Method to return currently selected bonus product line items\r\n * @returns {Object[]} currently selected bonus product line items\r\n */\r\n function selectedBonusProductLineItems() {\r\n return _basketData.selectedBonusProductLineItems;\r\n }\r\n\r\n /**\r\n * @description Method to return all variants for a bonus product\r\n * @returns {Object[]} currently selected bonus product variants\r\n */\r\n function allBonusProductVariants() {\r\n return _basketData.allBonusProductVariants;\r\n }\r\n\r\n /**\r\n * @description Method to check if product has an item price adjustment.\r\n * @param {Object} product product that is checked for discount\r\n * @param {Number} product.price price\r\n * @param {Number} product.priceAfterItemDiscount price after applied discounts\r\n * @returns {Boolean} true if product has item price adjustments\r\n */\r\n function hasItemDiscount(product) {\r\n return product.priceAfterItemDiscount < product.price;\r\n }\r\n\r\n /**\r\n * @description Method to get the bonus points from the basket data.\r\n * @returns {Number} bonus points for the basket\r\n */\r\n function bonusPoints() {\r\n return _basketData.bonusPoints;\r\n }\r\n\r\n /**\r\n * @description Method to get the free shipping amount from the basket data.\r\n * @returns {Number} amount needed to get free shipping\r\n */\r\n function freeShippingAmount () {\r\n return _basketData.freeShippingAmount;\r\n }\r\n\r\n /**\r\n * @description Method to get the free shipping amount from the basket data.\r\n * @returns {Number} amount needed to get free shipping\r\n */\r\n function freeShippingPercentage () {\r\n return _basketData.freeShippingPercentage;\r\n }\r\n\r\n /**\r\n * @description Method to calculate the total order price adjustment value for the basket data.\r\n * @returns {Number} total order price adjustment\r\n * @private\r\n */\r\n function _getTotalOrderPriceAdjustment() {\r\n var totalDiscount = 0,\r\n discountsLength = _basketData.orderPriceAdjustments.length,\r\n i;\r\n\r\n for (i = 0; i < discountsLength; i++) {\r\n totalDiscount = totalDiscount + _basketData.orderPriceAdjustments[i].price;\r\n }\r\n\r\n return totalDiscount;\r\n }\r\n\r\n /**\r\n * @description Method to check if object of price adjustments is empty\r\n * @param {Object} priceAdjustment object to check\r\n * @returns {Number} returns number of entries in object\r\n */\r\n function hasPriceAdjustments(priceAdjustment) {\r\n return Object.keys(priceAdjustment).length;\r\n }\r\n\r\n /**\r\n * @description Method to check if bonus product is a selected choice of bonus product line item\r\n * @param {String} productId id of the product to check\r\n * @returns {Boolean} true if bonus product is selected choice of bonus product line item false otherwise\r\n */\r\n function isChoiceOfBonusProductLineItem(productId) {\r\n if (_basketData.hasOwnProperty('selectedBonusProducts') && angular.isArray(_basketData.selectedBonusProducts)) {\r\n return _basketData.selectedBonusProducts.indexOf(productId) > -1;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * @description Method to extend the product data in the basket item with the extended product data that contains\r\n * availability, images, prices, links and variations and promotion data for price adjustments of product items.\r\n * @returns {Object} promise\r\n * @private\r\n */\r\n function _extendBasketProductsWithProductData() {\r\n var defer = $q.defer();\r\n\r\n _basketData.products.forEach(function(product, index) {\r\n productService.getProduct(product.id).then(function (productData) {\r\n var shallowCopyOfProductData = JSON.parse(JSON.stringify(productData));\r\n // adds the basket product data to the product data and assigns it to the basket product\r\n // this is necessary since price information from the basket should not be overwritten\r\n _basketData.products[index] = Object.assign(shallowCopyOfProductData, _basketData.products[index]);\r\n });\r\n _extendProductPriceAdjustmentsWithPromotionData(product, index);\r\n });\r\n $log.debug('BasketData: ', _basketData);\r\n defer.resolve();\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to update product availability data (stock/ats).\r\n * TODO check if promise is needed\r\n * TODO add time stamp to prevent unnecessary reuqests\r\n * @returns {Object} promise\r\n * @private\r\n */\r\n function _updateProductAvailabilityData() {\r\n var defer = $q.defer();\r\n\r\n _basketData.products.forEach(function(product, index) {\r\n productService.getAvailability(product.id).then(function (availabilityData) {\r\n _basketData.products[index].stock = availabilityData.inventory.ats;\r\n _basketData.products[index].hasOrderableVariants = productService.hasOrderableVariants(_basketData.products[index]);\r\n });\r\n });\r\n $log.debug('BasketData: ', _basketData);\r\n defer.resolve();\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to get promotions for an item price adjustment and add promotion data to the adjustments data.\r\n * This methods also checks if coupons are connected with the price adjustment.\r\n * TODO check if promise is needed\r\n * @param {Object} product basket product item that is checked for price adjustments\r\n * @param {Object[]} product.priceAdjustments product price adjustments\r\n * @param {String} product.priceAdjustments[].promotionId promotion id\r\n * @param {String} product.priceAdjustments[].couponCode coupon code\r\n * @param {Number} productIndex index of the product item in the basket data\r\n * @returns {Promise} promise\r\n * @private\r\n */\r\n function _extendProductPriceAdjustmentsWithPromotionData(product, productIndex) {\r\n var defer = $q.defer();\r\n\r\n if (product.hasOwnProperty('priceAdjustments')) {\r\n product.priceAdjustments.forEach(function (priceAdjustment, index) {\r\n promotionService.getPromotion(priceAdjustment.promotionId).then(function (promotionData) {\r\n if (promotionData.callOutMessage) {\r\n _basketData.products[productIndex].priceAdjustments[index].callOutMessage = $sce.getTrustedHtml(promotionData.callOutMessage);\r\n }\r\n if (promotionData.promoTagName || promotionData.callOutMessage) {\r\n _basketData.products[productIndex].priceAdjustments[index].promoTagName = promotionData.promoTagName || promotionData.callOutMessage;\r\n }\r\n if (priceAdjustment.couponCode) {\r\n _setCalloutMessageToCoupon(priceAdjustment.couponCode, promotionData.callOutMessage);\r\n }\r\n });\r\n });\r\n }\r\n defer.resolve();\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to get promotions for an order price adjustment and add promotion data to the adjustments data.\r\n * This methods also checks if coupons are connected with the price adjustment.\r\n * TODO check if promise is needed\r\n * TODO add promotion information for if a coupon is connected with the promotion\r\n * @returns {Object} promise\r\n * @private\r\n */\r\n function _extendOrderPriceAdjustmentsWithPromotionData() {\r\n var defer = $q.defer();\r\n\r\n _basketData.orderPriceAdjustments.forEach(function (priceAdjustment, index) {\r\n promotionService.getPromotion(priceAdjustment.promotionId).then(function (promotionData) {\r\n if (promotionData.callOutMessage) {\r\n _basketData.orderPriceAdjustments[index].callOutMessage = promotionData.callOutMessage;\r\n }\r\n if (priceAdjustment.couponCode) {\r\n _setCalloutMessageToCoupon(priceAdjustment.couponCode, promotionData.callOutMessage);\r\n }\r\n });\r\n });\r\n\r\n defer.resolve();\r\n\r\n return defer.promise;\r\n }\r\n\r\n /**\r\n * @description Method to set a callout message to the coupon item.\r\n * @param {String} couponCode code of the coupon to which the callout message should be added\r\n * @param {String} callOutMessage the callout message to add to the coupon\r\n * @returns {Boolean} true if a coupon was found to which the message is added false otherwise\r\n * @private\r\n */\r\n function _setCalloutMessageToCoupon(couponCode, callOutMessage) {\r\n var matchingCoupon = _basketData.coupons.find(function (coupon) {\r\n return coupon.code === couponCode;\r\n });\r\n\r\n matchingCoupon.callOutMessage = matchingCoupon ? callOutMessage : null;\r\n\r\n return !!matchingCoupon;\r\n }\r\n\r\n // /**\r\n // * @description Method to set a callout name to the coupon item.\r\n // * @param {String} couponCode code of the coupon to which the callout message should be added\r\n // * @param {String} couponName the callout name to add to the coupon\r\n // * @returns {Boolean} true if a coupon was found to which the message is added false otherwise\r\n // * @private\r\n // */\r\n // function _setCouponNameToCoupon(couponCode, couponName) {\r\n // var matchingCoupon = _basketData.coupons.find(function (coupon) {\r\n // return coupon.code === couponCode;\r\n // });\r\n\r\n // matchingCoupon.couponName = matchingCoupon ? couponName : null;\r\n\r\n // return !!matchingCoupon;\r\n // }\r\n\r\n /**\r\n * @description Method to calculate the total list prices for all basket sale products. Multiplies the list price with the product quantity.\r\n * Method is not used anymore.\r\n * TODO can be removed\r\n * @returns {void}\r\n * @private\r\n */\r\n function _calculateTotalListPricesForSaleProducts() {\r\n var listPrice;\r\n productItems().forEach(function (product) {\r\n listPrice = productService.productListPrice(product);\r\n product.listPrice = listPrice;\r\n product.totalListPrice = listPrice * product.quantity;\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to check all basket product items for valid quantity values.\r\n * @returns {void}\r\n * @private\r\n */\r\n function _checkValidQuantities() {\r\n _quantityErrors = {};\r\n productItems().forEach(function (product) {\r\n checkValidQuantity(product.basketItemId, product.quantity, product.stock);\r\n });\r\n }\r\n\r\n /**\r\n * @description Method to check if a basket product item has a valid quantity.\r\n * @param {String} basketItemId id of the basket product item (not product id)\r\n * @param {Number} quantity current quantity of the basket item\r\n * @param {Number} stock current stock of the basket item\r\n * @returns {Boolean} true if the quantity is not 0 and lower than the stock false otherwise\r\n */\r\n function checkValidQuantity(basketItemId, quantity, stock) {\r\n var isValid = true;\r\n if (quantity > 0 && quantity <= stock) {\r\n _removeQuantityError(basketItemId);\r\n } else {\r\n _addQuantityError(basketItemId);\r\n isValid = false;\r\n }\r\n return isValid;\r\n }\r\n\r\n /**\r\n * @description Method to add a quantity error for a basket product item.\r\n * @param {String} basketItemId id of the basket product item (not product id)\r\n * @returns {void}\r\n * @private\r\n */\r\n function _addQuantityError(basketItemId) {\r\n if (!_quantityErrors.hasOwnProperty(basketItemId)) {\r\n _quantityErrors[basketItemId] = true;\r\n }\r\n service.quantityError = true;\r\n }\r\n\r\n /**\r\n * @description Method to remove quantity error for a basket product item.\r\n * @param {String} basketItemId id of the basket product item (not product id)\r\n * @returns {void}\r\n * @private\r\n */\r\n function _removeQuantityError(basketItemId) {\r\n if (_quantityErrors[basketItemId]) {\r\n delete _quantityErrors[basketItemId];\r\n }\r\n if (Object.keys(_quantityErrors).length === 0) {\r\n service.quantityError = false;\r\n }\r\n }\r\n\r\n /**\r\n * @description Method to get the applicablePaymentMethods from the basket data.\r\n * @returns {String[]} array of applicable payment methods\r\n */\r\n function applicablePaymentMethods() {\r\n return _basketData.applicablePaymentMethods;\r\n }\r\n\r\n /**\r\n * @description Method to get the isLoyaltyCustomer from the basket data.\r\n * @returns {Boolean} whether customer is a loyalty customer\r\n */\r\n function isLoyaltyCustomer() {\r\n return _basketData.isLoyaltyCustomer;\r\n }\r\n\r\n /**\r\n * @description Method to get the isEmployeeAccount from the basket data.\r\n * @returns {Boolean} whether customer is an employee\r\n */\r\n function isEmployeeAccount() {\r\n return _basketData.isEmployeeAccount;\r\n }\r\n\r\n /**\r\n * @description Method to get the isCallawayAccount from the basket data.\r\n * @returns {Boolean} whether customer is an employee\r\n */\r\n function isCallawayAccount() {\r\n return _basketData.isCallawayAccount;\r\n }\r\n\r\n /**\r\n * @description Method to get the isFranchiseStore from the basket data.\r\n * @returns {Boolean} whether customer is an employee\r\n */\r\n function isFranchiseStore() {\r\n return _basketData.isFranchiseStore;\r\n }\r\n\r\n /**\r\n * @description Method to get the agent from the basket data.\r\n * @returns {Boolean} whether customer is an agent\r\n */\r\n function agent() {\r\n return _basketData.agent;\r\n }\r\n\r\n /**\r\n * @description Method to determine whether the current customer is logged in.\r\n * @returns {Boolean} true if the customer is logged in.\r\n */\r\n function isCustomerLoggedIn() {\r\n return _basketData.isCustomerLoggedIn;\r\n }\r\n\r\n /**\r\n * @description Method to get the original order total.\r\n * @returns {Number} the original order total, computed by adding all of the products' list prices.\r\n */\r\n function getOriginalOrderTotal() {\r\n return _basketData.originalOrderTotal;\r\n }\r\n\r\n /**\r\n * @description Method to get the sessionCurrency from the basket data.\r\n * @returns {String} currency code\r\n */\r\n function sessionCurrency() {\r\n return _basketData.sessionCurrency;\r\n }\r\n\r\n /**\r\n * @description Method to get the applicableCreditCards from the basket data.\r\n * @returns {Object[]} array of applicable credit cards\r\n */\r\n function applicableCreditCards() {\r\n return _basketData.applicableCreditCards;\r\n }\r\n\r\n /**\r\n * @description Method to get the non coupon promotion totals from the basket data.\r\n * @returns {Object} object that contains the total non coupon promotion prices for every promotion\r\n */\r\n function promotionTotal() {\r\n return _basketData.promotionTotal;\r\n }\r\n\r\n /**\r\n * @description Method to get determine whether the employee order limit has been reached.\r\n * @returns {Boolean} true if the order limit has been reached/exceeded.\r\n */\r\n function orderLimitReached() {\r\n return _basketData.orderLimitReached;\r\n }\r\n\r\n /**\r\n * @description Method to get the basket refusal reason.\r\n * @returns {String} the refusal reason code.\r\n */\r\n function refusalReason() {\r\n return _basketData.refusalReason;\r\n }\r\n\r\n /**\r\n * @description Method to get the basket order limit error message\r\n * @returns {String} the error message\r\n */\r\n function orderLimitMsg() {\r\n return _basketData.orderLimitMsg;\r\n }\r\n\r\n /**\r\n * @description Method to determine whether to show free shipping notification message\r\n * @returns {Boolean} true if after applying coupon code, free shipping is no longer available\r\n */\r\n function showShippingNotification() {\r\n return _basketData.showShippingNotification;\r\n }\r\n\r\n /**\r\n * @description Method to retrieve approaching discounts\r\n * @returns {Boolean} true if after applying coupon code, free shipping is no longer available\r\n */\r\n function approachingDiscounts() {\r\n return _basketData.approachingDiscounts;\r\n }\r\n }\r\n}(angular));\r\n","'use strict';\r\n\r\n(function (angular) {\r\n\r\n // initialize basket angular app\r\n // bootstrap app manually as only the first app on a page can be initialized by data-ng-app (which is the framework/header)\r\n angular.bootstrap(document.getElementById('jwsdw-basket-module'), ['jwsdw.basket']);\r\n}(angular));"],"names":["angular","ngTouch","module","makeSwipeDirective","directiveName","direction","eventName","directive","$parse","$swipe","scope","element","attr","startCoords","valid","swipeHandler","pointerTypes","isDefined","push","bind","start","coords","event","cancel","end","validSwipe","deltaY","Math","abs","y","deltaX","x","$apply","triggerHandler","$event","info","angularVersion","factory","POINTER_EVENTS","mouse","move","touch","pointer","getCoordinates","originalEvent","touches","length","e","changedTouches","clientX","clientY","getEvents","eventType","res","forEach","pointerType","join","eventHandlers","totalX","totalY","lastPos","active","events","on","preventDefault","window","config","$compileProvider","debugInfoEnabled","$inject","constant","jwsdwSettings","basket","id","listPriceBook","salePriceBook","productGetImageBaseUrl","BasketController","$scope","$log","$anchorScroll","$window","$location","$timeout","dataService","productService","basketService","contentService","BASKET_ID","SETTINGS","trackAddToBasketService","vm","this","_initObserver","recommendedProduct","let","recommendationBlock","observer","IntersectionObserver","entries","entry","isIntersecting","sendEvent","sendRecommendedProductImpressions","jwsdwApi","tracking","ensureConsent","disconnect","root","rootMargin","threshold","document","getElementById","observe","recommendedProductObserver","removeItem","product","markForRemoval","markedForRemoval","removing","basketItemId","then","removed","tileHeight","outerHeight","fadeOut","basketSuccess","basketData","updateProduct","itemId","initialProductId","variantId","quantity","addItem","_refreshBasketView","updateBonusProduct","addBonusItem","couponSuccess","couponItem","couponItems","concat","couponGiftCertificateItems","find","coupon","code","toUpperCase","couponCode","couponError","errorData","$","validate","showErrors","basketCouponCode","details","message","openBonusPointsInfoPicker","jwsdwMediator","publish","bonusPoints","level","_browserSupportsHistoryAPI","history","pushState","_refreshProductView","promise","Promise","updating","populateCartQuantityOptions","i","maxCartQuantityPerItem","quantityOptions","updateProgressBar","css","freeShippingPercentage","proceedingToCheckout","proceedingToDirectCheckout","sessionError","invalidProductError","quantityError","bonusProductActive","gPayLoaded","couponInputRevealed","recommendedProductDismissed","refusalReason","search","reason","undefined","wishlistCount","maxWishlistItemsForGuest","wishlist","onRemoveButtonClick","onRemoveCancelButtonClick","updateQuantity","checkValidQuantity","stock","addCoupon","removeCoupon","couponId","removeBonusCoupon","toggleBonusProduct","checkout","prepareCheckout","catch","validationResult","debug","getBasket","directCheckout","error","errorType","onEditButtonClick","isBonus","openPriceOverridePicker","regex","RegExp","adjustmentTotal","priceAdjustments","filter","priceAdjustment","toString","promotionId","test","manualAdjustment","price","productId","oldPrice","priceAfterItemDiscount","openVoucherPicker","getContent","response","width","content","isVisible","err","onMoveToWishlistButtonClick","markedForWishlist","onMoveToWishlistCancelButtonClick","moveItemToWishlist","movingToWishlist","customerAuthenticated","showMaxGuestWishlistMessage","callback","addToWishlist","addToWishlistSuccess","addToWishlistError","data","products","pid","color","items","movedToWishlist","toggleCouponInput","addRecommendedProduct","productID","isRemovedBonusProduct","onRemoveRecommButtonClick","$onInit","init","openPicker","location","href","pathname","errorMessage","errorMessages","productItems","hasOwnProperty","isBonusProduct","sessionStorage","setItem","recommendedProductItem","googlePay","applicablePaymentMethods","indexOf","getScript","onLoaded","orderLimitReached","replace","orderLimitMsg","showShippingNotification","subscribe","cartQuantity","productCount","$watch","$locationProvider","html5Mode","controller","$q","$sce","promotionService","_callback","_basketData","_totalOrderPriceAdjustment","_ready","_quantityErrors","service","ready","empty","update","orderTotal","merchandizeTotalGrossPrice","adjustedMerchandizeTotalPrice","shippingTotal","totalOrderPriceAdjustment","productLevelPriceAdjustments","orderCouponPriceAdjustments","orderPriceAdjustments","coupons","couponGiftCertificates","giftCardItems","giftCards","isReducedProduct","hasItemDiscount","isSaleProduct","isTaxIncluded","getTaxRate","isMixedTaxRate","taxRate","productQuantity","basketItem","freeShippingAmount","isChoiceOfBonusProductLineItem","isArray","selectedBonusProducts","isLoyaltyCustomer","isEmployeeAccount","isCallawayAccount","isFranchiseStore","sessionCurrency","agent","isCustomerLoggedIn","getOriginalOrderTotal","originalOrderTotal","promotionTotal","selectableBonusProductsList","selectableBonusProducts","allBonusProductVariants","hasBonusDiscountLineItem","hideBonusProductImage","maxBonusProducts","defaultSelectableBonusProduct","selectedBonusProductLineItems","outOfStockBonus","hasPriceAdjustments","Object","keys","approachingDiscounts","taxTotal","applicableCreditCards","basketError","defer","productIds","map","jwsdwUtil","arrayUtils","unique","getProducts","_productDataSuccess","_productDataError","resolve","productData","_checkValidQuantities","_calculateTotalListPricesForSaleProducts","unavailableProductIds","reduce","_recheckAndDeleteUnavailableProducts","productItem","getProduct","promises","_getTotalOrderPriceAdjustment","_extendOrderPriceAdjustmentsWithPromotionData","_extendBasketProductsWithProductData","_updateProductAvailabilityData","all","some","pli","totalDiscount","discountsLength","index","shallowCopyOfProductData","JSON","parse","stringify","assign","_extendProductPriceAdjustmentsWithPromotionData","getAvailability","availabilityData","inventory","ats","hasOrderableVariants","productIndex","getPromotion","promotionData","callOutMessage","getTrustedHtml","promoTagName","_setCalloutMessageToCoupon","matchingCoupon","listPrice","productListPrice","totalListPrice","isValid","_removeQuantityError","_addQuantityError","bootstrap"],"mappings":"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"}