/* Minification failed. Returning unminified contents.
(2700,70-71): run-time error JS1195: Expected expression: >
(2701,72-73): run-time error JS1195: Expected expression: >
(2755,70-71): run-time error JS1195: Expected expression: >
(2756,72-73): run-time error JS1195: Expected expression: >
(2924,70-71): run-time error JS1195: Expected expression: >
(2925,72-73): run-time error JS1195: Expected expression: >
 */
ngAWDSApp.directive('postcodeDirective', ['HttpFactory', '$window', function (HttpFactory, $window) {
    return {
        restrict: 'A',
        scope: {
            postcodeSelected: '=',
            errorMsg: '='
        },
        template: '<style>.postcode-group-item span {width: 33.33%;float:left} .postcode-group-item {float: left; width: 100%} .postcode-group{position: absolute;width:100%; max-height:300px; overflow: auto}</style>'
                    + '<div class="input" ng-class="{\'has-error\': errorMsg != \'\'}">'
                        + '<input type="text" ng-model="postcodeSelected.locality" ng-change="searchKey()" ng-focus="searchKey()" ng-blur="onBlur()" ng-model-options="{debounce: 500}" class="form-control locality">'
                        + '<input type="text" readonly ng-model="postcodeSelected.state" class="form-control state">'
                        + '<input type="text" readonly ng-model="postcodeSelected.pnum" class="form-control pnum">'
                        + '<span ng-show="errorMsg != \'\'" class="help-block with-errors">{{errorMsg}}</span>'
                    + '</div>'
                    + '<ul class="postcode-group list-group">'
                        + '<li class="postcode-group-item list-group-item" ng-repeat="item in postcodes" ng-click="onSelectPostCode(item)">'
                            + '<span class="locality">{{item.locality}}</span>'
                            + '<span class="state">{{item.state}}</span>'
                            + '<span class="pnum">{{item.pcode}}</span>'
                        + '</li>'
                    + '</ul>',

        link: function ($scope, $element, $attr) {
            $($element).find('.state, .pnum').css({
                "width": "33.33%",
                "position": "relative",
                "left": "33%",
                "top": "-40px",
                "background-color": "transparent",
                "border-color": "transparent",
                "box-shadow": "none",
                "display": "unset"
            });
            $($element).find('.state, .pnum').click(function () {
                $($element).find('.locality').focus();
            });
            $scope.PCodeRecords = [];
            var GetPCode = function (searchText) {
                return HttpFactory.get({ searchText: searchText }, 'Stock/WSStock/Postcode');
            }

            $scope.ValidatePCode = function () {                
                if ($scope.postcodeSelected == null || $scope.postcodeSelected == {}) {
                    $scope.errorMsg = "This field is required";
                } else {
                    if (IsNullOrEmpty($scope.postcodeSelected.locality))
                    {
                        $scope.errorMsg = "Please select a suburb from the dropdown list.";
                        $scope.postcodeSelected = {};
                    }
                    else {
                        GetPCode($scope.postcodeSelected.locality).then(function (response) {
                            if (response.data.length > 0) {
                                $($element).find('.postcode-group').show();
                            } else {
                                $($element).find('.postcode-group').hide();
                            }

                            var isMatch = false;
                            for (var i = 0; i < response.data.length; i++) {
                                if ($scope.postcodeSelected.locality == response.data[i].locality && $scope.postcodeSelected.state == response.data[i].state && $scope.postcodeSelected.pnum == response.data[i].pcode_num) {
                                    isMatch = true;
                                    break;
                                }
                            }
                            if (!isMatch) {
                                $scope.errorMsg = "Please select a suburb from the dropdown list.";
                                $scope.postcodeSelected.state = null;
                                $scope.postcodeSelected.pnum = null;
                            } else {
                                $scope.errorMsg = "";
                            }
                            $scope.PCodeRecords = response.data;
                        }, function (response) {
                            $scope.PCodeRecords = [];
                        });
                    }
                }
            }

            $(document).mouseup(function (e) {
                var container = $element;
                if (!container.is(e.target) && container.has(e.target).length === 0) {
                    $($element).find('.postcode-group').hide();
                }
            });
            $scope.searchKey = function () {
                $scope.ValidatePCode();
                $scope.postcodes = $scope.PCodeRecords;
            }
            $scope.onSelectPostCode = function (item) {
                $scope.postcodeSelected = {
                    locality: item.locality,
                    state: item.state,
                    pnum: item.pcode,
                }
                $scope.errorMsg = "";
                $($element).find('.postcode-group').hide();
            }
        }
    }
}]);

(function (global, factory) {
    'use strict';

    if (typeof exports === 'object' && typeof module !== 'undefined') {
        // commonJS
        module.exports = factory(require('angular'));
    }
    else if (typeof define === 'function' && define.amd) {
        // AMD
        define(['module', 'angular'], function (module, angular) {
            module.exports = factory(angular);
        });
    }
    else {
        factory(global.angular);
    }
}(this, function (angular) {
    var helperService = new HelperService();

    angular
        .module('autoCompleteModule', ['ngSanitize'])
        .directive('autoComplete', autoCompleteDirective)
        .directive('autoCompleteItem', autoCompleteItemDirective)
        .directive('autoCompleteNoMatch', autoCompleteNoMatchDirective);

    autoCompleteDirective.$inject = ['$q', '$compile', '$document', '$window', '$timeout'];
    function autoCompleteDirective($q, $compile, $document, $window, $timeout) {

        return {
            restrict: 'A',
            scope: {},
            transclude: false,
            controllerAs: 'ctrl',
            bindToController: {
                initialOptions: '&autoComplete'
            },
            require: ['autoComplete', 'ngModel'],
            link: postLinkFn,
            controller: MainCtrl
        };

        function postLinkFn(scope, element, attrs, ctrls) {
            var ctrl = ctrls[0]; //directive controller
            ctrl.textModelCtrl = ctrls[1]; // textbox model controller

            // store the jquery element on the controller
            ctrl.target = element;

            $timeout(function () {
                // execute the options expression
                $q.when(ctrl.initialOptions()).then(_initialize);
            });

            function _initialize(options) {
                options = options || {};

                ctrl.init(angular.extend({}, defaultOptions, options));

                _initializeContainer();
                _wireupEvents();
            }

            function _initializeContainer() {
                ctrl.container = _getContainer();

                if (ctrl.options.containerCssClass) {
                    ctrl.container.addClass(ctrl.options.containerCssClass);
                }

                // if a jquery parent is specified in options append the container to that
                // otherwise append to body
                if (ctrl.options.dropdownParent) {
                    ctrl.options.dropdownParent.append(ctrl.container);
                }
                else {
                    $document.find('body').append(ctrl.container);
                    ctrl.container.addClass('auto-complete-absolute-container');
                }

                // keep a reference to the <ul> element
                ctrl.elementUL = angular.element(ctrl.container[0].querySelector('ul.auto-complete-results'));
            }

            function _getContainer() {
                if (angular.isElement(ctrl.options.dropdownParent)) {
                    return _getCustomContainer();
                }

                return _getDefaultContainer();
            }

            function _getCustomContainer() {
                var container = ctrl.options.dropdownParent;

                container.addClass('auto-complete-container unselectable');
                container.attr('data-instance-id', ctrl.instanceId);

                var linkFn = $compile(_getDropdownListTemplate());
                var elementUL = linkFn(scope);
                container.append(elementUL);

                return container;
            }

            function _getDefaultContainer() {
                var linkFn = $compile(_getContainerTemplate());
                return linkFn(scope);
            }

            function _getContainerTemplate() {
                var html = '';
                html += '<div class="auto-complete-container unselectable"';
                html += '     data-instance-id="{{ ctrl.instanceId }}"';
                html += '     ng-show="ctrl.containerVisible">';
                html += _getDropdownListTemplate();
                html += '</div>';

                return html;
            }

            function _getDropdownListTemplate() {
                var html = '';
                html += '     <ul class="auto-complete-results">';
                html += '         <li ng-if="ctrl.renderItems.length"';
                html += '             ng-repeat="renderItem in ctrl.renderItems track by renderItem.id"';
                html += '             ng-click="ctrl.selectItem($index, true)"';
                html += '             class="auto-complete-item" data-index="{{ $index }}"';
                html += '             ng-class="ctrl.getSelectedCssClass($index)">';
                html += '               <auto-complete-item index="$index"';
                html += '                      item-template-link-fn="ctrl.itemTemplateLinkFn"';
                html += '                      render-item="renderItem"';
                html += '                      search-text="ctrl.searchText" />';
                html += '         </li>';
                html += '         <li ng-if="!ctrl.renderItems.length && ctrl.options.noMatchTemplateEnabled"';
                html += '             class="auto-complete-item auto-complete-no-match">';
                html += '               <auto-complete-no-match';
                html += '                      template="ctrl.options.noMatchTemplate"';
                html += '                      search-text="ctrl.searchText" />';
                html += '         </li>';
                html += '     </ul>';

                return html;
            }

            function _wireupEvents() {

                // when the target(textbox) gets focus activate the corresponding container
                element.on(DOM_EVENT.FOCUS, function () {
                    scope.$evalAsync(function () {
                        ctrl.activate();
                        if (ctrl.options.activateOnFocus) {
                            _waitAndQuery(element.val(), 100);
                        }
                    });
                });

                element.on(DOM_EVENT.INPUT, function () {
                    scope.$evalAsync(function () {
                        _tryQuery(element.val());
                    });
                });

                element.on(DOM_EVENT.KEYDOWN, function (event) {
                    var $event = event;
                    scope.$evalAsync(function () {
                        _handleElementKeyDown($event);
                    });
                });

                ctrl.container.find('ul').on(DOM_EVENT.SCROLL, function () {
                    if (!ctrl.options.pagingEnabled) {
                        return;
                    }

                    var list = this;
                    scope.$evalAsync(function () {
                        if (!ctrl.containerVisible) {
                            return;
                        }

                        // scrolled to the bottom?
                        if ((list.offsetHeight + list.scrollTop) >= list.scrollHeight) {
                            ctrl.tryLoadNextPage();
                        }
                    });
                });

                $document.on(DOM_EVENT.KEYDOWN, function (event) {
                    var $event = event;
                    scope.$evalAsync(function () {
                        _handleDocumentKeyDown($event);
                    });
                });

                $document.on(DOM_EVENT.CLICK, function (event) {
                    var $event = event;
                    scope.$evalAsync(function () {
                        _handleDocumentClick($event);
                    });
                });

                // $window is a reference to the browser's window object
                angular.element($window).on(DOM_EVENT.RESIZE, function () {
                    if (ctrl.options.hideDropdownOnWindowResize) {
                        scope.$evalAsync(function () {
                            ctrl.autoHide();
                        });
                    }
                });
            }

            function _ignoreKeyCode(keyCode) {
                return [
                    KEYCODE.TAB,
                    KEYCODE.ALT,
                    KEYCODE.CTRL,
                    KEYCODE.LEFTARROW,
                    KEYCODE.RIGHTARROW,
                    KEYCODE.MAC_COMMAND_LEFT,
                    KEYCODE.MAC_COMMAND_RIGHT
                ].indexOf(keyCode) !== -1;
            }

            function _handleElementKeyDown(event) {
                var keyCode = event.charCode || event.keyCode || 0;

                if (_ignoreKeyCode(keyCode)) {
                    return;
                }

                switch (keyCode) {
                    case KEYCODE.UPARROW:
                        ctrl.scrollToPreviousItem();

                        event.stopPropagation();
                        event.preventDefault();

                        break;

                    case KEYCODE.DOWNARROW:
                        ctrl.scrollToNextItem();

                        event.stopPropagation();
                        event.preventDefault();

                        break;

                    case KEYCODE.ENTER:
                        ctrl.selectItem(ctrl.selectedIndex, true);

                        //prevent postback upon hitting enter
                        event.preventDefault();
                        event.stopPropagation();

                        break;

                    case KEYCODE.ESCAPE:
                        ctrl.restoreOriginalText();
                        ctrl.autoHide();

                        event.preventDefault();
                        event.stopPropagation();

                        break;

                    default:
                        break;
                }
            }

            function _handleDocumentKeyDown() {
                // hide inactive dropdowns when multiple auto complete exist on a page
                helperService.hideAllInactive();
            }

            function _handleDocumentClick(event) {
                // hide inactive dropdowns when multiple auto complete exist on a page
                helperService.hideAllInactive();

                // ignore inline
                if (ctrl.isInline()) {
                    return;
                }

                // no container. probably destroyed in scope $destroy
                if (!ctrl.container) {
                    return;
                }

                // ignore target click
                if (event.target === ctrl.target[0]) {
                    event.stopPropagation();
                    return;
                }

                if (_containerContainsTarget(event.target)) {
                    event.stopPropagation();
                    return;
                }

                ctrl.autoHide();
            }

            function _tryQuery(searchText) {
                // query only if minimum number of chars are typed; else hide dropdown
                if ((ctrl.options.minimumChars === 0)
                    || (searchText && searchText.trim().length !== 0 && searchText.length >= ctrl.options.minimumChars)) {
                    _waitAndQuery(searchText);
                    return;
                }

                ctrl.autoHide();
            }

            function _waitAndQuery(searchText, delay) {
                // wait few millisecs before calling query(); this to check if the user has stopped typing
                var promise = $timeout(function () {
                    // has searchText unchanged?
                    if (searchText === element.val()) {
                        ctrl.query(searchText);
                    }

                    //cancel the timeout
                    $timeout.cancel(promise);

                }, (delay || 300));
            }

            function _containerContainsTarget(target) {
                // use native Node.contains
                // https://developer.mozilla.org/en-US/docs/Web/API/Node/contains
                var container = ctrl.container[0];
                if (angular.isFunction(container.contains) && container.contains(target)) {
                    return true;
                }

                // otherwise use .has() if jQuery is available
                if (window.jQuery && angular.isFunction(ctrl.container.has) &&
                    ctrl.container.has(target).length > 0) {

                    return true;
                }

                // assume target is not in container
                return false;
            }

            // cleanup on destroy
            var destroyFn = scope.$on('$destroy', function () {
                if (ctrl.container) {
                    ctrl.container.remove();
                    ctrl.container = null;
                }

                destroyFn();
            });
        }
    }

    MainCtrl.$inject = ['$q', '$window', '$document', '$timeout', '$templateRequest', '$compile', '$exceptionHandler'];
    function MainCtrl($q, $window, $document, $timeout, $templateRequest, $compile, $exceptionHandler) {
        var that = this;
        var originalSearchText = null;
        var queryCounter = 0;
        var dataLoadInProgress = false;
        var endOfPagedList = false;
        var currentPageIndex = 0;

        this.target = null;
        this.instanceId = -1;
        this.selectedIndex = -1;
        this.renderItems = [];
        this.containerVisible = false;
        this.searchText = null;
        this.itemTemplateLinkFn = null;

        this.isInline = function () {
            // if a dropdown jquery parent is provided it is assumed inline
            return angular.isElement(that.options.dropdownParent);
        };

        this.init = function (options) {
            that.instanceId = helperService.registerInstance(that);
            that.options = options;
            that.containerVisible = that.isInline();

            _safeCallback(that.options.ready, publicApi);
        };

        this.activate = function () {
            helperService.setActiveInstanceId(that.instanceId);
            // do not reset if the container (dropdown list) is currently visible
            // Ex: Switching to a different tab or window and switching back
            // again when the dropdown list is visible.
            if (!that.containerVisible) {
                originalSearchText = that.searchText = null;
            }
        };

        this.query = function (searchText) {
            that.empty();
            _reset();

            return _query(searchText, 0);
        };

        this.show = function () {
            // the show() method is called after the items are ready for display
            // the textbox position can change (ex: window resize) when it has focus
            // so reposition the dropdown before it's shown
            _positionDropdown();

            // callback
            _safeCallback(that.options.dropdownShown);
        };

        this.autoHide = function () {
            if (that.options && that.options.autoHideDropdown) {
                _hideDropdown();
            }
        };

        this.empty = function () {
            that.selectedIndex = -1;
            that.renderItems = [];
        };

        this.restoreOriginalText = function () {
            if (!originalSearchText) {
                return;
            }

            _setTargetValue(originalSearchText);
        };

        this.scrollToPreviousItem = function () {
            var itemIndex = _getItemIndexFromOffset(-1);
            if (itemIndex === -1) {
                return;
            }

            _scrollToItem(itemIndex);
        };

        this.scrollToNextItem = function () {
            var itemIndex = _getItemIndexFromOffset(1);
            if (itemIndex === -1) {
                return;
            }

            _scrollToItem(itemIndex);

            if (_shouldLoadNextPageAtItemIndex(itemIndex)) {
                _loadNextPage();
            }
        };

        this.selectItem = function (itemIndex, closeDropdownAndRaiseCallback) {
            var item = that.renderItems[itemIndex];
            if (!item) {
                return;
            }

            that.selectedIndex = itemIndex;

            _updateTarget();

            if (closeDropdownAndRaiseCallback) {
                that.autoHide();

                _safeCallback(that.options.itemSelected, { item: item.data });
            }
        };

        this.getSelectedCssClass = function (itemIndex) {
            return (itemIndex === that.selectedIndex) ? that.options.selectedCssClass : '';
        };

        this.tryLoadNextPage = function () {
            if (_shouldLoadNextPage()) {
                _loadNextPage();
            }
        };


        function _loadNextPage() {
            return _query(originalSearchText, (currentPageIndex + 1));
        }

        function _query(searchText, pageIndex) {
            var params = {
                searchText: searchText,
                paging: {
                    pageIndex: pageIndex,
                    pageSize: that.options.pageSize
                },
                queryId: ++queryCounter
            };

            var renderListFn = (that.options.pagingEnabled ? _renderPagedList : _renderList);

            return _queryInternal(params, renderListFn.bind(that, params));
        }

        function _queryInternal(params, renderListFn) {
            // backup original search term in case we need to restore if user hits ESCAPE
            originalSearchText = params.searchText;

            dataLoadInProgress = true;

            _safeCallback(that.options.loading);

            return $q.when(that.options.data(params.searchText, params.paging),
                function successCallback(result) {
                    // verify that the queryId did not change since the possibility exists that the
                    // search text changed before the 'data' promise was resolved. Say, due to a lag
                    // in getting data from a remote web service.
                    if (_didQueryIdChange(params)) {
                        that.autoHide();
                        return;
                    }

                    if (_shouldHideDropdown(params, result)) {
                        that.autoHide();
                        return;
                    }

                    renderListFn(result).then(function () {
                        that.searchText = params.searchText;
                        that.show();
                    });

                    // callback
                    _safeCallback(that.options.loadingComplete);
                },
                function errorCallback(error) {
                    that.autoHide();

                    _safeCallback(that.options.loadingComplete, { error: error });
                }).then(function () {
                    dataLoadInProgress = false;
                });
        }

        function _getItemIndexFromOffset(itemOffset) {
            var itemIndex = that.selectedIndex + itemOffset;

            if (itemIndex >= that.renderItems.length) {
                return -1;
            }

            return itemIndex;
        }

        function _scrollToItem(itemIndex) {
            if (!that.containerVisible) {
                return;
            }

            that.selectItem(itemIndex);

            var attrSelector = 'li[data-index="' + itemIndex + '"]';

            // use jquery.scrollTo plugin if available
            // http://flesler.blogspot.com/2007/10/jqueryscrollto.html
            if (window.jQuery && window.jQuery.scrollTo) {  // requires jquery to be loaded
                that.elementUL.scrollTo(that.elementUL.find(attrSelector));
                return;
            }

            var li = that.elementUL[0].querySelector(attrSelector);
            if (li) {
                // this was causing the page to jump/scroll
                //    li.scrollIntoView(true);
                that.elementUL[0].scrollTop = li.offsetTop;
            }
        }

        function _safeCallback(fn, args) {
            if (!angular.isFunction(fn)) {
                return;
            }

            try {
                return fn.call(that.target, args);
            } catch (ex) {
                //ignore
            }
        }

        function _positionDropdownIfVisible() {
            if (that.containerVisible) {
                _positionDropdown();
            }
        }

        function _positionDropdown() {
            // no need to position if container has been appended to
            // parent specified in options
            if (that.isInline()) {
                return;
            }

            var dropdownWidth = null;
            if (that.options.dropdownWidth && that.options.dropdownWidth !== 'auto') {
                dropdownWidth = that.options.dropdownWidth;
            }
            else {
                // same as textbox width
                dropdownWidth = that.target[0].getBoundingClientRect().width + 'px';
            }
            that.container.css({ 'width': dropdownWidth });

            if (that.options.dropdownHeight && that.options.dropdownHeight !== 'auto') {
                that.elementUL.css({ 'max-height': that.options.dropdownHeight });
            }

            // use the .position() function from jquery.ui if available (requires both jquery and jquery-ui)
            var hasJQueryUI = !!(window.jQuery && window.jQuery.ui);
            if (that.options.positionUsingJQuery && hasJQueryUI) {
                _positionUsingJQuery();
            }
            else {
                _positionUsingDomAPI();
            }
        }

        function _positionUsingJQuery() {
            var defaultPosition = {
                my: 'left top',
                at: 'left bottom',
                of: that.target,
                collision: 'none flip'
            };

            var position = angular.extend({}, defaultPosition, that.options.positionUsing);

            // jquery.ui position() requires the container to be visible to calculate its position.
            if (!that.containerVisible) {
                that.container.css({ 'visibility': 'hidden' });
            }
            that.containerVisible = true; // used in the template to set ng-show.
            $timeout(function () {
                that.container.position(position);
                that.container.css({ 'visibility': 'visible' });
            });
        }

        function _positionUsingDomAPI() {
            var rect = that.target[0].getBoundingClientRect();
            var DOCUMENT = $document[0];

            var scrollTop = DOCUMENT.body.scrollTop || DOCUMENT.documentElement.scrollTop || $window.pageYOffset;
            var scrollLeft = DOCUMENT.body.scrollLeft || DOCUMENT.documentElement.scrollLeft || $window.pageXOffset;

            that.container.css({
                'left': rect.left + scrollLeft + 'px',
                'top': rect.top + rect.height + scrollTop + 'px'
            });

            that.containerVisible = true;
        }

        function _updateTarget() {
            var item = that.renderItems[that.selectedIndex];
            if (!item) {
                return;
            }

            _setTargetValue(item.value);
        }

        function _setTargetValue(value) {
            that.target.val(value);
            that.textModelCtrl.$setViewValue(value);
        }

        function _hideDropdown() {
            if (that.isInline() || !that.containerVisible) {
                return;
            }

            // reset scroll position
            //that.elementUL[0].scrollTop = 0;
            that.containerVisible = false;
            that.empty();

            _reset();

            // callback
            _safeCallback(that.options.dropdownHidden);
        }

        function _shouldHideDropdown(params, result) {
            // do not hide the dropdown if the no match template is enabled
            // because the no match template is rendered within the dropdown container
            if (that.options.noMatchTemplateEnabled) {
                return false;
            }

            // do we have results to render?
            if (!_.isEmpty(result)) {
                return false;
            }

            // if paging is enabled hide the dropdown only when rendering the first page
            if (that.options.pagingEnabled) {
                return (params.paging.pageIndex === 0);
            }

            return true;
        }

        function _didQueryIdChange(params) {
            return (params.queryId !== queryCounter);
        }

        function _renderList(params, result) {
            return _getRenderFn().then(function (renderFn) {
                if (_.isEmpty(result)) {
                    return;
                }

                that.renderItems = _renderItems(renderFn, result);
            });
        }

        function _renderPagedList(params, result) {
            return _getRenderFn().then(function (renderFn) {
                if (_.isEmpty(result)) {
                    return;
                }

                var items = _renderItems(renderFn, result);

                // in case of paged list we add to the array instead of replacing it
                angular.forEach(items, function (item) {
                    that.renderItems.push(item);
                });

                currentPageIndex = params.paging.pageIndex;
                endOfPagedList = (items.length < that.options.pageSize);
            });
        }

        function _renderItems(renderFn, dataItems) {
            // limit number of items rendered in the dropdown
            var dataItemsToRender = _.slice(dataItems, 0, that.options.maxItemsToRender);

            var itemsToRender = _.map(dataItemsToRender, function (data, index) {
                // invoke render callback with the data as parameter
                // this should return an object with a 'label' and 'value' property where
                // 'label' is the template for display and 'value' is the text for the textbox
                // If the object has an 'id' property, it will be used in the 'track by' clause of ng-repeat in the template
                var item = renderFn(data);

                if (!item || !item.hasOwnProperty('label') || !item.hasOwnProperty('value')) {
                    return null;
                }

                // store the data on the renderItem and add to array
                item.data = data;
                // unique 'id' for use in the 'track by' clause
                item.id = item.hasOwnProperty('id') ? item.id : (item.value + item.label + index);

                return item;
            });

            return _.filter(itemsToRender, function (item) {
                return (item !== null);
            });
        }

        function _getRenderFn() {
            // user provided function
            if (angular.isFunction(that.options.renderItem) && that.options.renderItem !== angular.noop) {
                that.itemTemplateLinkFn = null;
                return $q.when(that.options.renderItem.bind(null));
            }

            return _getItemTemplate().then(function (template) {
                that.itemTemplateLinkFn = $compile(template);
                return _getRenderItem.bind(null, template);
            }).catch($exceptionHandler);
        }

        function _getItemTemplate() {
            // itemTemplateUrl
            if (that.options.itemTemplateUrl) {
                return $templateRequest(that.options.itemTemplateUrl);
            }

            // itemTemplate or default
            var template = that.options.itemTemplate || '<span ng-bind-html="entry.item"></span>';
            return $q.when(template);
        }

        function _getRenderItem(template, data) {
            var value = (angular.isObject(data) && that.options.selectedTextAttr) ? data[that.options.selectedTextAttr] : data;
            return {
                value: value,
                label: template
            };
        }

        function _shouldLoadNextPage() {
            return that.options.pagingEnabled && !dataLoadInProgress && !endOfPagedList;
        }

        function _shouldLoadNextPageAtItemIndex(itemIndex) {
            if (!_shouldLoadNextPage()) {
                return false;
            }

            var triggerIndex = that.renderItems.length - that.options.invokePageLoadWhenItemsRemaining - 1;
            return itemIndex >= triggerIndex;
        }

        function _reset() {
            originalSearchText = that.searchText = null;
            currentPageIndex = 0;
            endOfPagedList = false;
        }

        function _setOptions(options) {
            if (_.isEmpty(options)) {
                return;
            }

            angular.forEach(options, function (value, key) {
                if (defaultOptions.hasOwnProperty(key)) {
                    that.options[key] = value;
                }
            });
        }

        var publicApi = (function () {
            return {
                setOptions: _setOptions,
                positionDropdown: _positionDropdownIfVisible,
                hideDropdown: _hideDropdown
            };
        })();
    }

    autoCompleteItemDirective.$inject = ['$compile', '$rootScope', '$sce', '$controller'];
    function autoCompleteItemDirective($compile, $rootScope, $sce, $controller) {
        return {
            restrict: 'E',
            transclude: 'element',
            scope: {},
            controllerAs: 'ctrl',
            bindToController: {
                index: '<',
                renderItem: '<',
                searchText: '<',
                itemTemplateLinkFn: '<'
            },
            controller: function () { },
            link: function (scope, element) {
                var linkFn = null;
                if (_.isFunction(scope.ctrl.itemTemplateLinkFn)) {
                    linkFn = scope.ctrl.itemTemplateLinkFn;
                }
                else {
                    // Needed to maintain backward compatibility since the parameter passed to $compile must be html.
                    // When 'item' is returned from the 'options.renderItem' callback the 'label' might contain
                    // a trusted value [returned by a call to $sce.trustAsHtml(html)]. We can get the original
                    // html that was provided to $sce.trustAsHtml using the valueOf() function.
                    // If 'label' is not a value that had been returned by $sce.trustAsHtml, it will be returned unchanged.
                    var template = $sce.valueOf(scope.ctrl.renderItem.label);
                    linkFn = $compile(template);
                }

                linkFn(createEntryScope(scope), function (clonedElement) {
                    // append to the directive element's parent (<li>) since this directive element is replaced (transclude is set to 'element').
                    $(element[0].parentNode).append(clonedElement);
                });
            }
        };

        function createEntryScope(directiveScope) {
            var entryScope = $rootScope.$new(true);

            // for now its an empty controller. Additional logic can be added to this controller if needed
            var entry = entryScope.entry = $controller(angular.noop);

            var deregisterWatchesFn = _.map(['index', 'renderItem', 'searchText'], function (key) {
                return directiveScope.$watch(('ctrl.' + key), function (newVal) {
                    switch (key) {
                        case 'renderItem':
                            // add 'item' property on entryScope for backward compatibility
                            entry.item = entryScope.item = newVal.data;
                            break;
                        default:
                            entry[key] = newVal;
                            break;
                    }
                });
            });

            helperService.deregisterOnDestroy(directiveScope, deregisterWatchesFn);

            return entryScope;
        }
    }

    autoCompleteNoMatchDirective.$inject = ['$compile', '$rootScope', '$controller'];
    function autoCompleteNoMatchDirective($compile, $rootScope, $controller) {
        return {
            restrict: 'E',
            transclude: 'element',
            scope: {},
            controllerAs: 'ctrl',
            bindToController: {
                template: '<',
                searchText: '<'
            },
            controller: function () { },
            link: function (scope, element) {
                var linkFn = $compile(scope.ctrl.template);
                linkFn(createEntryScope(scope), function (clonedElement) {
                    // append to the directive element's parent (<li>) since this directive element is replaced (transclude is set to 'element').
                    $(element[0].parentNode).append(clonedElement);
                });
            }
        };

        function createEntryScope(directiveScope) {
            var entryScope = $rootScope.$new(true);

            // for now its an empty controller. Additional logic can be added to this controller if needed
            var entry = entryScope.entry = $controller(angular.noop);

            var deregisterFn = directiveScope.$watch('ctrl.searchText', function (newVal) {
                entry.searchText = newVal;
            });

            helperService.deregisterOnDestroy(directiveScope, [deregisterFn]);

            return entryScope;
        }
    }

    function HelperService() {
        var that = this;
        var plugins = [];
        var instanceCount = 0;
        var activeInstanceId = 0;

        this.registerInstance = function (instance) {
            if (instance) {
                plugins.push(instance);
                return ++instanceCount;
            }

            return -1;
        };

        this.setActiveInstanceId = function (instanceId) {
            activeInstanceId = instanceId;
            that.hideAllInactive();
        };

        this.hideAllInactive = function () {
            angular.forEach(plugins, function (ctrl) {
                // hide if this is not the active instance
                if (ctrl.instanceId !== activeInstanceId) {
                    ctrl.autoHide();
                }
            });
        };

        this.deregisterOnDestroy = function (scope, deregisterWatchesFn) {
            // cleanup on destroy
            var destroyFn = scope.$on('$destroy', function () {
                _.each(deregisterWatchesFn, function (deregisterFn) {
                    deregisterFn();
                });

                destroyFn();
            });
        };
    }

    var DOM_EVENT = {
        RESIZE: 'resize',
        SCROLL: 'scroll',
        CLICK: 'click',
        KEYDOWN: 'keydown',
        FOCUS: 'focus',
        INPUT: 'input'
    };

    var KEYCODE = {
        TAB: 9,
        ENTER: 13,
        CTRL: 17,
        ALT: 18,
        ESCAPE: 27,
        LEFTARROW: 37,
        UPARROW: 38,
        RIGHTARROW: 39,
        DOWNARROW: 40,
        MAC_COMMAND_LEFT: 91,
        MAC_COMMAND_RIGHT: 93
    };

    var defaultOptions = {
        /**
         * CSS class applied to the dropdown container.
         * @default null
         */
        containerCssClass: null,
        /**
         * CSS class applied to the selected list element.
         * @default auto-complete-item-selected
         */
        selectedCssClass: 'auto-complete-item-selected',
        /**
         * Minimum number of characters required to display the dropdown.
         * @default 1
         */
        minimumChars: 1,
        /**
         * Maximum number of items to render in the list.
         * @default 20
         */
        maxItemsToRender: 20,
        /**
         * If true displays the dropdown list when the textbox gets focus.
         * @default false
         */
        activateOnFocus: false,
        /**
         * Width in "px" of the dropddown list. This can also be applied using CSS.
         * @default 'auto'
         */
        dropdownWidth: 'auto',
        /**
         * Maximum height in "px" of the dropddown list. This can also be applied using CSS.
         * @default 'auto'
         */
        dropdownHeight: 'auto',
        /**
         * a jQuery object to append the dropddown list.
         * @default null
         */
        dropdownParent: null,
        /**
         * If the data for the dropdown is a collection of objects, this should be the name 
         * of a property on the object. The property value will be used to update the input textbox.
         * @default null
         */
        selectedTextAttr: null,
        /**
         * A template for the dropddown list item. For example "<p ng-bind-html='entry.item.name'></p>";
         * Or using interpolation "<p>{{entry.item.lastName}}, {{entry.item.firstName}}></p>".
         * @default null
         */
        itemTemplate: null,
        /**
         * This is similar to template but the template is loaded from the specified URL, asynchronously.
         * @default null
         */
        itemTemplateUrl: null,
        /**
         * Set to true to enable server side paging. See "data" callback for more information.
         * @default false
         */
        pagingEnabled: false,
        /**
         * The number of items to display per page when paging is enabled.
         * @default 5
         */
        pageSize: 5,
        /**
         * When using the keyboard arrow key to scroll down the list, the "data" callback will 
         * be invoked when at least this many items remain below the current focused item. 
         * Note that dragging the vertical scrollbar to the bottom of the list might also invoke a "data" callback.
         * @default 1
         */
        invokePageLoadWhenItemsRemaining: 1,
        /**
         * Set to true to position the dropdown list using the position() method from the jQueryUI library.
         * See <a href="https://api.jqueryui.com/position/">jQueryUI.position() documentation</a>
         * @default true
         * @bindAsHtml true
         */
        positionUsingJQuery: true,
        /**
         * Options that will be passed to jQueryUI position() method.
         * @default null
         */
        positionUsing: null,
        /**
         * Set to true to let the plugin hide the dropdown list. If this option is set to false you can hide the dropdown list
         * with the hideDropdown() method available in the ready callback.
         * @default true
         */
        autoHideDropdown: true,
        /**
         * Set to true to hide the dropdown list when the window is resized. If this option is set to false you can hide
         * or re-position the dropdown list with the hideDropdown() or positionDropdown() methods available in the ready.
         * callback.
         * @default true
         */
        hideDropdownOnWindowResize: true,
        /**
         * Set to true to enable the template to display a message when no items match the search text.
         * @default true
         */
        noMatchTemplateEnabled: true,
        /**
         * The template used to display the message when no items match the search text.
         * @default "<span>No results match '{{entry.searchText}}'></span>"
         */
        noMatchTemplate: "<span>No results match '{{entry.searchText}}'</span>",
        /**
         * Callback after the plugin is initialized and ready. The callback receives an object with the following methods:
         * @default angular.noop
         */
        ready: angular.noop,
        /**
         * Callback before the "data" callback is invoked.
         * @default angular.noop
         */
        loading: angular.noop,
        /**
         * Callback to get the data for the dropdown. The callback receives the search text as the first parameter.
         * If paging is enabled the callback receives an object with "pageIndex" and "pageSize" properties as the second parameter.
         * This function must return a promise.
         * @default angular.noop
         */
        data: angular.noop,
        /**
         * Callback after the items are rendered in the dropdown
         * @default angular.noop
         */
        loadingComplete: angular.noop,
        /**
         * Callback for custom rendering a list item. This is called for each item in the dropdown.
         * This must return an object literal with "value" and "label" properties where
         * "label" is the template for display and "value" is the text for the textbox.
         * If the object has an "id" property, it will be used in the "track by" clause of the ng-repeat of the dropdown list.
         * @default angular.noop
         */
        renderItem: angular.noop,
        /**
         * Callback after an item is selected from the dropdown. The callback receives an object with an "item" property representing the selected item.
         * @default angular.noop
         */
        itemSelected: angular.noop,
        /**
         * Callback after the dropdown is shown.
         * @default angular.noop
         */
        dropdownShown: angular.noop,
        /**
         * Callback after the dropdown is hidden.
         * @default angular.noop
         */
        dropdownHidden: angular.noop
    };

}));
;

