API Docs for: 0.6.0
Show:

File: penske\scratch.js

function ($scope, $http, nowServer, $timeout, spUtil, spScUtil, spModal, i18n, $window, $location, spAriaUtil, nowAttachmentHandler, $log, $sce, $q, spAtf, spSCNavStateManager, cabrillo) {
	/**
	 * This is a copy of the SC Order Guide widget created to preserve modifications with
	 * the updates from upgrading the instance.
	 * 
	 * This header is used to parse this with YUIDocs for documentation creation and can be
	 * parsed with a YUIDocs documentation parser.
	 * 
	 * See the YUIDocs site for syntax or additional details;
	 * https://yui.github.io/yuidoc/
	 * 
	 * Note that only the additions performed are documented in this fashion. ServiceNow code
	 * that was not modified or used was left as is.
	 * 
	 * The modifications to this widget are summarized below for future considerations:
	 * + Displaying the "For" and "At" in the top right corner to indicate the employee being affected and the location at which this is being considered
	 *
	 * Future modifications should be noted above for consideration after upgrades.
	 * 
	 * @author Alexander Anderson
	 * @class CWTSCOrderGuide
	 * @extends SPWidget
	 * @version 2.1
	 */
	
	var c = this;
    $scope.guide_step = 0;
    $scope.m = $scope.data.msgs;
    $scope.evaluatingIncludes = false;
    $scope.data.isMEE = $scope.options.native_mobile == 'true';
    $scope.isItemOpened = false;
    /**
     * ServiceNow variable used for mapping sys_id values to the underlying glideform.
     * 
     * This is updated on load, so for clarity and asynchronous timing, the values from
     * here should be loaded in the function at time of need rather than attempting to
     * pre-load any values.
     * @property includedGformInstances
     * @type Object
     * @private
     */
    // Variable Declaration correction (missing var) and public mapping in scope
    var includedGformInstances = {};
    /**
     * Mapped along side includedGformInstances but is persisted to preserve values for
     * reference. Currently only saves the GlideForm for the data.sys_id reference.
     * 
     * @property _glideForms
     * @type Object
     */
    $scope._glideForms = {};
    /**
     * The GlideForm for the Order Guide itself. Set after load.
     * @property primaryGlideForm
     * @type Object
     */
    $scope.primaryGlideForm = null;

    $rootScope.$on('spModel.gForm.rendered', function () {
        if ($scope.guide_step === 0) {
            addCabrilloBottomButtons({
                title: [$scope.data.msgs.nextMsg],
                fn: [$scope.goNext]
            });
        }
        $timeout(function () {
            spAtf.init().then(function (atf) {
                $scope._atf = atf;
                atf.expose('catalog_util', catalogUtil);
            });
        }, 10);
    });

    if ($scope.options.isServiceWorkspace && $window.frameElement) {
        var workspaceParams = {};
        workspaceParams.sysparm_parent_table = $window.frameElement.getAttribute('parent-table');
        workspaceParams.sysparm_parent_sys_id = $window.frameElement.getAttribute('parent-sys-id');
        $scope.data.workspaceParams = workspaceParams;
    }

    if ($scope.data.sc_cat_item) {
        $scope.data.sc_cat_item.description = $sce.trustAsHtml($scope.data.sc_cat_item.description);

        if ($scope.data.sc_cat_item.request_method == "request")
            $scope.submitButtonMsg = $scope.m.requestMsg;
        else if ($scope.data.sc_cat_item.request_method == "submit")
            $scope.submitButtonMsg = $scope.m.submitMsg;
        else
            $scope.submitButtonMsg = $scope.m.orderNowMsg;

        // Breadcrumbs
        if (!$scope.data.categories)
            $scope.data.categories = [];
        $scope.data.categories.forEach(function (category, index, categories) {
            categories[index].url = category.url + '&catalog_id=' + $scope.data.catalog_id;
        });
        if ($scope.data.categories.length > 0) {
            $scope.data.categories.unshift({
                label: $scope.data.sc_catalog || $scope.page.title,
                url: '?id=' + $scope.data.sc_category_page
            });
            $scope.data.categories.push({
                label: $scope.data.sc_cat_item.name,
                url: '#'
            });
            if ($scope.data.all_catalog_msg) {
                $scope.data.categories.unshift({
                    label: $scope.data.all_catalog_msg,
                    url: '?id=' + $scope.data.sc_category_page + "&catalog_id=-1"
                });
            }
        } else {
            $scope.data.categories.push({
                label: $scope.data.sc_cat_item.name,
                url: '#'
            });
        }

        $timeout(function () {
            $scope.$emit('sp.update.breadcrumbs', $scope.data.categories);
        });
        spUtil.setSearchPage('sc');
    } else {
        var notFoundBC = [{
                label: $scope.page.title,
                url: '?id=' + $scope.data.sc_catalog_page
            }
        ];
        $timeout(function () {
            $scope.$emit('sp.update.breadcrumbs', notFoundBC);
        });
        spUtil.setSearchPage('sc');
    }

    function isValidItemGform(g_form) {
        if (g_form.getSysId() === $scope.data.sc_cat_item.sys_id)
            return true;
        if ($scope.includedItems)
            for (var i in $scope.includedItems)
                if ($scope.includedItems[i].sys_id === g_form.getSysId())
                    return true;
        return false;
    }

    $scope.$on('spModel.gForm.initialized', function (e, gFormInstance) {
        if (!isValidItemGform(gFormInstance))
            return;
        includedGformInstances[gFormInstance.getSysId()] = gFormInstance;
        if($scope.data.sys_id == gFormInstance.getSysId()) {
        	$scope._glideForms[$scope.data.sys_id] = gFormInstance;
        	$scope.primaryGlideForm = gFormInstance;
        }
        
        spSCNavStateManager.register(gFormInstance);
        gFormInstance.$private.events.on('submitted', function (event) {
            gFormInstance.$private.processed = true;
            if (gFormInstance.getSysId() == $scope.data.sc_cat_item.sys_id) {
                $scope.$broadcast('$sp.service_catalog.form_submitted', {
                    action_name: 'submit'
                });
                $scope.guide_step = 1;
                evalIncludes();
                spSCNavStateManager.unregisterForms(Object.keys(includedGformInstances));
                $scope.itemShown = 0;
            } else
                processChooseOptions();
        });

        if ($scope.options.native_mobile == 'true') {
            cabrillo.viewLayout.showSpinner();
            cabrillo.viewLayout.setTitle($scope.data.sc_cat_item.name);
        }
        $timeout(function () {
            $rootScope.$emit('spModel.gForm.rendered');
            if ($scope.options.native_mobile == 'true') {
                cabrillo.viewLayout.hideSpinner();
            }
        }, 175);
    });

    $scope.$on('spModel.gForm.destroyed', function (e, sys_id) {
        delete includedGformInstances[sys_id];
    });

    var validationComplete = $rootScope.$on('$sp.service_catalog.form_validation_complete', function () {
            $scope.validating = false;
        });

    /* ************************************************************************************************ */
    /* *******************************       Guide Navigation Start     ******************************* */
    /* ****#####################################################################################******* */

    $scope.goPrev = function () {
        if ($scope.submitted)
            return;

        clearCabrilloBottomButtons();
        $scope.includedItems.forEach(function (item) {
            item.isOpen = false;
        })
        $scope.guide_step--;
        if ($scope.guide_step == 0)
            spSCNavStateManager.unregisterForms(Object.keys(includedGformInstances));

        if ($scope.guide_step === 1) {
            addCabrilloBottomButtons({
                title: [$scope.data.msgs.prevMsg, $scope.data.msgs.nextMsg],
                fn: [$scope.goPrev, $scope.goNext]
            });
        }
    }

    $scope.goNext = function (timeout) {
        var gForm;
        if ($scope.guide_step == 0) {
            $scope.$evalAsync(function () {
                gForm = includedGformInstances[$scope.data.sys_id];
                if (!spScUtil.isRegexDone($scope.data.sc_cat_item._fields))
                    $scope.validating = true;
                else if (gForm && !gForm.submit()) {
                    timeout = timeout || 2000;
                    if (cabrillo.isNative())
                        openItemWithInvalidFields();
                    $timeout(function () {
                        $scope.$broadcast('$sp.service_catalog.form_submit_failed', {
                            action_name: 'submit'
                        });
                    }, timeout);
                }
            });
        } else if ($scope.guide_step == 1) {
            $scope.itemsIncluded = $scope.includedItems.length;
            $scope.$evalAsync(function () {
                for (var i = 0; i < $scope.includedItems.length; i++) {
                    if ($scope.includedItems[i].included) {
                        var g_form = includedGformInstances[$scope.includedItems[i].sys_id];
                        g_form.$private.processed = false;
                        if (!spScUtil.isRegexDone($scope.includedItems[i]._fields))
                            $scope.validating = true;
                        else if (g_form && !g_form.submit()) {
                            timeout = timeout || 500;
                            $timeout(function () {
                                $scope.$broadcast('$sp.service_catalog.form_submit_failed', {
                                    action_name: 'submit'
                                });
                                openItemWithInvalidFields();
                            }, timeout);
                        }
                    } else
                        $scope.itemsIncluded--;
                }
            });
        }
    }

    $scope.toggleItemState = function (item) {
        if (item.included) {
            $scope.totalIncluded--;
            angular.element('#item_details_' + item.sys_id).find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]').attr('tabindex', -1);
        } else {
            $scope.totalIncluded++;
            angular.element('#item_details_' + item.sys_id).find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]').removeAttr('tabindex');
        }
    }

    function processChooseOptions() {
        var canSubmit = true;

        for (var i = 0; i < $scope.includedItems.length; i++) {
            if ($scope.includedItems[i].included) {
                var gForm = includedGformInstances[$scope.includedItems[i].sys_id];
                if (gForm && !gForm.$private.processed) {
                    canSubmit = false;
                    break;
                }
            }
        }
        if (canSubmit) {
            evalGuidePrice();
            spSCNavStateManager.unregisterForms(Object.keys(includedGformInstances));
            $scope.$broadcast('$sp.service_catalog.form_submitted', {
                action_name: 'submit'
            });
            $scope.guide_step = 2;
            $scope.showAddToCart = $scope.options.show_add_cart_button == 'true' && !$scope.data.sc_cat_item.no_cart;
            addCabrilloBottomButtons({
                title: [i18n.getMessage('Add to Cart'), $scope.submitButtonMsg],
                fn: [$scope.triggerAddToCart, $scope.triggerSubmit]
            });
        }
    }

    var openItemWithInvalidFields = (function () {
        var formsValidated = 0;
        return function () {
            formsValidated++;
            if (formsValidated == $scope.itemsIncluded) {
                var someFormIsInvalid = false;
                for (var i = 0; i < $scope.includedItems.length; i++) {
                    if ($scope.includedItems[i].included) {
                        var gForm = includedGformInstances[$scope.includedItems[i].sys_id];
                        if (!gForm)
                            return;

                        var fields = gForm.getFieldNames();
                        for (var j = 0; j < fields.length; j++) {
                            var field = gForm.getField(fields[j]);
                            if (field.isInvalid) {
                                if (cabrillo.isNative()) {
                                    $scope.includedItems[i].isOpen = true;
                                    $scope.showCancel($scope.includedItems[i].sys_id);
                                } else
                                    $scope.includedItems[i].isOpen = true;

                                someFormIsInvalid = true;
                                break;
                            }
                        }
                        if (cabrillo.isNative() && someFormIsInvalid)
                            break;
                    }
                }
                formsValidated = 0;
                if (!cabrillo.isNative())
                    focusInvalidField();
            }
        }
    })();

    function focusInvalidField() {
        $timeout(function () {
            for (var i = 0; i < $scope.includedItems.length; i++) {
                if ($scope.includedItems[i].included) {
                    var mandatory = $scope.includedItems[i]._mandatory;
                    if (mandatory && mandatory.length > 0) {
                        var elems = angular.element("[name*='" + mandatory[0].name + "']");
                        if (elems && elems.length > 0) //set focus the first element
                            elems[0].focus();
                        break;
                    } else {
                        var gForm = includedGformInstances[$scope.includedItems[i].sys_id];
                        getInvalidFields(gForm);
                        var invalidFields = gForm._invalidFields;
                        if (invalidFields && invalidFields.length > 0) {
                            var invalid = angular.element("[name*='" + invalidFields[0].name + "']");
                            if (invalid && invalid.length > 0) //set focus the first element
                                invalid[0].focus();
                            break;
                        }
                    }
                }
            }
        }, 500);
    }

    $scope.closeItemAccordion = function (itemOpened) {
        itemOpened.isOpen = false;
        cabrillo.viewLayout.setNavigationBarButtons();
        cabrillo.viewLayout.setTitle($scope.data.sc_cat_item.name);
        addCabrilloBottomButtons({
            title: [$scope.data.msgs.prevMsg, $scope.data.msgs.nextMsg],
            fn: [$scope.goPrev, $scope.goNext]
        });
        $scope.isItemOpened = false;
    }

    $scope.showItem = function (index) {
        if ($scope.itemShown == index)
            $scope.itemShown = -1;
        else
            $scope.itemShown = index;
    }

    $scope.showCancel = function (id) {
        var itemOpened,
        buttons;
        if (cabrillo.isNative()) {
            clearCabrilloBottomButtons();
            cabrillo.viewLayout.setNavigationBarButtons();
            cabrillo.viewLayout.hideBackButton();
            itemOpened = $scope.includedItems.find(function (item) {
                    return item.sys_id === id;
                });

            cabrillo.viewLayout.setTitle(itemOpened.name);
            buttons = [{
                    title: i18n.getMessage('Done'),
                    enabled: true
                }
            ];

            cabrillo.viewLayout.setNavigationBarButtons(buttons, function (index) {
                $scope.closeItemAccordion(itemOpened);
            });
        }
        $scope.isItemOpened = true;
    }

    /* ****************************************************************************************** */
    /* *******************************     Guide Navigation End    ****************************** */
    /* ****###############################################################################******* */
    /* ****************************************************************************************** */
    /* *******************************         Attachments         ****************************** */
    /* ****###############################################################################******* */

    function initAttachmentHandlers() {
        var setAttachments;
        var appendError = function (error) {
            spUtil.addErrorMessage(error.msg + error.fileName);
        };
        for (var i = 0; i < $scope.includedItems.length; i++) {
            $scope.includedItems[i].attachmentHandler = new nowAttachmentHandler(setAttachments, appendError);
            $scope.includedItems[i].attachmentHandler.setParams($scope.includedItems[i].targetTable, $scope.includedItems[i].sysparm_item_guid, 1024 * 1024 * $scope.data.maxAttachmentSize);
        }
    }

    $scope.$on('dialog.upload_too_large.show', function (e) {
        $log.error($scope.m.largeAttachmentMsg);
        spUtil.addErrorMessage($scope.m.largeAttachmentMsg);
    });

    $scope.initAttachmentCallbacks = function (itemIndex) {
        $scope.includedItems[itemIndex].attachmentHandler.setAttachments = function (attachments, action) {
            $scope.includedItems[itemIndex].attachments = attachments;
            if (action === "added") {
                $scope.includedItems[itemIndex].attachment_submitted = true;
            }
            if (action === "renamed")
                spAriaUtil.sendLiveMessage($scope.m.renameSuccessMsg);
            if (action === "deleted") {
                spAriaUtil.sendLiveMessage($scope.m.deleteSuccessMsg);
                if ($scope.includedItems[itemIndex].attachments.length == 0)
                    $scope.includedItems[itemIndex].attachment_submitted = false;
            }
            spUtil.get($scope, {
                action: "from_attachment"
            });
        };

        $scope.includedItems[itemIndex].confirmDeleteAttachment = function (attachment) {
            spModal.confirm($scope.data.msgs.delete_attachment).then(function () {
                $scope.includedItems[itemIndex].attachmentHandler.deleteAttachment(attachment);
                $scope.setFocusToAttachmentButton();
            });
        }
    }

    /* ****************************************************************************************** */
    /* *******************************       Attachments  End      ****************************** */
    /* ****###############################################################################******* */
    /* ****************************************************************************************** */
    /* *******************************        UTIL Functions       ****************************** */
    /* ****###############################################################################******* */

    function evalGuidePrice() {
        $scope.price = 0;
        var frequencyMap = {};
        for (var i = 0; i < $scope.includedItems.length; i++) {
            if ($scope.includedItems[i].included && $scope.includedItems[i].process_price) {
                var qty = parseInt($scope.includedItems[i].quantity);
                var pricing = $scope.includedItems[i]._pricing;
                var effectivePrice = 0;
                var effectiveRecurringPrice = 0;
                if (typeof $scope.includedItems[i].price != "undefined") {
                    effectivePrice = $scope.includedItems[i].price;
                }
                if (typeof $scope.includedItems[i].recurring_price != "undefined") {
                    effectiveRecurringPrice = $scope.includedItems[i].recurring_price;
                }

                if (effectiveRecurringPrice >= 0 && pricing.rfd) {
                    if (frequencyMap[pricing.rfd])
                        frequencyMap[pricing.rfd] += effectiveRecurringPrice * qty;
                    else
                        frequencyMap[pricing.rfd] = effectiveRecurringPrice * qty;
                }
                if (effectivePrice >= 0)
                    $scope.price += effectivePrice * qty;
            }
        }
        frequencyMap.price = $scope.price;
        $scope.server.get({
            action: "format_prices",
            prices: frequencyMap
        }).then(function (response) {
            $scope.frequencySequence = response.data.frequencySequence;
            $scope.price_display = response.data.frequencyMap.price;
            $scope.frequencyMap = response.data.frequencyMap;
        });
    }

    function evalIncludes() {
        // don't allow submit while waiting on included items eval
        $scope.evaluatingIncludes = true;
        $scope.includedItems = [];
        var guideData = getFieldsData($scope.data.sc_cat_item);
        guideData.sysparm_id = $scope.data.sys_id;
        guideData.without_cart = true;
        guideData._fields = $scope.data.sc_cat_item._fields;
        guideData.cascade = $scope.data.sc_cat_item.cascade;
        if ($scope.data.workspaceParams) {
            guideData.sysparm_parent_sys_id = $scope.data.workspaceParams.sysparm_parent_sys_id;
            guideData.sysparm_parent_table = $scope.data.workspaceParams.sysparm_parent_table;
        }
        $scope.server.get({
            action: "init_guide",
            orderGuideData: guideData
        }).then(function (response) {
            if (response.data.error) {
                $scope.guide_step--;
                return;
            }
            $scope.includedItems = response.data.items;
            $scope.showIncludeToggle = response.data.showIncludeToggle;
            initAttachmentHandlers();
            $scope.includedItems.forEach(function (item) {
                item.description = $sce.trustAsHtml(item.description);
            });
            $scope.totalIncluded = $scope.includedItems.length;
            $scope.conflictingCartDomainMsg = response.data.conflictingCartDomainMsg;
            $scope.evaluatingIncludes = false;

            addCabrilloBottomButtons({
                title: [$scope.data.msgs.prevMsg, $scope.data.msgs.nextMsg],
                fn: [$scope.goPrev, $scope.goNext]
            });
        });
    }

    function getInvalidFields(gForm) {
        gForm._invalidFields = [];
        var fields = gForm.getFieldNames();
        for (var j = 0; j < fields.length; j++) {
            var field = gForm.getField(fields[j]);
            if (field.isInvalid)
                gForm._invalidFields.push(field);
        }
    }

    function getCurrentGForm() {
        if ($scope.guide_step == 0)
            return includedGformInstances[$scope.data.sc_cat_item.sys_id];
        else {
            var openItem = $scope.includedItems.find(function (item) {
                    return item.isOpen === true;
                });
            return includedGformInstances[openItem.sys_id];
        }
    }

    function openItemHelper(item, state, defer) {
        for (var i = 0; i < $scope.includedItems.length; i++)
            if ($scope.includedItems[i].sys_id == item) {
                $scope.includedItems[i].included = state == 'true';
                $scope.includedItems[i].isOpen = true;
                $scope._atf.expose('g_form', spAtf.augmentForm(includedGformInstances[item]));
                defer.resolve();
            }
    }

    function getFieldsData(item) {
        var fieldData = {
            "variables": {}
        };
        for (var field in item._fields) {
            var fieldValue = "";
            if (item._fields[field].value != null && typeof item._fields[field].value != "string")
                fieldValue = JSON.stringify(item._fields[field].value);
            else
                fieldValue = item._fields[field].value;
            fieldData.variables[item._fields[field].name] = fieldValue;

        }
        return fieldData;
    }

    function getGuideItems(cartname) {
        var items = [];
        var item;
        for (var i = 0; i < $scope.includedItems.length; i++) {
            if ($scope.includedItems[i].included) {
                item = getFieldsData($scope.includedItems[i]);
                item.sysparm_id = item.sysparm_active = $scope.includedItems[i].sys_id;
                item.sysparm_quantity = $scope.includedItems[i].quantity;
                item.sysparm_cart_name = cartname;
                item.sysparm_item_guid = $scope.includedItems[i].sysparm_item_guid;
                items.push(item);
            }
        }
        return items;
    }

    /* ******************************************************************************************* */
    /* *******************************          UTIL Functions End           ********************* */
    /* ****################################################################################******* */
    /* ******************************************************************************************* */
    /* *******************************           Submit Handlers             ********************* */
    /* ****################################################################################******* */

    $scope.triggerAddToCart = function () {
        clearCabrilloBottomButtons();
        if ($scope.conflictingCartDomainMsg) {
            spUtil.addErrorMessage($scope.conflictingCartDomainMsg);
            return;
        }
        if ($scope.submitted)
            return;
        $scope.server.get({
            action: 'log_request',
            itemDetails: {
                sys_id: $scope.data.sc_cat_item.sys_id,
                name: $scope.data.sc_cat_item.name,
                sys_class_name: $scope.data.sc_cat_item.sys_class_name
            }
        });
        $scope.submitted = true;
        $scope.server.get({
            action: "add_to_cart",
            items: getGuideItems(""),
            sys_id: $scope.data.sys_id
        }).then(function (response) {
            $rootScope.$broadcast("$sp.service_catalog.cart.add_item");
            $rootScope.$broadcast("$sp.service_catalog.cart.update");
            $scope.$emit("$sp.sc_order_guide.add_to_cart");

            if (cabrillo.isNative()) {
                $scope.submitted = true;
                cabrillo.message.showMessage(cabrillo.message.SUCCESS_MESSAGE_STYLE, i18n.getMessage('Items have been added successfully to your cart'));
                $timeout(function () {
                    cabrillo.flowControl.flowEnded();
                    return;
                }, 200);
                return;
            }

            spModal.open({
                message: i18n.getMessage('Items have been added successfully'),
                size: 'sm',
                backdrop: 'static',
                keyboard: false,
                noDismiss: true,
                buttons: [{
                        label: i18n.getMessage('Catalog Home'),
                        cancel: true
                    }, {
                        label: i18n.getMessage('View Cart'),
                        primary: true
                    }
                ]
            }).then(function () {
                $location.search("id=sc_cart");
            }, function () {
                $location.search("id=sc_home");
            });
        });
    }

    // order / create request
    $scope.triggerSubmit = function () {
        clearCabrilloBottomButtons();
        if ($scope.submitted)
            return;

        $scope.server.get({
            action: 'log_request',
            itemDetails: {
                sys_id: $scope.data.sc_cat_item.sys_id,
                name: $scope.data.sc_cat_item.name,
                sys_class_name: $scope.data.sc_cat_item.sys_class_name
            }
        });
        $scope.submitted = true;
        var hasItems = $scope.includedItems.filter(function (item) {
                return item.sys_class_name != 'sc_cat_item_producer';
            }).length > 0;

        if ($scope.data.sys_properties.twostep && $scope.data.sc_cat_item.request_method != "submit") {
            //Required to pass as payload for usage as embeddedWidget
            var embeddedWidgetOptions = {
                "auto_redirect": "true",
                "requested_for_id": "",
                "requested_for_display": ""
            };
            var payload = {
                cart: '' + $scope.data.sys_id,
                itemDetails: {
                    items: getGuideItems('' + $scope.data.sys_id),
                    request_method: $scope.data.sc_cat_item.request_method
                },
                workspaceParams: $scope.data.workspaceParams,
                action: "order_guide"
            };
            for (var embeddedOption in embeddedWidgetOptions) {
                payload[embeddedOption] = c.options[embeddedOption] || embeddedWidgetOptions[embeddedOption];
            }
            $scope.server.get(payload).then(function (response) {
                var orderGuideModalCtrl;
                var unregister = $scope.$on('$sp.service_catalog.cart.cancel_order', function () {
                        orderGuideModalCtrl.close();
                        $scope.submitted = false;
                        $timeout(function () {
                            addCabrilloBottomButtons({
                                title: [i18n.getMessage('Add to Cart'), $scope.submitButtonMsg],
                                fn: [$scope.triggerAddToCart, $scope.triggerSubmit]
                            });
                        });
                    });
                var closeModalOnSubmit = $scope.$on("$sp.service_catalog.cart.submitted", function () {
                        orderGuideModalCtrl.close();
                        $scope.submitted = true;
                    });
                var orderGuideModal = angular.copy(response.data.orderGuideModal);
                orderGuideModal.options.afterOpen = function (ctrl) {
                    orderGuideModalCtrl = ctrl;
                };
                orderGuideModal.options.afterClose = function () {
                    unregister();
                    closeModalOnSubmit();
                    $scope.orderGuideModal = null;
                    orderGuideModalCtrl = null;
                };
                $scope.orderGuideModal = orderGuideModal;
            });
            return $scope.submitted;
        } else {
            $scope.data.action = 'checkout_guide';
            $scope.data.guideItems = getGuideItems('' + $scope.data.sys_id);
            $scope.server.update().then(function (response) {
                $scope.data.action = undefined;
                $scope.data.guideItems = undefined;
                $scope.$emit("$sp.sc_order_guide.submitted", $scope.data.result);
                $scope.submitted = true;
                if ($scope.options.auto_redirect == 'false') {
                    spUtil.addInfoMessage($scope.m.requestSubmitted);
                    return;
                } else {
                    if ($scope.data.result.request_id)
                        $location.search('id=sc_request&is_new_order=true&table=sc_request&sys_id=' + $scope.data.result.request_id);
                    else
                        $location.search('id=requests');

                }
            });
            return $scope.submitted;
        }
    }

    /* ******************************************************************************************* */
    /* *******************************        Submit Handlers End           ********************** */
    /* ****################################################################################******* */

    var catalogUtil = {
        updateGform: function () {
            var g_form = getCurrentGForm();
            if (g_form)
                $scope._atf.expose('g_form', spAtf.augmentForm(g_form));
        },

        addRow: function (fieldId, timeoutInMS) {
            var deferred = $q.defer();
            var g_form = getCurrentGForm();
            if (g_form) {
                if (timeoutInMS <= 0)
                    timeoutInMS = 1000;
                $scope.$broadcast("$sp.sc_multi_row.create_row", fieldId, g_form.getSysId());
                $scope.$on('spModel.gForm.initialized', function (e, gFormInstance) {
                    if (gFormInstance.getSysId() == fieldId)
                        deferred.resolve();
                });
                $timeout(function () {
                    deferred.reject();
                }, timeoutInMS);
            } else
                deferred.reject();
            return deferred.promise;
        },

        navigateToStep: function (num, timeout) {
            var defer = $q.defer();
            var step = parseInt(num) - 1;
            if (Math.abs(step - $scope.guide_step) != 1) {
                defer.reject("Can't navigate to next step");
                return defer.promise;
            }
            if (step > $scope.guide_step)
                $scope.goNext(timeout);
            else {
                $scope.goPrev();
                defer.resolve();
            }
            var cleanup = $scope.$on('$sp.service_catalog.form_submit_failed', function () {
                    cleanup();
                    defer.reject("Can't navigate to next step");
                });
            var cleanup1 = $scope.$on('$sp.service_catalog.form_submitted', function () {
                    cleanup1();
                    defer.resolve("Can navigate to next step");
                });
            return defer.promise;
        },

        validateIncludedList: function (list, stage) {
            var items = list.split(',').reduce(function (obj, item) {
                    obj[item] = false;
                    return obj;
                }, {});
            var included = stage == 1 ? $scope.includedItems : $scope.includedItems.filter(function (item) {
                    return item.included == true;
                });
            if (Object.keys(items).length != included.length)
                return false;
            for (var i = 0; i < included.length; i++)
                if (!items.hasOwnProperty(included[i].sys_id))
                    return false;
            return true;
        },

        openItem: function (item, state, timeoutInMS) {
            if (timeoutInMS <= 0)
                timeoutInMS = 10000;
            var defer = $q.defer();
            if (includedGformInstances[item]) {
                openItemHelper(item, state, defer);
            }
            $scope.$on('spModel.gForm.initialized', function (e, gFormInstance) {
                if (gFormInstance.getSysId() == item) {
                    openItemHelper(item, state, defer);
                }
            });
            $timeout(function () {
                defer.reject();
            }, timeoutInMS);
            return defer.promise;
        },

        getPrice: function () {
            var res = {};
            var item = $scope.includedItems.find(function (itemData) {
                    return itemData.isOpen == true;
                });
            if (item) {
                res.price = item.price;
                res.recurring_price = item.recurring_price;
                res.recurring_frequency = item.recurring_frequency;
            }
            return res;
        },

        getGuidePrice: function () {
            return $scope.price_display;
        },

        addToCart: function () {
            var defer = $q.defer();
            $scope.triggerAddToCart();
            if (!$scope.submitted)
                defer.reject("Can't submit form.");
            else
                defer.resolve();
            return defer.promise;
        },

        submitOrderGuide: function () {
            var defer = $q.defer();
            if ($scope.triggerSubmit()) {
                if ($scope.data.sys_properties.twostep && $scope.data.sc_cat_item.request_method != "submit") {
                    defer.resolve();
                } else {
                    var cleanUp = $scope.$on('$sp.sc_order_guide.submitted', function (o, result) {
                            $timeout(function () {
                                cleanUp();
                                result.single_step = true;
                                defer.resolve(result);
                            }, 10);
                        });
                }
            } else
                defer.reject();
            return defer.promise;
        }
    };

    /* ****************************************************************************************** */
    /* *******************************                ATF End            ************************ */
    /* ****###############################################################################******* */
    /* ****************************************************************************************** */
    /* *******************************            Cabrillo Start         ************************ */
    /* ****###############################################################################******* */

    function clearCabrilloBottomButtons() {
        if (cabrillo.isNative()) {
            cabrillo.viewLayout.setBottomButtons();
        }
    }

    function showCabrilloBottomButtons() {
        if (!cabrillo.isNative())
            return;

        if ($scope.guide_step === 0) {
            addCabrilloBottomButtons({
                title: [$scope.data.msgs.nextMsg],
                fn: [$scope.goNext]
            });
        }

        if ($scope.guide_step === 1) {
            var itemOpened = $scope.includedItems.find(function (item) {
                    return item.isOpen;
                });

            if (itemOpened) {
                $scope.showCancel(itemOpened.sys_id);
            }
        }
    }

    function addCabrilloBottomButtons(buttonDetails) {
        if (cabrillo.isNative()) {
            var buttons = [];
            clearCabrilloBottomButtons();
            switch ($scope.guide_step) {
            case 0:
                buttons = [{
                        title: buttonDetails.title[0],
                        enabled: true,
                        backgroundColor: $scope.data.sys_properties.mobileNativeColor,
                        textColor: '#FFFFFF'
                    }
                ];

                cabrillo.viewLayout.setBottomButtons(buttons, function (buttonIndex) {
                    buttonDetails.fn[buttonIndex]();
                });
                cabrillo.viewLayout.showBackButton();
                break;

            case 1:
                buttons = [{
                        title: buttonDetails.title[0],
                        enabled: true,
                        backgroundColor: '#f7f7f7',
                        textColor: '#000000'
                    }, {
                        title: buttonDetails.title[1],
                        enabled: true,
                        backgroundColor: $scope.data.sys_properties.mobileNativeColor,
                        textColor: '#FFFFFF'
                    }
                ];
                cabrillo.viewLayout.setBottomButtons(buttons, function (buttonIndex) {
                    //Disable next button in choose option if all the items are marked as not included.
                    // however the previous button should still work
                    if (!($scope.submitted || $scope.totalIncluded <= 0) || buttonIndex === 0) {
                        buttonDetails.fn[buttonIndex]();
                    }
                });
                cabrillo.viewLayout.hideBackButton();
                break;

            case 2:
                if ($scope.data.sys_properties.cartEnabled && $scope.showAddToCart) {
                    buttons = [{
                            title: buttonDetails.title[0],
                            enabled: true,
                            backgroundColor: '#f7f7f7',
                            textColor: '#000000'
                        }, {
                            title: buttonDetails.title[1],
                            enabled: true,
                            backgroundColor: $scope.data.sys_properties.mobileNativeColor,
                            textColor: '#FFFFFF'
                        }
                    ];
                    cabrillo.viewLayout.setBottomButtons(buttons, function (buttonIndex) {
                        buttonDetails.fn[buttonIndex]();
                    });
                } else {
                    buttons = [{
                            title: buttonDetails.title[1],
                            enabled: true,
                            backgroundColor: $scope.data.sys_properties.mobileNativeColor,
                            textColor: '#FFFFFF'
                        }
                    ];
                    cabrillo.viewLayout.setBottomButtons(buttons, function (buttonIndex) {
                        buttonDetails.fn[1]();
                    });
                }
                cabrillo.viewLayout.hideBackButton();
                break;
            }
        }
    }

    var mespOpenPopupUnregister = $rootScope.$on("mesp.popup.open", function () {
            // Timeout is to give a better user experience otherwise when this popup opens,
            // the cabrillo buttons will be displayed immediately giving a bad user experience.
            $timeout(function () {
                clearCabrilloBottomButtons();
            });
        });

    var mespClosePopupUnregister = $rootScope.$on("mesp.popup.close", function () {
            // Timeout is to give a better user experience otherwise when this popup opens,
            // the cabrillo buttons will be displayed immediately giving a bad user experience.
            $timeout(function () {
                showCabrilloBottomButtons();
            });
        });

    /* ********************************************************************************************* */
    /* *******************************            Cabrillo End           *************************** */
    /* ****##################################################################################******* */
	
    /**
     * Value displayed in the "For" or "At" form locations when the values are not known or while the form
     * is loading, such as the GlideForm not yet being available.
     * 
     * This would otherwise result in empty displays or errors in the console if the considerations were
     * skipped.
     * @property waitingValue
     * @type String
     */
    var waitingValue = "[ Waiting... ]";
    
    /**
     * Maps values for display purposes that have been stored for preservation.
     * 
     * This is used to keep values in place after "goNext" is called to 
     * @property locakedValues
     * @type Object
     */
    var lockedValues = {};
    
	/**
	 * Retrieves the employee name from the glide form using the "getDisplayValue" method and parses
	 * the username from the string if one is determined to be present. The presence of a "-" character
	 * is used to determine this.  
	 * 
	 * Due to different variables being used to store the employee depeneding on access type, the type
	 * is read and used to determine the name to use with a general fall back on various naming conventions
	 * to isolate the name in a general case should variables change.
	 * 
	 * The general fallback fails however as values are not (and likely should not) clear when the access
	 * type changes, meaning a name could become "stuck" displaying in the event the access type changes
	 * if this has not been updated with the map of "access type" to "variable used for employee name".
	 * 
	 * However it would be recommended to consolidate the usage fo variables to one variable representing
	 * the employee for any access type, and that variable is assumed to be "requested_for" in the code
	 * below, and assignment priority is given to that variable name where considerations are made.
	 * 
	 * Uses the private {{crossLink "localGlideForm"}}{{/crossLink}} value for gathering values.
	 * @method getEmployeeName 
	 * @return {String} The Employee name per the localized GlideForm.
	 */
	$scope.getEmployeeName = function() {
		var localGlideForm = $scope._glideForms[$scope.data.sys_id],
			index,
			type,
			name,
			hide;
		
		
		if(localGlideForm || $scope.primaryGlideForm) {
			localGlideForm = localGlideForm || $scope.primaryGlideForm;
			type = localGlideForm.getDisplayValue("access_request_main");

			// Isolate Name by Access Type
			switch(type) {
				case "delete":
					name = localGlideForm.getDisplayValue("employee_terminated");
					break;
				case "transfer":
				case "modify":
					name = localGlideForm.getDisplayValue("employee_name");
					break;
				case "add":
					name = localGlideForm.getDisplayValue("e_first_name") + " " + localGlideForm.getDisplayValue("e_last_name")
					break;
				default:
					name = localGlideForm.getDisplayValue("requested_for") || localGlideForm.getDisplayValue("employee") || localGlideForm.getDisplayValue("employee_name") || localGlideForm.getDisplayValue("employee_terminated") || localGlideForm.getDisplayValue("u_requested_for") || localGlideForm.getDisplayValue("u_requested_for") || localGlideForm.getDisplayValue("u_employee") || localGlideForm.getDisplayValue("u_employee_terminated");
			}
			
			if(name && typeof(name) === "string") {
				// Clean Username from Name string
				index = name.indexOf(" - ");
				if(index !== -1) {
					name = name.substring(index + 3);
				}
				name = name.trim();
				hide = name.toLowerCase();
				if(name && hide !== "hideme" && hide !== "deme") { // Handle odd initialization cases
					return name;
				}
			}
		}
		
		return waitingValue;
	};
	
	/**
	 * Retrieves the name of the location from the glide form using "getDisplayValue".  
	 * 
	 * Uses the private {{crossLink "localGlideForm"}}{{/crossLink}} value for gathering values.
	 * @method getLocationName 
	 * @return {String} The name of the Location per the localized GlideForm.
	 */
	$scope.getLocationName = function() {
		var localGlideForm = includedGformInstances[$scope.data.sys_id];
		if(localGlideForm || $scope.primaryGlideForm) {
			localGlideForm = localGlideForm || $scope.primaryGlideForm;
			return localGlideForm.getDisplayValue("location") || waitingValue;
		}
		
		return waitingValue;
	};
}