ngAWDSApp.factory("ShoppingCartService", ['ShoppingCartFactory', 'LoginService', 'NotificationExtend', '$rootScope', '$filter', '$timeout', '$interval', '$parse', '$window', 'FormMailFactory', 'vcRecaptchaService', '$q', function (ShoppingCartFactory, LoginService, Notification, $rootScope, $filter, $timeout, $interval, $parse, $window, FormMailFactory, vcRecaptchaService, $q) {
    var timerInterval;
    var timerTimeout;
    var ProductSourceTypeOptions = {
        EclipseStock: "EclipseStock",
        EclipsePart: "EclipsePart",
        TPEHonda: "TPEHonda",
        TPEKawasaki: "TPEKawasaki",
        TPEYamaha: "TPEYamaha",
        TPEKTM: "TPEKTM",
        ERNewModel: "ERNewModel",
        ERProduct: "ERProduct",
        ERVehReqQuote: "ERVehReqQuote"
    };
    var $scope;
    var $element = $('body');
    var isRenderPaypalButton = false;
    var moShoppingSetting = {};
    var mlFreePickupsForAUSPostService = [];
    var moAUSPostPickupService = {
        "code": "Pick_Up_In_Store",
        "name": "Pick Up In Store",
        "price": 0,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "Free_Pickup",
                        "name": "Free pickup",
                        "price": 0,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostDeliveryBusinessDayOption = {
        "code": "DeliveryBusinessDay",
        "name": "Same business day delivery (orders before 11am)",
        "price": null,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "DeliveryBusinessDay",
                        "name": "Business Day",
                        "price": null,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostDeliveryByTotalBasketOption = {
        "code": "DeliveryByTotalBasket",
        "name": null,//"Same business day delivery (orders before 11am)",
        "price": null,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "DeliveryByTotalBasket",
                        "name": "",//"Business Day",
                        "price": null,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostFreeFreightCode = {
        "code": "Free_Freight_Code",//*** enable Free_Freight_Code option when mapped discount code
        "name": "Free Freight Code",
        "price": 0,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "Free_Delivery",
                        "name": "Free Delivery",
                        "price": 0,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostFreightEnquiryOption = {
        "code": "Freight_Enquiry_Code",
        //"name": "Get A Quote For Local Courier Delivery",
        "name": "Get A Quote For Delivery",
        "price": null,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "Freight_Enquiry",
                        "name": "Freight Costs TBA",
                        "price": null,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostStandardDeliveryFeeOption = {
        "code": "Standard_Delivery_Fee_Code",
        "name": "Delivery",
        "price": null,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "Standard_Delivery_Fee",
                        "name": "Standard Delivery",
                        "price": null,
                        "suboptions": {}
                    }
                ]
            }
    };
    var moAUSPostExpressPostOption = {
        "code": "Delivery_Express_Post_Code",
        "name": "Delivery",
        "price": null,
        "max_extra_cover": null,
        "options":
            {
                "option": [
                    {
                        "code": "Delivery_Express_Post",
                        "name": "Express Post (Australia Wide)",
                        "price": null,
                        "suboptions": {}
                    }
                ]
            }
    };

    var moAusPostDefault = {};

    var getDefaultShoppingCartOptions = function () {
        return {
            IsShowShoppingCart: true,
            IsShowMenuTotalPrice: false,
            IsShowQtyMinusAndPlus: false,
            IsAuthentinal: false,
            IsOnlyDeposit: false,
            IsPayment: false,
            HasDiscountInSubtotal: true,
            iWebsiteId: 0,
            iTotalBulkyPrice: 0,
            iTotalDiscountCodePrice: null,
            ErrorMsgSocialLogin: "",
            ClientSourceType: {},
            Recaptcha: {},
            RecaptchaDD: {},
            RecaptchaCOD: {},
            LoginViewModel: {
                IsCreateAccount: false,
                ClientSource: "",
                Email: "",
                Password: "",
                FullName: ""
            },
            PendingSales: []
        }
    }
    var setScope = function (scope) {
        $scope = scope;
    }
    var getScopeDirective = function () {
        return $scope;
    }
    var setShoppingSetting = function (oShoppingSetting) {
        moShoppingSetting = oShoppingSetting;
    }
    var getPropertyPrice = function (sPriceType, oShoppingSetting)
    {
        var sPropertyPrice = 'Price';
        if (oShoppingSetting.WSPSFleetPriceLabel != null && sPriceType == 'Fleet') {
            sPropertyPrice = 'FleetPrice';
        }
        return sPropertyPrice;
    }
    var toViewModel = function (response)
    {
        var jsonData = response.data;

        //#region mapping cart item
        if (jsonData.Carts != null && jsonData.Carts.length > 0)
        {
            for (var i = 0; i < jsonData.Carts.length; i++)
            {
                if (jsonData.Carts[i].ItemDetail != null)
                {
                    if (jsonData.Carts[i].Source == ProductSourceTypeOptions.EclipsePart) {
                        jsonData.Carts[i].WSPartItem = angular.fromJson(jsonData.Carts[i].ItemDetail);
                        jsonData.Carts[i].ItemDetail = null;
                    }
                }
                
            }
        }
        //#endregion

        if (jsonData.ShoppingSetting.HasWSPSBindBranchQAVToWebstore == true)
        {
        }

        return jsonData;
    }

    //#region GeneralFunction 
    var setStatusButton = function (jqElement, sStatus) {
        if (jqElement && jqElement.length > 0) {
            jqElement.button(sStatus);
        }
    }
    var disableButton = function (jqElement, isDisable) {
        if (jqElement && jqElement.length > 0) {
            isDisable = isDisable != null ? isDisable : true;
            if (isDisable) {
                jqElement.attr('disabled', 'disabled');
            } else {
                jqElement.removeAttr('disabled');
            }
        }
    }
    var getLocationState = function (cbSuccess) {
        ShoppingCartFactory.getLocationState().then(function (response) {
            var lLocationStates = response.data;
            lLocationStates = $filter('filter')(lLocationStates, function (x) { return x.Value != 'PNG' && x.Value != 'NZ ' });
            cbSuccess(lLocationStates);
        });
    }
    var getDealerBranches = function (sPickupAtLocation, cbSuccess) {
        sPickupAtLocation = sPickupAtLocation || null;
        ShoppingCartFactory.getDealerBranches().then(function (response) {
            var jsonData = angular.fromJson(response.data);
            var lResult = [];
            if (sPickupAtLocation != null) {
                for (var i = 0; i < jsonData.length; i++) {
                    if (jsonData[i].Value == sPickupAtLocation)
                    {
                        lResult.push(jsonData[i]);
                        break;
                    }
                }
                cbSuccess(lResult);
            } else {
                cbSuccess(jsonData);
            }
        });
    }
    var getPickupAtLocationItem = function (lItems) {
        var sLocation = null;
        for (var i = 0; i < lItems.length; i++) {
            var sPickupAtLocation = $rootScope.webApp.util.getParameterByName('pickupatbranch', lItems[i].SpecialOptions);
            if ($rootScope.webApp.util.hasVal(sPickupAtLocation)) {
                sLocation = sPickupAtLocation;
                break;
            }
        }
        return sLocation;
    }

    var updateClientInfo = function (oClient, oClientSourceType, cbSuccess) {
        var oPostcodeSuburb = null;
        if (oClient != null) {
            //oClient.Phone = Number(oClient.Phone);
            if (Number(oClient.Phone) == 0) {
                oClient.Phone = null;
            }
            cbSuccess(oClient);
        }
        else {                                    
            cbSuccess({Source: oClientSourceType.NonRegistered});
        }
    }
    var loadScriptTagGAEcommerceTracking = function () {
        //function initScript(d, s, id) {
        //    var js, fjs = d.getElementsByTagName(s)[0];
        //    if (d.getElementById(id)) {                
        //        return;
        //    }
        //    else {
        //        js = d.createElement(s); js.id = id;
        //        js.src = ('https:' == d.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        //        js.async = true;
        //        fjs.parentNode.insertBefore(js, fjs);
        //        //js.onload = function () {                    
        //        //};
        //    }
        //}
        //initScript(document, 'script', 'ga-ecommerce-tracking');
        var src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        _createElementScript('ga-ecommerce-tracking', src, true, null);
        //(function() {
        //    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        //    ga.src = ('https:' == document.location.protocol ? 'https://ssl': 'http://www') + '.google-analytics.com/ga.js';
        //    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        //})();
    }
    var _createElementScript = function (id, src, async, cbOnload) {
        var d = document;
        var s = 'script';
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) {
            return;
        }
        else {
            js = d.createElement(s); js.id = id;
            js.src = src;
            js.async = async;
            fjs.parentNode.insertBefore(js, fjs);
            if (angular.isFunction(cbOnload)) {
                js.onload = cbOnload;
            }
            //js.onload = function () {                    
            //};
        }
    }
    var createElementScript = function (oCardHeader) {        

        if ($rootScope.util.equalsLowerCase(oCardHeader.CreditCardType, 'tyro'))
        {
            createAllElementScripts(['tyro']);
        }
    }
    var createAllElementScripts = function (arrPaymentType) {

        if (arrPaymentType && arrPaymentType.length > 0)
        {
            for (var i = 0; i < arrPaymentType.length; i++) {
                if ($rootScope.webApp.util.indexOfLowerCase(arrPaymentType[i],'tyro')) {
                    _createElementScript('simplify-pay', 'https://www.simplify.com/commerce/simplify.pay.js', true, null);//*** SimplifyCommerce
                }

                //if (arrPaymentType[i].indexOfLowerCase('stripe')) {
                if ($rootScope.webApp.util.indexOfLowerCase(arrPaymentType[i], 'stripe')) {
                    _createElementScript('stripe-pay', 'https://js.stripe.com/v3/', true, null);//*** Stripe
                }
            }
            

        }
        
    }
    
    var hasPayWithPayright = function () {
        return moShoppingSetting.HasPayWithPayright;
    }

    //#endregion
    
    //#region html functions 
    var getPriceQty = function (price, qty) {
        price = CNumberNull(price);
        if (price != null) {
            price = price.toFixed(2);
        }
        return price * qty;
    }
    var getDeliveryFee = function (oAusPostCalculate, lPendingSales) {
        var iDeliveryFee = null;
        if (moShoppingSetting.HasDeliveryOptions)
        {
            if (angular.isDefined(oAusPostCalculate) && angular.isDefined(oAusPostCalculate.postage_result)) {
                if (oAusPostCalculate.postage_result.service == "Pick_Up_In_Store"
                    || oAusPostCalculate.postage_result.service == "Free_Delivery") {
                    iDeliveryFee = 0;
                }
                else if (oAusPostCalculate.postage_result.service == moAUSPostFreeFreightCode.code) {
                    iDeliveryFee = moAUSPostFreeFreightCode.price;
                }
                else if (oAusPostCalculate.postage_result.service == moAUSPostDeliveryBusinessDayOption.code) {
                    iDeliveryFee = moAUSPostDeliveryBusinessDayOption.price;
                }
                else if (moShoppingSetting.jsonDeliveryLocal && oAusPostCalculate.postage_result.service == moShoppingSetting.jsonDeliveryLocal.code) {
                    iDeliveryFee = moShoppingSetting.jsonDeliveryLocal.price;
                }
                else if (moShoppingSetting.jsonDeliveryCourier && oAusPostCalculate.postage_result.service == moShoppingSetting.jsonDeliveryCourier.code) {
                    iDeliveryFee = moShoppingSetting.jsonDeliveryCourier.price;
                }
                else if (oAusPostCalculate.postage_result.service == moAUSPostDeliveryByTotalBasketOption.code) {
                    iDeliveryFee = moAUSPostDeliveryByTotalBasketOption.price;
                }
                else if (oAusPostCalculate.postage_result.service == moAUSPostFreightEnquiryOption.code) {
                    iDeliveryFee = 0;
                } else {
                    var iDealerExtraFee = 0;
                    if ($scope.AusPost.ServiceIn != null
                        //&& $scope.AusPost.ServiceIn == 'Bind_LWHW_To_Option_Standard'
                        && ($rootScope.webApp.util.indexOfLowerCase($scope.AusPost.ServiceIn, 'Bind_LWHW_To_Option_Standard')
                                || $rootScope.webApp.util.indexOfLowerCase($scope.AusPost.ServiceIn, 'Bind_LWHW_To_Option_Inc_Oversize'))
                        && moShoppingSetting.HasWSPSBindLWHWToWebstore == true)
                    {
                        //*** the extra fee has included in _calcAusPostBind_LWHW_To_Option_Standard function
                        iDealerExtraFee = 0;
                    }
                    else {
                        if ($rootScope.util.hasVal($scope.AusPost.DealerExtraFee)) {
                            iDealerExtraFee = $rootScope.util.toNumber($scope.AusPost.DealerExtraFee);
                        }
                    }

                    var iNewAgeGoldCoastWebsiteId = 369;//NewAgeGoldCoast special setting
                    var iNewAgeAdelaide = 371;
                    if ($scope.ShoppingCart.WebsiteId == iNewAgeGoldCoastWebsiteId || $scope.ShoppingCart.WebsiteId == iNewAgeAdelaide)
                    {
                        iDeliveryFee = $rootScope.util.toNumber(oAusPostCalculate.postage_result.total_cost) + (iDealerExtraFee);
                    } else {
                        iDeliveryFee = $rootScope.util.toNumber(oAusPostCalculate.postage_result.total_cost) + (iDealerExtraFee) + $rootScope.util.toNumber(getTotalBulkyPrice(lPendingSales));
                    }                    
                }
            }
        }
        
        return iDeliveryFee;
    }
    var getFittedPrice = function (item) {
        var price = null;
        if ($rootScope.webApp.util.hasVal(item.SpecialOptions)) {
            var sVal = $rootScope.webApp.util.getParameterByName('fittedPrice', item.SpecialOptions);
            if ($rootScope.webApp.util.hasVal(sVal)) {
                price = Number(sVal);
            }
        }
        return price;
    }
    var getBulkyPrice = function (item) {
        var price = null;
        if ($rootScope.webApp.util.hasVal(item.SpecialOptions)) {
            var sBulky = $rootScope.webApp.util.getParameterByName('bulky', item.SpecialOptions);
            if ($rootScope.webApp.util.hasVal(sBulky)) {
                price = (Number(sBulky) * (Number(item['Quantity'])));
            }
        }
        return price;
    }
    var getBulkyPriceOfERProduct = function (item) {
        var price = null;
        if ($rootScope.util.hasVal(item.SpecialOptions)) {
            var sBulky = $rootScope.util.getParameterByName('ERBulky', item.SpecialOptions);
            if ($rootScope.util.hasVal(sBulky)) {
                price = (Number(sBulky) * item.Quantity);
            }
        }
        return price;
    }
    var getPriceDepositAmount = function (item, oShoppingSetting) {
        var priceTemp = null;
        var sPropertyPrice = getPropertyPrice(item.PriceType, oShoppingSetting);        
        item[sPropertyPrice] = CNumberNull(item[sPropertyPrice]);
        if (item[sPropertyPrice] != null) {
            item[sPropertyPrice] = item[sPropertyPrice].toFixed(2);
            if (item.IsUseDeposit == true) {
                if ($rootScope.util.hasVal(oShoppingSetting.MaxPriceDepositCond)) {
                    if ($rootScope.util.hasVal(oShoppingSetting.FixedPriceDeposit)) {
                        priceTemp = Number(oShoppingSetting.FixedPriceDeposit);
                    } else {
                        if (Number(item[sPropertyPrice]) > Number(oShoppingSetting.MaxPriceDepositCond)) {
                            priceTemp = oShoppingSetting.MaxPriceDepositCond / 10;
                        } else {
                            priceTemp = item[sPropertyPrice] / 10;
                        }
                    }
                } else {
                    priceTemp = item[sPropertyPrice] / 10;
                }
                priceTemp = priceTemp.toFixed(2);
            }
            else {
                priceTemp = item[sPropertyPrice];
            }
        }
        return priceTemp;
    }
    var getDiscountCodePrice = function (item, oShoppingDiscountCode, oShoppingSetting) {
        var totalItem = getPriceDepositAmount(item, oShoppingSetting) * item.Quantity;
        item.DiscountPrice = totalItem * (oShoppingDiscountCode.DiscountAmount / 100);
        return totalItem - item.DiscountPrice;
    }
    var getDiscountCodePriceNotQty = function (item, oShoppingDiscountCode, oShoppingSetting) {
        var totalItem = getPriceDepositAmount(item, oShoppingSetting);
        item.DiscountPrice = totalItem * (oShoppingDiscountCode.DiscountAmount / 100);
        return totalItem - item.DiscountPrice;
    }
    var getTotalDiscountCodePrice = function (oShoppingDiscountCode, lPendingSales) {
        if (oShoppingDiscountCode.ResponseMessage == "IsValid") {
            //var lParts = $filter('filter')(lPendingSales, function (x) { return x.RefType.indexOf('Part') == 0 });//*** (Ontime #6413) get all Parts by RefType has value is part and PartNumber
            var lParts = $filter('filter')(lPendingSales, function (x) { return true });//(Ontime #8666: ability to control which type of product the discount code applies)
            if (lParts.length > 0) {
                var totalPart = 0;
                angular.forEach(lParts, function (value) {
                    var lShoppingDiscountCodeDetail = $filter('filter')(oShoppingDiscountCode.ShoppingDiscountCodeDetail, function (x) { return x.ProductSourceType == value['Source'] });
                    if (lShoppingDiscountCodeDetail.length > 0) {
                        if (value['Source'] == ProductSourceTypeOptions.EclipsePart)
                        {
                            var lShoppingDiscountWSPCategories = $filter('filter')(lShoppingDiscountCodeDetail, function (x) { return $rootScope.webApp.util.toNumber(x.WSPartCategoryId) > 0 });
                            if (lShoppingDiscountWSPCategories.length > 0) {
                                var sWSPCateIds = $rootScope.webApp.util.getParameterByName('wspcateIds', value.SpecialOptions);
                                if ($rootScope.webApp.util.hasVal(sWSPCateIds))
                                {
                                    var splitWSPCateIds = sWSPCateIds.split(';');
                                    for (var i = 0; i < lShoppingDiscountWSPCategories.length; i++) {
                                        if (splitWSPCateIds.indexOf(lShoppingDiscountWSPCategories[i].WSPartCategoryId+'') >= 0)
                                        {
                                            totalPart = totalPart + (Number(value['Quantity']) * getPriceDepositAmount(value, $scope.oShoppingSetting));
                                            break;
                                        }
                                    }
                                }                                

                            } else {
                                totalPart = totalPart + (Number(value['Quantity']) * getPriceDepositAmount(value, $scope.oShoppingSetting));
                            }
                        } else {
                            totalPart = totalPart + (Number(value['Quantity']) * getPriceDepositAmount(value, $scope.oShoppingSetting));
                        }                        
                    }
                });
                return totalPart * (oShoppingDiscountCode.DiscountAmount / 100);
            }
        }
        return null;
    }
    var getTotalPendingSalePrice = function (oShoppingSetting, lPendingSales) {
        var sum = 0;
        angular.forEach(lPendingSales, function (item) {
            sum = sum + ($rootScope.util.toNumber(item['Quantity']) * getPriceDepositAmount(item, oShoppingSetting));
        });
        return sum;
    }
    var getTotalBulkyPrice = function (lPendingSales) {
        var tempBulky = null;
        angular.forEach(lPendingSales, function (item) {
            tempBulky = tempBulky + getBulkyPrice(item);
        });
        return tempBulky != null ? Number(tempBulky) : null;
    }
    var getTotalBulkyPriceOfERProduct = function (lPendingSales) {
        var tempBulky = null;
        angular.forEach(lPendingSales, function (item) {
            tempBulky = tempBulky + getBulkyPriceOfERProduct(item);
        });
        return tempBulky;
    }
    var getTotalBasketWithoutDeliveryFee = function (oShoppingDiscountCode, oShoppingSetting, lPendingSales) {
        //var iTotalBulkyPrice = getTotalBulkyPrice(lPendingSales);
        var price = null;
        var iTotalDiscountCodePrice = getTotalDiscountCodePrice(oShoppingDiscountCode, lPendingSales);

        if (iTotalDiscountCodePrice != null) {
            $scope.ShoppingCart.iTotalDiscountCodePrice = iTotalDiscountCodePrice;
            price = getTotalPendingSalePrice(oShoppingSetting, lPendingSales) - iTotalDiscountCodePrice;// + getDeliveryFee(oAusPostCalculate, lPendingSales);
        }
        else {
            price = getTotalPendingSalePrice(oShoppingSetting, lPendingSales);// + getDeliveryFee(oAusPostCalculate, lPendingSales);
        }

        return price;
    }
    var getTotalBasket = function (oShoppingDiscountCode, oAusPostCalculate, oShoppingSetting, lPendingSales) {
        //var iTotalBulkyPrice = getTotalBulkyPrice(lPendingSales);
        var price = null;
        //var iTotalDiscountCodePrice = getTotalDiscountCodePrice(oShoppingDiscountCode, lPendingSales);        
        //if (iTotalDiscountCodePrice != null) {
        //    $scope.ShoppingCart.iTotalDiscountCodePrice = iTotalDiscountCodePrice;
        //    price = getTotalPendingSalePrice(oShoppingSetting, lPendingSales) - iTotalDiscountCodePrice;// + getDeliveryFee(oAusPostCalculate, lPendingSales);
        //}
        //else {
        //    price = getTotalPendingSalePrice(oShoppingSetting, lPendingSales);// + getDeliveryFee(oAusPostCalculate, lPendingSales);
        //}

        price = getTotalBasketWithoutDeliveryFee(oShoppingDiscountCode, oShoppingSetting, lPendingSales);
        var iDeliveryFee = getDeliveryFee(oAusPostCalculate, lPendingSales);

        if (iDeliveryFee != null) {
            price = price + iDeliveryFee;
        }

        return price;
    }

    var getSourceCodeAndDesc = function (oItem) {
        var sVal = "";
        var sSourceDesc = csourceCodeToDesc(oItem);
        if (sSourceDesc != "") {
            sVal = sSourceDesc + " " + oItem.ItemCode;// + " " + oItem.ItemDesc;

        }

        if ($rootScope.webApp.util.indexOfLowerCase(oItem.ItemDesc, 'Colour:') == true || $rootScope.webApp.util.indexOfLowerCase(oItem.ItemDesc, 'Size:') == true) {
            sVal = sVal + " " + oItem.ItemDesc
        } else {
            //sVal = oItem.ItemDesc
        }

        return sVal;
    }
    var getLoginDropdownContextHeaderTemplate = function (options) {        
        var sTemplate = "";
        if ($rootScope.webApp.util.toBool(options.HasWishlist)) {            
            sTemplate = "scLoginDropdownContextHeaderWishlistTemplate.html";
        } else {            
            if ($rootScope.webApp.util.toBool($rootScope.webApp.isShoppingLoginLink)) {                
                sTemplate = "scLoginLinkDropdownContextHeaderTemplate.html";
            } else {
                sTemplate = "scLoginDropdownContextHeaderTemplate.html";
            }
        }
        return sTemplate;
    }
    var csourceCodeToDesc = function (oItem) {
        //convert source code to desc
        var sVal = "";
        switch (oItem.Source) {
            case 'EclipseStock':
                sVal = "Stock Number:";
                break;
            case 'ERNewModel':
                sVal = "Model:";
                break;
            case 'ERProduct':
                sVal = "Product Number:";
                break;
            case 'EclipsePart':
                sVal = "Part Number:";
                break;
            case 'TPEKawasaki':
                sVal = "Kawasaki Part #:";
                break;
            case 'TPEHonda':
                sVal = "Honda Part #:";
                break;
            case 'TPEYamaha':
                sVal = "Yamaha Part #:";
                break;
            case 'TPEKTM':
                sVal = "KTM Part #:";
                break;
            default:
                break;
        }
        return sVal;
    }
    var hasBulkyItem = function (oItem) {
        // the function is check Only pickup in store
        var bVal = false;
        var sBulkyItem = $rootScope.webApp.util.getParameterByName('isBulkyItem', oItem.SpecialOptions);
        if ($rootScope.webApp.util.toBool(sBulkyItem)) {
            bVal = true;
        }
        return bVal;
    }
    var hasFittedItem = function (oItem) {        
        var bVal = false;
        var sBulkyItem = $rootScope.webApp.util.getParameterByName('fitted', oItem.SpecialOptions);
        if ($rootScope.webApp.util.trimString(sBulkyItem) == "1") {
            bVal = true;
        }
        return bVal;
    }
    var hasFittedItemInList = function (lPendingSales) {
        var bVal = false;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (hasFittedItem(lPendingSales[i])) {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var hasWSPSFleetPriceInList = function (lPendingSales) {
        if (moShoppingSetting.WSPSFleetPriceLabel == null) return false;
        var bVal = false;        
        for (var i = 0; i < lPendingSales.length; i++) {
            if (Number(lPendingSales[i].FleetPrice) > 0) {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var hasTickedFleetPriceInList = function (lPendingSales) {
        if (moShoppingSetting.WSPSFleetPriceLabel == null) return false;
        var bVal = false;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (lPendingSales[i].PriceType == 'Fleet') {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var hasAusPostServiceIn = function (sAusPostServiceName)
    {
        var bVal = false;
        if (($scope && $scope.AusPost && $scope.AusPost.ServiceIn != null) && (moShoppingSetting && moShoppingSetting.AusPostIsUnused == false))
        {
            if ($scope.AusPost.ServiceIn.indexOf(';') > -1) {
                var aServiceIn = $scope.AusPost.ServiceIn.split(';');
                bVal = (aServiceIn.indexOf(sAusPostServiceName) > -1);
            } else {
                bVal = $rootScope.webApp.util.equalsLowerCase($scope.AusPost.ServiceIn, sAusPostServiceName);                
            }
        }
        return bVal;
    }
    var hasBulkyWSCategory = function (oItem) {        
        return getBulkyPrice(oItem) != null;
    }
    var hasBulkyWSCategoryInList = function (lPendingSales) {        
        var bVal = false;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (hasBulkyWSCategory(lPendingSales[i]))
            {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var hasPickupOnlyItem = function (oItem) {
        var bVal = false;
        var sBulkyItem = $rootScope.webApp.util.getParameterByName('pickupOnly', oItem.SpecialOptions);
        if ($rootScope.webApp.util.toBool(sBulkyItem)) {
            bVal = true;
        }
        return bVal;
    }
    var hasSmallParcelItem = function (oItem) {
        var bVal = false;
        var sParam = $rootScope.webApp.util.getParameterByName('smParcel', oItem.SpecialOptions);
        if ($rootScope.webApp.util.toBool(sParam)) {
            bVal = true;
        }
        return bVal;
    }
    var hasExceededParcelItemInList = function (lPendingSales) {
        var bVal = false;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (hasExceededParcelItem(lPendingSales[i])) {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var hasExceededParcelItem = function (oPendingItem) {
        
        var len = $rootScope.webApp.util.getParameterByName('len', oPendingItem.SpecialOptions);
        var wd = $rootScope.webApp.util.getParameterByName('wd', oPendingItem.SpecialOptions);
        var ht = $rootScope.webApp.util.getParameterByName('h', oPendingItem.SpecialOptions);
        var wt = $rootScope.webApp.util.getParameterByName('wt', oPendingItem.SpecialOptions);
        len = $rootScope.webApp.util.toFloat(len);
        wd = $rootScope.webApp.util.toFloat(wd);
        ht = $rootScope.webApp.util.toFloat(ht);
        wt = $rootScope.webApp.util.toFloat(wt);

        var oSizeItem = {
            id: oPendingItem.RefId,
            L: len,
            W: wd,
            H: ht,
            WT: wt,
            Qty: oPendingItem.Quantity
        }
        return _hasExceededParcelSizeItem(oSizeItem);
        
    }
    var hasPickupOnlyCategoryInListItems = function (lPendingSales) {
        var bVal = false;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (hasPickupOnlyItem(lPendingSales[i]))
            {
                bVal = true;
                break;
            }
        }
        return bVal;
    }
    var isAllSmallParcelInListItems = function (lPendingSales) {
        var bVal = true;
        for (var i = 0; i < lPendingSales.length; i++) {
            if (hasSmallParcelItem(lPendingSales[i]) == false) {
                bVal = false;
                break;
            }
        }
        return bVal;
    }

    var isAllowChangeQty = function (iWebsiteId, oItem) {
        if (iWebsiteId == 342)//*** Minh ::20200618:: allow change qty on the patrol website.
        {
            return true;
        }

        var bVal = false;
        if (oItem.Source != 'EclipseStock' && oItem.Source != 'ERNewModel') {
            bVal = true;
        }
        return bVal;
    }
    var isOnlyPickupInStore = function (iWebsiteId, lPendingSales) {        
        var bVal = false;
        //|| hasPickupOnlyItem(x) == true
        //if (iWebsiteId == 229)
        //{
        //    return true;//*** Minh::20210531:: Rova range only pickup in store while waiting complete task #12178 new view required to handle bulky from engineroom parts.
        //}
        if ($filter('filter')(lPendingSales, function (x) { return hasBulkyItem(x) == true || x.Source == 'ERNewModel' || x.Source == 'EclipseStock' }).length > 0) {
            bVal = true;//we can use systemparam for ERNewModel-bulky items like WSPartBulky setup
        }
        return bVal;
    }
    var isShowItemCode = function (oItem) {
        var sCode = csourceCodeToDesc(oItem);
        return sCode != "";
        //return oItem.Source == 'TPEKawasaki' || oItem.Source == 'TPEYamaha';
    }
    var isShowBulkyItemLabel = function (oItem) {
        var bVal = false;
        //var bHasBulkyItem = hasBulkyItem(oItem);
        //if ($rootScope.webApp.util.toBool(bHasBulkyItem)) {
        //    return true;
        //}

        var priceERBulkyItem = getBulkyPriceOfERProduct(oItem);
        if (Number(priceERBulkyItem) > 0) {
            return true;
        }

        var priceBulkyItem = getBulkyPrice(oItem);
        if (Number(priceBulkyItem) > 0) {
            return true;
        }

        return bVal;
    }
    var isValidSpecialOptions = function (oItem, sParam, sVal) {
        var bVal = false;
        
        if ($rootScope.util.hasVal(oItem.SpecialOptions)) {
            var sParamValue = $rootScope.util.getParameterByName(sParam, oItem.SpecialOptions);
            if ($rootScope.util.equalsLowerCase(sParamValue, sVal)) {
                bVal = true;
            }
        }


        return bVal;
    }
    //#endregion

    //#region login
    var showSignupOrLoginForm = function (IsSignUp) {
        $scope.ShoppingCart.LoginViewModel = {
            IsCreateAccount: IsSignUp,
            ClientSource: $scope.ShoppingCart.ClientSourceType.System,
            Email: "",
            Password: "",
            FullName: ""
        }
        $scope.ShoppingCartFormLogin.submitted = false;
        $scope.ShoppingCartFormLogin.Email.$setValidity("serverMessage", true);
        $parse('ShoppingCartFormLogin.Email.$error.serverMessage').assign($scope, undefined);
        $scope.ShoppingCartFormLogin.$setPristine();
        //$scope.ShoppingCartFormLogin.$setValidity();
        $scope.ShoppingCartFormLogin.$setUntouched();
        //$scope.$apply();
    }
    var submitLoginForm = function (sClientSourceType, cbSuccess) {
        $scope.ShoppingCart.LoginViewModel.ClientSource = sClientSourceType;
        var params = angular.copy($scope.ShoppingCart.LoginViewModel);
        if (params.ClientSource != $scope.ShoppingCart.ClientSourceType.System) {
            params.Password = "";
            ShoppingCartFactory.Login(params).then(function (response) {
                var jsonData = response.data;                
                $scope.ShoppingCart.IsAuthentinal = true;
                $scope.ShoppingCart.LoginViewModel.FullName = jsonData.Client.FullName;
                $scope.ShoppingCart.LoginViewModel.FirstName = jsonData.Client.FirstName;
                $scope.ShoppingCart.LoginViewModel.LastName = jsonData.Client.LastName;
                cbSuccess(response);
            }, function () { })
        }
        else {
            $scope.ShoppingCartFormLogin.submitted = true;
            if ($scope.ShoppingCartFormLogin.$valid) {
                params.Password = LoginService.Base64.encode(params.Password);
                ShoppingCartFactory.Login(params).then(function (response) {
                    var jsonData = response.data;
                    var serverMessage = $parse('ShoppingCartFormLogin.Email.$error.serverMessage');
                    if (jsonData.ErrorMsg != "") {
                        //*** show error message ***
                        $scope.ShoppingCartFormLogin.Email.$setValidity("serverMessage", false);
                        serverMessage.assign($scope, jsonData.ErrorMsg);
                    } else {
                        //*** hide popup login ***
                        $scope.ShoppingCartFormLogin.Email.$setValidity("serverMessage", true);
                        serverMessage.assign($scope, undefined);
                        $scope.ShoppingCart.IsAuthentinal = true;
                        $scope.ShoppingCart.LoginViewModel.FullName = jsonData.Client.FullName;
                        $scope.ShoppingCart.LoginViewModel.FirstName = jsonData.Client.FirstName;
                        $scope.ShoppingCart.LoginViewModel.LastName = jsonData.Client.LastName;
                        cbSuccess(response);
                    }
                }, function () { })
            }
        }
    }
    var submitLoginFB = function () {
        var fetchUserDetails = function () {
            $window.FB.api('/me?fields=name,email,picture', function (res) {
                if (!res || res.error) {
                    $scope.ShoppingCart.ErrorMsgSocialLogin = "Error occured while fetching user details.";
                }
                else {
                    $scope.ShoppingCart.LoginViewModel.Email = res.email;
                    $scope.ShoppingCart.LoginViewModel.FullName = res.name;
                    if ($rootScope.webApp.util.hasVal($scope.ShoppingCart.LoginViewModel.FullName) == false) {
                        $scope.ShoppingCart.LoginViewModel.FullName = $scope.ShoppingCart.LoginViewModel.Email.split('@')[0];
                    }
                    $scope.ShoppingCart.Login($scope.ShoppingCart.ClientSourceType.Facebook);
                }
            });
        }

        if (typeof ($window.FBAppId) == "undefined") {
            console.error("sys-ex: FB app ID is undefined");
        } else {
            $window.FB.getLoginStatus(function (response) {
                if (response.status === "connected") {
                    fetchUserDetails();
                } else {
                    $window.FB.login(function (response) {
                        if (response.status === "connected") {
                            fetchUserDetails();
                        }
                    }, { scope: 'email,public_profile', auth_type: 'rerequest' });
                }
            });
        }
    }
    var submitLoginGoogle = function () {

        var GoogleAuthFetchUserDetails = function () {
            var currentUser = $scope.gauth.currentUser.get();
            var profile = currentUser.getBasicProfile();
            //var idToken = currentUser.getAuthResponse().id_token;
            //var accessToken = currentUser.getAuthResponse().access_token;
            //var aaaa =  {
            //    token: accessToken,
            //    idToken: idToken,
            //    name: profile.getName(),
            //    email: profile.getEmail(),
            //    uid: profile.getId(),
            //    provider: "google",
            //    imageUrl: profile.getImageUrl()
            //}
            //console.warn("Minh: GoogleAuthFetchUserDetails", {
            //    FullName: profile.getName(),
            //    GivenName: profile.getGivenName(),
            //    FamilyName: profile.getFamilyName()
            //});

            $scope.ShoppingCart.LoginViewModel.Email = profile.getEmail();
            $scope.ShoppingCart.LoginViewModel.FullName = profile.getName();
            $scope.ShoppingCart.LoginViewModel.FirstName = profile.getGivenName();
            $scope.ShoppingCart.LoginViewModel.LastName = profile.getFamilyName();

            if ($rootScope.webApp.util.hasVal($scope.ShoppingCart.LoginViewModel.FullName) == false) {
                $scope.ShoppingCart.LoginViewModel.FullName = $scope.ShoppingCart.LoginViewModel.Email.split('@')[0];
            }
            if ($rootScope.webApp.util.hasVal($scope.ShoppingCart.LoginViewModel.FirstName) == false) {
                $scope.ShoppingCart.LoginViewModel.FirstName = $scope.ShoppingCart.LoginViewModel.FullName;
            }
           
            $scope.ShoppingCart.Login($scope.ShoppingCart.ClientSourceType.Google);
        }

        if (typeof ($window.GoogleAppId) == "undefined" && typeof ($rootScope.webApp.ga.appId) == "undefined")
        {
            console.error("sys-ex: google app ID is undefined");
        } else {
            if (typeof ($scope.gauth) == "undefined") {
                $scope.gauth = gapi.auth2.getAuthInstance();
                if (!$scope.gauth.isSignedIn.get()) {
                    $scope.gauth.signIn().then(function (googleUser) {
                        console.warn("Minh: googleUser", googleUser)
                        //socialLoginService.setProvider("google");
                        //$rootScope.$broadcast('event:social-sign-in-success', fetchUserDetails());
                        GoogleAuthFetchUserDetails();
                    }, function (err) {
                        console.log(err);
                    });
                } else {
                    //socialLoginService.setProvider("google");
                    //$rootScope.$broadcast('event:social-sign-in-success', fetchUserDetails());
                    GoogleAuthFetchUserDetails();
                }
            }
        }        
        
    }
    var submitLogoutForm = function (cbSuccess) {
        $scope.ShoppingCart.IsAuthentinal = false;        
        ShoppingCartFactory.Logout().then(function (response) {
            ////*** check logout-social ***
            //switch ($scope.ShoppingCart.LoginViewModel.ClientSource) {
            //    case $scope.ShoppingCart.ClientSourceType.Facebook:
            //        $window.FB.logout();
            //        break;
            //    case $scope.ShoppingCart.ClientSourceType.Google:
            //        var auth2 = gapi.auth2.getAuthInstance();
            //        auth2.signOut().then(function () {
            //            $scope.gauth = undefined;
            //        });
            //        break;
            //    case $scope.ShoppingCart.ClientSourceType.System:
            //        break;
            //}
            submittedLogoutForm();
            cbSuccess(response);
            
        }, function () { })
    }
    var submittedLogoutForm = function () {
        $scope.ShoppingCart.IsAuthentinal = false;
        //*** check logout-social ***
        switch ($scope.ShoppingCart.LoginViewModel.ClientSource) {
            case $scope.ShoppingCart.ClientSourceType.Facebook:
                $window.FB.logout();
                break;
            case $scope.ShoppingCart.ClientSourceType.Google:
                var auth2 = gapi.auth2.getAuthInstance();
                auth2.signOut().then(function () {
                    $scope.gauth = undefined;
                });
                break;
            case $scope.ShoppingCart.ClientSourceType.System:
                break;
        }
        //cbSuccess();
    }
    //#endregion

    //#region AUS Post
    var _updateAusPostServicePrice = function (oParam, cbSuccess) {
        var oLWHWMax = _getLWHWMax($scope.ShoppingCart.PendingSales);
        if (oLWHWMax.isUsed) {
            oParam.Length = oLWHWMax.Length;
            oParam.Width = oLWHWMax.Width;
            oParam.Height = oLWHWMax.Height;
            oParam.Weight = oLWHWMax.Weight;
        }

        ShoppingCartFactory.GetAusPostCalculate(oParam).then(function (response) {
            var AusPostCalculate = response.data;
            oParam.postage_result = AusPostCalculate.postage_result;
            return cbSuccess(oParam);
        }, function (responseError) {
            return null;
        });
    }
    var _getLWHWMax = function (lPendingSales) {
        var oAusPostServicesParams = {
            isUsed: false
        };
        var bAllSmallParcel = isAllSmallParcelInListItems(lPendingSales);
        if (bAllSmallParcel) {
            oAusPostServicesParams.Length = 2;//maximum Length 105cm
            oAusPostServicesParams.Width = 10;//maximum Width 105cm
            oAusPostServicesParams.Height = 2;//maximum Height 105cm
            oAusPostServicesParams.Weight = 0.5;//maximum Weight 22kg
            oAusPostServicesParams.isUsed = true;
        } else {
            if (moShoppingSetting.HasWSPSBindLWHWToWebstore) {
                var len, wd, ht, wt;//cm //&len={0}&wd={0}&h={0}&wt={0}
                var lenMax = 0; wdMax = 0; htMax = 0; wtMax = 0;
                //var hasDimensionsInBasket = false;
                for (var i = 0; i < lPendingSales.length; i++) {
                    if ($rootScope.webApp.util.hasVal(lPendingSales[i].SpecialOptions)) {

                        len = $rootScope.webApp.util.getParameterByName('len', lPendingSales[i].SpecialOptions);
                        wd = $rootScope.webApp.util.getParameterByName('wd', lPendingSales[i].SpecialOptions);
                        ht = $rootScope.webApp.util.getParameterByName('h', lPendingSales[i].SpecialOptions);
                        wt = $rootScope.webApp.util.getParameterByName('wt', lPendingSales[i].SpecialOptions);

                        len = $rootScope.webApp.util.toFloat(len);
                        wd = $rootScope.webApp.util.toFloat(wd);
                        ht = $rootScope.webApp.util.toFloat(ht);
                        wt = $rootScope.webApp.util.toFloat(wt);
                        console.log("ubs-part-specs: #" + lPendingSales[i].RefId + " - " + lPendingSales[i].ItemTitle + " Length-Width-Height-weight", len, wd, ht, wt);
                        if (len > 0 && len > lenMax) lenMax = len;
                        if (wd > 0 && wd > wdMax) wdMax = wd;
                        if (ht > 0 && ht > htMax) htMax = ht;
                        if (wt > 0) wtMax = wtMax + wt;//sum weight
                    }
                }
                //console.log("ubs-part-specs: max(Length-Width-Height); total weight ", len, wd, ht, wt);
                if ((lenMax + wdMax + htMax + wtMax) > 0) {

                    if (lenMax > 0) oAusPostServicesParams.Length = lenMax > 105 ? 105 : lenMax;//maximum Length 105cm
                    if (wdMax > 0) oAusPostServicesParams.Width = wdMax > 105 ? 105 : wdMax;//maximum Width 105cm
                    if (htMax > 0) oAusPostServicesParams.Height = htMax > 105 ? 105 : htMax;//maximum Height 105cm
                    if (wtMax > 0) oAusPostServicesParams.Weight = wtMax > 22 ? 22 : wtMax;//maximum Weight 22kg

                    console.log("ubs-part-specs: after validated max value with API, max(Length-Width-Height); total weight", lenMax, wdMax, htMax, wtMax);

                    //*** calculate cubic meters (Length (in meter) X Width (in meter) X Height (in meter) = Cubic meter (m3))
                    //*** AusPost: maximum dimensions 0.25 cubic metres
                    var cubicMetres = (lenMax / 100) * (wdMax / 100) * (htMax / 100);
                    if (cubicMetres > 0.25) {
                        oAusPostServicesParams.Length = 105;
                        oAusPostServicesParams.Width = 105;
                        oAusPostServicesParams.Height = 22;
                        console.log("ubs-part-specs: the cubic Metres more then 0.25, use default (Length-Width-Height)", oAusPostServicesParams.Length, oAusPostServicesParams.Width, oAusPostServicesParams.Height);
                    }

                    oAusPostServicesParams.isUsed = true;

                } else {
                    //*** no items in the basket have dimensions 
                    //*** use default Dimensions in system
                }
            }
        }
        return oAusPostServicesParams;
    }
    var _calcDeliveryExpressPostNum = function (tempVal, Num, nextNum) {
        var newNum = 0;
        var newVal = 0;

        if (tempVal > Num) {
            var iTemp = tempVal / Num;
            newNum = parseInt(iTemp);
            if ((iTemp % 1) == 0) {
                newVal = 0;
            }
            else {
                if (tempVal > nextNum) {
                    newNum++;
                }
                newVal = tempVal - (newNum * Num);
            }
        }
        else if (tempVal == Num) {
            newNum = 1;
            newVal = 0;
        }
        else {

            if (tempVal > nextNum) {
                newNum++;
                newVal = 0;
            } else {
                newNum = 0;
                newVal = tempVal;
            }
        }
        return {
            newNum: newNum,
            newVal: newVal
        };
    }
    var _calcDeliveryExpressPost = function (lPendingSales) {
        
        var totalPrice = null;

        if (moShoppingSetting.HasDeliveryFreightEnquiry == false && $rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryExpressPost) && angular.isDefined(moShoppingSetting.lWSPCSpecialAusPosts))
        {
            //moShoppingSetting.lWSPCSpecialAusPosts
            var totalNum = 0;
            for (var i = 0; i < lPendingSales.length; i++)
            {
                var sSatchelSize = $rootScope.webApp.util.getParameterByName('satchel', lPendingSales[i].SpecialOptions);
                if ($rootScope.webApp.util.hasVal(sSatchelSize)) {
                    totalNum += (lPendingSales[i].Quantity * Number(sSatchelSize));
                    console.warn('Minh: ' + lPendingSales[i].ItemCode + ' total-satchel: ', (lPendingSales[i].Quantity * Number(sSatchelSize)));
                }
            }
            if (totalNum < 1)
            {
                return null;
            }

            var aTemps = moShoppingSetting.lWSPCSpecialAusPosts.sort(moShoppingSetting.lWSPCSpecialAusPosts.sortBy("Num", true, parseInt));
            var tempVal = totalNum;
            var maxWhile = 1;
            while (true) {

                for (var j = 0; j < aTemps.length; j++)
                {
                    var nextNum = 0;
                    if ((j + 1) == aTemps.length) nextNum = 0;
                    else {
                        nextNum = aTemps[j + 1].Num;
                    }                    
                    var oExtra = _calcDeliveryExpressPostNum(tempVal, aTemps[j].Num, nextNum);
                    if (oExtra.newNum > 0) {
                        console.warn('Minh: ', oExtra.newNum + ' satchel:' + aTemps[j].Num + ' price:' + aTemps[j].Price);
                        totalPrice += oExtra.newNum * aTemps[j].Price;
                    }
                    tempVal = oExtra.newVal;
                }

                //var oExtra = _calcDeliveryExpressPostNum(tempVal, 8, 4);
                //if (oExtra.newNum > 0) totalPrice += oExtra.newNum * 30;
                //tempVal = oExtra.newVal;

                //var oLarge = _calcDeliveryExpressPostNum(tempVal, 4, 2);
                //if (oLarge.newNum > 0) totalPrice += oLarge.newNum * 25;
                //tempVal = oLarge.newVal;

                //var oMedium = _calcDeliveryExpressPostNum(tempVal, 2, 1);
                //if (oMedium.newNum > 0) totalPrice += oMedium.newNum * 20;
                //tempVal = oMedium.newVal;

                //var oSmall = _calcDeliveryExpressPostNum(tempVal, 1, 0);
                //if (oSmall.newNum > 0) totalPrice += oSmall.newNum * 15;
                //tempVal = oSmall.newVal;

                if (tempVal < 1 || maxWhile < 100) break;
                maxWhile++;
            }

        }
        return totalPrice;
    }


    var _hasExceededParcelSizeItem = function (oSizeItem) {
        var bVal = false;

        var sWeightLimitTo = $rootScope.webApp.util.getParameterByName("wt_limit", $scope.AusPost.ServiceIn);

        if ($rootScope.webApp.util.ausPostDelivery.isValidByObj(oSizeItem) == false
               || ($rootScope.webApp.util.hasVal(sWeightLimitTo) && oSizeItem.WT > Number(sWeightLimitTo))) {
            bVal = true;//*** invalid Parcel ***
        }
        return bVal;
    }
    var _calcAusPostBind_LWHW_To_Option_Inc_Oversize = function (lPendingItems, oAusPost, cbSuccess)
    {
        var lItemsOversize = [];
        var lItems = [];
        var bAllValid = true;
        var iOversizeFee = 50;
        if ($rootScope.util.hasVal($scope.AusPost.OversizeFee)) {
            iOversizeFee = $rootScope.util.toNumber($scope.AusPost.OversizeFee);
        }
        //var sWeightLimitTo = $rootScope.webApp.util.getParameterByName("wt_limit", $scope.AusPost.ServiceIn);

        //*** validate items
        for (var i = 0; i < lPendingItems.length; i++) {
            if ($rootScope.webApp.util.ausPostDelivery.isValidByObj(lPendingItems[i]) == false) {
                //bAllValid = false;
                //break;
                lItemsOversize.push(lPendingItems[i]);
            } else {
                lItems.push(lPendingItems[i]);
            }
        }
        

        if (bAllValid) {
            var lResults = [];
            var aParcelCost = [];
            var aExpressCost = [];
            var lQtyItems = [];

            //#region Insert Quantity Items
            for (var i = 0; i < lItems.length; i++) {
                var iQty = lItems[i].Qty || 1;
                if (iQty > 1) {
                    for (var j = 0; j < iQty - 1; j++) {
                        lQtyItems.push({
                            id: lItems[i].RefId,
                            idChild: lItems[i].RefId + '-' + j,
                            L: lItems[i].L,
                            W: lItems[i].W,
                            H: lItems[i].H,
                            WT: lItems[i].WT,
                            Qty: lItems[i].Qty
                        });
                    }
                }
            }
            if (lQtyItems.length > 0) {
                lItems = lItems.concat(lQtyItems);
            }
            //#region

            var _joinBox = function (oItem, lItems) {
                var _maxLength = 0; _maxWidth = 0;
                for (var k = 0; k < lItems.length; k++) {
                    if (lItems[k].grpName === undefined) {
                        _maxLength = (oItem.totalL < lItems[k].L) ? lItems[k].L : oItem.totalL;
                        _maxWidth = (oItem.totalW < lItems[k].W) ? lItems[k].W : oItem.totalW;

                        if ($rootScope.webApp.util.ausPostDelivery.isValidWeight(oItem.totalWT + lItems[k].WT)
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((oItem.totalH + lItems[k].H))
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((_maxLength))
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((_maxWidth))
                            && $rootScope.webApp.util.ausPostDelivery.isValidCubicMeter(_maxLength, _maxWidth, oItem.totalH + lItems[k].H)) {
                            lItems[k].grpName = oItem.grpName;
                            lItems[k].isMain = false;
                            oItem.totalWT = (oItem.totalWT + lItems[k].WT);
                            oItem.totalH = (oItem.totalH + lItems[k].H);
                            oItem.totalW = _maxWidth;//(oItem.totalW + lItems[k].W);
                            oItem.totalL = _maxLength;//(oItem.totalL + lItems[k].L);
                            //break;
                        }
                    }
                }
            }

            var iTotalItem = lItems.length;
            for (var i = 0; i < iTotalItem; i++) {
                if (lItems[i].grpName === undefined) {
                    lItems[i].grpName = 'box' + i;
                    lItems[i].isMain = true;
                    lItems[i].totalL = (lItems[i].L);
                    lItems[i].totalWT = (lItems[i].WT);
                    lItems[i].totalH = (lItems[i].H);
                    lItems[i].totalW = (lItems[i].W);
                    _joinBox(lItems[i], lItems);
                }
            }

            var _lSendToServerPromises = [];
            for (var i = 0; i < iTotalItem; i++) {
                if (lItems[i].isMain == true) {

                    var oItemRegular = {
                        idMain: lItems[i].id,
                        grpName: lItems[i].grpName,
                        FromPostcode: oAusPost.FromPostcode,
                        ToPostcode: oAusPost.ToPostcode,
                        Length: lItems[i].totalL,
                        Width: lItems[i].totalW,
                        Height: lItems[i].totalH,
                        Weight: lItems[i].totalWT,
                        ServiceCode: 'AUS_PARCEL_REGULAR'
                    };
                    _lSendToServerPromises.push(ShoppingCartFactory.GetAusPostCalculate(oItemRegular));

                    var oItemExpress = angular.copy(oItemRegular);
                    oItemExpress.ServiceCode = 'AUS_PARCEL_EXPRESS';
                    _lSendToServerPromises.push(ShoppingCartFactory.GetAusPostCalculate(oItemExpress));

                    //sendAusPost(oItem, 'AUS_PARCEL_REGULAR', _cbAusPost);
                    //sendAusPost(oItem, 'AUS_PARCEL_EXPRESS', _cbAusPost);

                }
            }

            var _renderOption = function (params)
            {
                var lOptionsAUS_PARCEL = [];
                var iDealerExtraFee = 0;
                if ($rootScope.util.hasVal($scope.AusPost.DealerExtraFee)) {
                    iDealerExtraFee = $rootScope.util.toNumber($scope.AusPost.DealerExtraFee);
                }

                if (params.totalParcelCost > 0) {
                    lOptionsAUS_PARCEL.push({
                        "code": "AUS_PARCEL_REGULAR",
                        "name": "Parcel Post",
                        "price": (params.totalParcelCost + iDealerExtraFee),
                        "options": {
                            "option": [
                                {
                                    "code": "AUS_SERVICE_OPTION_STANDARD",
                                    "name": "Standard Service",
                                    "price": (params.totalParcelCost + iDealerExtraFee),
                                    "suboptions": {}
                                }
                            ]
                        }
                    });
                }
                if (params.totalExpressCost > 0) {
                    lOptionsAUS_PARCEL.push({
                        "code": "AUS_PARCEL_EXPRESS",
                        "name": "Express Post",
                        "price": (params.totalExpressCost + iDealerExtraFee),
                        "options": {
                            "option": [
                                {
                                    "code": "AUS_SERVICE_OPTION_STANDARD",
                                    "name": "Standard Service",
                                    "price": (params.totalExpressCost + iDealerExtraFee),
                                    "suboptions": {}
                                }
                            ]
                        }
                    });
                }
                return lOptionsAUS_PARCEL;
            }
            if (_lSendToServerPromises.length > 0)
            {
                $q.all(_lSendToServerPromises).then(function (responses) {

                    for (var i = 0; i < responses.length; i++) {
                        var response = responses[i].data;
                        if (angular.isDefined(response.postage_result)) {
                            if (response.postage_result.service == 'Parcel Post') {
                                aParcelCost.push(CNumberZero(response.postage_result.total_cost));
                            } else if (response.postage_result.service == 'Express Post') {
                                aExpressCost.push(CNumberZero(response.postage_result.total_cost));
                            }
                        }
                    }
                    if (lItemsOversize.length > 0)
                    {
                        for (var i = 0; i < lItemsOversize.length; i++) {
                            aParcelCost.push(CNumberZero(lItemsOversize[i].Qty * iOversizeFee));
                            aExpressCost.push(CNumberZero(lItemsOversize[i].Qty * iOversizeFee));
                        }
                    }

                    var totalParcelCost = aParcelCost.reduce((a, b) => a + b, 0);//*** sum = total
                    var totalExpressCost = aExpressCost.reduce((a, b) => a + b, 0);//*** sum = total

                    lResults = _renderOption({ totalParcelCost: totalParcelCost, totalExpressCost: totalExpressCost });
                    cbSuccess({ lAusPostServiceItems: lResults });

                    //var iDealerExtraFee = 0;
                    //if ($rootScope.util.hasVal($scope.AusPost.DealerExtraFee)) {
                    //    iDealerExtraFee = $rootScope.util.toNumber($scope.AusPost.DealerExtraFee);
                    //}
                    //if (totalParcelCost > 0) {
                    //    lResults.push({
                    //        "code": "AUS_PARCEL_REGULAR",
                    //        "name": "Parcel Post",
                    //        "price": (totalParcelCost + iDealerExtraFee),
                    //        "options": {
                    //            "option": [
                    //                {
                    //                    "code": "AUS_SERVICE_OPTION_STANDARD",
                    //                    "name": "Standard Service",
                    //                    "price": (totalParcelCost + iDealerExtraFee),
                    //                    "suboptions": {}
                    //                }
                    //            ]
                    //        }
                    //    });
                    //}
                    //if (totalExpressCost > 0) {
                    //    lResults.push({
                    //        "code": "AUS_PARCEL_EXPRESS",
                    //        "name": "Express Post",
                    //        "price": (totalExpressCost + iDealerExtraFee),
                    //        "options": {
                    //            "option": [
                    //                {
                    //                    "code": "AUS_SERVICE_OPTION_STANDARD",
                    //                    "name": "Standard Service",
                    //                    "price": (totalExpressCost + iDealerExtraFee),
                    //                    "suboptions": {}
                    //                }
                    //            ]
                    //        }
                    //    });
                    //}
                    //cbSuccess({ lAusPostServiceItems: lResults });
                });
            }
            else
            {
                if (lItemsOversize.length > 0)
                {
                    for (var i = 0; i < lItemsOversize.length; i++) {
                        aParcelCost.push(CNumberZero(lItemsOversize[i].Qty * iOversizeFee));
                        aExpressCost.push(CNumberZero(lItemsOversize[i].Qty * iOversizeFee));
                    }
                    var totalParcelCost = aParcelCost.reduce((a, b) => a + b, 0);//*** sum = total
                    var totalExpressCost = aExpressCost.reduce((a, b) => a + b, 0);//*** sum = total

                    lResults = _renderOption({ totalParcelCost: totalParcelCost, totalExpressCost: totalExpressCost });
                    cbSuccess({ lAusPostServiceItems: lResults });
                }
                else {
                    console.log('Minh: the basket does not have any parcels');
                    cbSuccess({ lAusPostServiceItems: [] });
                }
            }
        }
        else {
            cbSuccess({ lAusPostServiceItems: [] });
        }
    }
    var _calcAusPostBind_LWHW_To_Option_Standard = function (lItems, oAusPost, cbSuccess) {
        /* oItem = {
                id: lItems[i].RefId,
                L: len,
                W: wd,
                H: ht,
                WT: wt,
                Qty: lPendingSales[i].Quantity
            }
        */

        var sWeightLimitTo = $rootScope.webApp.util.getParameterByName("wt_limit", $scope.AusPost.ServiceIn);

        var bAllValid = true;
        //*** validate items
        for (var i = 0; i < lItems.length; i++) {
            //if ($rootScope.webApp.util.ausPostDelivery.isValidByObj(lItems[i]) == false) {
            //    bAllValid = false;
            //    break;
            //}
            if (_hasExceededParcelSizeItem(lItems[i]) == true) {
                bAllValid = false;
                break;
            }
        }

        if (bAllValid) {
            var lResults = [];
            var aParcelCost = [];
            var aExpressCost = [];
            var lQtyItems = [];            

            //#region Insert Quantity Items
            for (var i = 0; i < lItems.length; i++) {
                var iQty = lItems[i].Qty || 1;
                if (iQty > 1)
                {
                    for (var j = 0; j < iQty-1; j++) {
                        lQtyItems.push({
                            id: lItems[i].RefId,
                            idChild: lItems[i].RefId + '-' + j,
                            L: lItems[i].L,
                            W: lItems[i].W,
                            H: lItems[i].H,
                            WT: lItems[i].WT,
                            Qty: lItems[i].Qty
                        });
                    }
                }
            }
            if (lQtyItems.length > 0)
            {
                lItems = lItems.concat(lQtyItems);
            }
            //#region

            //var _joinBox = function (oItem, lItems) {
            //    for (var k = 0; k < lItems.length; k++) {
            //        if (lItems[k].grpName === undefined) {
            //            if (isValidLength((oItem.totalL + lItems[k].L)) && isValidLength((oItem.totalW + lItems[k].W)) && isValidLength((oItem.totalH + lItems[k].H))
            //              && isValidWeight(oItem.totalWT + lItems[k].WT)
            //              && isValidCubicMeter(oItem.totalL + lItems[k].L, oItem.totalW + lItems[k].W, oItem.totalH + lItems[k].H)) {
            //                lItems[k].grpName = oItem.grpName;
            //                lItems[k].isMain = false;
            //                oItem.totalL = (oItem.totalL + lItems[k].L);
            //                oItem.totalWT = (oItem.totalWT + lItems[k].WT);
            //                oItem.totalH = (oItem.totalH + lItems[k].H);
            //                oItem.totalW = (oItem.totalW + lItems[k].W);
            //                //break;
            //            }
            //        }
            //    }
            //}
            var _joinBox = function (oItem, lItems) {
                var _maxLength = 0; _maxWidth = 0;
                for (var k = 0; k < lItems.length; k++) {
                    if (lItems[k].grpName === undefined) {
                        _maxLength = (oItem.totalL < lItems[k].L) ? lItems[k].L : oItem.totalL;
                        _maxWidth = (oItem.totalW < lItems[k].W) ? lItems[k].W : oItem.totalW;

                        if ($rootScope.webApp.util.ausPostDelivery.isValidWeight(oItem.totalWT + lItems[k].WT)
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((oItem.totalH + lItems[k].H))
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((_maxLength))
                            && $rootScope.webApp.util.ausPostDelivery.isValidLength((_maxWidth))
                            && $rootScope.webApp.util.ausPostDelivery.isValidCubicMeter(_maxLength, _maxWidth, oItem.totalH + lItems[k].H))
                        {
                            lItems[k].grpName = oItem.grpName;
                            lItems[k].isMain = false;
                            oItem.totalWT = (oItem.totalWT + lItems[k].WT);
                            oItem.totalH = (oItem.totalH + lItems[k].H);
                            oItem.totalW = _maxWidth;//(oItem.totalW + lItems[k].W);
                            oItem.totalL = _maxLength;//(oItem.totalL + lItems[k].L);
                            //break;
                        }
                    }
                }
            }

            var iTotalItem = lItems.length;
            for (var i = 0; i < iTotalItem; i++) {
                if (lItems[i].grpName === undefined) {
                    lItems[i].grpName = 'box' + i;
                    lItems[i].isMain = true;
                    lItems[i].totalL = (lItems[i].L);
                    lItems[i].totalWT = (lItems[i].WT);
                    lItems[i].totalH = (lItems[i].H);
                    lItems[i].totalW = (lItems[i].W);
                    _joinBox(lItems[i], lItems);
                }
            }

            var _lSendToServerPromises = [];
            for (var i = 0; i < iTotalItem; i++) {
                if (lItems[i].isMain == true) {

                    var oItemRegular = {
                        idMain: lItems[i].id,
                        grpName: lItems[i].grpName,
                        FromPostcode: oAusPost.FromPostcode,
                        ToPostcode: oAusPost.ToPostcode,
                        Length: lItems[i].totalL,
                        Width: lItems[i].totalW,
                        Height: lItems[i].totalH,
                        Weight: lItems[i].totalWT,
                        ServiceCode: 'AUS_PARCEL_REGULAR'
                    };
                    
                    _lSendToServerPromises.push(ShoppingCartFactory.GetAusPostCalculate(oItemRegular));

                    var oItemExpress = angular.copy(oItemRegular);
                    oItemExpress.ServiceCode = 'AUS_PARCEL_EXPRESS';
                    _lSendToServerPromises.push(ShoppingCartFactory.GetAusPostCalculate(oItemExpress));

                    //sendAusPost(oItem, 'AUS_PARCEL_REGULAR', _cbAusPost);
                    //sendAusPost(oItem, 'AUS_PARCEL_EXPRESS', _cbAusPost);

                }
            }
            if (_lSendToServerPromises.length > 0) {
                $q.all(_lSendToServerPromises).then(function (responses) {

                    for (var i = 0; i < responses.length; i++) {
                        var response = responses[i].data;
                        if (angular.isDefined(response.postage_result))
                        {
                            if (response.postage_result.service == 'Parcel Post') {
                                aParcelCost.push(CNumberZero(response.postage_result.total_cost));
                            } else if (response.postage_result.service == 'Express Post') {
                                aExpressCost.push(CNumberZero(response.postage_result.total_cost));
                            }
                        }
                    }

                    var totalParcelCost = aParcelCost.reduce((a, b) => a + b, 0);//*** sum = total
                    var totalExpressCost = aExpressCost.reduce((a, b) => a + b, 0);//*** sum = total

                    var iDealerExtraFee = 0;
                    if ($rootScope.util.hasVal($scope.AusPost.DealerExtraFee)) {
                        iDealerExtraFee = $rootScope.util.toNumber($scope.AusPost.DealerExtraFee);
                    }

                    if (totalParcelCost > 0) {
                        var sOptName = $rootScope.webApp.util.getParameterByName("regular_optn", $scope.AusPost.ServiceIn);
                        if ($rootScope.webApp.util.hasVal(sOptName) == false) {
                            sOptName = 'Standard Service';
                        }
                        lResults.push({
                            "code": "AUS_PARCEL_REGULAR",
                            "name": "Parcel Post",
                            "price": (totalParcelCost + iDealerExtraFee),
                            "options": {
                                "option": [
                                    {
                                        "code": "AUS_SERVICE_OPTION_STANDARD",
                                        "name": sOptName,//"Standard Service",
                                        "price": (totalParcelCost + iDealerExtraFee),
                                        "suboptions": {}
                                    }
                                ]
                            }
                        });
                    }
                    if (totalExpressCost > 0) {
                        var sOptName = $rootScope.webApp.util.getParameterByName("express_optn", $scope.AusPost.ServiceIn);
                        if ($rootScope.webApp.util.hasVal(sOptName) == false) {
                            sOptName = 'Standard Service';
                        }
                        lResults.push({
                            "code": "AUS_PARCEL_EXPRESS",
                            "name": "Express Post",
                            "price": (totalExpressCost + iDealerExtraFee),
                            "options": {
                                "option": [
                                    {
                                        "code": "AUS_SERVICE_OPTION_STANDARD",
                                        "name": sOptName,//"Standard Service",
                                        "price": (totalExpressCost + iDealerExtraFee),
                                        "suboptions": {}
                                    }
                                ]
                            }
                        });
                    }
                    cbSuccess({ lAusPostServiceItems: lResults });
                });
            } else {
                console.log('Minh: the basket does not have any parcels');
                cbSuccess({ lAusPostServiceItems: [] });
            }
        } else {
            cbSuccess({ lAusPostServiceItems: [] });
        }
    }
    var _calcAusPostBindBranch_To_Option_FreePickup = function (lItems, cbSuccess)
    {
        if (moShoppingSetting.HasWSPSBindBranchQAVToWebstore == null || moShoppingSetting.HasWSPSBindBranchQAVToWebstore == false) return;

        /**** requirement 
        * case 1: 
        *   Item A : branch A, branch B
        *   Item B : branch A, branch B
        *   => show pickup at branch A and brand B
        * 
        * case 2: 
        *   Item A : branch A
        *   Item B : branch B
        *   => hide pickup options
        *
        * case 3: 
        *   Item A : branch A, branch B
        *   Item B : branch A
        *   => show pickup at branch A
        */

        /* flagItems = []
        * first: get valid Branch: if QAV > 0, push to flagItems
        * second: get valid Branch: if QAV > 0, if not exist flagItems => break => different branches
        * 
        * item A, branch A, branch B
        * item B, branch B
        */
        
        //*** override free-pickup-option
        var flagItems = [];
        var flagCols = [];
        var lFreePickupOptions = [];

        var flagItemsValidQAV = [];
        var bIsDifferentBranches = false;
        for (var i = 0; i < lItems.length; i++)
        {
            if (lItems[i].WSPartItem != null && angular.isDefined(lItems[i].WSPartItem)) {
                var lValidBranches = $filter('filter')(lItems[i].WSPartItem.PartBranches, function (x) { return angular.isDefined(x.BranchName) && x.QAV > 0 });
                var oItem = {
                    //item: lItems[i].WSPartItem[i].Id
                    //branch1: 'A',
                    //branch2: 'B'
                }
                for (var j = 0; j < lValidBranches.length; j++) {
                    if (flagCols.indexOf(lValidBranches[j].Id) < 0) flagCols.push(lValidBranches[j].Id);

                    for (var c = 0; c < flagCols.length; c++) {
                        if (flagCols.indexOf(lValidBranches[j].Id) < 0) {
                            oItem[lValidBranches[j].Id] = undefined;
                        } else {
                            oItem[lValidBranches[j].Id] = lValidBranches[j].BranchName;
                        }
                    }
                    //oItem[lValidBranches[j].Id] = lValidBranches[j].BranchName;
                }                
                flagItems.push(oItem);
                //flagItems[{123: 'A', 124: 'B'}, {123: 'A', 124: null}]
            }
        }
        for (var i = 0; i < flagCols.length; i++)
        {
            var lHasUndefined = $filter('filter')(flagItems, function (x) { return angular.isUndefined(x[flagCols[i]]); });//get list items have undefined value
            if (lHasUndefined.length < 1) {
                lFreePickupOptions.push({
                    "code": "Free_Pickup_" + $rootScope.webApp.util.replaceAllSpecialCharsToDashLower( flagItems[0][flagCols[i]]),
                    "name": "Free pickup " + flagItems[0][flagCols[i]],
                    "price": 0,
                    "suboptions": {}
                });
            }
        }
        //for (var i = 0; i < lItems.length; i++)
        //{
        //    if (lItems[i].WSPartItem != null && angular.isDefined(lItems[i].WSPartItem))
        //    {
        //        var lValidBranches = $filter('filter')(lItems[i].WSPartItem.PartBranches, function (x) { return angular.isDefined(x.BranchName) && x.QAV > 0 });
        //        var flagItem = {
        //            item: lItems[i].WSPartItem[i].Id,
        //            branches: lValidBranches,
        //            totalBranch: lValidBranches.length
        //        }
        //        flagItemsValidQAV.push(flagItem);
        //    }
        //}
        //flagItemsValidQAV = $filter('orderBy')(flagItemsValidQAV, 'totalBranch', true);
        //for (var i = 0; i < flagItemsValidQAV.length; i++)
        //{            
        //    if (flagItems.length < 1) flagItems = flagItems.concat(flagItemsValidQAV[i].branches);
        //    else {
        //        for (var j = 0; j < flagItemsValidQAV[i].branches.length; j++) {
        //            if (flagItems.indexOf(flagItemsValidQAV[i].branches[j].BranchName) < 0)
        //            {
        //                //different branches between branches
        //                bIsDifferentBranches = true;
        //                break;
        //            }
        //        }
        //    }
        //    if (bIsDifferentBranches == true) break;
        //}

        if(lFreePickupOptions.length > 0)
        {
            moAUSPostPickupService = {
                "code": "Pick_Up_In_Store",
                "name": "Pick Up In Store",
                "price": 0,
                "max_extra_cover": null,
                "options":
                    {
                        "option": lFreePickupOptions
                        //"option": [
                        //    {
                        //        "code": "Free_Pickup_Toowoomba",
                        //        "name": "Free pickup Toowoomba",
                        //        "price": 0,
                        //        "suboptions": {}
                        //    },
                        //    {
                        //        "code": "Free_Pickup_Dalby",
                        //        "name": "Free pickup Dalby",
                        //        "price": 0,
                        //        "suboptions": {}
                        //    }
                        //]
                    }
            }
        }
        else{
            moAUSPostPickupService = {
                isShowing: false
            }
        }
        
    }
    var _addFreePickupOptionToShipping = function (oAusPostServices)
    {
        if (angular.isUndefined(moAUSPostPickupService.isShowing) || (angular.isDefined(moAUSPostPickupService.isShowing) && moAUSPostPickupService.isShowing == true))
        {
            //oAusPostServices.service.push(moAUSPostPickupService);
            oAusPostServices.service.spliceIfNotExist(moAUSPostPickupService, 0, function (oService) {
                return oService.code == moAUSPostPickupService.code;//push pickup in-store option
            });
        }
        return oAusPostServices;
    }

    var loadAusPostServices = function (lPendingSales, oAusPostServices, oAusPost, iWebsiteId, cbSuccess) {
        //*** delivery options dropdownlist
        var _cbloadAusPostServices = function (response) {
            //***begin NewAgeGoldCoast special setting
            var iNewAgeGoldCoastWebsiteId = 369;
            var iNewAgeAdelaide = 371;
            var iEliteMotorcycles325 = 325;

            if (iWebsiteId == iNewAgeGoldCoastWebsiteId || iWebsiteId == iNewAgeAdelaide)//NewAgeGoldCoast special setting
            {
                if (oAusPost.ToPostcode != null && oAusPost.FromPostcode != null) {
                    if (hasBulkyWSCategoryInList(lPendingSales) == true) {
                        var iPostCodeRangeFrom = 4000; var iPostCodeRangeTo = 5000;
                        var iPostCodeLocal = 4301;
                        if (iWebsiteId == iNewAgeAdelaide)
                        {
                            iPostCodeRangeFrom = 5000;
                            iPostCodeRangeTo = 6000;
                            iPostCodeLocal = 5201;
                        }

                        if (oAusPost.ToPostcode >= iPostCodeRangeFrom && oAusPost.ToPostcode < iPostCodeRangeTo) {
                            moShoppingSetting.HasStandardDeliveryFee = true;
                            var tempPrice = angular.copy(moShoppingSetting.StandardDeliveryFee);
                            if (oAusPost.ToPostcode < iPostCodeLocal) {
                                for (var i = 0; i < lPendingSales.length; i++) {                                    
                                    if (hasBulkyWSCategory(lPendingSales[i]) == true) {
                                        var bulkyPrice = getBulkyPrice(lPendingSales[i]);
                                        tempPrice = tempPrice + (49 * lPendingSales[i].Quantity);
                                    }
                                }
                            } else {                                
                                for (var i = 0; i < lPendingSales.length; i++) {                                    
                                    if (hasBulkyWSCategory(lPendingSales[i]) == true)
                                    {
                                        var bulkyPrice = getBulkyPrice(lPendingSales[i]);
                                        if (bulkyPrice == 10) {
                                            tempPrice = tempPrice + (70 * lPendingSales[i].Quantity);
                                        } else {
                                            tempPrice = tempPrice + (110 * lPendingSales[i].Quantity);
                                        }
                                    }
                                }                                
                            }
                            
                            moShoppingSetting.StandardDeliveryFee = tempPrice;

                            moShoppingSetting.HasDeliveryFreightEnquiry = false;
                        } else {
                            moShoppingSetting.HasStandardDeliveryFee = false;
                            moShoppingSetting.HasDeliveryFreightEnquiry = true;
                            moAUSPostFreightEnquiryOption = {
                                "code": "Freight_Enquiry_Code",
                                "name": "Get a quote for interstate shipping (outside of QLD)",
                                "price": null,
                                "max_extra_cover": null,
                                "options":
                                    {
                                        "option": [
                                            {
                                                "code": "Freight_Enquiry",
                                                "name": "Shipping Costs TBA",
                                                "price": null,
                                                "suboptions": {}
                                            }
                                        ]
                                    }
                            };
                        }

                    } else {
                        moShoppingSetting.HasStandardDeliveryFee = true;
                        moShoppingSetting.HasDeliveryFreightEnquiry = false;
                        //moShoppingSetting.StandardDeliveryFee = 10;///default from system-params
                    }
                    

                } else {
                    response.bIsAddMoreOption = false;
                }                
            } 
            //***end NewAgeGoldCoast special setting

            //region webApp.WebsiteIdCode.EliteMotorcycles325
            if (iWebsiteId == webApp.WebsiteIdCode.EliteMotorcycles325)
            {
                moAUSPostPickupService = {
                    "code": "Pick_Up_In_Store",
                    "name": "Pick Up In Store",
                    "price": 0,
                    "max_extra_cover": null,
                    "options":
                        {
                            "option": [
                                {
                                    "code": "Free_Pickup_Toowoomba",
                                    "name": "Free pickup Toowoomba",
                                    "price": 0,
                                    "suboptions": {}
                                },
                                {
                                    "code": "Free_Pickup_Dalby",
                                    "name": "Free pickup Dalby",
                                    "price": 0,
                                    "suboptions": {}
                                }                                
                            ]
                        }
                }
            }
            //endregion
            if (moShoppingSetting.HasWSPSBindBranchQAVToWebstore == true)
            {
                _calcAusPostBindBranch_To_Option_FreePickup(lPendingSales);
            }

            if ($rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryPickUpInStore)) {
                //override label
                if ($window.webApp.userPortal != 'trade')
                {
                    var _jsonDeliveryPickUpInStore = angular.fromJson(moShoppingSetting.DeliveryPickUpInStore);
                    moAUSPostPickupService.name = _jsonDeliveryPickUpInStore.name;
                    moAUSPostPickupService.options.option[0].name = _jsonDeliveryPickUpInStore.optName || null;
                }                
            }

            if (response.bIsAddMoreOption == true)
            {
                if (angular.isUndefined(response.oAusPostServices.service)) response.oAusPostServices.service = [];
                var iIndexArray = 0;
                //*** insert Pickup Instore option
                //response.oAusPostServices = _addFreePickupOptionToShipping(response.oAusPostServices);
                response.oAusPostServices.service.spliceIfNotExist(moAUSPostPickupService, iIndexArray, function (oService) {
                    return oService.code == moAUSPostPickupService.code &&
                        (angular.isUndefined(moAUSPostPickupService.isShowing) ||
                        (angular.isDefined(moAUSPostPickupService.isShowing) && moAUSPostPickupService.isShowing == true));//push pickup in-store option
                });
                
                if (hasPickupOnlyCategoryInListItems(lPendingSales) == false) {
                    if (hasTickedFleetPriceInList(lPendingSales) == false) {
                        //*** insert Standard Delivery option
                        if ($rootScope.webApp.util.hasVal(moShoppingSetting.StandardDeliveryFee)) {
                            var totalBulkyPrice = getTotalBulkyPrice(lPendingSales);

                            moAUSPostStandardDeliveryFeeOption.price = Number(moShoppingSetting.StandardDeliveryFee);
                            moAUSPostStandardDeliveryFeeOption.options.option[0].price = Number(moShoppingSetting.StandardDeliveryFee);
                            moAUSPostStandardDeliveryFeeOption.options.option[0].flatFee = totalBulkyPrice;
                            iIndexArray++;
                            response.oAusPostServices.service.spliceIfNotExist(moAUSPostStandardDeliveryFeeOption, iIndexArray, function (oService) {
                                return oService.code == moAUSPostStandardDeliveryFeeOption.code;//push Standard Delivery option
                            });
                        }
                        //*** insert Freight Enquiry option
                        if (moShoppingSetting.HasDeliveryFreightEnquiry == true) {
                            iIndexArray++;
                            response.oAusPostServices.service.spliceIfNotExist(moAUSPostFreightEnquiryOption, iIndexArray, function (oService) {
                                return oService.code == moAUSPostFreightEnquiryOption.code;//push Freight Enquiry option
                            });
                        }
                        //*** insert Delivery ExpressPost option
                        if (moShoppingSetting.HasDeliveryFreightEnquiry == false && $rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryExpressPost)) {

                            moAUSPostExpressPostOption.options.option[0].name = moShoppingSetting.DeliveryExpressPost;
                            var priceExpressPost = _calcDeliveryExpressPost(lPendingSales);
                            if (priceExpressPost != null) {
                                moAUSPostExpressPostOption.price = priceExpressPost;
                                moAUSPostExpressPostOption.options.option[0].price = priceExpressPost;
                                iIndexArray++;
                                response.oAusPostServices.service.spliceIfNotExist(moAUSPostExpressPostOption, iIndexArray, function (oService) {
                                    return oService.code == moAUSPostExpressPostOption.code;//push Standard Delivery option
                                });
                            }
                        }

                        //*** insert Standard Delivery option
                        if ($rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryBusinessDay)) {
                            if ($window.webApp.userPortal == 'trade') {
                                var totalBulkyPrice = getTotalBulkyPrice(lPendingSales);

                                moAUSPostDeliveryBusinessDayOption.price = moShoppingSetting.DeliveryBusinessDay;
                                moAUSPostDeliveryBusinessDayOption.options.option[0].price = moShoppingSetting.DeliveryBusinessDay;
                                moAUSPostDeliveryBusinessDayOption.options.option[0].flatFee = totalBulkyPrice;
                                iIndexArray++;
                                response.oAusPostServices.service.spliceIfNotExist(moAUSPostDeliveryBusinessDayOption, iIndexArray, function (oService) {
                                    return oService.code == moAUSPostDeliveryBusinessDayOption.code;//push Delivery Business Day
                                });
                            }                            
                        }
                        //*** insert DeliveryLocal Delivery option
                        if ($rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryLocal)) {
                            if ($window.webApp.userPortal == 'trade') {
                                var totalBulkyPrice = getTotalBulkyPrice(lPendingSales);
                                moShoppingSetting.jsonDeliveryLocal = angular.fromJson(moShoppingSetting.DeliveryLocal)
                                //moShoppingSetting.jsonDeliveryLocal.price = moShoppingSetting.DeliveryBusinessDay;
                                //moShoppingSetting.jsonDeliveryLocal.options.option[0].price = moShoppingSetting.DeliveryBusinessDay;
                                moShoppingSetting.jsonDeliveryLocal.options.option[0].flatFee = totalBulkyPrice;
                                iIndexArray++;
                                response.oAusPostServices.service.spliceIfNotExist(moShoppingSetting.jsonDeliveryLocal, iIndexArray, function (oService) {
                                    return oService.code == moShoppingSetting.jsonDeliveryLocal.code;//push DeliveryLocal
                                });
                            }
                        }
                        //*** insert DeliveryCourier Delivery option
                        if ($rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryCourier)) {
                            if ($window.webApp.userPortal == 'trade') {
                                var totalBulkyPrice = getTotalBulkyPrice(lPendingSales);
                                moShoppingSetting.jsonDeliveryCourier = angular.fromJson(moShoppingSetting.DeliveryCourier)
                                //moShoppingSetting.jsonDeliveryCourier.price = moShoppingSetting.DeliveryBusinessDay;
                                //moShoppingSetting.jsonDeliveryCourier.options.option[0].price = moShoppingSetting.DeliveryBusinessDay;
                                moShoppingSetting.jsonDeliveryCourier.options.option[0].flatFee = totalBulkyPrice;
                                iIndexArray++;
                                response.oAusPostServices.service.spliceIfNotExist(moShoppingSetting.jsonDeliveryCourier, iIndexArray, function (oService) {
                                    return oService.code == moShoppingSetting.jsonDeliveryCourier.code;//push DeliveryCourier
                                });
                            }
                        }


                        //*** insert Delivery by Total Basket option
                        if ($rootScope.webApp.util.hasVal(moShoppingSetting.DeliveryByTotalBasket)) {
                            if ($window.webApp.userPortal != 'trade') {                                
                                var totalBasket = getTotalBasketWithoutDeliveryFee($scope.ShoppingDiscountCode, moShoppingSetting, lPendingSales);
                                try {
                                    var _jsonDeliveryByTotalBasket = angular.fromJson(moShoppingSetting.DeliveryByTotalBasket);
                                    var _name = null; _price = null;
                                    if ($rootScope.webApp.util.hasVal(_jsonDeliveryByTotalBasket.con))
                                    {
                                        if (totalBasket < _jsonDeliveryByTotalBasket.con) {
                                            _price = _jsonDeliveryByTotalBasket.les.price;
                                            _name = _jsonDeliveryByTotalBasket.les.name;
                                        } else {
                                            _price = _jsonDeliveryByTotalBasket.abo.price;
                                            _name = _jsonDeliveryByTotalBasket.abo.name;
                                        }
                                        moAUSPostDeliveryByTotalBasketOption.price = _price;
                                        moAUSPostDeliveryByTotalBasketOption.name = _name;
                                        moAUSPostDeliveryByTotalBasketOption.options.option[0].price = _price;
                                        //AUSPostDeliveryByTotalBasketOption.options.option[0].name = _name;
                                        moAUSPostDeliveryByTotalBasketOption.options.option[0].flatFee = getTotalBulkyPrice(lPendingSales);
                                        iIndexArray++;
                                        response.oAusPostServices.service.spliceIfNotExist(moAUSPostDeliveryByTotalBasketOption, iIndexArray, function (oService) {
                                            return oService.code == moAUSPostDeliveryByTotalBasketOption.code;//push Delivery by Total Basket option
                                        });
                                    }
                                    


                                    
                                } catch (_e) {
                                    console.error('Can not include DeliveryByTotalBasket Option', _e);
                                }
                                
                            }
                        }
                        
                        //#region BrisbaneYamahaPart3040: include extra delivery fee                        
                        if (iWebsiteId == webApp.WebsiteIdCode.BrisbaneYamahaPart3040) {
                            var _extraFeeOfBrisbaneYamahaPart3040 = 25;
                            var _bHasAnyItemEPCItem = $filter('filter')(lPendingSales, function (x) { return $rootScope.webApp.util.startWithLowerCase(x.Source, 'TPE'); }).length > 0;
                            var _bHasAnyItemNoneLWHW = $filter('filter')(lPendingSales, function (x) { return $rootScope.webApp.util.toFloat($rootScope.webApp.util.getParameterByName('len', x.SpecialOptions)) <=0; }).length > 0;
                            if (_bHasAnyItemEPCItem == true || _bHasAnyItemNoneLWHW == true)
                            {
                                if ($filter('filter')(response.oAusPostServices.service, function (x) { return x.code != 'Pick_Up_In_Store'; }).length > 0) {
                                    for (var i = 0; i < response.oAusPostServices.service.length; i++) {
                                        if (response.oAusPostServices.service[i].code != 'Pick_Up_In_Store') {
                                            response.oAusPostServices.service[i].price = response.oAusPostServices.service[i].price + _extraFeeOfBrisbaneYamahaPart3040;
                                            response.oAusPostServices.service[i].options.option[0].price = response.oAusPostServices.service[i].options.option[0].price + _extraFeeOfBrisbaneYamahaPart3040;
                                        }
                                    }
                                }
                                else {
                                    var totalBulkyPrice = getTotalBulkyPrice(lPendingSales);
                                    moAUSPostStandardDeliveryFeeOption.price = _extraFeeOfBrisbaneYamahaPart3040;
                                    moAUSPostStandardDeliveryFeeOption.options.option[0].price = _extraFeeOfBrisbaneYamahaPart3040;
                                    moAUSPostStandardDeliveryFeeOption.options.option[0].flatFee = totalBulkyPrice;
                                    response.oAusPostServices.service.spliceIfNotExist(moAUSPostStandardDeliveryFeeOption, 1, function (oService) {
                                        return oService.code == moAUSPostStandardDeliveryFeeOption.code;//push Standard Delivery option
                                    });
                                }
                            }
                            
                        }
                        //#endregion 
                    }
                }

                //***begin NewAgeGoldCoast special setting
                if (iWebsiteId == iNewAgeGoldCoastWebsiteId || iWebsiteId == iNewAgeAdelaide)//NewAgeGoldCoast special setting
                {
                    $scope.changeDeliveryAusPostService($scope.DeliveryAusPostService);//callback controller function to refresh delivery price
                }
                //***end NewAgeGoldCoast special setting
            }
            console.log('Minh: load shipping methods: ', response);
            cbSuccess(response);
        }

        if (moAusPostDefault == {}) {
            moAusPostDefault = angular.copy(oAusPost);
        }
        if (moShoppingSetting.HasDeliveryOptions) {
            if (angular.isUndefined(oAusPostServices)) oAusPostServices = {};
            if (angular.isUndefined(oAusPostServices.service)) oAusPostServices.service = [];
            var sDeliveryOption = "";

            if (isOnlyPickupInStore(iWebsiteId, lPendingSales) || hasPickupOnlyCategoryInListItems(lPendingSales) || hasWSPSFleetPriceInList(lPendingSales)) {
                if (hasWSPSFleetPriceInList(lPendingSales)) {
                    oAusPostServices.service = $filter('filter')(oAusPostServices.service, function (x) { return x.code.indexOf('Pick_Up_In_Store') >= 0 });
                }

                //if only Pick Up In Store option, set default CardHeader value
                if ($filter('filter')(oAusPostServices.service, function (x) { return x.code.indexOf('Pick_Up_In_Store') >= 0 }).length < 1) {
                    //oAusPostServices.service.push(moAUSPostPickupService);
                    sDeliveryOption = moAUSPostPickupService.name + ($rootScope.webApp.util.hasVal(moAUSPostPickupService.options.option[0].name) ? ' - ' + moAUSPostPickupService.options.option[0].name : '');// "Pick Up In Store - Free_Pickup";
                }
                _cbloadAusPostServices({ oAusPostServices: oAusPostServices, sDeliveryOption: sDeliveryOption, bIsAddMoreOption: true });
                
            }
            else if ($scope.ShoppingDiscountCode && $scope.ShoppingDiscountCode.DiscountId > 0 && $scope.ShoppingDiscountCode.FlagFreeFreightCode == true) {
                //pickup in-store and Free Freight options
                oAusPostServices.service = [];
                //oAusPostServices.service.push(moAUSPostPickupService);
                oAusPostServices.service.push(moAUSPostFreeFreightCode);
                _cbloadAusPostServices({ oAusPostServices: oAusPostServices, bIsAddMoreOption: true });

            }
            else {
                if (oAusPost.FromPostcode == null) console.error("sys-error: the main dealership does not have postcode");
                //*** delivery AusPost options
                if (moShoppingSetting.AusPostIsUnused == false) {
                    if (oAusPost.ToPostcode != null && oAusPost.FromPostcode != null) {
                        var oAusPostServicesParams = angular.copy(oAusPost);
                        var oLWHWMax = {};

                        var _cbSuccess = function (response, hasPostedMaxLWHWToServer) {
                            if (angular.isDefined(response.data.error)) {
                                var isPostToServerAgain = false;
                                switch (response.data.error.errorMessage) {
                                    case "The maximum weight of a parcel is 22 kg.":
                                    case "The height cannot exceed 105cm.":
                                    case "The width cannot exceed 105cm.":
                                    case "The length cannot exceed 105cm.":
                                    case "The Cubic Measurement cannot exceed 0.25 cubic meters.":
                                        isPostToServerAgain = true;
                                        break;
                                    default:
                                        if ($rootScope.webApp.util.indexOfLowerCase(response.data.error.errorMessage, 'cannot exceed')) {
                                            isPostToServerAgain = true;
                                        } else {
                                            isPostToServerAgain = false;//unknow exception => show only pickup in store option
                                        }
                                        break;
                                }
                                if (isPostToServerAgain) {
                                    if (hasPostedMaxLWHWToServer == false) {
                                        _postToServer(true);
                                    } else {
                                        oAusPostServices = {
                                            service: []
                                        };//set default value
                                        oAusPostServices.service.push(moAUSPostPickupService);
                                        //oAusPostServices = _addFreePickupOptionToShipping(oAusPostServices);
                                        _cbloadAusPostServices({ oAusPostServices: oAusPostServices });
                                    }
                                } else {
                                    oAusPostServices = {
                                        service: []
                                    };//set default value
                                    oAusPostServices.service.push(moAUSPostPickupService);
                                    //oAusPostServices = _addFreePickupOptionToShipping(oAusPostServices);
                                    _cbloadAusPostServices({ oAusPostServices: oAusPostServices });
                                }
                            }
                            else {
                                oAusPostServices = response.data.services;
                                if (oAusPost.ServiceIn != null) {
                                    
                                    var aServiceIn = [];
                                    if (oAusPost.ServiceIn.indexOf(';') > -1) {
                                        aServiceIn = oAusPost.ServiceIn.split(';');
                                    }
                                    else
                                    {
                                        if (oAusPost.ServiceIn == 'AUS_PARCEL_EXPRESS_SATCHEL') {
                                            //*** if oAusPost.ServiceIn is AUS_PARCEL_EXPRESS_SATCHEL, show options 'AUS_PARCEL_EXPRESS_SATCHEL_SMALL' and 'AUS_PARCEL_EXPRESS_SATCHEL_500G'
                                            aServiceIn = ['AUS_PARCEL_EXPRESS_SATCHEL_SMALL', 'AUS_PARCEL_EXPRESS_SATCHEL_500G'];
                                        } else {
                                            aServiceIn = [oAusPost.ServiceIn];
                                        }
                                        
                                    }

                                    var _services = [];
                                    var _sServiceIn = '';
                                    var _sOptionIn = '';
                                    var _sServiceInAndQueryStr = '';
                                    var _sQueryStr = '';
                                    var _sServiceName = '';
                                    var _sOptionName = '';

                                    for (var i = 0; i < aServiceIn.length; i++) {
                                        _sOptionIn = '';
                                        _sServiceInAndQueryStr = '';
                                        _sQueryStr = '';
                                        _sServiceName = '';
                                        _sOptionName = '';

                                        _sServiceInAndQueryStr = aServiceIn[i];

                                        if (_sServiceInAndQueryStr.indexOf('?') > -1) {
                                            _sServiceInAndQueryStr = aServiceIn[i].split('?')[0];
                                            _sQueryStr = aServiceIn[i].split('?')[1];
                                            _sServiceName = $rootScope.webApp.util.getParameterByName('srvn', '?' + _sQueryStr);
                                            _sOptionName = $rootScope.webApp.util.getParameterByName('optn', '?' + _sQueryStr);
                                        } else {
                                            _sServiceInAndQueryStr = aServiceIn[i];
                                        }

                                        if (_sServiceInAndQueryStr.indexOf(':OPTION') > -1) {
                                            _sServiceIn = _sServiceInAndQueryStr.split(':')[0];
                                            _sOptionIn = _sServiceInAndQueryStr.split(':')[1];
                                        }
                                        else {
                                            _sServiceIn = _sServiceInAndQueryStr;//aServiceIn[i];
                                        }

                                        //if (aServiceIn[i].indexOf(':OPTION') > -1) {
                                        //    _sServiceIn = aServiceIn[i].split(':')[0];
                                        //    _sOptionIn = aServiceIn[i].split(':')[1];
                                        //}
                                        //else
                                        //{                                            
                                        //    _sServiceIn = aServiceIn[i];
                                        //}


                                        if (oAusPostServices.service.length > 0) {
                                            /**** Notes Array.indexOf(String) is different String.indexOf(String) 
                                            * *** example Array: if(aServiceIn.indexOf(x.code) > -1)
                                            * ['AUS_PARCEL_EXPRESS_SATCHEL'].indexOf('AUS_PARCEL_EXPRESS') => return false;
                                            * ['AUS_PARCEL_EXPRESS'].indexOf('AUS_PARCEL_EXPRESS') => return true;
                                            * *** example String: if(_sServiceIn.indexOf(x.code) > -1)
                                            * 'AUS_PARCEL_EXPRESS_SATCHEL'.indexOf('AUS_PARCEL_EXPRESS') => return true;
                                            * ['AUS_PARCEL_EXPRESS'].indexOf('AUS_PARCEL_EXPRESS_SATCHEL') => return false;
                                            */
                                            for (var j = 0; j < oAusPostServices.service.length; j++) {
                                                var _oService = oAusPostServices.service[j];
                                                if (_oService.code == _sServiceIn)
                                                {
                                                    if ($rootScope.webApp.util.hasVal(_sServiceName))
                                                    {
                                                        _oService.name = _sServiceName;
                                                    }
                                                    if ($rootScope.webApp.util.hasVal(_sOptionIn)) {
                                                        _oService.options.option = $filter('filter')(_oService.options.option, function (x) { return x.code.indexOf(_sOptionIn) > -1; });

                                                        if ($rootScope.webApp.util.hasVal(_sOptionName) && _oService.options.option.length > 0) {
                                                            _oService.options.option[0].name = _sOptionName;
                                                        }
                                                    }

                                                    _services.push(_oService);                                                    
                                                }
                                            }
                                        }
                                    }

                                    oAusPostServices.service = _services;
                                }
                                //oAusPostServices.service.unshift(moAUSPostPickupService);//push pickup in-store option

                                if (oAusPostServices.service.length > 0) {
                                    for (var i = 0; i < oAusPostServices.service.length; i++) {

                                        if (oAusPostServices.service[i].code != "Pick_Up_In_Store" && oAusPostServices.service[i].code != "Free_Delivery") {

                                            var _option = oAusPostServices.service[i].options.option;                                            

                                            for (var j = 0; j < _option.length; j++) {
                                                //var oAusPostTemp = angular.copy(oAusPost);
                                                var oAusPostTemp = angular.copy(oAusPostServicesParams);

                                                oAusPostTemp.ServiceCode = oAusPostServices.service[i].code;
                                                oAusPostTemp.OptionCode = _option[j].code;
                                                oAusPostTemp.bIsLastItem = ((j + 1) == _option.length) && (i + 1) == oAusPostServices.service.length;
                                                _updateAusPostServicePrice(oAusPostTemp, function (response) {
                                                    var iDealerExtraFee = 0;
                                                    if ($rootScope.util.hasVal($scope.AusPost.DealerExtraFee)) {
                                                        iDealerExtraFee = $rootScope.util.toNumber($scope.AusPost.DealerExtraFee);
                                                    }

                                                    for (var k = 0; k < oAusPostServices.service.length; k++) {
                                                        if (response.ServiceCode == oAusPostServices.service[k].code) {
                                                            var existingOptions = oAusPostServices.service[k].options.option;
                                                            for (var kj = 0; kj < existingOptions.length; kj++) {
                                                                if (response.OptionCode == existingOptions[kj].code) {
                                                                    existingOptions[kj].price = CNumberZero(response.postage_result.total_cost) + iDealerExtraFee;//($scope.ShoppingCart.WebsiteId == 341 ? 0 : iDealerExtraFee);
                                                                }
                                                            }
                                                        }
                                                    }
                                                    //if last item, return callback GetAusPostServices function
                                                    if (response.bIsLastItem && angular.isFunction(cbSuccess)) {
                                                        _cbloadAusPostServices({ oAusPostServices: oAusPostServices, bIsAddMoreOption: true });//include pickup and ...
                                                    }
                                                });
                                            }
                                        }
                                    }
                                }
                                else {
                                    _cbloadAusPostServices({ oAusPostServices: oAusPostServices, bIsAddMoreOption: true });
                                }
                            }
                        }
                        var _cbError = function (responseError, isMaxLWHW) {

                            console.error('sys error fnGetAusPostServices', responseError, oAusPostServicesParams);
                            oAusPostServices = {
                                service: []
                            };
                            //set default value
                            //oAusPostServices.service.push(moAUSPostPickupService);
                            _cbloadAusPostServices({ oAusPostServices: oAusPostServices, bIsAddMoreOption: true });

                        }
                        var _postToServer = function (isMaxLWHW) {
                            //get auspost service codes
                            if (isMaxLWHW) {
                                //*** try again with maximum LWHW
                                oAusPostServicesParams.Length = 105;
                                oAusPostServicesParams.Width = 105;
                                oAusPostServicesParams.Height = 22;
                                oAusPostServicesParams.Weight = 22;
                                isMaxLWHW = true;
                                console.log("ubs-part-specs: has error. try again with max(Length-Width-Height); total weight", oAusPostServicesParams.Length, oAusPostServicesParams.Width, oAusPostServicesParams.Height, oAusPostServicesParams.Weight);
                            }
                            ShoppingCartFactory.GetAusPostServices(oAusPostServicesParams).then(function (response) {
                                _cbSuccess(response, isMaxLWHW);
                            }, function (responseError) {
                                _cbError(responseError, isMaxLWHW);

                            });
                        }

                        if (oAusPost.ServiceIn != null
                            && ($rootScope.webApp.util.indexOfLowerCase(oAusPost.ServiceIn, 'Bind_LWHW_To_Option_Standard')
                                || $rootScope.webApp.util.indexOfLowerCase(oAusPost.ServiceIn, 'Bind_LWHW_To_Option_Inc_Oversize'))
                            && moShoppingSetting.HasWSPSBindLWHWToWebstore == true) {
                            //*** Shipping Criteria
                            //*** get list sizes
                            var lSizesTemp = [];
                            var len, wd, ht, wt;
                            var bFlagInlcudeNoneLWHW = false;
                            var bHasAnyItemEPCItem = false;
                            var bHasAnyItemNoneLWHW = false;
                            for (var i = 0; i < lPendingSales.length; i++) {
                                if ($rootScope.webApp.util.startWithLowerCase(lPendingSales[i].Source, 'TPE')) {
                                    bHasAnyItemEPCItem = true;//*** BrisbaneYamahaPart3040: include extra delivery fee
                                }
                                else
                                {
                                    if ($rootScope.webApp.util.hasVal(lPendingSales[i].SpecialOptions))
                                    {
                                        bFlagInlcudeNoneLWHW = false;
                                        len = $rootScope.webApp.util.getParameterByName('len', lPendingSales[i].SpecialOptions);
                                        wd = $rootScope.webApp.util.getParameterByName('wd', lPendingSales[i].SpecialOptions);
                                        ht = $rootScope.webApp.util.getParameterByName('h', lPendingSales[i].SpecialOptions);
                                        wt = $rootScope.webApp.util.getParameterByName('wt', lPendingSales[i].SpecialOptions);
                                        len = $rootScope.webApp.util.toFloat(len);
                                        wd = $rootScope.webApp.util.toFloat(wd);
                                        ht = $rootScope.webApp.util.toFloat(ht);
                                        wt = $rootScope.webApp.util.toFloat(wt);

                                        if (iWebsiteId == webApp.WebsiteIdCode.BrisbaneYamahaPart3040) {
                                            //#region BrisbaneYamahaPart3040: include extra delivery fee
                                            if (len > 0) {
                                                bFlagInlcudeNoneLWHW = true;
                                            } else {
                                                bHasAnyItemNoneLWHW = true;
                                            }
                                            //#endregion
                                        } else {
                                            //bFlagInlcudeNoneLWHW == true;
                                            bFlagInlcudeNoneLWHW = true;
                                        }
                                    
                                        if (bFlagInlcudeNoneLWHW == true) {
                                            
                                            lSizesTemp.push({
                                                id: lPendingSales[i].RefId,
                                                L: len,
                                                W: wd,
                                                H: ht,
                                                WT: wt,
                                                Qty: lPendingSales[i].Quantity
                                            });
                                        }
                                    }
                                }
                            }
                            if (lSizesTemp.length > 0)
                            {
                                var __cbCalcAusPost = function (response) {
                                    if (response.lAusPostServiceItems.length > 0) {

                                        oAusPostServices.service = response.lAusPostServiceItems;
                                        _cbloadAusPostServices({ oAusPostServices: oAusPostServices, bIsAddMoreOption: true });
                                    } else {
                                        _cbloadAusPostServices({ oAusPostServices: {}, bIsAddMoreOption: true });
                                    }
                                }
                                if ($rootScope.webApp.util.indexOfLowerCase(oAusPost.ServiceIn, 'Bind_LWHW_To_Option_Inc_Oversize')) {
                                    _calcAusPostBind_LWHW_To_Option_Inc_Oversize(lSizesTemp, oAusPost, __cbCalcAusPost);
                                }
                                else {
                                    _calcAusPostBind_LWHW_To_Option_Standard(lSizesTemp, oAusPost, __cbCalcAusPost);
                                }
                            } else {
                                _cbloadAusPostServices({ oAusPostServices: {}, bIsAddMoreOption: true });
                            }

                        } else {

                            oLWHWMax = _getLWHWMax($scope.ShoppingCart.PendingSales);
                            if (oLWHWMax.isUsed) {
                                oAusPostServicesParams.Length = oLWHWMax.Length;
                                oAusPostServicesParams.Width = oLWHWMax.Width;
                                oAusPostServicesParams.Height = oLWHWMax.Height;
                                oAusPostServicesParams.Weight = oLWHWMax.Weight;
                            }

                            _postToServer(false);
                        }
                    }
                    else {
                        _cbloadAusPostServices({ oAusPostServices: {}, bIsAddMoreOption: true });
                    }
                } else {

                    _cbloadAusPostServices({ oAusPostServices: {}, bIsAddMoreOption: true });
                }
            }
        } else {
            _cbloadAusPostServices({ oAusPostServices: {}, sDeliveryOption: "FREE DELIVERY AUSTRALIA WIDE" });
        }        
    }
    //#endregion

    //#region DOMEvent
    var changeQty = function (oItem, cbSuccess) {
        var oValidQuantity = validQuantity(oItem);
        if (oValidQuantity.isValid) {
            if (!angular.isNumber(oItem.Quantity) || oItem.Quantity < 1) {
                oItem.Quantity = 1;
            }
            ShoppingCartFactory.AddProductItem(oItem).then(function (response) {
                ////cbSuccess(response);
                var jsonData = angular.fromJson(response.data);
                $scope.TotalRecordsShoppingCart = jsonData.TotalRecords;
                //$scope.ShoppingCart.PendingSales = jsonData.Carts;
            }, function () { });
        } else {
            if (angular.isFunction(cbSuccess)) {
                cbSuccess({
                    isValid: oValidQuantity.isValid,
                    sMsg: oValidQuantity.sMsg
                });
            } else {
                showQtyNotification({ ItemTitle: oValidQuantity.sMsg });
            }            
        }
        
    }
    var changeQtyPlus = function (oItem, cbSuccess)
    {
        ++oItem.Quantity;
        changeQty(oItem, cbSuccess);
    }
    var changeQtyMinus = function (oItem, cbSuccess) {
        if (oItem.Quantity == 1) return;
        --oItem.Quantity;
        changeQty(oItem, cbSuccess);
    }
    var showQtyNotification = function (oOpt)
    {   
        Notification.errorQty(oOpt.ItemTitle);
    }
    var showErrorShoppingNotification = function (title, msg)
    {
        Notification.errorShopping(msg, title);
    }
    var applyDiscountCode = function (oShoppingDiscountCode, cbSuccess) {
        
        ShoppingCartFactory.applyDiscountCode(oShoppingDiscountCode).then(function (response) {
            var jsonData = response.data
            oShoppingDiscountCode = jsonData.DiscountCodeView;
            if (jsonData.Products.length > 0) {
                $scope.ShoppingCart.PendingSales = jsonData.Products;
            }
            switch (oShoppingDiscountCode.ResponseMessage) {
                case "IsValid":
                    //store to local_storage                            
                    //localstorageFactory.setObject("ShoppingDiscountCode", $scope.ShoppingDiscountCode);
                    break;
                case "Inactive":
                    oShoppingDiscountCode.ResponseMessage = "NOT ACTIVE CODE";
                    break;
                case "LimitUser":
                    oShoppingDiscountCode.ResponseMessage = "LIMIT CODE";
                    break;
                case "Expired":
                    oShoppingDiscountCode.ResponseMessage = "DATE EXPIRED";
                    break;
                case "IsInvalid":
                    oShoppingDiscountCode.ResponseMessage = "INVALID CODE";
                    break;
                default://IsEmpty
                    oShoppingDiscountCode.ResponseMessage = "The code is required.";
                    break;
            }
            cbSuccess(oShoppingDiscountCode);
            
        }, function (responseError) {
            
        });
    }
    var removeDiscountCode = function (oShoppingDiscountCode, cbSuccess) {
        ShoppingCartFactory.removeDiscountCode(oShoppingDiscountCode).then(function (response) {
            cbSuccess(response);
        }, function (responseError) { });
    }
    var changeDeliveryAusPostService = function (sValue, oAusPost, oCardHeader, oAusPostServices, oAusPostCalculate, cbSuccess) {
        oCardHeader.DeliveryOption = null;
        var isShowResult = false;

        if (!IsNullOrEmpty(sValue)) {
            isShowResult = true;
            oAusPost.ServiceCode = sValue.split("::")[0];
            oAusPost.OptionCode = sValue.split("::")[1];
            var selectedService = {};
            var selectedOption = {};
            oAusPostServices.service = oAusPostServices.service || [];
            for (var i = 0; i < oAusPostServices.service.length; i++) {
                if (oAusPostServices.service[i].code == oAusPost.ServiceCode) {
                    oCardHeader.DeliveryOption = oAusPostServices.service[i].name;
                    selectedService = oAusPostServices.service[i];
                    for (var j = 0; j < oAusPostServices.service[i].options.option.length; j++) {
                        if (oAusPostServices.service[i].options.option[j].code == oAusPost.OptionCode) {
                            oCardHeader.DeliveryOption = oCardHeader.DeliveryOption + " - " + oAusPostServices.service[i].options.option[j].name;
                            selectedOption = oAusPostServices.service[i].options.option[j];
                            break;
                        }
                    }
                    break;
                }
            }

            if (oAusPost.ServiceCode == "Pick_Up_In_Store") {                
                var oCost = {
                    "item": "Free pickup",
                    "cost": 0
                };
                if (moAUSPostPickupService.options.option.length > 1)
                {
                    for (var i = 0; i < moAUSPostPickupService.options.option.length; i++) {
                        if (moAUSPostPickupService.options.option[i].code == oAusPost.OptionCode) {
                            oCost = {
                                "item": moAUSPostPickupService.options.option[i].name, //"Free pickup",
                                "cost": moAUSPostPickupService.options.option[i].price
                            };
                            break;
                        }
                    }
                }
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostPickupService.code,// "Pick_Up_In_Store",
                        "delivery_time": "",
                        "total_cost": moAUSPostPickupService.price,
                        "costs": {
                            "cost": oCost
                        }
                    }
                };                
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            } else if (oAusPost.ServiceCode == "Free_Delivery") {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": "Free_Delivery",
                        "delivery_time": "",
                        "total_cost": 0,
                        "costs": {
                            "cost": {
                                "item": "Free Delivery",
                                "cost": 0
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            } else if (oAusPost.ServiceCode == "Delivery_Fee") {
                var cost = 10;
                if ($window.webApp.oWebsite.WebsiteID == 229) {
                    cost = selectedOption.price;
                } else {
                    cost = 10;
                }
                oAusPostCalculate = {
                    "postage_result": {
                        "service": "Delivery_Fee",
                        "delivery_time": "",
                        "total_cost": cost,
                        "costs": {
                            "cost": {
                                "item": "Delivery",
                                "cost": cost
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (oAusPost.ServiceCode == moAUSPostFreeFreightCode.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostFreeFreightCode.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostFreeFreightCode.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostFreeFreightCode.options.option[0].name,
                                "cost": moAUSPostFreeFreightCode.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (oAusPost.ServiceCode == moAUSPostDeliveryBusinessDayOption.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostDeliveryBusinessDayOption.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostDeliveryBusinessDayOption.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostDeliveryBusinessDayOption.options.option[0].name,
                                "cost": moAUSPostDeliveryBusinessDayOption.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (moShoppingSetting.jsonDeliveryLocal && oAusPost.ServiceCode == moShoppingSetting.jsonDeliveryLocal.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moShoppingSetting.jsonDeliveryLocal.code,
                        "delivery_time": "",
                        "total_cost": moShoppingSetting.jsonDeliveryLocal.price,
                        "costs": {
                            "cost": {
                                "item": moShoppingSetting.jsonDeliveryLocal.options.option[0].name,
                                "cost": moShoppingSetting.jsonDeliveryLocal.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }

            else if (moShoppingSetting.jsonDeliveryCourier && oAusPost.ServiceCode == moShoppingSetting.jsonDeliveryCourier.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moShoppingSetting.jsonDeliveryCourier.code,
                        "delivery_time": "",
                        "total_cost": moShoppingSetting.jsonDeliveryCourier.price,
                        "costs": {
                            "cost": {
                                "item": moShoppingSetting.jsonDeliveryCourier.options.option[0].name,
                                "cost": moShoppingSetting.jsonDeliveryCourier.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (oAusPost.ServiceCode == moAUSPostDeliveryByTotalBasketOption.code) {
                console.warn('Minh: onchange->changeDeliveryAusPostService', moAUSPostDeliveryByTotalBasketOption);
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostDeliveryByTotalBasketOption.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostDeliveryByTotalBasketOption.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostDeliveryByTotalBasketOption.options.option[0].name,
                                "cost": moAUSPostDeliveryByTotalBasketOption.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (oAusPost.ServiceCode == moAUSPostFreightEnquiryOption.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostFreightEnquiryOption.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostFreightEnquiryOption.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostFreightEnquiryOption.options.option[0].name,
                                "cost": moAUSPostFreightEnquiryOption.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            } else if (oAusPost.ServiceCode == moAUSPostStandardDeliveryFeeOption.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostStandardDeliveryFeeOption.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostStandardDeliveryFeeOption.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostStandardDeliveryFeeOption.options.option[0].name,
                                "cost": moAUSPostStandardDeliveryFeeOption.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else if (oAusPost.ServiceCode == moAUSPostExpressPostOption.code) {
                oAusPostCalculate = {
                    "postage_result": {
                        "service": moAUSPostExpressPostOption.code,
                        "delivery_time": "",
                        "total_cost": moAUSPostExpressPostOption.price,
                        "costs": {
                            "cost": {
                                "item": moAUSPostExpressPostOption.options.option[0].name,
                                "cost": moAUSPostExpressPostOption.options.option[0].price
                            }
                        }
                    }
                };
                cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
            }
            else {

                if (oAusPost.ServiceIn != null                    
                    //&& (oAusPost.ServiceIn == 'Bind_LWHW_To_Option_Standard' || oAusPost.ServiceIn == 'Bind_LWHW_To_Option_Inc_Oversize')
                    && ($rootScope.webApp.util.indexOfLowerCase(oAusPost.ServiceIn, 'Bind_LWHW_To_Option_Standard')
                                || $rootScope.webApp.util.indexOfLowerCase(oAusPost.ServiceIn, 'Bind_LWHW_To_Option_Inc_Oversize'))
                    && moShoppingSetting.HasWSPSBindLWHWToWebstore == true) {
                    oAusPostCalculate = {
                        "postage_result": {
                            "service": selectedService.name,
                            "delivery_time": "",
                            "total_cost": selectedOption.price,
                            "costs": {
                                "cost": {
                                    "item": selectedService.name,
                                    "cost": selectedOption.price
                                }
                            }
                        }
                    };
                    cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });

                }
                else {
                    if (moShoppingSetting.HasWSPSBindLWHWToWebstore) {
                        var oLWHWMax = _getLWHWMax($scope.ShoppingCart.PendingSales);
                        if (oLWHWMax.isUsed) {
                            oAusPost.Length = oLWHWMax.Length;
                            oAusPost.Width = oLWHWMax.Width;
                            oAusPost.Height = oLWHWMax.Height;
                            oAusPost.Weight = oLWHWMax.Weight;
                        }
                    }

                    ShoppingCartFactory.GetAusPostCalculate(oAusPost).then(function (response) {
                        oAusPostCalculate = response.data;
                        cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
                    }, function (responseError) {
                        oAusPostCalculate = undefined;
                    });
                }
                
            }
        } else {
            isShowResult = false;
            oAusPostCalculate = undefined;
            cbSuccess({ isShowResult: isShowResult, oAusPostCalculate: oAusPostCalculate });
        }
    }

    var updateSSDraftOrder = function (data, cbSuccess) {

        ShoppingCartFactory.updateSSDraftOrder(data).then(function (response) {
            //var jsonData = response.data;
            cbSuccess(response);
        }, function (responseError) {

        });
    }

    //#endregion

    //#region save
    var validQuantity = function (oItem) {
        var bValid = true;
        var iQty = 0;
        var sMsg = "";
       


        var isBindQAVToWebstore = ($rootScope.webApp.util.hasVal(oItem.SpecialOptions) && $rootScope.webApp.util.indexOfLowerCase(oItem.SpecialOptions, 'qav='));
        if (isBindQAVToWebstore) {
            var sQuantityAvailable = $rootScope.webApp.util.getParameterByName("qav", oItem.SpecialOptions);
            if (oItem.Quantity < 1 || oItem.Quantity > $rootScope.webApp.util.toNumber(sQuantityAvailable)) {                
                iQty = $rootScope.webApp.util.toNumber(sQuantityAvailable);
                bValid = false;
            }
        }
        else
        {
            var isBindQOHToWebstore = ($rootScope.webApp.util.hasVal(oItem.SpecialOptions) && $rootScope.webApp.util.indexOfLowerCase(oItem.SpecialOptions, 'qoh='));
            if (isBindQOHToWebstore) {
                var sQuantityOnHand = $rootScope.webApp.util.getParameterByName("qoh", oItem.SpecialOptions);
                if (oItem.Quantity < 1 || oItem.Quantity > $rootScope.webApp.util.toNumber(sQuantityOnHand)) {                    
                    iQty = $rootScope.webApp.util.toNumber(sQuantityOnHand);
                    bValid = false;
                }
            }
        }
        if (bValid == false) {
            sMsg = "Sorry! we only have " + iQty + (iQty > 1 ? " items" : " item") + " currently in stock.";
        }
        return {
            isValid: bValid,
            sMsg: sMsg
        };
    }
    var addParamToSpecialOptions = function (sSpecialOptions, sName, sVal) {
        if ($rootScope.webApp.util.hasVal(sSpecialOptions)) {
            var sValExisting = $rootScope.webApp.util.getParameterByName(sName, sSpecialOptions);
            if ($rootScope.webApp.util.hasVal(sValExisting)) {

                if (sSpecialOptions.indexOf('&' + sName + '=') > -1) {
                    sSpecialOptions = sSpecialOptions.replace('&' + sName + '=' + sValExisting, '&' + sName + '=' + sVal);
                }
                else if (sSpecialOptions.indexOf('?' + sName + '=') > -1) {
                    sSpecialOptions = sSpecialOptions.replace('?' + sName + '=' + sValExisting, '?' + sName + '=' + sVal);
                }
            }
            else {
                //Is not existing
                sSpecialOptions += '&' + sName + '=' + sVal;
            }
        } else {
            sSpecialOptions = '?' + sName + '=' + sVal;
        }
        return sSpecialOptions;
    }

    var addProductItem = function (oItem, cbSuccess) {
        oItem.Price = CNumberNull(oItem.Price);
        if (oItem.Price != null) {
            oItem.Price = oItem.Price.toFixed(2);
        }
        oItem.FleetPrice = CNumberNull(oItem.FleetPrice);
        if (oItem.FleetPrice != null) {
            oItem.FleetPrice = oItem.FleetPrice.toFixed(2);
        }
        var oValidQuantity = validQuantity(oItem);
        if (oValidQuantity.isValid) {

            if (angular.isDefined(oItem.IsContFinance) && $rootScope.webApp.util.toBool(oItem.IsContFinance)) {
                oItem.SpecialOptions = addParamToSpecialOptions(oItem.SpecialOptions, 'IsContFinance', 'true');
            }
            if (angular.isDefined(oItem.IsContInsuExtWarr) && $rootScope.webApp.util.toBool(oItem.IsContInsuExtWarr)) {
                oItem.SpecialOptions = addParamToSpecialOptions(oItem.SpecialOptions, 'IsContInsuExtWarr', 'true');
            }

            ShoppingCartFactory.AddProductItem(oItem).then(function (response) {
                var jsonData = angular.fromJson(response.data);

                if (angular.isDefined(jsonData.ErrorMsg) && $rootScope.webApp.util.hasVal(jsonData.ErrorMsg))
                {
                    if (angular.isDefined(jsonData.ValidQty) && $rootScope.webApp.util.toBool(jsonData.ValidQty) == false) {
                        showQtyNotification({ ItemTitle: jsonData.ErrorMsg });
                    } else {
                        showErrorShoppingNotification('Add To Basket Error.', jsonData.ErrorMsg);
                    }
                }
                else {
                    $scope.TotalRecordsShoppingCart = jsonData.TotalRecords;//*** SUM-Qty
                    $scope.ShoppingCart.PendingSales = jsonData.Carts;
                    var oCartItem = jsonData.CartItem;
                    //$scope.NotiCart = oItem;
                    if ($rootScope.webApp.util.toBool(oItem.bRedirectToCheckoutImmediately) == false) {
                        
                        Notification.basketNoti(oCartItem, { action: 'A', isWishlist: false });//*** add to cart ***

                        //var sMsgNotification = _getNotificationTemplate(oCartItem, { action: 'A', isWishlist: false });
                        //$timeout(function () {
                        //    Notification.primary(sMsgNotification);//*** add to cart ***
                        //}, 1);
                    }
                    cbSuccess(response);
                }
                
            }, function () { });
        }
        else {            
            showQtyNotification({ ItemTitle: oValidQuantity.sMsg });
        }
    }
    var addWishlist = function (oItem, cbSuccess) {
        oItem.Price = CNumberNull(oItem.Price);
        if (oItem.Price != null) {
            oItem.Price = oItem.Price.toFixed(2);
        }
        //var oValidQuantity = validQuantity(oItem);
        //if (oValidQuantity.isValid) {
            ShoppingCartFactory.addWishlist(oItem).then(function (response) {
                var jsonData = angular.fromJson(response.data);
                $scope.TotalRecordsWishlist = jsonData.TotalRecords;
                //$scope.ShoppingCart.PendingSales = jsonData.Carts;
                var oCartItem = jsonData.Record;
                //$scope.NotiCart = oItem;
                //var priceCal = getPriceQty(oCartItem.Price, oCartItem.Quantity);
                //var sMsgNotification = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti">'
                //                //+ '<a class="close-icon" ng-click="nClick()">&times;</a>'
                //                + '<div class="popup-shopping">'
                //                    + '<div class="img-shop"><img src="' + oCartItem.PicPath + '" class="img-responsive"></div>'
                //                    + '<div class="item-class">'
                //                        + '<p class="title ng-binding">' + oCartItem.ItemTitle + '</p>'
                //                        + (priceCal > 0 ? '<p class="price ng-binding">PRICE: ' + $filter('currency')(priceCal, "$", 2) + '</p>' : '')
                //                        + '<p><b>ITEM ADDED TO WISHLIST</b></p>'
                //                        //+ '<p><a href="' + $rootScope.util.getUrlHasPrefix('/shopping-basket/checkout') + '">PROCEED TO CHECKOUT</a></p>'
                //                    + '</div>'
                //                + '</div>'
                //            + '</div>';

                Notification.basketNoti(oCartItem, { action: 'A', isWishlist: true });//*** add wishlist ***
                //var sMsgNotification = _getNotificationTemplate(oCartItem, { action: 'A', isWishlist : true });
                //$timeout(function () {
                //    Notification.primary(sMsgNotification);//*** add to wishlist ***
                //}, 1);
                cbSuccess(response);
            }, function () { });
        //} else {
        
        //}
    }
    
    var removeWishlist = function (oItem, cbSuccess) {        
        ShoppingCartFactory.removeWishlist(oItem).then(function (response) {
            var jsonData = angular.fromJson(response.data);
            $scope.TotalRecordsWishlist = jsonData.TotalRecords;
            //var sMsgNotification = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti">'
            //                + '<div class="popup-shopping">'                                
            //                    + '<div class="item-class">'
            //                        + '<p class="title ng-binding">' + oItem.ItemTitle + '</p>'                                    
            //                        + '<p><b>ITEM REMOVED TO WISHLIST</b></p>'
            //                    + '</div>'
            //                + '</div>'
            //            + '</div>';
            Notification.basketNoti(oItem, { action: 'R', isWishlist: true });//*** remove wishlist ***
            //var sMsgNotification = _getNotificationTemplate(oItem, { action: 'R', isWishlist: true });
            //$timeout(function () {
            //    Notification.primary(sMsgNotification);//*** remove wishlist ***
            //}, 1);
            cbSuccess(response);
        }, function () { });
    }
    var addEnquiryCart = function (oItem, cbSuccess) {
        //oItem.Price = CNumberNull(oItem.Price);
        //if (oItem.Price != null) {
        //    oItem.Price = oItem.Price.toFixed(2);
        //}
        //var oValidQuantity = validQuantity(oItem);
        //if (oValidQuantity.isValid) {
        ShoppingCartFactory.addEnquiryCart(oItem).then(function (response) {
            var jsonData = angular.fromJson(response.data);
            $scope.TotalRecordsEnquiryCart = jsonData.TotalRecords;
            $scope.ShoppingCart.EnquiryCarts = jsonData.Records;
            var oCartItem = jsonData.Record;

            Notification.basketNoti(oCartItem, { action: 'A', isEnquiryCart: true });//*** add to cart ***

            //var sMsgNotification = _getNotificationTemplate(oCartItem, { action: 'A', isEnquiryCart: true });
            //$timeout(function () {
            //    Notification.primary(sMsgNotification);//*** add to enquiry cart ***
            //}, 1);
            cbSuccess(response);
        }, function () { });
        //} else {

        //}
    }

    var removeEnquiryCart = function (oItem, cbSuccess) {
        ShoppingCartFactory.removeEnquiryCart(oItem).then(function (response) {
            var jsonData = angular.fromJson(response.data);

            var index = $scope.ShoppingCart.EnquiryCarts.indexOf(oItem);
            $scope.ShoppingCart.EnquiryCarts.splice(index, 1);
            $scope.TotalRecordsEnquiryCart = jsonData.TotalRecords;

            Notification.basketNoti(oItem, { action: 'R', isEnquiryCart: true });//*** remove enquiry cart ***
            //var sMsgNotification = _getNotificationTemplate(oItem, { action: 'R', isEnquiryCart: true });
            //$timeout(function () {
            //    Notification.primary(sMsgNotification);//*** remove enquiry cart ***
            //}, 1);
            cbSuccess(response);
        }, function () { });
    }
    var removeAllEnquiryCarts = function (cbSuccess) {
        ShoppingCartFactory.removeAllEnquiryCarts().then(function (response) {
            //var jsonData = angular.fromJson(response.data);
            $scope.ShoppingCart.EnquiryCarts = [];
            $scope.TotalRecordsEnquiryCart = 0;
            cbSuccess(response);
        }, function () { });
    }

    var removeProductItem = function (oItem, cbSuccess) {        
        ShoppingCartFactory.RemoveProductItem(oItem).then(function (response) {
            var jsonData = angular.fromJson(response.data);
            var index = $scope.ShoppingCart.PendingSales.indexOf(oItem);
            $scope.ShoppingCart.PendingSales.splice(index, 1);
            $scope.TotalRecordsShoppingCart = jsonData.TotalRecords;//*** SUM-Qty
            cbSuccess(response);
        }, function () { });
    }
    var removeAllProductItem = function (cbSuccess) {
        ShoppingCartFactory.RemoveAllCartItems().then(function (response) {
            //var jsonData = angular.fromJson(response.data);
            $scope.ShoppingCart.PendingSales = [];
            $scope.TotalRecordsShoppingCart = 0;
            cbSuccess(response);
        }, function () { });
    }
    var _getNotificationTemplate = function (oNotiItem, opt) {
        opt = opt || {};
        opt.isWishlist = opt.isWishlist || false;
        opt.isEnquiryCart = opt.isEnquiryCart || false;

        var iTemplateNum = 1;
        var sHtml = '';
        var sHtmlButtons = '';

        if ($rootScope.webApp.ssConfig) {
            if ($rootScope.webApp.ssConfig.noti_template_num) {
                iTemplateNum = $rootScope.webApp.ssConfig.noti_template_num || 1;
            }
        }
        if (opt.isWishlist) {
            var priceCal = getPriceQty(oNotiItem.Price, oNotiItem.Quantity);
            switch (iTemplateNum) {
                case 2:
                    if (opt.action == 'A') {
                        sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                + '<div class="myaccount-popup color-success">'
                                    + '<div class="myaccount-popup-content">'
                                       + '<h3>Item Added to Your Wishlist</h3>'
                                       + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                       + (priceCal > 0 ? '<p class="price ng-binding">PRICE: ' + $filter('currency')(priceCal, "$", 2) + '</p>' : '')
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    }
                    else {
                        //remove wishlist item
                        sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                + '<div class="myaccount-popup color-success">'
                                    + '<div class="myaccount-popup-content">'
                                       + '<h3>Item Removed to Your Wishlist</h3>'
                                       + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    }

                    break;
                default:
                    sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                //+ '<a class="close-icon" ng-click="nClick()">&times;</a>'
                                + '<div class="popup-shopping">'
                                    + '<div class="img-shop"><img src="' + oNotiItem.PicPath + '" class="img-responsive"></div>'
                                    + '<div class="item-class">'
                                        + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                        + (priceCal > 0 ? '<p class="price ng-binding">PRICE: ' + $filter('currency')(priceCal, "$", 2) + '</p>' : '')
                                        + '<p><b>ITEM ADDED TO WISHLIST</b></p>'
                                        //+ '<p><a href="' + $rootScope.util.getUrlHasPrefix('/shopping-basket/checkout') + '">PROCEED TO CHECKOUT</a></p>'
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    break;
            }
        }
        else if (opt.isEnquiryCart) {
            //var priceCal = getPriceQty(oNotiItem.Price, oNotiItem.Quantity);
            switch (iTemplateNum) {
                case 2:
                    if (opt.action == 'A') {
                        sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                + '<div class="myaccount-popup color-success">'
                                    + '<div class="myaccount-popup-content">'
                                       + '<h3>Item Added to Your Enquiry</h3>'
                                       + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'                                       
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    }
                    else {
                        //remove ENQUIRY item
                        sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                + '<div class="myaccount-popup color-success">'
                                    + '<div class="myaccount-popup-content">'
                                       + '<h3>Item Removed to Your Enquiry</h3>'
                                       + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    }

                    break;
                default:
                    sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                //+ '<a class="close-icon" ng-click="nClick()">&times;</a>'
                                + '<div class="popup-shopping">'
                                    + '<div class="img-shop"><img src="' + oNotiItem.PicPath + '" class="img-responsive"></div>'
                                    + '<div class="item-class">'
                                        + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                        + (priceCal > 0 ? '<p class="price ng-binding">PRICE: ' + $filter('currency')(priceCal, "$", 2) + '</p>' : '')
                                        + '<p><b>ITEM ADDED TO ENQUIRY</b></p>'
                                        //+ '<p><a href="' + $rootScope.util.getUrlHasPrefix('/shopping-basket/checkout') + '">PROCEED TO CHECKOUT</a></p>'
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    break;
            }
        }
        else {
            //*** default: add to cart notification template
            switch (iTemplateNum) {
                case 2:
                    if ($rootScope.webApp.util.equalsLowerCase(oNotiItem.SalePortal, 'trade') == false) {
                        sHtmlButtons = '<a href="' + $rootScope.webApp.util.getUrlHasPrefix('/shopping-basket') + '" class="btn-1 btn-cart">Go to Cart <i></i></a>'
                                        + '<a href="' + $rootScope.webApp.util.getUrlHasPrefix('/shopping-basket/checkout') + '" class="btn-2 btn-checkout">Check Out <i></i></a>';
                    }
                    sHtmlButtons = '<div class="myaccount-btn-list">'
                                        + sHtmlButtons
                                    + '</div>';
                    sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                + '<div class="myaccount-popup color-success">'
                                    + '<div class="myaccount-popup-content">'
                                       + '<h3>Item Added to Your Cart</h3>'
                                       + '<p class="title ng-binding">' + oNotiItem.ItemTitle + ' x ' + oNotiItem.Quantity + '</p>'
                                       + '<p class="price ng-binding"><b>Total</b> ' + $filter('currency')(getPriceQty(oNotiItem.Price, oNotiItem.Quantity), "$", 2) + '</p>'
                                       + sHtmlButtons
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    break;
                default:
                    sHtml = '<div class="ui-notification custom-template notification-shoppingcart shopping-noti noti-v' + iTemplateNum + '">'
                                //+ '<a class="close-icon" ng-click="nClick()">&times;</a>'
                                + '<div class="popup-shopping">'
                                    + '<div class="img-shop"><img src="' + oNotiItem.PicPath + '" class="img-responsive"></div>'
                                    + '<div class="item-class">'
                                        + '<p class="title ng-binding">' + oNotiItem.ItemTitle + '</p>'
                                        + '<p class="price ng-binding">PRICE: ' + $filter('currency')(getPriceQty(oNotiItem.Price, oNotiItem.Quantity), "$", 2) + '</p>'
                                        + '<p><b>ITEM ADDED TO CART</b></p>'
                                        + '<p><a href="' + $rootScope.webApp.util.getUrlHasPrefix('/shopping-basket/checkout') + '">PROCEED TO CHECKOUT</a></p>'
                                    + '</div>'
                                + '</div>'
                            + '</div>';
                    break;
            }

        }
        return sHtml;
    }
    var saveToGAEcommerceTracking = function (data, sGATransactionId, cbSuccess) {
        if (sGATransactionId != null && data.SaleId != null)
        {
            ShoppingCartFactory.getOrderById({ OrderId: data.SaleId }).then(function (response) {
                if (response.data != null) {
                    var jsonData = angular.fromJson(response.data);
                    var _gaq = _gaq || [];
                    _gaq.push(['_setAccount', sGATransactionId]); //'UA-XXXXX-X'
                    _gaq.push(['_setDomainName', 'none']);
                    _gaq.push(['_trackPageview']);
                    _gaq.push(['_addTrans',
                      jsonData.SaleId,           // transaction ID - required // Order Id
                      jsonData.ShoppingClient.WebsiteDealerName,  // affiliation or store name // dealer name
                      //"UBS-DEV TEST",  // affiliation or store name // dealer name
                      jsonData.TotalSalePriceInc,          // total - required
                      null,           // tax
                      jsonData.DeliveryFee,              // shipping
                      jsonData.DeliverySuburb,       // city
                      jsonData.DeliveryState,     // state or province
                      'AUS'             // country
                    ]);

                    // add item might be called for every item in the shopping cart
                    // where your ecommerce engine loops through each item in the cart and
                    // prints out _addItem for each
                    for (var i = 0; i < jsonData.ShoppingSaleDetail.length; i++) {
                        var item = jsonData.ShoppingSaleDetail[i];
                        _gaq.push(['_addItem',
                          item.SaleId,           // transaction ID - required // Order Id
                          item.RefId,           // SKU/code - required
                          item.ItemTitle,        // product name
                          csourceCodeToDesc(item),   // category or variation
                          item.SalePriceInc,          // unit price - required
                          item.Quantity               // quantity - required
                        ]);
                    }

                    _gaq.push(['_trackTrans']); //submits transaction to the Analytics servers
                }
                cbSuccess(response);
            }, function (responseError) {
                cbSuccess(responseError);
            });
        } else {
            cbSuccess({});
        }
        
    }
    //#endregion

    //#region payment
    var _mappingOrderData = function ()
    {
        
    }
    var createPaypalButton = function (sElementId, lPendingSales, oClient, oCardHeader, oCardDetail, formCreditCard, oPaypalSetting, oShoppingDiscountCode, oAusPostCalculate, oShoppingSetting, cbSuccess) {
        if (oPaypalSetting.IsUsePayMethod) {
            oCardDetail.PayingType = "Paypal";
            var lItems = [];
            var totalPrice = 0;
            var subTotalPrice = 0;
            var dDeliveryFee = 0;

            angular.forEach(lPendingSales, function (value) {
                //var price = (Number(value['Quantity']) * $scope.getPriceDepositAmount(value));
                var price = (value.DiscountCode != null ? (getDiscountCodePriceNotQty(value, oShoppingDiscountCode, oShoppingSetting)) : (getPriceDepositAmount(value, oShoppingSetting)));
                lItems.push({
                    //name: value.ItemCode,
                    //description: value.ItemTitle,
                    //quantity: value.Quantity,
                    ////price: getPriceDepositAmount(value, oShoppingSetting),
                    //price: value.DiscountCode != null ? (getDiscountCodePriceNotQty(value, oShoppingDiscountCode, oShoppingSetting)) : (getPriceDepositAmount(value, oShoppingSetting)),//var getDiscountCodePrice = function (item, oShoppingDiscountCode, oShoppingSetting) {
                    //currency: 'AUD',
                    //sku: value.RefId,
                    name: value.ItemTitle,//value.ItemCode,//Maximum length: 127.
                    //unit_amount: $scope.oOrderModel.DepositAmount,
                    unit_amount: {
                        value: price,//*** Must equal unit_amount * quantity for all items
                        currency_code: 'AUD'
                    },
                    quantity: value.Quantity,
                    description: value.ItemTitle,//Maximum length: 127.                    
                    sku: value.RefId//Maximum length: 127.

                });
                //subTotalPrice += price;
            });

            /*
            var lItems = [];
                    lItems.push({
                        name: $scope.oCardItem.ItemCode,//Maximum length: 127.
                        //unit_amount: $scope.oOrderModel.DepositAmount,
                        unit_amount: {
                            value: $scope.oOrderModel.DepositAmount,//*** Must equal unit_amount * quantity for all items
                            currency_code: 'AUD'
                        },
                        quantity: 1,
                        description: $scope.oCardItem.ItemTitle,//Maximum length: 127.                    
                        sku: $scope.oCardItem.RefId//Maximum length: 127.
                    });
            */

            var sTotalBasket = $filter('currency')(getTotalBasket(oShoppingDiscountCode, oAusPostCalculate, oShoppingSetting, lPendingSales), "", 2);
            var sDeliveryFee = $filter('currency')(getDeliveryFee(oAusPostCalculate, lPendingSales), "", 2);

            if ($rootScope.webApp.util.hasVal(sTotalBasket)) totalPrice = Number(sTotalBasket.replace(/[^0-9.-]+/g, ""));
            if ($rootScope.webApp.util.hasVal(sDeliveryFee)) dDeliveryFee = Number(sDeliveryFee.replace(/[^0-9.-]+/g, ""));

            //totalPrice = Number($filter('currency')($scope.getTotalBasket(), "", 2).replace(/[^0-9.-]+/g, ""));
            //var dDeliveryFee = Number($filter('currency')($scope.getDeliveryFee(), "", 2).replace(/[^0-9.-]+/g, ""));// $scope.getDeliveryFee();
            if ((totalPrice - dDeliveryFee) > 0) {
                subTotalPrice = Number($filter('currency')(totalPrice - dDeliveryFee, "", 2).replace(/[^0-9.-]+/g, ""));
            }
            
            var recipient_name = "";
            if ($rootScope.webApp.util.hasVal(oClient.FullName) == false) {
                recipient_name = oClient.FirstName + ' ' + oClient.LastName;
            } else {
                recipient_name = oClient.FullName;
            }

            var oShippingAddress = {
                recipient_name: recipient_name,
                line1: oClient.Delivery.Address,
                line2: null,
                city: oClient.Delivery.Suburb,
                country_code: "AU",
                postal_code: oClient.Delivery.Postcode,
                phone: oClient.Phone,
                state: oClient.Delivery.State
            };

            //// Render the PayPal button
            renderPaypalButton(sElementId, oPaypalSetting.IsSandbox, oPaypalSetting.ClientKey,
                totalPrice, subTotalPrice, dDeliveryFee, lItems, oShippingAddress, function (payment) {
                //*** callback checked-out function
                var bValidatePayment = validatePayment(null, oCardHeader, oCardDetail, oShoppingDiscountCode, oClient, lPendingSales, formCreditCard);
                if (bValidatePayment) {
                    //if (payment.state.toUpperCase() == "APPROVED") {
                    var oCardHeaderCopied = angular.copy($scope.CardHeader);
                    if ($rootScope.webApp.util.equalsLowerCase(payment.status, "approved") || $rootScope.webApp.util.equalsLowerCase(payment.status, "completed")) {
                        try {
                            oCardHeaderCopied.TransactionId = payment.purchase_units[0].payments.captures[0].id;
                        } catch (e) {
                            oCardHeaderCopied.TransactionId = payment.id;
                        }
                    } else {
                        //*** payment.status is CREATED or FAILED
                        oCardHeaderCopied.PayingType = oCardHeaderCopied.PayingType + payment.status;
                    }
                    $rootScope.webApp.util.showLoadingIcon($element, true);
                    ShoppingCartFactory.paymentPaypal(oCardHeaderCopied).then(function (response) {
                        cbSuccess(response);
                    }, function (responseError) {
                        $rootScope.webApp.util.showLoadingIcon($element, false);
                    });
                }
            });
        } else {
            console.error("Minh: ", "Unavailable Method");
        }
    }
    var getPaymentSetting = function (sPaymentMethod, cbSuccess)
    {
        switch (sPaymentMethod) {
            case 'Paypal':
                ShoppingCartFactory.getPaypalSetting({}).then(function (response) {
                    var oPaypalSetting = angular.fromJson(response.data);
                    if (oPaypalSetting.IsUsePayMethod) {
                        //LoginService.InitPaypal();
                        LoginService.InitPaypalByClientId(oPaypalSetting.ClientKey);
                    }
                    cbSuccess(response);
                }, function (responseError) {
                });
                break;
            case 'Zippay':
                ShoppingCartFactory.getZipPaySetting({}).then(function (response) {
                    cbSuccess(response);
                }, function (responseError) {
                });
                break;
        }
    }
    var renderPaypalButton = function (sElementId, isSandbox, sClientKey, dAmountTotal, subTotalPrice, dDeliveryFee, lItems, oShippingAddress, cbExecute) {
        if (!isRenderPaypalButton) {
            isRenderPaypalButton = true;
            //var sSandbox = "sandbox";
            //if ($rootScope.util.toBool(isSandbox) == false) sSandbox = "production";
            ////$window.paypal.Button.render({
            //$window.paypal.Buttons({
            //    //https://developer.paypal.com/docs/api/payments/#definition-item
            //    //https://developer.paypal.com/docs/api/payments/#payment_create
            //    //<script src="https://www.paypalobjects.com/api/checkout.js"></script>
            //    //https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/client-side-REST-integration/
            //    // Set your environment
            //    env: sSandbox, // sandbox | production
            //    // Specify the style of the button
            //    style: {
            //        layout: 'vertical',  // horizontal | vertical
            //        size: 'responsive',    // small | medium | large | responsive
            //        shape: 'rect',      // pill | rect
            //        color: 'gold'       // gold | blue | silver | white | black
            //    },
            //    // Specify allowed and disallowed funding sources
            //    //
            //    // Options:
            //    // - paypal.FUNDING.CARD
            //    // - paypal.FUNDING.CREDIT
            //    // - paypal.FUNDING.ELV
            //    funding: {
            //        allowed: [
            //          paypal.FUNDING.CARD,
            //          paypal.FUNDING.CREDIT
            //        ],
            //        disallowed: []
            //    },
            //    // Enable Pay Now checkout flow (optional)
            //    commit: true,// Show a 'Pay Now' button
            //    // PayPal Client IDs - replace with your own
            //    // Create a PayPal app: https://developer.paypal.com/developer/applications/create
            //    client: {
            //        sandbox: sClientKey,//app: as-test; paypal account: minhgiang2312068@gmail.com
            //        production: sClientKey
            //    },
            //    commit: true, // Show a 'Pay Now' button  
            //    /* payment() is called when the button is clicked */
            //    payment: function (data, actions) {
            //        //*****************https://developer.paypal.com/docs/checkout/how-to/server-integration/#how-a-server-integration-works
            //        ///* Set up a url on your server to create the payment */
            //        //var CREATE_URL = '/example/createPayment';
            //        ///* Make a call to your server to set up the payment */
            //        //return ShoppingCartFactory.createPaymentPaypal().then(function (response) {
            //        //    return response.body.id;
            //        //})
            //        //return paypal.request.post(CREATE_URL)
            //        //    .then(function(response) {
            //        //        return response.body.id;
            //        //    });
            //        return actions.payment.create({
            //            transactions: [{
            //                amount: {
            //                    total: dAmountTotal,//'30.00',
            //                    currency: 'AUD',
            //                    details: {
            //                        subtotal: subTotalPrice,
            //                        //tax: 0,
            //                        shipping: dDeliveryFee,
            //                        //handling_fee: "1.00",
            //                        //shipping_discount: "-1.00",
            //                        //insurance: "0.01"
            //                    }
            //                },
            //                //description: 'The payment transaction description.',
            //                item_list: {
            //                    items: lItems,
            //                    shipping_address: oShippingAddress
            //                }
            //            }],
            //            //note_to_payer: 'Contact us for any questions on your order.'
            //        });
            //    },
            //    onAuthorize: function (data, actions) {
            //        ///* Set up a url on your server to execute the payment */
            //        //var EXECUTE_URL = '/example/executePayment';
            //        ///* Set up the data you need to pass to your server */
            //        //var data = {
            //        //    paymentID: data.paymentID,
            //        //    payerID: data.payerID
            //        //};
            //        ///* Make a call to your server to execute the payment */
            //        //return paypal.request.post(EXECUTE_URL, data)
            //        //    .then(function (res) {
            //        //        window.alert('Payment Complete!');
            //        //    });
            //        return actions.payment.execute().then(function (payment) {
            //            cbExecute(payment);
            //            // The payment is complete!
            //            // You can now show a confirmation message to the customer
            //        });
            //    },
            //    onCancel: function (data, actions) {
            //        //console.warn("Minh: onCancel", data, actions);
            //    },
            //    onError: function (err) {
            //        alert(err);
            //        console.error("Minh: ", err);
            //    }
            ////}, sElementId);
            //}).render(sElementId);

            $window.myPaypalButton = $window.paypal.Buttons({
                locale: 'en_US',
                //// onInit is called when the button first renders
                //onInit: function (data, actions) {
                //    if ($scope.myForm.$invalid) {
                //        actions.disable(); // Allow for validation in onClick()
                //    }
                //    $scope.oPaypalAction = actions; // Save for later enable()/disable() calls
                //},
                //onClick: $scope.btnPaypalClick,
                createOrder: function (data, actions) {
                    // This function sets up the details of the transaction, including the amount and line item details.
                    //var lItems = [];
                    //lItems.push({
                    //    name: $scope.oCardItem.ItemCode,//Maximum length: 127.
                    //    //unit_amount: $scope.oOrderModel.DepositAmount,
                    //    unit_amount: {
                    //        value: $scope.oOrderModel.DepositAmount,//*** Must equal unit_amount * quantity for all items
                    //        currency_code: 'AUD'
                    //    },
                    //    quantity: 1,
                    //    description: $scope.oCardItem.ItemTitle,//Maximum length: 127.                    
                    //    sku: $scope.oCardItem.RefId//Maximum length: 127.
                    //});
                    //var totalPrice = Number($filter('currency')($scope.oOrderModel.DepositAmount, "", 2).replace(/[^0-9.-]+/g, ""));

                    return actions.order.create({
                        //application_context: {
                        //    shipping_preference: 'NO_SHIPPING'
                        //},
                        purchase_units: [{
                            amount: {
                                value: dAmountTotal,//'30.00',
                                currency_code: 'AUD',
                                breakdown: {
                                    item_total: {
                                        value: subTotalPrice,// plus tax_total plus shipping plus handling plus insurance minus shipping_discount minus discount.
                                        currency_code: 'AUD'
                                    },
                                    shipping: {
                                        value: dDeliveryFee,
                                        currency_code: 'AUD'
                                    }
                                }
                            },
                            items: lItems
                        }],
                    });
                },
                onApprove: function (data, actions) {
                    return actions.order.capture().then(function (payment) {
                        cbExecute(payment);
                        // The payment is complete!
                        // You can now show a confirmation message to the customer
                    });// The payment is complete!
                },
                //onCancel: function (data, actions) {
                //    //console.warn("Minh: onCancel", data, actions);
                //},
                onError: function (err) {
                    alert(err);
                    console.error("Minh: ", err);
                }

            });
            $window.myPaypalButton.render(sElementId);

        }
    }
    var resetRenderPaypalButtonFlag = function (sElementId) {
        isRenderPaypalButton = false;
        //$(sElementId).html('');
        $window.myPaypalButton.close();
    }
    var renderSecurePayUI = function () {
        $scope.CardDetail.PayingType = "Securepay";
        $scope.mySecurePayUI = new securePayUI.init({
            containerId: 'securepay-v2-ui-container',
            scriptId: 'securepay-v2-ui-jscheckout',
            clientId: $scope.oShoppingSetting.SecurePayClientId, //'YOUR_CLIENT_ID',
            merchantCode: $scope.oShoppingSetting.SecurePayMerchantCode,//'YOUR_MERCHANT_CODE',
            card: {
                allowedCardTypes: ['visa', 'mastercard'],
                showCardIcons: true,
                onCardTypeChange: function (cardType) {
                    // card type has changed
                },
                onBINChange: function (cardBIN) {
                    // card BIN has changed
                },
                onFormValidityChange: function (valid) {
                    // form validity has changed
                },
                onTokeniseSuccess: function (tokenisedCard) {
                    // card was successfully tokenised or saved card was successfully retrieved 
                    //console.warn("Minh: onTokeniseSuccess", tokenisedCard);
                    $scope.CardHeader.SecurePayCardToken = tokenisedCard.token;
                    ShoppingCartFactory.paymentSecurePay($scope.CardHeader).then(function (response) {
                        //$rootScope.util.showLoadingIcon($element, false);
                        $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                        //disableButton($(e.target), false);
                        //setStatusButton($(e.target), "reset");
                    }, function (responseError) {
                        $rootScope.util.showLoadingIcon($element, false);
                        //disableButton($(e.target), false);
                        //setStatusButton($(e.target), "reset");
                    });

                    /* response data
                        bin: "444433" //Bank identification number.
                        createdAt: "2021-10-14T21:13:44.754+11:00"
                        expiryMonth: "11"
                        expiryYear: "22"
                        last4: "111"
                        merchantCode: "5AR0055"
                        scheme: "visa"
                        token: "4147458121088632" //Token for anonymous payments expires after 30 minutes.
                    */
                },
                onTokeniseError: function (errors) {
                    // tokenization failed
                    console.warn("Minh: onTokeniseError", errors);
                }
            },
            style: {
                backgroundColor: 'rgba(135, 206, 250, 0.1)',
                label: {
                    font: {
                        family: 'Arial, Helvetica, sans-serif',
                        size: '1.1rem',
                        color: 'darkblue'
                    }
                },
                input: {
                    font: {
                        family: 'Arial, Helvetica, sans-serif',
                        size: '1.1rem',
                        color: 'darkblue'
                    }
                }
            },
            onLoadComplete: function () {
                // the UI Component has successfully loaded and is ready to be interacted with
                //console.warn("Minh: onLoadComplete");
            }
        });
    }


    var validatePayment = function (e, oCardHeader, oCardDetail, oShoppingDiscountCode, oClient, lPendingSales, formCreditCard) {
        var jqButton = e != null ? $(e.target) : null;
        var bResult = false;
        //angular.element(e.target).button("loading");
        setStatusButton(jqButton, "loading")
        disableButton(jqButton, true);


        var bValidItem = false;
        if (lPendingSales.length > 0) {
            bValidItem = true;
            for (var i = 0; i < lPendingSales.length; i++) {
                if (lPendingSales[i].Source != ProductSourceTypeOptions.EclipseStock && lPendingSales[i].Source != ProductSourceTypeOptions.ERNewModel
                    && lPendingSales[i].Source != ProductSourceTypeOptions.ERVehReqQuote)
                {
                    if (lPendingSales[i].Quantity == null || (lPendingSales[i].Quantity != null && lPendingSales[i].Quantity < 1)) {
                        bValidItem = false;
                        Notification.errorStd(lPendingSales[i].ItemTitle + ' - The qty is required.');
                    }
                }
                
            }
        }

        if (bValidItem == true)
        {   
            if ($scope.ShoppingCart.IsSingleForm == true)
            {
                if ($scope.frmCheckoutModel.$valid)
                {
                    //oCardHeader.CardDetail = oCardDetail;
                    bResult = true;
                    disableButton(jqButton, false);
                    setStatusButton(jqButton, "reset");
                }
                
            }
            else
            {
                oCardHeader.Client = oClient;
                oCardHeader.ListItems = lPendingSales;
                if (oShoppingDiscountCode.ResponseMessage == "IsValid") {
                    oCardHeader.DiscountCode = oShoppingDiscountCode.DiscountCode;
                    oCardHeader.DiscountPrice = getTotalDiscountCodePrice(oShoppingDiscountCode, lPendingSales);
                }

                if (oCardDetail.PayingType == "CreditCard") {
                    formCreditCard.submitted = true;
                    //$scope.ShoppingCart.IsPayment = false;
                    if ($rootScope.util.equalsLowerCase(oCardHeader.CreditCardType, 'tyro')) {
                        bResult = true;
                    } else {
                        if (formCreditCard.$valid) {

                            var sExpirydate = oCardDetail.Expiry + "";
                            if (sExpirydate.length == 3) sExpirydate = "0" + sExpirydate;
                            oCardDetail.ExpiryMonth = sExpirydate.substring(0, 2);
                            oCardDetail.ExpiryYear = sExpirydate.substring(2, 4);
                            oCardHeader.CardDetail = oCardDetail;

                            bResult = true;

                        } else {
                            disableButton(jqButton, false);
                            setStatusButton(jqButton, "reset");
                        }
                    }

                } else if (oCardDetail.PayingType == "DirectDeposit") {
                    $scope.formDirectDeposit.submitted = true;
                    if ($scope.formDirectDeposit.$valid) {

                        bResult = true;
                    } else {
                        disableButton(jqButton, false);
                        setStatusButton(jqButton, "reset");
                    }

                }
                else {
                    //*** Paypal, Zip, PayLater
                    oCardHeader.CardDetail = oCardDetail;
                    bResult = true;
                }
            }
            
        }
        else {
            disableButton(jqButton, false);
            setStatusButton(jqButton, "reset");
        }
        if (bResult)
        {
            updateBasketBeforeSave(oCardHeader);
        }
        return bResult;
    }
    var updateBasketBeforeSave = function (oCardHeader)
    {
        if (oCardHeader.PickupLocationId != null)
        {
            for (var i = 0; i < $scope.lSCDealershipBranches.length; i++) {
                if ($scope.lSCDealershipBranches[i].Value == oCardHeader.PickupLocationId)
                {
                    oCardHeader.PickupLocation = $scope.lSCDealershipBranches[i].Text;
                    break;
                }
            }
        }

        //*** update data before send order to server
        if (angular.isDefined(oCardHeader.IsReqQuote)) {
            //oCardHeader.Notes = 'I would like a quote to have the item/s fitted at the workshop.</br>' + oCardHeader.Notes;
            oCardHeader.SpecialOptions = $rootScope.webApp.util.setParameterByName(oCardHeader.SpecialOptions, 'IsReqQuote', (oCardHeader.IsReqQuote == true ? '1' : '0'));
            console.warn('Minh: added IsReqQuote to SpecialOptions', oCardHeader.SpecialOptions);
        }

    }
    var savePayment = function (e) {

        $scope.CardDetail.PayingType = "CreditCard";
        $scope.ShoppingCart.IsPayment = false;
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);

            if (angular.isUndefined($scope.ShoppingCart.IsSingleForm) || $scope.ShoppingCart.IsSingleForm == false) {
                if ($rootScope.webApp.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
                    $scope.CardHeader.CapCode = $scope.ShoppingCart.Recaptcha.CaptCode;//using ubs captcha                    
                    $scope.CardHeader.CapId = $scope.ShoppingCart.Recaptcha.CaptID;
                }
                else {
                    $scope.CardHeader.CapCode = $scope.ShoppingCart.Recaptcha.response;//re-captcha checkbox
                }
            }
            ShoppingCartFactory.paymentCreditCard($scope.CardHeader).then(function (response) {
                //$rootScope.util.showLoadingIcon($element, false);
                $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                _savePaymentError(responseError);
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var payWithZip = function (e) {
        //*** pay with paypal: save function in init() function ***
        if ($scope.oZipPaySetting.IsUsePayMethod) {
            $scope.CardDetail.PayingType = "Zip";
            var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
            if (bValidatePayment) {
                $rootScope.util.showLoadingIcon($element, true);                
                ShoppingCartFactory.createACheckoutZip($scope.CardHeader).then(function (response) {
                    $rootScope.util.showLoadingIcon($element, false);
                    var jsonData = response.data;
                    if (angular.isDefined(jsonData.error) || angular.isUndefined(jsonData.uri)) {
                        showErrorShoppingNotification("The Zip payment option is not currently available.", jsonData.error + "<br/>Please try another payment method.");
                    } else {
                        window.location.href = jsonData.uri;
                    }
                    //$window.MyZip.popup = window.open(jsonData.uri, "_blank", "toolbar=yes,scrollbars=yes,resizable=yes");
                    
                    disableButton($(e.target), false);
                    setStatusButton($(e.target), "reset");
                }, function (responseError) {
                    $rootScope.util.showLoadingIcon($element, false);
                    disableButton($(e.target), false);
                    setStatusButton($(e.target), "reset");
                });
            }
        } else {
            console.error("Minh: payWithZip ", "Unavailable Method");
        }
    }
    var createAChargeZip = function () {
        if ($scope.oZipPaySetting.IsUsePayMethod) {
            $rootScope.util.showLoadingIcon($element, true);
            ShoppingCartFactory.createAChargeZip({ saleId: $scope.oZipParams.sale, checkoutId: $scope.oZipParams.checkoutId }).then(function (response) {
                $rootScope.util.showLoadingIcon($element, false);
                var jsonData = response.data;
                if (angular.isDefined(jsonData.error)) {
                    alert(jsonData.error.message);
                    console.error("Minh: ", jsonData.error);
                } else {
                    if (angular.isDefined(jsonData.status) && jsonData.status == "Paid") {
                        $window.location.href = "/";
                    } else {
                        $scope.updateSaleAfterCreatedACharge($scope.oZipParams.sale, jsonData.receipt_number);
                    }
                }
            }, function (responseError) {
                $rootScope.util.showLoadingIcon($element, false);
            });
        } else {
            console.error("Minh: ", "Unavailable Method");
        }
    }
    var updateSaleAfterCreatedACharge = function (saleId, receiptNumber) {
        $rootScope.util.showLoadingIcon($element, true);
        ShoppingCartFactory.updateSaleAfterCreatedACharge({ saleId: saleId, receiptNumber: receiptNumber }).then(function (response) {
            //var jsonData = response.data;
            $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
            //$rootScope.util.showLoadingIcon($element, false);
        }, function (responseError) {
            $rootScope.util.showLoadingIcon($element, false);
        });
    }
    var payLater = function (e) {
        $scope.CardDetail.PayingType = "PayLater";
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment && $scope.ShoppingDiscountCode.FlagTradeCode == true) {
            $rootScope.util.showLoadingIcon($element, true);
            ShoppingCartFactory.paymentPayLater($scope.CardHeader).then(function (response) {
                //$rootScope.util.showLoadingIcon($element, false);
                $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                _savePaymentError(responseError);
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var payDirectDeposit = function (e) {
        $scope.CardDetail.PayingType = "DirectDeposit";
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);

            if ($rootScope.webApp.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
                $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaDD.CaptCode;//using ubs captcha                    
                $scope.CardHeader.CapId = $scope.ShoppingCart.RecaptchaDD.CaptID;
            }
            else {
                $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaDD.response;//re-captcha checkbox

            }
            $scope.CardHeader.CardDetail = {
                PayingType: "DirectDeposit"
            };
            ShoppingCartFactory.paymentDirectDeposit($scope.CardHeader).then(function (response) {
                //$rootScope.util.showLoadingIcon($element, false);
                $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                _savePaymentError(responseError);
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var payWithEnquiry = function (e, sPayingType) {
        $scope.CardDetail.PayingType = sPayingType;
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);
            //if ($rootScope.webApp.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
            //    $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaDD.CaptCode;//using ubs captcha                    
            //    $scope.CardHeader.CapId = $scope.ShoppingCart.RecaptchaDD.CaptID;
            //}
            //else {
            //    $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaDD.response;//re-captcha checkbox

            //}
            $scope.CardHeader.CardDetail = {
                PayingType: sPayingType
            };
            ShoppingCartFactory.paymentWithEnquiry($scope.CardHeader).then(function (response) {
                //$rootScope.util.showLoadingIcon($element, false);
                $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                _savePaymentError(responseError);
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var payWithCOD = function (e) {
        $scope.CardDetail.PayingType = 'COD';
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);
            if ($rootScope.webApp.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
                $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaCOD.CaptCode;//using ubs captcha                    
                $scope.CardHeader.CapId = $scope.ShoppingCart.RecaptchaCOD.CaptID;
            }
            else {
                $scope.CardHeader.CapCode = $scope.ShoppingCart.RecaptchaCOD.response;//re-captcha checkbox
            }
            $scope.CardHeader.CardDetail = {
                PayingType: 'COD'
            };
            ShoppingCartFactory.paymentWithCOD($scope.CardHeader).then(function (response) {
                //$rootScope.util.showLoadingIcon($element, false);
                $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess 
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                _savePaymentError(responseError);
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var _savePaymentError = function (responseError) {
        if (responseError.data && responseError.data.error && responseError.data.error.message) {
            showErrorShoppingNotification('(Payment Error)', responseError.data.error.message);
        } else {
            showErrorShoppingNotification('(Unknown Error)', 'Please contact administrator.');
            console.error('(Unknown Error)', responseError);
        }
        $timeout(function () {
            $rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout"));
        }, 5000);
    }
    var payWithTyro = function (e) {
        if (angular.isDefined(SimplifyCommerce)) {

            //return ShoppingCartService.getTotalBasket($scope.ShoppingDiscountCode, $scope.AusPostCalculate, $scope.oShoppingSetting, $scope.ShoppingCart.PendingSales);
            

            var eleButtonPay = $(e.target).closest('.btn-pay-group').find('.btn-tyro-pay');//.click();

            saveOrderTemp(e, function (response) {
                var jsonData = response.data;

                var sAmount = getTotalBasket($scope.ShoppingDiscountCode, $scope.AusPostCalculate, $scope.oShoppingSetting, $scope.ShoppingCart.PendingSales);
                var amount = $rootScope.util.to5CentRounding(sAmount).replace('.', '').replace('$', '');

                var sRedirectUrl = $rootScope.webApp.util.getUrlHasPrefix("stock/shoppingcart/TyroResponse");
                if ($rootScope.webApp.util.hasVal($rootScope.webApp.formMailOptions.redirectToThankYou.shoppingCartDirective)) {
                    sRedirectUrl = sRedirectUrl + "?thank=" + $rootScope.webApp.formMailOptions.redirectToThankYou.shoppingCartDirective;
                } else {
                    sRedirectUrl = sRedirectUrl + "?thank=" + 'stock';
                }

                SimplifyCommerce.hostedPayments(tyroResponsePayment,
                {
                    scKey: moShoppingSetting.TyroPublicApiKey,
                    currency: 'AUD',
                    color: "#12B830",
                    reference: 'SaleId' + jsonData.oCardHeaderItem.SaleId,
                    amount: amount,
                    redirectUrl: sRedirectUrl
                });//.enablePayBtn();

                eleButtonPay.click();
            });
        } else {
            console.error("SimplifyCommerce is undefinded");
            showErrorShoppingNotification('The Tyro-SimplifyCommerce payment option is not currently available.', 'Please try another payment method.');
        }

        var tyroResponsePayment = function (response) {
            // response handler
            console.warn("Minh: hostedPayments", response);
            var data = response.data;
            if (data) {
                if (data.error) {
                    // Show any validation errors
                    if (data.error.code == "validation") {
                        var fieldErrors = data.error.fieldErrors,
                            fieldErrorsLength = fieldErrors.length,
                            errorList = "";
                        for (var i = 0; i < fieldErrorsLength; i++) {
                            errorList += "<div class='error'>Field: '" + fieldErrors[i].field +
                                         "' is invalid - " + fieldErrors[i].message + "</div>";
                        }
                        showErrorShoppingNotification('Tyro Validation Error.', errorList);
                    }
                    // Re-enable the submit button
                    //$("#process-payment-btn").removeAttr("disabled");
                } else if (angular.isDefined(date.close) && date.close == true) {
                    $scope.formDelivery.isSaved = false;
                }
                else {
                    // The token contains id, last4, and card type
                    var token = data["id"];
                    // Insert the token into the form so it gets submitted to the server
                    //$paymentForm.append("<input type='hidden' name='simplifyToken' value='" + token + "' />");
                    // Submit the form to the server
                    //$paymentForm.get(0).submit();
                    alert('Payment token: ' + token);
                }
            }


        }
    }
    
    var payWithSecurePay = function (e) {
        $scope.CardDetail.PayingType = "Securepay";
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);            
            $scope.mySecurePayUI.tokenise();
        }
        
    }
    var createACheckoutPayright = function () {
        //var oOption = {
        //    url: '',
        //    data: {
        //        "merchantRef": "Sale#123456",
        //        "saleAmount": "100",
        //        "type": "standard",
        //        "redirectUrl": $rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout")
        //    }
        //}
        
        //*** pay with paypal: save function in init() function ***

        openSCWindow({
            //url: oData.redirectEndpoint,
            name: 'Payright',
            //sParam: params
            winClose: function () {
                //***
                $rootScope.webApp.util.showLoadingIcon($element, true);
                ShoppingCartFactory.verifyCheckoutPayright({ checkoutId: $rootScope.PayrightCheckoutId }).then(function (response) {
                    var jsonData = angular.fromJson(response.data);
                    //$rootScope.webApp.util.showLoadingIcon($element, false);
                    $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess

                }, function (responseError) {
                    $rootScope.util.showLoadingIcon($element, false);
                });
            }
        });

        if ($scope.oShoppingSetting.HasPayWithPayright) {
            $scope.CardDetail.PayingType = "Payright";
            var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
            if (bValidatePayment) {
                $rootScope.webApp.util.showLoadingIcon($element, true);
                ShoppingCartFactory.createACheckoutPayright($scope.CardHeader).then(function (response) {
                    $rootScope.webApp.util.showLoadingIcon($element, false);
                    var jsonData = response.data;

                    if (angular.isDefined(jsonData.error) && jsonData.error != null) {                        
                        showErrorShoppingNotification('Payright can\'t Create A Checkout.', jsonData.error.message);
                        $rootScope.webApp.util.showLoadingIcon($element, false);
                        disableButton($(e.target), false);
                        setStatusButton($(e.target), "reset");

                    } else {
                        var oData = jsonData.data;//payright return data object
                        //window.location.href = jsonData.uri;                        

                        //*** Can NOT open window when ajax success because browser blocked. so we open window with empty content and replace url after ajax success
                        $rootScope.webApp.SCWindow.location.replace(oData.redirectEndpoint);
                        $rootScope.PayrightCheckoutId = oData.checkoutId;
                        //openSCWindow({        
                        //    url: oData.redirectEndpoint,
                        //    name: 'Payright',
                        //    //sParam: params
                        //});

                        disableButton($(e.target), false);
                        setStatusButton($(e.target), "reset");
                    }
                    
                }, function (responseError) {
                    $rootScope.webApp.util.showLoadingIcon($element, false);
                    disableButton($(e.target), false);
                    setStatusButton($(e.target), "reset");
                });
            }
        } else {
            console.error("Minh: pay-with-payright ", "Unavailable Method");
        }
        
    }

    var openSCWindow = function (option) {        
        var oOption = angular.merge({
            url: '',
            name: '',
            sParam: null,//'scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=600,height=300,left=100,top=100', // default value
            winClose: function () { }
        }, option);

        if ($rootScope.webApp.util.hasVal(oOption.sParam) == false)
        {
            try {
                var w = 900;
                var h = 500;
                // Fixes dual-screen position                             Most browsers      Firefox
                var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
                var dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;

                var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
                var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;

                var systemZoom = width / window.screen.availWidth;
                var left = (width - w) / 2 / systemZoom + dualScreenLeft;
                var top = (height - h) / 2 / systemZoom + dualScreenTop;

                oOption.sParam = "scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=" + (w / systemZoom) + ",height=" + (h / systemZoom) + ",left=" + (left) + ",top=" + (top) + "";
            } catch (e) {
                console.error("open window default position because Center has error: ", e);
                oOption.sParam = "scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=600,height=300,left=100,top=100";
            }
        }

        $rootScope.webApp.SCWindow = $window.open(oOption.url, oOption.name, oOption.sParam);
        //$rootScope.webApp.SCWindow.focus();

        var eleLoadingIcon = $rootScope.webApp.util.showLoadingIcon2($('body'), true);

        //*** browser on mobile can NOT auto close window when the API redirectEndPoint back if use postMessage function
        //$window.webApp.win.postMessage('order#123', $rootScope.webApp.util.rootURL);//*** define domain name before open window to fix Cross-domain error
        //*** fire a event message when use postMessage
        //if ($window.addEventListener) {
        //    $window.addEventListener('message', function (e) {
        //        console.warn('Minh: listener message-event', e);
        //    }, false)
        //} else if ($window.attachEvent) {
        //    $window.attachEvent('message', function (e) {
        //        console.warn('Minh: listener message-event', e);
        //    }, false)
        //}

        //#region detect window is closed        
        var intervalSCWindow;
        function checkWindowClosed() {
            if ($rootScope.webApp.SCWindow.closed) {
                clearInterval(intervalSCWindow);
                oOption.winClose();
                $rootScope.webApp.util.showLoadingIcon2($('body'), false);                
                //eleLoadingIcon.remove();
            }
        }
        intervalSCWindow = setInterval(checkWindowClosed, 50);
        $timeout(checkWindowClosed, 1);
        //#endregion

        //#region close all child windows before parent is closed.
        var isOnIOS = navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPhone/i);
        var eventName = isOnIOS ? "pagehide" : "beforeunload";
        window.addEventListener(eventName, function (event) {
            window.event.cancelBubble = true; // Don't know if this works on iOS but it might!            
            $rootScope.webApp.SCWindow.close();
        });
        //#endregion

        //#region DOM Event
        //set focus child-window when clicked outsite

        $(document).on('click', 'body .loading-icon-section', function () {
            if ($rootScope.webApp.SCWindow.closed == false) {
                if ($rootScope.webApp.util.isMobile()) {
                    alert("Please switch tabs to reactivate the window.");
                } else {
                    $rootScope.webApp.SCWindow.focus();
                }
            }
        });
        $(document).on('click', 'body .loading-icon-section .btnclose', function () {
            $rootScope.webApp.SCWindow.close();
        })

        
        //#endregion
    }

    var saveOrderTemp = function (e, cbSuccess) {
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);
            ShoppingCartFactory.saveOrderTemp($scope.CardHeader).then(function (response) {
                $rootScope.util.showLoadingIcon($element, false);
                var jsonData = response.data;
                
                cbSuccess(response);

                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }

    //#endregion

    //#region Stripe payment
    var createCardElementStripe = function (sElementId, publishableKey) {
        if (angular.isDefined($window.Stripe)) {
            $scope.stripeObj = Stripe(publishableKey);//*** init stripe
            $scope.stripeElements = $scope.stripeObj.elements();
            var elementStyles = {
                base: {
                    fontSize: '16px',
                    fontWeight: 600,
                }
            };

            if ($rootScope.webApp.oWebsite.WebsiteID == 309) {
                elementStyles.base.color = '#fff';//hawkesburymotorcycles
            }
            $scope.stripeCard = $scope.stripeElements.create('card', {
                style: elementStyles,
                hidePostalCode: true
            });
            $scope.stripeCard.mount(sElementId);//*** append card element to div

        }
        else
        {            
            if (angular.isUndefined(timerInterval))
            {
                var delayInterval = 100; var totalRepeatInterval = 10; var countInterval = 1;
                timerInterval = $interval(function () {
                    countInterval++;
                    var bIsStrop = (angular.isDefined($window.Stripe)) || (countInterval > totalRepeatInterval);//waiting Stripe library loaded
                    if (bIsStrop)
                    {   
                        if (angular.isDefined($window.Stripe))
                        {
                            
                            createCardElementStripe(sElementId, publishableKey);
                        }
                        else {
                            if (countInterval > totalRepeatInterval);
                            {
                                //*** if still is Undefined, show message
                                console.error("Stripe.js is undefinded");
                                showErrorShoppingNotification("The Stripe payment option is not currently available.", "Please try another payment method.");
                            }
                        }
                        $interval.cancel(timerInterval);
                        timerInterval = undefined;
                    }
                }, delayInterval, totalRepeatInterval);
            }            
            //console.error("Stripe.js is undefinded");
            //showErrorShoppingNotification("The Stripe payment option is not currently available.", "Please try another payment method.");
        }
    }
    var createPaymentIntentStripe = function (e, cbSuccess) {
        ///get client-secret
        var bValidatePayment = validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
        if (bValidatePayment) {
            $rootScope.util.showLoadingIcon($element, true);
            ShoppingCartFactory.createPaymentIntentStripe($scope.CardHeader).then(function (response) {
                $rootScope.util.showLoadingIcon($element, false);
                //var jsonData = response.data;
                cbSuccess(response);

                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            }, function (responseError) {
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            });
        }
    }
    var confirmCardPaymentStripe = function (e) {
        $rootScope.util.showLoadingIcon($element, true);
        $scope.stripeObj.confirmCardPayment(
            $scope.oRecordStripe.ClientSecret,
            {
                payment_method: {
                    card: $scope.stripeCard
                    //billing_details: {
                    //    name: nameInput.value,
                    //},
                },
            }
        ).then(function (response) {
            console.warn('Minh: stripe-confirm response', response)
            if (response.error && response.error.message) {
                $scope.CreditCardError.push(response.error.message);
                showErrorShoppingNotification('Stripe-Confirm Error.', response.error.message);
                //var oRecordStripe = {
                //    ClientSecret: $scope.oRecordStripe.ClientSecret
                //};
                $scope.oRecordStripe = {};
                $rootScope.util.showLoadingIcon($element, false);
                disableButton($(e.target), false);
                setStatusButton($(e.target), "reset");
            } else {
                $scope.CreditCardError = [];
                //*** update order status and send email to customer

                ShoppingCartFactory.confirmPaymentIntent({
                    PaymentIntentId: $scope.oRecordStripe.PaymentIntentId,
                    SaleId: $scope.oRecordStripe.SaleId,                    
                    Status: response.paymentIntent.status
                }).then(function (response) {
                    //$rootScope.util.showLoadingIcon($element, false);
                    //var jsonData = response.data;
                    $scope.savePaymentSuccess(response);//*** hide icon in the function savePaymentSuccess

                    disableButton($(e.target), false);
                    setStatusButton($(e.target), "reset");
                }, function (responseError) {
                    $rootScope.util.showLoadingIcon($element, false);
                    disableButton($(e.target), false);
                    setStatusButton($(e.target), "reset");
                });
            }
        });
    }


    var payWithStripe = function (e) {
        if (angular.isDefined(Stripe)) {
            $scope.CardDetail.PayingType = "Stripe";
            if ($scope.oRecordStripe && $scope.oRecordStripe.ClientSecret) {
                //*** confirm card payment again
                confirmCardPaymentStripe(e);
            } else {
                createPaymentIntentStripe(e, function (response) {
                    var jsonData = response.data;
                    var jsonData = angular.fromJson(response.data);
                    if (jsonData.Errors != null && jsonData.Errors.length > 0) {
                        $scope.CreditCardError = jsonData.Errors;
                        var sErrorMsg = "";
                        for (var i = 0; i < $scope.CreditCardError.length; i++) {
                            sErrorMsg += $scope.CreditCardError + "<br/>";
                        }                        
                        showErrorShoppingNotification('Stripe can\'t Create Payment Intent.', sErrorMsg);
                        AWDSApp.util.showLoadingIcon($element, false);
                        if (e) {
                            disableButton($(e.target), false);
                            setStatusButton($(e.target), "reset");
                        }
                    }
                    else {                        
                        $scope.oRecordStripe = {
                            SaleId: jsonData.SaleId,
                            ClientSecret: jsonData.ClientSecret,
                            PaymentIntentId: jsonData.PaymentIntentId
                        }
                        confirmCardPaymentStripe(e);
                    }
                });
            }

        } else {
            console.error("Stripe.js is undefinded");            
            showErrorShoppingNotification("The Stripe payment option is not currently available.", "Please try another payment method.");
        }
    }
    //#endregion
    /*
        #region clear sessions
        //var sSessionUID = oCardHeaderItem.ListItems.Select(x => x.SessionUID).First();
        var oShoppingSession = ShoppingService.GetShoppingSessionBySessionId(sSessionUID);
        oShoppingSession.DraftOrder = null;
        ShoppingService.SaveShoppingSession(oShoppingSession);

        ShoppingService.RemoveAllPendingSaleBySessionUID(sSessionUID, this.UserPortal);
        oERLogger.AddLogMsg("Removed all pending sale", ERLogMessageType.DEBUG);
        RemoveSessionDiscountCode(oERLogger);
        #endregion

        #region send mail for Admin and Customer
        CardHeaderItem oCardHeaderItemViewModel = ToCardHeaderItemViewModel(oShoppingSaleHeader);

        SendMailTransactionCompletion(oCardHeaderItemViewModel, miWebsiteId, oERLogger);
        ShoppingCartService.SendOrderToUbsESB(oCardHeaderItemViewModel, miWebsiteId, oERLogger, WebsiteServices);
        #endregion
    */
    //#region Captcha
    var reloadUbsCaptcha = function () {
        if ($rootScope.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
            FormMailFactory.getUbsCaptcha({}).then(function (response) {
                $scope.ShoppingCart.Recaptcha = response.data;
            }, function (responseError) {

            })
        } else {
            console.error("Minh: ", "cannot reload ubs captcha because RecaptchaSiteKey has value");
        }
    }
    var loadGGCaptcha = function () {
        function __onCreateAndSuccess(response, fn) {
            if (angular.isDefined(fn) && fn == 'create') {
                console.log('recap-' + fn + ' widget ' + response);
                $scope.ShoppingCart.Recaptcha.widgetId = response;
            } else {
                console.log('recap-' + fn + ' response ');
                $scope.ShoppingCart.Recaptcha.response = response;
            }
        }

        $scope.ShoppingCart.Recaptcha = {
            response: null,//https://github.com/VividCortex/angular-recaptcha
            widgetId: null, SetResponse: __onCreateAndSuccess, SetWidgetId: __onCreateAndSuccess,
            //SetResponse: function (response) {
            //    $scope.ShoppingCart.Recaptcha.response = response;
            //},
            //SetWidgetId: function (widgetId) {
            //    $scope.ShoppingCart.Recaptcha.widgetId = widgetId;                
            //},
            Reset: function () {
                vcRecaptchaService.reload($scope.ShoppingCart.Recaptcha.widgetId);
                $scope.ShoppingCart.Recaptcha.response = null;
                
            }
        }
    }
    var reloadUbsCaptchaDD = function () {
        if ($rootScope.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
            FormMailFactory.getUbsCaptcha({}).then(function (response) {
                $scope.ShoppingCart.RecaptchaDD = response.data;
            }, function (responseError) {

            })
        } else {
            console.error("Minh: ", "cannot reload ubs captcha because RecaptchaSiteKey has value");
        }
    }
    var loadGGCaptchaDD = function ()
    {
        function __onCreateAndSuccess(response, fn) {
            if (angular.isDefined(fn) && fn == 'create') {
                console.log('recap-' + fn + ' widget ' + response);
                $scope.ShoppingCart.RecaptchaDD.widgetId = response;
            } else {
                console.log('recap-' + fn + ' response ');
                $scope.ShoppingCart.RecaptchaDD.response = response;
            }
        }

        $scope.ShoppingCart.RecaptchaDD = {
            response: null,//https://github.com/VividCortex/angular-recaptcha            
            widgetId: null, SetResponse: __onCreateAndSuccess, SetWidgetId: __onCreateAndSuccess,
            //SetResponse: function (response) {
            //    $scope.ShoppingCart.RecaptchaDD.response = response;                
            //},
            //SetWidgetId: function (widgetId) {
            //    $scope.ShoppingCart.RecaptchaDD.widgetId = widgetId;                
            //},
            Reset: function () {
                vcRecaptchaService.reload($scope.ShoppingCart.RecaptchaDD.widgetId);
                $scope.ShoppingCart.RecaptchaDD.response = null;
            }
        }
    }
    var reloadUbsCaptchaCOD = function () {
        if ($rootScope.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
            FormMailFactory.getUbsCaptcha({}).then(function (response) {
                $scope.ShoppingCart.RecaptchaCOD = response.data;
            }, function (responseError) {

            })
        } else {
            console.error("Minh: ", "cannot reload ubs captcha because RecaptchaSiteKey has value");
        }
    }
    var loadGGCaptchaCOD = function () {
        function __onCreateAndSuccess(response, fn) {
            if (angular.isDefined(fn) && fn == 'create') {
                console.log('recap-' + fn + ' widget ' + response);
                $scope.ShoppingCart.RecaptchaCOD.widgetId = response;
            } else {
                console.log('recap-' + fn + ' response ');
                $scope.ShoppingCart.RecaptchaCOD.response = response;
            }
        }

        $scope.ShoppingCart.RecaptchaCOD = {
            response: null,//https://github.com/VividCortex/angular-recaptcha            
            widgetId: null, SetResponse: __onCreateAndSuccess, SetWidgetId: __onCreateAndSuccess,
            Reset: function () {
                vcRecaptchaService.reload($scope.ShoppingCart.RecaptchaCOD.widgetId);
                $scope.ShoppingCart.RecaptchaCOD.response = null;
            }
        }
    }
    //#endregion

    return {
        toViewModel: toViewModel,//mapping model to viewmodel


        getDefaultShoppingCartOptions: getDefaultShoppingCartOptions,
        setScope: setScope,
        getScopeDirective: getScopeDirective,
        setShoppingSetting: setShoppingSetting,

        addParamToSpecialOptions: addParamToSpecialOptions,
        addProductItem: addProductItem,
        addWishlist: addWishlist,
        addEnquiryCart: addEnquiryCart,
        applyDiscountCode: applyDiscountCode,
        updateSSDraftOrder: updateSSDraftOrder,

        disableButton: disableButton,

        updateClientInfo: updateClientInfo,

        removeWishlist: removeWishlist,
        removeEnquiryCart: removeEnquiryCart,
        removeAllEnquiryCarts: removeAllEnquiryCarts,
        removeProductItem: removeProductItem,
        removeAllProductItem: removeAllProductItem,
        removeDiscountCode: removeDiscountCode,
        renderPaypalButton: renderPaypalButton,
        resetRenderPaypalButtonFlag: resetRenderPaypalButtonFlag,
        renderSecurePayUI: renderSecurePayUI,

        createElementScript: createElementScript,//*** load payment lib
        createAllElementScripts: createAllElementScripts,//*** load payment libs

        showQtyNotification: showQtyNotification,
        showErrorShoppingNotification: showErrorShoppingNotification,
        changeQty: changeQty,
        changeQtyMinus: changeQtyMinus,
        changeQtyPlus: changeQtyPlus,
        changeDeliveryAusPostService: changeDeliveryAusPostService,
        csourceCodeToDesc: csourceCodeToDesc,
        createPaypalButton: createPaypalButton,

        getPaymentSetting: getPaymentSetting,
        getLocationState: getLocationState,
        getDealerBranches: getDealerBranches,
        getPickupAtLocationItem: getPickupAtLocationItem,
        getPriceQty: getPriceQty,
        getDeliveryFee: getDeliveryFee,
        getFittedPrice: getFittedPrice,
        getBulkyPrice: getBulkyPrice,
        getDiscountCodePrice: getDiscountCodePrice,
        getDiscountCodePriceNotQty: getDiscountCodePriceNotQty,
        getPriceDepositAmount: getPriceDepositAmount,
        getTotalDiscountCodePrice: getTotalDiscountCodePrice,
        getTotalPendingSalePrice: getTotalPendingSalePrice,
        getTotalBulkyPrice: getTotalBulkyPrice,
        getTotalBulkyPriceOfERProduct: getTotalBulkyPriceOfERProduct,
        getTotalBasket: getTotalBasket,
        getSourceCodeAndDesc: getSourceCodeAndDesc,
        getLoginDropdownContextHeaderTemplate: getLoginDropdownContextHeaderTemplate,

        loadAusPostServices: loadAusPostServices,
        loadScriptTagGAEcommerceTracking: loadScriptTagGAEcommerceTracking,

        hasAusPostServiceIn: hasAusPostServiceIn,
        hasBulkyItem: hasBulkyItem,
        hasFittedItem: hasFittedItem,
        hasFittedItemInList: hasFittedItemInList,
        hasPickupOnlyItem: hasPickupOnlyItem,
        hasPickupOnlyCategoryInListItems: hasPickupOnlyCategoryInListItems,
        hasWSPSFleetPriceInList: hasWSPSFleetPriceInList,
        hasTickedFleetPriceInList: hasTickedFleetPriceInList,
        hasExceededParcelItemInList: hasExceededParcelItemInList,

        isAllowChangeQty: isAllowChangeQty,
        isOnlyPickupInStore: isOnlyPickupInStore,
        isShowItemCode: isShowItemCode,
        isShowBulkyItemLabel: isShowBulkyItemLabel,
        isValidSpecialOptions: isValidSpecialOptions,

        setStatusButton: setStatusButton,
        showSignupOrLoginForm: showSignupOrLoginForm,
        submitLoginForm: submitLoginForm,
        submitLoginFB: submitLoginFB,
        submitLoginGoogle: submitLoginGoogle,
        submitLogoutForm: submitLogoutForm,
        submittedLogoutForm: submittedLogoutForm,
        saveToGAEcommerceTracking: saveToGAEcommerceTracking,

        payWithStripe: payWithStripe,
        createCardElementStripe: createCardElementStripe,

        //payment
        savePayment: savePayment,
        validatePayment: validatePayment,
        validQuantity: validQuantity,
        payWithTyro: payWithTyro,        
        payWithZip: payWithZip,
        payWithSecurePay: payWithSecurePay,
        createAChargeZip: createAChargeZip,
        updateSaleAfterCreatedACharge: updateSaleAfterCreatedACharge,
        payLater: payLater,
        payDirectDeposit: payDirectDeposit,
        payWithEnquiry: payWithEnquiry,
        payWithCOD: payWithCOD,
        createACheckoutPayright: createACheckoutPayright,

        hasPayWithPayright: hasPayWithPayright,

        reloadUbsCaptcha: reloadUbsCaptcha,
        loadGGCaptcha: loadGGCaptcha,
        reloadUbsCaptchaDD: reloadUbsCaptchaDD,
        loadGGCaptchaDD: loadGGCaptchaDD,
        reloadUbsCaptchaCOD: reloadUbsCaptchaCOD,
        loadGGCaptchaCOD: loadGGCaptchaCOD
    }
}]);
ngAWDSApp.factory("LoginService", ['$window', '$cookies', '$q', '$rootScope', '$filter', function ($window, $cookies, $q, $rootScope, $filter) {
    var fbKey, fbApiV, googleKey, linkedInKey;
    // Create Base64 Object // https://scotch.io/tutorials/how-to-encode-and-decode-strings-with-base64-in-javascript
    var Base64 = {
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        encode: function (e) { var t = ""; var n, r, i, s, o, u, a; var f = 0; e = Base64._utf8_encode(e); while (f < e.length) { n = e.charCodeAt(f++); r = e.charCodeAt(f++); i = e.charCodeAt(f++); s = n >> 2; o = (n & 3) << 4 | r >> 4; u = (r & 15) << 2 | i >> 6; a = i & 63; if (isNaN(r)) { u = a = 64 } else if (isNaN(i)) { a = 64 } t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a) } return t },
        decode: function (e) { var t = ""; var n, r, i; var s, o, u, a; var f = 0; e = e.replace(/[^A-Za-z0-9+/=]/g, ""); while (f < e.length) { s = this._keyStr.indexOf(e.charAt(f++)); o = this._keyStr.indexOf(e.charAt(f++)); u = this._keyStr.indexOf(e.charAt(f++)); a = this._keyStr.indexOf(e.charAt(f++)); n = s << 2 | o >> 4; r = (o & 15) << 4 | u >> 2; i = (u & 3) << 6 | a; t = t + String.fromCharCode(n); if (u != 64) { t = t + String.fromCharCode(r) } if (a != 64) { t = t + String.fromCharCode(i) } } t = Base64._utf8_decode(t); return t },
        _utf8_encode: function (e) { e = e.replace(/\r\n/g, "\n"); var t = ""; for (var n = 0; n < e.length; n++) { var r = e.charCodeAt(n); if (r < 128) { t += String.fromCharCode(r) } else if (r > 127 && r < 2048) { t += String.fromCharCode(r >> 6 | 192); t += String.fromCharCode(r & 63 | 128) } else { t += String.fromCharCode(r >> 12 | 224); t += String.fromCharCode(r >> 6 & 63 | 128); t += String.fromCharCode(r & 63 | 128) } } return t },
        _utf8_decode: function (e) { var t = ""; var n = 0; var r = c1 = c2 = 0; while (n < e.length) { r = e.charCodeAt(n); if (r < 128) { t += String.fromCharCode(r); n++ } else if (r > 191 && r < 224) { c2 = e.charCodeAt(n + 1); t += String.fromCharCode((r & 31) << 6 | c2 & 63); n += 2 } else { c2 = e.charCodeAt(n + 1); c3 = e.charCodeAt(n + 2); t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63); n += 3 } } return t },
        generateCode: function (capId) {
            var sCode = $rootScope.webApp.oWebsite.WebsiteID + capId + $filter('toDateStrShort')(new Date());//code format: webid + form.CapId + dd/MM/yyyy
            return this.encode(sCode);
        }
    }

    var _SetFbKey = function (appId, apiVersion) {
        if ($rootScope.webApp.util.hasVal(appId)) {
            fbKey = appId;
            fbApiV = apiVersion;
            function initScript(d, s, id) {

                var js, fjs = d.getElementsByTagName(s)[0];
                if (d.getElementById(id)) {
                    window.FB.init({
                        appId: fbKey,
                        cookie: true,
                        xfbml: true,
                        version: fbApiV,
                        status: true
                    });
                    return;
                }
                else {
                    js = d.createElement(s); js.id = id;
                    js.src = "https://connect.facebook.net/en_US/sdk.js";
                    fjs.parentNode.insertBefore(js, fjs);
                    js.onload = function () {
                        window.FB.init({
                            appId: fbKey,
                            cookie: true,
                            xfbml: true,
                            version: fbApiV,
                            status: true
                        });
                    };
                }
            }

            initScript(document, 'script', 'facebook-jssdk');
        }
    }
    var _SetGoogleKey = function (value) {
        if ($rootScope.webApp.util.hasVal(value)) {
            googleKey = value;
            var d = document, gJs, ref = d.getElementsByTagName('script')[0];
            gJs = d.createElement('script');
            gJs.async = true;
            gJs.src = "//apis.google.com/js/platform.js"

            gJs.onload = function () {
                //*** params = gapi.auth2.ClientConfig
                var params = {
                    client_id: value,
                    fetch_basic_profile: false,
                    scope: 'email'
                }
                gapi.load('auth2', function () {
                    gapi.auth2.init(params).then(function (response) {
                        //console.warn('The function called with the GoogleAuth object when it is fully initialized.', response);
                    }, function (responseError) {
                        //console.warn('The function called with an object containing an error property, if GoogleAuth failed to initialize.', responseError);
                    });
                });
            };

            ref.parentNode.insertBefore(gJs, ref);
        }
    }
    var _SetLinkedInKey = function (value) {
        linkedInKey = value;
        var lIN, d = document, ref = d.getElementsByTagName('script')[0];
        lIN = d.createElement('script');
        lIN.async = false;
        lIN.src = "//platform.linkedin.com/in.js";
        lIN.text = ("api_key: " + linkedInKey).replace("\"", "");
        ref.parentNode.insertBefore(lIN, ref);
    }

    var _SetLoginType = function (type) {
        $cookies.put('awds_login_type', type);
    }
    var _Logout = function () {
        var provider = $cookies.get('awds_login_type');
        switch (provider) {
            case "google":
                //its a hack need to find better solution.
                var gElement = document.getElementById("gSignout");
                if (typeof (gElement) != 'undefined' && gElement != null) {
                    gElement.remove();
                }
                var d = document, gSignout, ref = d.getElementsByTagName('script')[0];
                gSignout = d.createElement('script');
                gSignout.src = "https://accounts.google.com/Logout";
                gSignout.type = "text/html";
                gSignout.id = "gSignout";
                $cookies.remove('awds_login_type');
                //$rootScope.$broadcast('event:social-sign-out-success', "success");
                ref.parentNode.insertBefore(gSignout, ref);
                break;
            case "linkedIn":
                IN.User.logout(function () {
                    $cookies.remove('awds_login_type');
                    //$rootScope.$broadcast('event:social-sign-out-success', "success");
                }, {});
                break;
            case "facebook":
                $window.FB.logout(function (res) {
                    $cookies.remove('awds_login_type');
                    //$rootScope.$broadcast('event:social-sign-out-success', "success");
                });
                break;
        }

    }

    var _LoginFB = function () {
        //var fetchUserDetails = function () {
        //    var deferred = $q.defer();
        //    $window.FB.api('/me?fields=name,email,picture', function (res) {
        //        if (!res || res.error) {
        //            deferred.reject('Error occured while fetching user details.');
        //        } else {
        //            deferred.resolve({
        //                name: res.name,
        //                email: res.email,
        //                uid: res.id,
        //                provider: "facebook",
        //                imageUrl: res.picture.data.url
        //            });
        //        }
        //    });
        //    return deferred.promise;
        //}

        //$window.FB.getLoginStatus(function (response) {

        //    if (response.status === "connected") {
        //        fetchUserDetails().then(function (userDetails) {
        //            userDetails["token"] = response.authResponse.accessToken;
        //            //_SetLoginType("facebook");
        //            return userDetails;
        //        });
        //    } else {
        //        $window.FB.login(function (response) {
        //            debugger;
        //            if (response.status === "connected") {
        //                fetchUserDetails().then(function (userDetails) {
        //                    userDetails["token"] = response.authResponse.accessToken;
        //                    //_SetLoginType("facebook");
        //                    return userDetails;
        //                });
        //            }
        //        }, { scope: 'email,public_profile', auth_type: 'rerequest' });
        //    }
        //});
    }

    var _InitPaypal = function () {
        $rootScope.webApp.util.loadPaypalScript(function () { });
        //function initScript(d, s, id) {
        //    var js, fjs = d.getElementsByTagName(s)[0];
        //    if (d.getElementById(id)) {
        //        return;
        //    }
        //    else {
        //        js = d.createElement(s); js.id = id;
        //        js.src = "https://www.paypalobjects.com/api/checkout.js";
        //        fjs.parentNode.insertBefore(js, fjs);
        //        js.onload = function () {
        //        };
        //    }
        //}

        //initScript(document, 'script', 'paypal-jscheckout');
    }
    var _InitPaypalByClientId = function (clientId) {
        $rootScope.webApp.util.loadPaypalScriptByClientId(clientId, function () { });
    }
    var _InitSecurepayV2Lib = function (isSandbox) {
        $rootScope.webApp.util.loadSecurepayV2Script(isSandbox, function () { });
    }

    return {
        SetFbKey: _SetFbKey,
        SetGoogleKey: _SetGoogleKey,
        SetLinkedInKey: _SetLinkedInKey,

        GetGoogleKey: googleKey,
        GetLinkedInKey: linkedInKey,

        Logout: _Logout,
        LoginFB: _LoginFB,
        Base64: Base64,
        InitPaypal: _InitPaypal,
        InitPaypalByClientId: _InitPaypalByClientId,
        InitSecurepayV2Lib: _InitSecurepayV2Lib
    }
}]);

ngAWDSApp.factory("ShoppingCartFactory", ['$q', '$http', '$rootScope', 'HttpFactory', function ($q, $http, $rootScope, HttpFactory) {
    var sShoppingCartCtrlApi = "Stock/ShoppingCart/";

    var getUriCtrl = function (sAction) {
        return "Stock/ShoppingCart/" + sAction;
    }

    var _HTTPGet = function (oParams, sUrl) {

        return HttpFactory.get(oParams, sUrl);

        //var result = $q.defer();
        //$http({
        //    method: 'GET',
        //    url: $rootScope.util.getUrlHasPrefix(sUrl),
        //    params: oParams,
        //    beforeSend: function (req) {
        //    }
        //}).then(function (response) {
        //    result.resolve(response);
        //}, function (response) {
        //    result.reject(response);
        //});
        //return result.promise;
    }
    var _HTTPPost = function (oData, sUrl) {
        return HttpFactory.post(oData, sUrl);

        //var result = $q.defer();
        //$http({
        //    method: 'POST',
        //    url: $rootScope.util.getUrlHasPrefix(sUrl),
        //    data: oData,
        //    beforeSend: function (req) {
        //    }
        //}).then(function (response) {
        //    result.resolve(response);
        //}, function (response) {
        //    result.reject(response);
        //});
        //return result.promise;
    }
    
    var _getLocationState = function () {
        return HttpFactory.get({}, 'Stock/Website/GetLocationState');
    }
    var _getDealerBranches = function () {
        return HttpFactory.get({}, 'Stock/Website/GetDealerBranches');
    }
    var _GetShoppingBasKetData = function () {
        //return _HTTPGet({}, (sShoppingCartCtrlApi + "GetShoppingBasKetData?rd=2" + Math.floor(Math.random() * 1000)).toLowerCase());
        return _HTTPGet({}, (sShoppingCartCtrlApi + "GetShoppingBasKetData?rd=2" + $rootScope.webApp.util.generateKey(10)));
    }

    var _getDefaultDataByAction = function (oParams, sAction) {
        return HttpFactory.post(oParams, getUriCtrl(sAction));
    }

    var _GetPendingSales = function () {
        return _HTTPGet({}, sShoppingCartCtrlApi + "GetPendingSales");
    }
    var _getOrderById = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + 'GetOrderById');
    }
    var _GetAusPostServices = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "AusPostServices");
    }
    var _GetAusPostCalculate = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "AusPostCalculate");
    }
    var _getPaypalSetting = function (oData) {
        return _HTTPGet(oData, sShoppingCartCtrlApi + "GetPaypalSetting");
    }
    var _getZipPaySetting = function (oData) {
        return _HTTPGet(oData, sShoppingCartCtrlApi + "GetZipPaySetting");
    }
    var _TotalRecordsPendingSale = function () {
        return _HTTPPost({ id: Math.random().toString(36).substring(7) }, sShoppingCartCtrlApi + "TotalRecordsPendingSale");
    }
    var _AddProductItem = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "AddProductItemV2");//addWishlist
    }
    var _addWishlist = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "AddWishlist");
    }
    var _removeWishlist = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveWishlist");
    }
    var _addEnquiryCart = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "AddEnquiryCart");
    }
    var _removeEnquiryCart = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveEnquiryCart");
    }
    
    var _removeAllEnquiryCarts = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveAllEnquiryCarts");
    }
    var _RemoveProductItem = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveProductItem");
    }
    var _RemoveAllCartItems = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveAllCartItems");
    }

    var _RegisterContact = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RegisterContact");
    }
    var _DeliveryContact = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "DeliveryContact");
    }
    var _PaymentCreditCard = function (oData) {
        //payment credit card
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentCreditCard");
    }
    var _PaymentPaypal = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentPaypal");
    }
    var _paymentPayLater = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentPayLater");
    }
    var _paymentDirectDeposit = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentDirectDeposit");
    }
    var _paymentWithEnquiry = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentWithEnquiry");
    }
    //paymentWithCOD
    var _paymentWithCOD = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentWithCOD");
    }
    var _paymentSecurePay = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "PaymentSecurePay");
    }
    var _CreatePaymentPaypal = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreatePaymentPaypal");
    }
    var _ExecutePaymentPaypal = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "ExecutePaymentPaypal");
    }
    var _createACheckoutZip = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreateACheckoutZip");
    }
    var _createAChargeZip = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreateAChargeZip");
    }
    var _createACheckoutZipV2 = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreateACheckoutZipV2");
    }
    var _createAChargeZipV2 = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreateAChargeZipV2");
    }

    var _createACheckoutPayright = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "CreateACheckoutPayright"); 
    }
    var _verifyCheckoutPayright = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "VerifyCheckoutPayright");
    }
    var _repaymentPayright = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RepaymentPayright");
    }
    var _testStandardPayload = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "TestStandardPayload");
    }

    var _updateSaleAfterCreatedACharge = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "UpdateSaleAfterCreatedACharge");
    }
    var _saveOrderTemp = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "SaveOrderTemp");
    }
    var _createPaymentIntentStripe = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "StripeCreatePaymentIntent");
    }
    var _confirmPaymentIntent = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "StripeConfirmPaymentIntent");
    }

    var _Login = function (oData) {
        if (oData.ClientSource != 'System') {
            return _HTTPPost(oData, sShoppingCartCtrlApi + "LoginSocial");
        } else {
            return _HTTPPost(oData, sShoppingCartCtrlApi + "Login");
        }
        
    }
    var _Logout = function () {
        return _HTTPGet({}, sShoppingCartCtrlApi + "Logout");
    }

    var _ApplyDiscountCode = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "ApplyDiscountCode");
    }
    var _RemoveDiscountCode = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "RemoveDiscountCode");
    }

    var _updateSSDraftOrder = function (oData) {
        return _HTTPPost(oData, sShoppingCartCtrlApi + "UpdateSSDraftOrder");
    }
    return {
        getDealerBranches: _getDealerBranches,
        getLocationState: _getLocationState,
        GetShoppingBasKetData: _GetShoppingBasKetData,
        getDefaultDataByAction: _getDefaultDataByAction,

        GetPendingSales: _GetPendingSales,
        GetAusPostServices: _GetAusPostServices,
        GetAusPostCalculate: _GetAusPostCalculate,
        getPaypalSetting: _getPaypalSetting,
        getZipPaySetting: _getZipPaySetting,
        getOrderById: _getOrderById,
        TotalRecordsPendingSale: _TotalRecordsPendingSale,
        RegisterContact: _RegisterContact,
        DeliveryContact: _DeliveryContact,
        RemoveProductItem: _RemoveProductItem,
        RemoveAllCartItems: _RemoveAllCartItems,
        removeDiscountCode: _RemoveDiscountCode,
        AddProductItem: _AddProductItem,
        addWishlist: _addWishlist,
        removeWishlist: _removeWishlist,
        addEnquiryCart: _addEnquiryCart,
        removeEnquiryCart: _removeEnquiryCart,
        removeAllEnquiryCarts : _removeAllEnquiryCarts,
        applyDiscountCode: _ApplyDiscountCode,
        updateSSDraftOrder: _updateSSDraftOrder,

        Login: _Login,
        Logout: _Logout,
        createPaymentPaypal: _CreatePaymentPaypal,
        executePaymentPaypal: _ExecutePaymentPaypal,
        paymentCreditCard: _PaymentCreditCard,
        paymentPayLater: _paymentPayLater,
        paymentDirectDeposit: _paymentDirectDeposit,
        paymentWithEnquiry: _paymentWithEnquiry,
        paymentWithCOD: _paymentWithCOD,
        paymentSecurePay: _paymentSecurePay,
        paymentPaypal: _PaymentPaypal,
        createACheckoutZip: _createACheckoutZip,
        createAChargeZip: _createAChargeZip,
        createACheckoutZipV2: _createACheckoutZipV2,
        createAChargeZipV2: _createAChargeZipV2,
        createACheckoutPayright: _createACheckoutPayright,
        verifyCheckoutPayright: _verifyCheckoutPayright,
        repaymentPayright: _repaymentPayright,
        updateSaleAfterCreatedACharge: _updateSaleAfterCreatedACharge,
        saveOrderTemp: _saveOrderTemp,
        createPaymentIntentStripe: _createPaymentIntentStripe,
        confirmPaymentIntent: _confirmPaymentIntent,
        testStandardPayload: _testStandardPayload
    };
}]);

;
ngAWDSApp.directive('shoppingCartDirective', ['$window', 'ShoppingCartFactory', '$rootScope', 'LoginService', '$timeout', 'Notification', '$filter', 'ShoppingCartService',
    function ($window, ShoppingCartFactory, $rootScope, LoginService, $timeout, Notification, $filter, ShoppingCartService) {
        return {
            restrict: 'A',
            scope: true,
            link: function ($scope, $element, $attrs) {
                //#region *** Checkout ***
                angular.element($element).find('.nav-tabs > li a[title]').tooltip();
                //Wizard
                angular.element($element).find('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
                    var eleTarget = $(e.target);
                    if (eleTarget.parent().hasClass('disabled')) {
                        return false;
                    }
                });
                //$(".next-step").click(function (e) {
                //    var $active = $('.wizard .nav-tabs li.active');
                //    $active.next().removeClass('disabled');
                //    nextTab($active);
                //});
                angular.element($element).find(".prev-step").click(function (e) {
                    var $active = $('.wizard .nav-tabs li.active');
                    prevTab($active);
                });

                function prevTab(elem) {
                    $(elem).prev().find('a[data-toggle="tab"]').click();
                }
                //#endregion

                //*** active tab PayNow in Areas-stock-detail page ***
                $timeout(function () {
                    var hash = $window.location.hash;
                    //angular.element($element).find('#areasStockDetailTab ' + sHrefTab + ', .areasViewDetailTab ' + sHrefTab).tab('show');
                    angular.element($element).find('.areasViewDetailTab a[href="' + hash + '"]').tab('show');
                });

            },
            controller: ['$scope', '$element', '$attrs', '$parse', function ($scope, $element, $attrs, $parse) {
                $scope.ShoppingCart = ShoppingCartService.getDefaultShoppingCartOptions();
                $scope.CardHeader = {};
                $scope.CardDetail = {};
                $scope.CreditCardError = [];
                $scope.PostcodeSuburbErrorMsg = "";
                $scope.CardHeader.DeliveryFee = null;
                $scope.CardHeader.DeliveryOption = null;
                $scope.isRenderPaypalButton = false;
                $scope.IsShowResultDeliveryAusPostService = false;//*** if dropdownlist DeliveryAusPostService  not set, then hide label on right side
                $scope.NotiCart = {};//*** notification popup
                $scope.AusPostServices = {};
                $scope.ShoppingDiscountCode = {};
                $scope.oZipPaySetting = {};
                $scope.oPaypalSetting = {};
                //$scope.formCreditCard = {};
                $scope.oShoppingSetting = {};
                $scope.isSCShoppingBasKetDataLoaded = false;
                $scope.isSCShopCartCtrlLoaded = false;

                
                //try {
                //    if ($rootScope.webApp.util.hasVal($rootScope.webApp.util.getParameterByName('checkoutId', $window.location.href)) && $window.opener != null) {
                //        debugger;
                //        alert('Minh: API redireted - window is: ' + $window.opener);
                //        $window.close();
                //    }
                //} catch (e) {
                //    alert('Minh: Error - ' + e.message);
                //}


                //#region ScreenInitilise
                $scope.init = function () {
                    ShoppingCartService.setScope($scope);
                    ShoppingCartFactory.GetShoppingBasKetData().then(function (response) {
                        var jsonData = response.data;

                        ShoppingCartService.setShoppingSetting(jsonData.ShoppingSetting);

                        $scope.oShoppingSetting = jsonData.ShoppingSetting;
                        $scope.oShoppingSetting.lWSPCSpecialAusPosts = jsonData.WSPCSpecialAusPosts;

                        $scope.CardHeader.CreditCardType = jsonData.CreditCardType;
                        $scope.CardDetail.PayingType = "CreditCard";//*** default paymethod

                        $scope.TotalRecordsShoppingCart = jsonData.TotalRecordsPendingSale;//*** SUM-Qty
                        $scope.oZipParams = jsonData.ZipParams;
                        $scope.oPaypalSetting = angular.fromJson(jsonData.PaypalParams);

                        $scope.oZipParams.IsSandbox = $scope.oZipParams.IsSandBox;
                        $scope.oPaypalSetting.IsSandbox = $scope.oPaypalSetting.IsSandBox;

                        $scope.AusPost = jsonData.AusPost;


                        $scope.ShoppingCart.WebsiteId = jsonData.WebsiteId;
                        $scope.ShoppingCart.IsAuthentinal = jsonData.IsAuthentinal;
                        $scope.ShoppingCart.ClientSourceType = jsonData.ClientSourceType;
                        $scope.ShoppingCart.PendingSales = jsonData.Carts;
                        $scope.ShoppingCart.LoginViewModel.FullName = jsonData.Client.FullName;
                        $scope.ShoppingCart.LoginViewModel.FirstName = jsonData.Client.FirstName;
                        $scope.ShoppingCart.LoginViewModel.LastName = jsonData.Client.LastName;
                        $scope.ShoppingCart.LoginViewModel.ClientSource = jsonData.Client.Source;
                        $scope.ShoppingCart.LoginViewModel.Email = jsonData.Client.Email;
                        $scope.ShoppingDiscountCode = jsonData.ShoppingDiscountCode;
                        if ($scope.ShoppingDiscountCode.DiscountCode == null && $scope.ShoppingDiscountCode.ResponseMessage == 'IsEmpty') {
                            $scope.ShoppingDiscountCode.ResponseMessage = null;
                        }
                        //$scope.ShoppingCart.copyLoginViewModel = angular.copy($scope.ShoppingCart.LoginViewModel);                    
                                
                        ////#region SAMotorcycle - quickly fixing bug about "not allow paypal  for category gift card" 
                        //for (var i = 0; i < $scope.ShoppingCart.PendingSales.length; i++) {
                        //    var item = $scope.ShoppingCart.PendingSales[i];
                        //    var sGiftCards = $rootScope.webApp.util.getParameterByName('giftCards', item.SpecialOptions);
                        //    if (sGiftCards == "1")
                        //    {
                        //        $scope.oPaypalSetting.IsUsePayMethod = false;
                        //        break;
                        //    }
                        //}
                        ////#endregion

                        if (ShoppingCartService.hasFittedItemInList($scope.ShoppingCart.PendingSales)) {
                            $scope.oShoppingSetting.HasPartInstallation = true;//*** Bug #13490	this section should only appear when have fitted item in the cart
                        } else {
                            $scope.oShoppingSetting.HasPartInstallation = false;
                        }

                        //#region Payment  setting
                        $scope.oZipPaySetting = {
                            IsSandbox: $scope.oZipParams.IsSandbox,
                            IsUsePayMethod: $scope.oZipParams.IsUsePayMethod
                        };
                        //#endregion

                        $scope.isSCShoppingBasKetDataLoaded = true;
                        $scope.initFinally();


                        $scope.updateClientInfo(jsonData.Client);

                        //*** load payment libs
                        if ($element.find('.sc-checkout-view').length > 0) {
                            ShoppingCartService.getLocationState(function (lLocationStates) {
                                $scope.lLocationStates = lLocationStates;
                            });
                            $scope.loadCaptcha();

                            //ShoppingCartService.createElementScript($scope.CardHeader);
                            ShoppingCartService.createAllElementScripts($scope.oShoppingSetting.PaymentGateways);

                            
                            //if ($scope.oShoppingSetting.AusPostIsUnused == true) {
                            //    $scope.loadAusPostServices();
                            //}
                        }

                        $timeout(function () {
                            //*** zip will redirect result when created a checkout ***                    
                            if ($scope.oZipParams.isZipPaymentMethod) {
                                $scope.createAChargeZip();
                            }
                            //*** paypal ***                    
                            if ($scope.oPaypalSetting.IsUsePayMethod) {
                                //LoginService.InitPaypal();
                                LoginService.InitPaypalByClientId($scope.oPaypalSetting.ClientKey);
                            }
                            //*** securepay v2
                            if ($scope.oShoppingSetting.SecurePayIsV2) {
                                LoginService.InitSecurepayV2Lib($scope.oShoppingSetting.SecurePayIsSandbox);
                            }
                        });

                        ShoppingCartService.getLocationState(function (lLocationStates) {
                            $scope.lLocationStates = lLocationStates
                        });

                        $scope.ShoppingCart.iTotalBulkyPrice = ShoppingCartService.getTotalBulkyPrice($scope.ShoppingCart.PendingSales);                        

                        //LoginService.SetFbKey($window.FBAppId, "v2.11");
                        //LoginService.SetGoogleKey($window.GoogleAppId);
                        LoginService.SetFbKey($rootScope.webApp.fb.appId, "v2.11");
                        LoginService.SetGoogleKey($rootScope.webApp.ga.appId);

                        $scope.ShoppingCart.IsSingleForm = false;//$scope.oOptions.IsSingleForm;

                        //$scope.loadCaptcha();


                    }, function () { });
                }

                $scope.initShopCartCtrl = function (options) {
                    if (angular.isDefined(options.ShoppingOptions)) {
                        $scope.oShoppingOptions = angular.copy(options.ShoppingOptions);
                        delete options.ShoppingOptions;

                        $scope.isSCShopCartCtrlLoaded = true;

                        $scope.initFinally();


                    } else {
                        console.error("ShoppingCart1Ctrl: ShoppingOptions is null");
                    }
                    //$scope.oOptions = angular.merge({}, options);
                }
                $scope.initFinally = function () {
                    if ($scope.isSCShoppingBasKetDataLoaded == true && $scope.isSCShopCartCtrlLoaded == true)
                    {
                        if ($scope.oShoppingSetting.GAETTransactionId != null) {
                            ShoppingCartService.loadScriptTagGAEcommerceTracking();
                            //ShoppingCartService.saveToGAEcommerceTracking({ SaleId: 8590 }, $scope.oShoppingSetting.GAETTransactionId, function () {
                            //    console.warn("Minh: GAEcommerceTracking testing");
                            //});
                        }

                        if ($scope.oShoppingSetting.PaymentGateways.length == 1) {
                            if ($scope.ShoppingCart.IsSingleForm == true) {
                                if ($scope.oPaymentMethod.isShowCreditForm()) {
                                    $element.find('.sc-checkout-view #accordionPaymentGateways #panel-creditcard-section #collapseCreditCard').collapse('toggle');
                                    $scope.togglePanelPayment(null, 'CreditCard');
                                }
                                else if ($scope.oPaymentMethod.isShowStripe()) {
                                    $element.find('.sc-checkout-view #accordionPaymentGateways #panel-stripe-section #collapseStripe').collapse('toggle');
                                    $scope.togglePanelPayment(null, 'Stripe');
                                }
                                else if ($scope.oPaymentMethod.isShowPaypal()) {
                                    $element.find('.sc-checkout-view #accordionPaymentGateways #panel-paypal-section #collapseTwo').collapse('toggle');
                                    $scope.togglePanelPayment(null, 'Paypal');
                                }
                            }
                        }
                        $scope.oPaymentMethod.isValidBasketAmount();//*** ensure pendingsales is loaded

                    }
                }
                //#endregion

                //#region html functions
                $scope.ShoppingCart.GetPrice = ShoppingCartService.getPriceQty;
                $scope.ShoppingCart.getSourceDesc = ShoppingCartService.csourceCodeToDesc;
                $scope.ShoppingCart.getSourceCodeAndDesc = ShoppingCartService.getSourceCodeAndDesc;
                $scope.ShoppingCart.getLoginDropdownContextHeaderTemplate = ShoppingCartService.getLoginDropdownContextHeaderTemplate;

                $scope.ShoppingCart.isAllowChangeQty = function (oItem) {
                    return ShoppingCartService.isAllowChangeQty($scope.ShoppingCart.WebsiteId, oItem);
                }
                $scope.ShoppingCart.hasBulkyItem = ShoppingCartService.hasBulkyItem;
                $scope.ShoppingCart.showItemCode = ShoppingCartService.isShowItemCode;
                $scope.ShoppingCart.IsOnlyPickupInStore = function () {
                    return ShoppingCartService.isOnlyPickupInStore($scope.ShoppingCart.WebsiteId, $scope.ShoppingCart.PendingSales);
                }
                $scope.ShoppingCart.IsShowPickupAtLocation = function () {
                    var bVal = false;
                    if ($scope.oShoppingSetting.HasDeliveryOptions && ($scope.ShoppingCart.IsOnlyPickupInStore() || (angular.isDefined($scope.CardHeader) && $rootScope.util.indexOfLowerCase($scope.CardHeader.DeliveryOption, 'pick up in store'))))
                    {
                        bVal = true;
                    }
                    
                    return bVal;
                }

                $scope.hasValidateDeliveryAddressStep = function () {
                    var bResult = true;
                    if ($rootScope.webApp.oWebsite && $rootScope.webApp.oWebsite.WebsiteID == 261) {
                        if (ShoppingCartService.hasPickupOnlyCategoryInListItems($scope.ShoppingCart.PendingSales)) {
                            bResult = false;
                        } else {
                            //*** if select Free Pickup, remove required. else add required
                            if ($scope.DeliveryAusPostService == "Pick_Up_In_Store::Free_Pickup") {
                                bResult = false;
                            } else {
                                bResult = true;
                            }
                        }
                    }
                    return bResult;
                }
                $scope.isShowAddressInfoInDeliveryAddressStep = function () {
                    var bResult = true;
                    //*** hide/show Street, Suburb, State, & Postcode
                    //if ($rootScope.webApp.oWebsite && $rootScope.webApp.oWebsite.WebsiteID == 261) {
                    //    if (ShoppingCartService.hasPickupOnlyCategoryInListItems($scope.ShoppingCart.PendingSales)) {
                    //        bResult = false;
                    //    }
                    //}
                    bResult = $scope.hasValidateDeliveryAddressStep();
                    return bResult;
                }
                $scope.hasFillAllAddress = function () {
                    var bVal = false;
                    if ($scope.hasValidateDeliveryAddressStep()) {
                        if ($scope.formDelivery.DeliveryAddress.$valid && $scope.formDelivery.Suburb.$valid && $scope.formDelivery.State.$valid && $scope.formDelivery.Postcode.$valid) {
                            bVal = true;
                        }
                    }
                    return bVal;
                }
                $scope.ShoppingCart.isShowBulkyItemLabel = ShoppingCartService.isShowBulkyItemLabel;
                $scope.ShoppingCart.isValidSpecialOptions = ShoppingCartService.isValidSpecialOptions;

                $scope.hasPickupOnlyCategoryInListItems = function () {
                    return ShoppingCartService.hasPickupOnlyCategoryInListItems($scope.ShoppingCart.PendingSales);
                }
                $scope.isNoPaymentMethods = function () {
                    var bResult = false;
                    var bHasCreditCard = false;
                    if (webApp.util.hasVal($scope.CardHeader.CreditCardType) && webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'NONE')) {
                        bHasCreditCard = true;
                    }
                    if (bHasCreditCard == false && $scope.oPaypalSetting.IsUsePayMethod == false && $scope.oZipPaySetting.IsUsePayMethod == false && $scope.ShoppingDiscountCode.FlagTradeCode == false) {
                        bResult = true;
                    }
                    return bResult;
                }
                //#region hide/show payment methods
                $scope.oPaymentMethod = {
                    isShowLowStockEnquiry: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        var bVal = false;
                        if ($scope.ShoppingCart != null && $scope.ShoppingCart.PendingSales != null && $scope.isExistingPaymentMethod('LowStockEnquiry')) {
                            for (var i = 0; i < $scope.ShoppingCart.PendingSales.length; i++) {
                                var oItem = $scope.ShoppingCart.PendingSales[i];
                                if ($rootScope.webApp.util.hasVal(oItem.SpecialOptions) && $rootScope.webApp.util.indexOfLowerCase(oItem.SpecialOptions, 'qav-lse=')) {
                                    bVal = true;
                                    break;
                                }
                            }
                        }
                        return bVal;
                    },
                    isShowShippingQuoteEnquiry: function () {
                        if (this.isValidBasketAmount() == false) return false;

                        var bVal = false;
                        if ($scope.ShoppingCart != null && $scope.ShoppingCart.PendingSales != null && $scope.isExistingPaymentMethod('ShippingQuoteEnquiry')) {
                            for (var i = 0; i < $scope.ShoppingCart.PendingSales.length; i++) {
                                var oItem = $scope.ShoppingCart.PendingSales[i];
                                if ($rootScope.webApp.util.hasVal(oItem.SpecialOptions) && $rootScope.webApp.util.indexOfLowerCase(oItem.SpecialOptions, 'wspcquoteid=')) {
                                    bVal = true;
                                    break;
                                }
                            }
                        }
                        if (bVal == true) {
                            //*** show the payemnt when Delivery Get-a-Quote-for-Delivery option is selected
                            bVal = (angular.isDefined($scope.AusPostCalculate) && $scope.AusPostCalculate.postage_result.service == 'Freight_Enquiry_Code')
                        }
                        return bVal;
                    },
                    isShowCreditForm: function () {
                        if (this.isValidBasketAmount() == false) return false;

                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $rootScope.webApp.util.hasVal($scope.CardHeader.CreditCardType)
                            && !$rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'NONE')
                            && !$rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'tyro')
                            && !$rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'Stripe')
                            && !$rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'Paypal')
                            && !($rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'securepay')
                            && $scope.oShoppingSetting.SecurePayIsV2 == true);
                    },
                    isShowSecurepayV2: function () {
                        if (this.isValidBasketAmount() == false) return false;

                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return ($rootScope.webApp.util.hasVal($scope.CardHeader.CreditCardType) && $rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'securepay') && $scope.oShoppingSetting.SecurePayIsV2);
                    },
                    isShowTyro: function () {
                        if (this.isValidBasketAmount() == false) return false;

                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.isExistingPaymentMethod('tyro');
                    },
                    isShowStripe: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.isExistingPaymentMethod('Stripe');
                    },
                    isShowPaypal: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.oPaypalSetting.IsUsePayMethod == true;
                    },
                    isShowZip: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.oZipPaySetting.IsUsePayMethod == true && !$scope.ShoppingCart.IsOnlyDeposit;
                    },
                    isShowPayright: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.oShoppingSetting.HasPayWithPayright == true;
                    },
                    isShowDirectDeposit: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.oShoppingSetting.HasPayWithDirectDeposit == true;
                    },
                    isShowPayLater: function () {
                        if (this.isValidBasketAmount() == false) return false;
                        if (this.isShowShippingQuoteEnquiry() == true) return false;
                        if (this.isShowLowStockEnquiry() == true) return false;
                        return $scope.ShoppingDiscountCode.FlagTradeCode == true;

                    },
                    isValidBasketAmount: function () {
                        var bVal = true;
                        if ($rootScope.webApp.oWebsite.WebsiteID == $rootScope.webApp.WebsiteIdCode.BrisbaneYamahaPart3040) {
                            if ($scope.getTotalPricePendingSale() < 300) {
                                bVal = false;
                            }
                        }

                        return bVal;
                    }
                }

                //#endregion
                $scope.isExpandPaymentMethod = function (sMethodName) {
                    //**** Expand Payment method panel when only has one.
                    var bVal = false;
                    var lPaymentMethods = $scope.getPaymentMethodsList();
                    if (lPaymentMethods.length == 1) {
                        if ($rootScope.webApp.util.equalsLowerCase(lPaymentMethods[0], sMethodName)) {
                            bVal = true;
                        }
                    }
                    return bVal;
                }
                $scope.isExistingPaymentMethod = function (sMethodName) {
                    //**** Expand Payment method panel when only has one.
                    var bVal = false;
                    var lPaymentMethods = $scope.getPaymentMethodsList();
                    if (lPaymentMethods.length > 0) {
                        bVal = lPaymentMethods.indexOf(sMethodName) > -1;
                        //for (var i = 0; i < lPaymentMethods.length; i++) {
                        //    if ($rootScope.webApp.util.equalsLowerCase(lPaymentMethods[i], sMethodName)) {
                        //        bVal = true;
                        //        break;
                        //    }
                        //}

                    }
                    return bVal;
                }
                //#endregion

                //#region DOMEvent ***

                //#region payment options ***
                $scope.collapsePaypal = function () {
                    ShoppingCartService.createPaypalButton('#paypal-button', $scope.ShoppingCart.PendingSales,
                        $scope.client, $scope.CardHeader,
                        $scope.CardDetail, $scope.formCreditCard,
                        $scope.oPaypalSetting, $scope.ShoppingDiscountCode,
                        $scope.AusPostCalculate, $scope.oShoppingSetting,
                        function (response) {
                            $scope.savePaymentSuccess(response);
                        });
                }
                $scope.collapseZip = function () {
                    $scope.CardDetail.PayingType = "Zip";
                }
                $scope.collapsePayLater = function () {
                    $scope.CardDetail.PayingType = "PayLater";
                }
                $scope.collapsePayright = function () {
                    $scope.CardDetail.PayingType = "Payright";
                }
                $scope.collapseDirectDeposit = function () {
                    $scope.CardDetail.PayingType = "DirectDeposit";
                }

                $scope.collapseSecurepayV2 = function () {
                    ShoppingCartService.renderSecurePayUI();
                }
                $scope.payWithSecurepayV2 = function () {
                    console.warn("Minh: payWithSecurepayV2", $scope.mySecurePayUI);
                    //$scope.mySecurePayUI.tokenise();
                    ShoppingCartService.payWithSecurePay();
                }
                //$scope.resetWithSecurepayV2 = function () {
                //    $scope.mySecurePayUI.reset();
                //}

                //#endregion

                $scope.activeTabComplete = function () {
                    var eleComplete = $('.wizard .nav-tabs a[href="#complete"]');//.tab('show');
                    eleComplete.closest('ul').find('li').removeClass('disabled').removeClass('active').addClass("disabled");
                    eleComplete.closest('li').removeClass('disabled');
                    eleComplete.click();
                }

                $scope.changeDeliveryAusPostService = function (sDeliveryAusPostService) {
                    ShoppingCartService.changeDeliveryAusPostService(sDeliveryAusPostService,
                        $scope.AusPost, $scope.CardHeader, $scope.AusPostServices, $scope.AusPostCalculate,
                        function (response) {
                        $scope.IsShowResultDeliveryAusPostService = response.isShowResult;
                        $scope.AusPostCalculate = response.oAusPostCalculate;
                        $scope.getTotalBasket();
                    });
                }
                $scope.applyDiscountCode = function () {
                    ShoppingCartService.applyDiscountCode($scope.ShoppingDiscountCode, function (response) {
                        $scope.ShoppingDiscountCode = response;
                        $scope.calculatorDiscountCode();
                    });
                }
                $scope.removeDiscountCode = function () {
                    ShoppingCartService.removeDiscountCode($scope.ShoppingDiscountCode, function (response) {
                        var jsonData = response.data
                        $scope.ShoppingDiscountCode = jsonData.DiscountCodeView;
                        $scope.ShoppingCart.PendingSales = jsonData.Products;
                        $scope.calculatorDiscountCode();
                    })
                }

                //#region login ***
                $scope.ShoppingCart.SignUp = ShoppingCartService.showSignupOrLoginForm;
                $scope.ShoppingCart.Login = function (sClientSourceType) {
                    ShoppingCartService.submitLoginForm(sClientSourceType, function (response) {
                        var jsonData = response.data;
                        $scope.updateClientInfo(jsonData.Client);
                        $("[data-dismiss=modal]").trigger({ type: "click" });
                        SelectFirstTab();
                    });
                };
                $scope.ShoppingCart.LoginFB = ShoppingCartService.submitLoginFB;
                $scope.ShoppingCart.LoginGoogle = ShoppingCartService.submitLoginGoogle;
                $scope.ShoppingCart.Logout = function () {
                    ShoppingCartService.submitLogoutForm(function (response) {
                        if ($rootScope.webApp.util.toBool($rootScope.webApp.isShoppingLoginLink)) {
                            $rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("/"));
                        } else {
                            $scope.updateClientInfo(null);
                            SelectFirstTab();
                        }
                        
                    });
                };
                //#endregion

                $scope.testStandardPayload = function ()
                {
                    ShoppingCartFactory.testStandardPayload({}).then(function (response) {
                        var jsonData = angular.fromJson(response.data);
                        console.warn("Minh: testStandardPayload", jsonData);

                    }, function (responseError) {
                        
                    });
                }
                //#endregion

                //#region *** $Watch ***
                $scope.$on('btnLoginModalLogged', function (event, response) {
                    //*** the event is listen for $rootScope.$broadcast('btnLoginModalLogged', {}) event 
                    var jsonData = response.data;
                    $scope.ShoppingCart.IsAuthentinal = true;
                    $scope.ShoppingCart.LoginViewModel.FullName = jsonData.Client.FullName;
                    $scope.ShoppingCart.LoginViewModel.FirstName = jsonData.Client.FirstName;
                    $scope.ShoppingCart.LoginViewModel.LastName = jsonData.Client.LastName;
                    $scope.ShoppingCart.ClientSourceType = jsonData.Client.Source;
                    $scope.updateClientInfo(jsonData.Client);
                });

                $scope.$watch('ShoppingCart.PendingSales', function (newVal, oldVal) {
                    $scope.ShoppingCart.IsOnlyDeposit = false;
                    if (!IsNullOrEmpty(newVal)) {
                        if ($scope.ShoppingCart.PendingSales.length > 0) {
                            for (var i = 0; i < $scope.ShoppingCart.PendingSales.length; i++) {
                                if ($scope.ShoppingCart.PendingSales[i].IsUseDeposit == true) {
                                    $scope.ShoppingCart.IsOnlyDeposit = true;
                                    break;
                                }
                            }
                        }
                    }
                    $scope.calculatorDiscountCode();
                });
                $scope.$watch('client.Delivery.Postcode', function (newVal, oldVal) {
                    if (!IsNullOrEmpty(newVal)) {
                        $scope.AusPost.ToPostcode = newVal;
                        $scope.loadAusPostServices();
                    }
                });

                //#endregion

                //#region *** GeneralFunction ***
                $scope.updateClientInfo = function (oClient) {
                    //*** old function name is RebindData4Client
                    ShoppingCartService.updateClientInfo(oClient, $scope.ShoppingCart.ClientSourceType, function (response) {
                        $scope.client = response
                    });
                }
                $scope.loadDealerBranches = function (sPickupAtLocation) {                    
                    ShoppingCartService.getDealerBranches(sPickupAtLocation, function (data) {                        
                        $scope.lSCDealershipBranches = data;
                    });
                }
                $scope.loadCaptcha = function () {
                    if ($rootScope.util.isNullOrEmpty($rootScope.webApp.ga.recaptchaSiteKey)) {
                        //ubs captcha
                        //$scope.isUbsCaptcha = true;
                        ShoppingCartService.reloadUbsCaptcha();
                        ShoppingCartService.reloadUbsCaptchaDD();

                    } else {
                        //$scope.isUbsCaptcha = false;
                        //google captcha
                        ShoppingCartService.loadGGCaptcha();
                        ShoppingCartService.loadGGCaptchaDD();//directdeposit
                    }
                }
                $scope.loadAusPostServices = function () {
                    ShoppingCartService.loadAusPostServices($scope.ShoppingCart.PendingSales, $scope.AusPostServices, $scope.AusPost, $scope.ShoppingCart.WebsiteId, function (reponse) {
                        var bSetDefaultPickupInStore = false;
                        if ($rootScope.webApp.oWebsite.WebsiteID == $rootScope.webApp.WebsiteIdCode.RovaRange229) {
                            //229 is rova range site (task #12178 new view required to handle bulky from engineroom parts.)
                            //ERProduct enable use of bulky freight.  replace auspost deivery options
                            if (reponse.oAusPostServices == null || reponse.oAusPostServices == {} || typeof (reponse.oAusPostServices) == 'object') {
                                reponse.oAusPostServices.service = [{
                                    "code": "Pick_Up_In_Store",
                                    "name": "Pick Up In Store",
                                    "price": 0,
                                    "max_extra_cover": null,
                                    "options":
                                        {
                                            "option": [
                                                {
                                                    "code": "Free_Pickup",
                                                    "name": "Free pickup",
                                                    "price": 0,
                                                    "suboptions": {}
                                                }
                                            ]
                                        }
                                }];
                            }

                            var totalBulkyPrice = ShoppingCartService.getTotalBulkyPriceOfERProduct($scope.ShoppingCart.PendingSales);
                            if (totalBulkyPrice != null && totalBulkyPrice > 0) {
                                if (reponse.oAusPostServices != null && reponse.oAusPostServices.service != null && reponse.oAusPostServices.service.length > 0) {
                                    //***Minh::20201202:: this avalible until end-day 06/12/2020
                                    //*** add free-delivery option
                                    reponse.oAusPostServices.service = $filter('filter')(reponse.oAusPostServices.service, function (x) { return x.code == 'Pick_Up_In_Store' });

                                    var oFreeDelivery = {
                                        code: 'Delivery_Fee',
                                        name: 'Delivery',
                                        options: {
                                            option: [{
                                                code: 'Delivery_Fee',
                                                name: 'Delivery',
                                                price: totalBulkyPrice
                                            }]
                                        }
                                    };
                                    reponse.oAusPostServices.service.spliceIfNotExist(oFreeDelivery, 1, function (oService) {
                                        return oService.code == oFreeDelivery.code;
                                    });
                                }
                            } else {
                                bSetDefaultPickupInStore = true;                                
                            }
                        }

                        if (bSetDefaultPickupInStore == true)
                        {
                            //*** if only Pickup In Store, set selected
                            if (reponse.oAusPostServices.service.length == 1 && $filter('filter')(reponse.oAusPostServices.service, function (x) { return x.code == 'Pick_Up_In_Store' }).length > 0) {
                                //*** if the basket has pickup only category and, delivery option default "Free Pickup"
                                $scope.DeliveryAusPostService = "Pick_Up_In_Store::Free_Pickup";
                                $scope.changeDeliveryAusPostService($scope.DeliveryAusPostService);
                            }
                        }

                        $scope.AusPostServices = reponse.oAusPostServices;
                        if (angular.isDefined(reponse.sDeliveryOption) && reponse.sDeliveryOption != "") {
                            $scope.CardHeader.DeliveryOption = reponse.sDeliveryOption;
                        }
                    });                    
                }
                $scope.loadPaypalSetting = function () {
                    ShoppingCartService.getPaymentSetting('Paypal', function (response) {
                        $scope.oPaypalSetting = angular.fromJson(response.data);
                    });
                }
                $scope.loadZipPaySetting = function () {
                    ShoppingCartService.getPaymentSetting('Zippay', function (response) {
                        $scope.oZipPaySetting = angular.fromJson(response.data);
                    });
                }
                $scope.renderPaypalButton = function (isSandbox, sClientKey, dAmountTotal, subTotalPrice, dDeliveryFee, lItems, oShippingAddress, cbExecute) {
                    if (!$scope.isRenderPaypalButton) {
                        $scope.isRenderPaypalButton = true;
                        ShoppingCartService.renderPaypalButton('#paypal-button', isSandbox, sClientKey, dAmountTotal, subTotalPrice, dDeliveryFee, lItems, oShippingAddress, cbExecute);
                    }

                }
                $scope.getPaymentMethodsList = function () {
                    var aMethods = [];
                    if ($rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'none') == false) {
                        if ($rootScope.webApp.util.equalsLowerCase($scope.CardHeader.CreditCardType, 'tyro') == true) {
                            aMethods.push("Tyro");
                        } else {
                            //aMethods.push($scope.CardHeader.CreditCardType);
                            aMethods.push("CreditCard");
                        }

                    }
                    if ($scope.oPaypalSetting.IsUsePayMethod == true) {
                        aMethods.push("Paypal");
                    }
                    if ($scope.oZipPaySetting.IsUsePayMethod == true) {
                        aMethods.push("ZipPay");
                    }
                    if ($scope.oShoppingSetting.HasPayWithPayright == true) {
                        aMethods.push("Payright");
                    }
                    if ($scope.oShoppingSetting.HasPayWithDirectDeposit == true) {
                        aMethods.push("DirectDeposit");
                    }
                    if ($scope.ShoppingDiscountCode.FlagTradeCode == true) {
                        aMethods.push("PayLater");
                    }
                    if ($scope.oShoppingSetting.PaymentGateways && $scope.oShoppingSetting.PaymentGateways.indexOf('Stripe') > -1) {
                        aMethods.push("Stripe");
                    }
                    return aMethods;
                }
                //#region *** Price ***
                $scope.getPriceDepositAmount = function (item) {
                    return ShoppingCartService.getPriceDepositAmount(item, $scope.oShoppingSetting);
                }
                $scope.getDiscountCodePrice = function (item) {
                    return ShoppingCartService.getDiscountCodePrice(item, $scope.ShoppingDiscountCode, $scope.oShoppingSetting);
                }
                $scope.getTotalPricePendingSale = function () {
                    return ShoppingCartService.getTotalPendingSalePrice($scope.oShoppingSetting, $scope.ShoppingCart.PendingSales);
                }
                $scope.getDeliveryFee = function () {
                    $scope.CardHeader.DeliveryFee = null;
                    if ($scope.ShoppingCart.PendingSales.length > 0 && !$scope.ShoppingCart.IsOnlyDeposit) {
                        $scope.CardHeader.DeliveryFee = ShoppingCartService.getDeliveryFee($scope.AusPostCalculate, $scope.ShoppingCart.PendingSales);
                    }
                    return $scope.CardHeader.DeliveryFee;
                }
                $scope.getBulkyPrice = function (item) {
                    return ShoppingCartService.getBulkyPrice(item);
                }
                $scope.calculatorDiscountCode = function () {
                    $scope.ShoppingCart.iTotalDiscountCodePrice = ShoppingCartService.getTotalDiscountCodePrice($scope.ShoppingDiscountCode, $scope.ShoppingCart.PendingSales);
                }
                $scope.getTotalBasket = function () {
                    return ShoppingCartService.getTotalBasket($scope.ShoppingDiscountCode, $scope.AusPostCalculate, $scope.oShoppingSetting, $scope.ShoppingCart.PendingSales);
                }
                //#endregion

                //#endregion

                //#region Save
                //$scope.ShoppingCart.OnChangeQty = ShoppingCartService.changeQty;
                $scope.ShoppingCart.OnChangeQty = function (oItem, previousVal) {
                    //debugger;
                    ShoppingCartService.changeQty(oItem, function (response) {
                        if (response && response.isValid == false) {
                            oItem.Quantity = Number(previousVal);                            
                            ShoppingCartService.showQtyNotification({ ItemTitle: response.sMsg });
                            
                        }
                    });
                }
                $scope.ShoppingCart.changeQtyMinus = function (oItem) {
                    ShoppingCartService.changeQtyMinus(oItem, function (response) {
                        if (response && response.isValid == false) {
                            oItem.Quantity++;
                            ShoppingCartService.showQtyNotification({ ItemTitle: response.sMsg });
                        }
                    });
                }
                $scope.ShoppingCart.changeQtyPlus = function (oItem) {
                    ShoppingCartService.changeQtyPlus(oItem, function (response) {
                        if (response && response.isValid == false) {
                            oItem.Quantity--;
                            ShoppingCartService.showQtyNotification({ ItemTitle: response.sMsg });
                        }
                    });
                }
                $scope.ShoppingCart.AddCartItem = function (oItem) {
                    if ($rootScope.webApp.util.hasVal($scope.oShoppingSetting.CheckoutBySourceType) && $rootScope.webApp.util.indexOfLowerCase($scope.oShoppingSetting.CheckoutBySourceType, oItem.Source)) {
                        var sUrl = "";
                        if ($rootScope.webApp.util.hasVal(oItem.redirectTo)) {
                            sUrl = oItem.redirectTo;
                        } else {
                            if ($rootScope.webApp.util.hasVal(oItem.UrlExtra)) {
                                sUrl = $rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout/" + oItem.UrlExtra + "/" + oItem.Source + "/" + oItem.RefId + "/" + oItem.FilterId);
                            }
                            else {
                                sUrl = $rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout/" + oItem.Source + "/" + oItem.RefId + "/" + oItem.FilterId);
                            }
                        }
                        $rootScope.webApp.util.redirectTo(sUrl);
                    } else {
                        ShoppingCartService.addProductItem(oItem, function () {
                            if ($rootScope.webApp.util.toBool(oItem.bRedirectToCheckoutImmediately) == true) {
                                $rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("shopping-basket"));
                            } else {
                                $scope.calculatorDiscountCode();
                            }
                        });
                    }
                }
                $scope.ShoppingCart.RemoveCartItem = function (oItem) {
                    ShoppingCartService.removeProductItem(oItem, function () {
                        $scope.calculatorDiscountCode();
                    });
                }
                $scope.ShoppingCart.RemoveAllCartItems = function () {
                    ShoppingCartService.removeAllProductItem(function () {
                        $scope.calculatorDiscountCode();
                    });
                }

                $scope.saveContactAndNext = function () {
                    if ($scope.ShoppingCart.PendingSales.length > 0) {
                        $scope.formContact.submitted = true;
                        if ($scope.formContact.$valid) {
                            AWDSApp.util.showLoadingIcon($element, true);
                            $scope.client.FullName = $scope.client.FirstName + ' ' + $scope.client.LastName;
                            ShoppingCartFactory.RegisterContact($scope.client).then(function (response) {
                                AWDSApp.util.showLoadingIcon($element, false);
                                var jsonData = angular.fromJson(response.data);
                                $scope.updateClientInfo(jsonData);
                                $scope.PostcodeSuburbErrorMsg = "";
                                $scope.loadAusPostServices();
                                
                                if ($scope.oShoppingOptions.ViewOption.Checkout.IsShowLocation) {
                                    var sPickupAtLocation = ShoppingCartService.getPickupAtLocationItem($scope.ShoppingCart.PendingSales);
                                    if (sPickupAtLocation != null) {
                                        $scope.CardHeader.PickupLocationId = sPickupAtLocation;
                                    }
                                    $scope.loadDealerBranches(sPickupAtLocation);
                                }

                                nextTab();

                            }, function () {
                                AWDSApp.util.showLoadingIcon($element, false);
                            });
                        }
                    }
                }
                $scope.saveDeliveryAndNext = function () {
                    if ($scope.ShoppingCart.PendingSales.length > 0) {
                        $scope.formDelivery.submitted = true;
                        if (IsNullOrEmpty($scope.client.Delivery.Postcode)) {
                            $scope.PostcodeSuburbErrorMsg = "Please enter postcode.";
                        }
                        else {
                            if ($scope.formDelivery.$valid) {
                                AWDSApp.util.showLoadingIcon($element, true);
                                ShoppingCartFactory.DeliveryContact($scope.client).then(function (response) {
                                    AWDSApp.util.showLoadingIcon($element, false);
                                    jsonData = angular.fromJson(response.data);
                                    $scope.updateClientInfo(jsonData);
                                    if ($('#panel-paypal-section #collapseTwo').hasClass('in')) {
                                        ShoppingCartService.resetRenderPaypalButtonFlag('#paypal-button');
                                        $scope.collapsePaypal();//*** re-render paypal if expanded and has change delivery fee
                                    }
                                    if ($scope.isExpandPaymentMethod('Paypal')) {
                                        $scope.collapsePaypal();//init paypal lib when only payment method
                                        $('#panel-paypal-section #collapseTwo').addClass('in');
                                    }

                                    if ($scope.isExistingPaymentMethod('Stripe')) {
                                        ShoppingCartService.createCardElementStripe('#stripe-card-element', $scope.oShoppingSetting.StripePubishKey);//*** generate card-element form by StripeJS
                                    }

                                    nextTab();
                                }, function () {
                                    AWDSApp.util.showLoadingIcon($element, false);
                                });
                            }
                        }
                    }
                }
                $scope.savePaymentSuccess = function (response) {
                    var jsonData = angular.fromJson(response.data);
                    if (jsonData.Errors != null && jsonData.Errors.length > 0) {
                        $scope.CreditCardError = jsonData.Errors;
                        //$scope.CreditCardError = jsonData.Errors;

                        var sErrorMsg = "";
                        for (var i = 0; i < $scope.CreditCardError.length; i++) {
                            sErrorMsg += $scope.CreditCardError + "<br/>";
                        }
                        ShoppingCartService.showErrorShoppingNotification(sErrorMsg, 'Please check your payment details and try again.');
                        AWDSApp.util.showLoadingIcon($element, false);

                        if ($scope.CardDetail.PayingType == "CreditCard") {
                            $scope.loadCaptcha();
                        } else {
                            $timeout(function () {
                                $rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout"));
                            }, 5000);
                        }
                        
                    } else {
                        $scope.ShoppingCart.IsPayment = true;
                        $scope.CreditCardError = [];
                        $scope.ShoppingCart.PendingSales = [];
                        $scope.TotalRecordsShoppingCart = null;
                        //*** redirect to thank-you
                        //$scope.activeTabComplete();
                        //add order to google analytics - tracking ecommerce
                        ShoppingCartService.saveToGAEcommerceTracking(response, $scope.oShoppingSetting.GAETTransactionId, function () {
                            //$rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout"));
                            //$timeout(function () {
                            //    $rootScope.webApp.util.redirectTo($rootScope.webApp.util.getUrlHasPrefix("shopping-basket/checkout"));
                            //}, 5000);
                            $rootScope.webApp.util.redirectTo($rootScope.webApp.formMailOptions.redirectToThankYou.shoppingCartDirective, $rootScope.webApp.util.getUrlHasPrefix("stock/shoppingcart/thankyou"));
                        });
                        
                    }
                }
                $scope.savePayment = ShoppingCartService.savePayment;
                $scope.payWithStripe = ShoppingCartService.payWithStripe;
                $scope.payWithZip = ShoppingCartService.payWithZip;
                $scope.createAChargeZip = ShoppingCartService.createAChargeZip;
                $scope.updateSaleAfterCreatedACharge = ShoppingCartService.updateSaleAfterCreatedACharge;
                $scope.payLater = ShoppingCartService.payLater;
                $scope.payDirectDeposit = ShoppingCartService.payDirectDeposit;
                $scope.payWithPayright = ShoppingCartService.createACheckoutPayright;
                $scope.validatePayment = function (e) {
                    return ShoppingCartService.validatePayment(e, $scope.CardHeader, $scope.CardDetail, $scope.ShoppingDiscountCode, $scope.client, $scope.ShoppingCart.PendingSales, $scope.formCreditCard);
                }

                //#endregion

                function nextTab() {
                    var $active = angular.element($element).find('.wizard .nav-tabs li.active');
                    $active.next().removeClass('disabled');
                    $($active).next().find('a[data-toggle="tab"]').click();
                }
                function SelectFirstTab() {
                    if (angular.element($element).find('a[data-toggle="tab"]').length > 0) {
                        angular.element($element).find('a[data-toggle="tab"]:first').tab('show');
                    }
                }
            }]
        }
    }]);
