Article ID: 128642, created on Apr 11, 2016, last review on Apr 11, 2016

This article contains customizations which must be used during the deployment of the Office 365 6.3-6.4 and Azure CSP 1.0-1.1 Applications. These customizations must be applied to the provision Layout Template of your Odin Automation billing Online Store to configure the subdomain form.

Important:

  • Before applying the customizations, make sure that the versions of the Applications used on your installation belong to the versions stated in the KB. To view the versions of the Applications, log in to your control panel and go to Services > Applications.
  • The list of customizations for all versions of the Office 365 and Azure CSP Applications is provided in the KB article https://kb.odin.com/en/127370.

To learn more about the subdomain form, see the following sections:

  • Odin Automation Office 365 Integration Provider's Guide >> Syndication Partner Scenario > Configuring Office 365 Subdomain Form for Odin Automation billing Online Store
  • Odin Automation Office 365 Integration Provider's Guide >> Cloud Solution Provider Scenario > Configuring Office 365 Subdomain Form for Odin Automation billing Online Store
  • Odin Automation Azure CSP Integration Provider's Guide >> Configuring Billing > Configuring Azure CSP Subdomain Form for Odin Automation billing Online Store

To apply the customizations, in ORIGINAL_CODE replace CUSTOMIZATION_CODE_1, CUSTOMIZATION_CODE_2, CUSTOMIZATION_CODE_3, and CUSTOMIZATION_CODE_4 with the content provided below.

Note: ORIGINAL_CODE is an example. The provision Layout Template might be different on your installation.

ORIGINAL_CODE

<!--
  provision.tpl - Office 365 6.3-6.4 and Azure CSP 1.0-1.1
-->

{if $plan.ProvVisibleCount}
CUSTOMIZATION_CODE_1
  <fieldset>
    <legend class="editProv">{$smarty.session.LANG.REQUIRED_PARAMETERS}</legend>

      <table cellspacing="0" cellpadding="0">
      {foreach name=outerorder item=prov_id from=$state->plan.sortedProv}
      {assign var=itemOrderProv value=$plan.Prov[$prov_id]}
        {if $itemOrderProv.statusShow}
CUSTOMIZATION_CODE_2
        <tr>
          <td class="fieldLabel provLabel"><label{if $itemOrderProv.required == 1} class="required"{/if} for="prov_{$itemOrderProv.id}">{$itemOrderProv.name|escape:'html'}</label></td>
          <td class="fieldValue provValue" align="left" id="td__widget__prov_{$itemOrderProv.id}">
            {if $itemOrderProv.readonly}
            <div>{$itemOrderProv.defaultvalue}</div>
            {else}
            <div class="fieldEntry">
              {assign var=itemProvDescr value=$itemOrderProv.description}
              {if !strlen($itemOrderProv.description)}
                {assign var=itemProvDescr value= $itemOrderProv.name}
              {/if}
              {widget name="prov_"|cat:$itemOrderProv.id id="prov_"|cat:$itemOrderProv.id title=$itemProvDescr}
            </div>
            <div class="fieldComment">{if $itemOrderProv.hint && strlen($itemOrderProv.hint)}{$itemOrderProv.hint}{else}{$itemOrderProv.description}{/if}</div>
            {/if}
          </td>
        </tr>
CUSTOMIZATION_CODE_3
        {/if}
      {/foreach}
      </table>

    </legend>
  </fieldset>

CUSTOMIZATION_CODE_4
{/if}

<!--
  end of provision.tpl - Office 365 6.3-6.4 and Azure CSP 1.0-1.1
-->

CUSTOMIZATION_CODE_1

  <!-- beginning of CUSTOMIZATION_CODE_1 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->
  {assign var=officeId value='aps_defaults_o365'}
  {assign var=azureId value='aps_defaults_azure'}
  {assign var=inputId value='visible_azure_subdomain'}
  {assign var=isOfficeDefined value=$officeId|array_key_exists:$plan.Prov}
  {assign var=isAzureDefined value=$azureId|array_key_exists:$plan.Prov}
  {assign var=isAnonymous value=$account->AccountID == 0}
  <!-- end of CUSTOMIZATION_CODE_1 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->

CUSTOMIZATION_CODE_2

        <!-- beginning of CUSTOMIZATION_CODE_2 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->
        {if $itemOrderProv.id == $officeId && !$isAzureDefined && $isAnonymous || $itemOrderProv.id == $azureId }
        <tr>
            <td class="fieldLabel provLabel"><label class="required" for="{$inputId}">{$itemOrderProv.name}</label></td>
            <td class="fieldValue provValue" align="left" id="td__widget__{$inputId}">
                <div class="fieldEntry">
                    <div class="widget widgetRequired" id="widget__{$inputId}" type="o365subdomain" style="white-space:nowrap">
                        <input type="text" name="{$inputId}" id="{$inputId}" title="{$itemOrderProv.name}" onchange="checkDomainName(this)" _required="1" style="text-align:right" />.onmicrosoft.com
                    </div>
                    <div class="widgetWarningMessage" style="color:black; width:500px" id="info__{$inputId}"></div>
                    <div class="widgetWarningMessage" style="color:red; width:500px" id="error__{$inputId}"></div>
                    <div class="widgetWarningMessage" style="color:gray; width:500px" id="hint__{$inputId}">To activate your account in Microsoft cloud, please choose an initial subdomain name. You will be able to add or buy other domains later. The subdomain is mandatory, only Latin letters and numbers are allowed and the length cannot exceed 25 characters.</div>

                    {if $isOfficeDefined && $isAnonymous }
                    <div class="widget widgetRequired" id="widget__prov_{$officeId}" style="white-space:nowrap">
                        <input type="hidden" name="prov_{$officeId}" id="prov_{$officeId}" />
                    </div>
                    <div class="widgetErrorMessage" id="error__prov_{$officeId}"></div>
                    {/if}
                    {if $isAzureDefined}
                    <div class="widget widgetRequired" id="widget__prov_{$azureId}" style="white-space:nowrap">
                        <input type="hidden" name="prov_{$azureId}" id="prov_{$azureId}" />
                    </div>
                    <div class="widgetErrorMessage" id="error__prov_{$azureId}"></div>
                    {/if}
                </div>
                <div class="fieldComment">{$itemOrderProv.description}</div>
            </td>
        </tr>
        <!--  onkeyup="checkDomainName(this)" -->
        <script language=javascript>
            SW.Widget.o365subdomain = function (widget) {
                this.widget = widget;
                this.validationStage = 0;
                var w = this;
                var validateSubdomainNameCharacters = function(field){
                    var fieldValue = field.value.trim();
                    var pat = /[^0-9A-Za-z]/g;
                    if(!pat.test(fieldValue)){
                        return true;
                    }else{
                        var result=fieldValue.match(pat);
                        result
                        var u={};
                        var a =[]
                        for(var i = 0, l = result.length; i < l; ++i){
                            if(u.hasOwnProperty(result[i])) {
                                continue;
                            }
                            a.push(result[i]);
                            u[result[i]] = 1;
                        }
                        throw new SW.FieldError("Only Latin letters and numbers are allowed. The following characters cannot be accepted: " + a.join(" "), field);
                    }
                }
                var validateSubdomainNameLength = function(field){
                    var fieldValue = field.value.trim();
                    if(fieldValue.length > 0 && fieldValue.length < 26){
                        return true;
                    }else{
                        throw new SW.FieldError("The subdomain name should not be longer than 25 characters.", field);
                    }
                }
                var validateDomainAvailability  = function(field){
                    if (field.value.trim().length == 0)
                        return;
                    var infoId = "#info__{$inputId}";
                    switch(w.validationStage){
                        case 0:
                            var subdomain = field.value.trim();
                            var url = "https://login.windows.net/"+subdomain+".onmicrosoft.com/FederationMetadata/2007-06/FederationMetadata.xml";
                            jQuery.getJSON("https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url='" + encodeURIComponent(url) +
                               "'&format=json&callback=?", (function(inValue){
                                   return function(data){
                                       var widget = document.getElementById(field.id);
                                       if(widget.value == inValue)
                                           w.validationStage = data.query.count === 0 ? 3 : 2; w.validateAndRender(w.widget);
                                   }
                               })(subdomain)
                            );
                            w.validationStage = 1;// lack of break is intentional
                        case 1:
                            $(infoId).html("Checking for the subdomain availability...");
                            return false;
                        case 2:
                            $(infoId).empty();
                            throw new SW.FieldError("This subdomain is not available.", field);
                        case 3:
                            $(infoId).css('color', 'green');
                            $(infoId).html("The subdomain is available.");
                            $('#editplan_buttonContinue').removeAttr('disabled');
                            $('#editplan_buttonContinue').fadeTo( "slow" , 1, function() {});
                            {if $isOfficeDefined && $isAnonymous}
                            $('#prov_{$officeId}').val('{ "aps":{ "type":"http://www.parallels.com/Office365/Tenant/1.1" },"subdomain": "'+field.value.trim()+'" }');
                            {elseif $isAzureDefined}
                            $('#prov_{$azureId}').val('{ "aps":{ "type":"http://www.odin.com/app/azure-csp/tenant/1.0" },"domain_prefix": "'+field.value.trim()+'" }');
                            {/if}
                                return true;
                            };
                    }
                    this.customValidators = [validateSubdomainNameLength, validateSubdomainNameCharacters, validateDomainAvailability];
                }
                SW.Widget.o365subdomain.prototype = SW.Widget.text.prototype;
                function checkDomainName(inputElement) {
                    $("#info__{$inputId}").empty();
                    var widget = document.getElementById("widget__{$inputId}");
                    widget.jsValidator.validationStage = 0;
                    SW.Validate.field(inputElement, "widget__{$inputId}");
                }
                $("#{$inputId}" ).keypress(function() {
                    if (event.keyCode == 13) {
                        event.preventDefault();
                    }
                });
                $("#{$inputId}" ).keyup(function() {
                    var subdomainNameControl = $('#{$inputId}').val();
                    var errorField = $("#error__{$inputId}");
                    var infoField = $("#info__{$inputId}");
                    infoField.css('color', 'black');
                    if(subdomainNameControl.length > 0){
                        var nextButton = $('#editplan_buttonContinue');
                        nextButton.attr('disabled','disabled');
                        nextButton.fadeTo( "slow" , 0.1, function() {});
                        infoField.empty();
                        errorField.html("Please type longer subdomain.");
                    }
                    if(subdomainNameControl .length > 1){
                        errorField.empty();
                        infoField.html("Please click here to check the subdomain availability.");
                    }
                });
        </script>
        {/if}
        {if $itemOrderProv.id != $officeId && $itemOrderProv.id != $azureId}
        <!-- end of CUSTOMIZATION_CODE_2 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->

CUSTOMIZATION_CODE_3

        <!-- beginning of CUSTOMIZATION_CODE_3 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->
        {/if}
        <!-- end of CUSTOMIZATION_CODE_3 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->

CUSTOMIZATION_CODE_4

  <!-- beginning of CUSTOMIZATION_CODE_4 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->
  {if $itemOrderProv.id == $azureId && $isAzureDefined}
    <fieldset class="editPlanPeriod">
        <legend class="labelPlanPeriod">Detailed Pricing Information</legend>
        <div id="price_list_error" style="display:none; border-redius: 10px; background-color: #ffe8ea; color: #d92231; padding: 15px;">
            <span id="price_list_error_text"></span>
        </div>
        <div id="price_list"></div>
        <div id="price_list_loading" style="display: none;">
            <span style="padding-left: 30px; display: inline-block; background: #fff url('data:image/gif;base64,R0lGODlhIAAgALMLAI2NjeTk5GVlZby8vPHx8Xh4eKWlpdLS0tHR0Xd3d6SkpP///wAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFFAALACwAAAAAIAAgAAAEZHDJSau9OOvNu/9gKI5kiQmCeaGouhSFxKYLQYwwLNO2LeaxSu/2C1p8riQAwAkEPsulxun0RJkZ6tOKnW6TKoMBg0CMxGJLuSxCjxeDgWRtbr/j8XndhJeDJXl/goOEhYaHghEAIfkEBRQACwAsBwAHABIAEgAABE5wySlLoThbmykA1SYJAvZ94UiW0wliK9u+GdndnWHgE0EsOh3P5wvucMSfkLfwMZmDwS0QwESjGSqVcpUuDgeJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySkBoDhbm6kx1SYVBfZ94UiW0wliK9u+Gdnd3TDgkyAsOh3P5wvucMSfkLfwMZmHw41AwESjGSqVcpUuAgGJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySmNoThbm+kY1SYBAPZ94UiW0wliK9u+Gdnd3XHgU1EsOh3P5wvucMSfkLfwMZmBwE0gwESjGSqVcpUuCASJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySnHoDhbmylC1SYZBvZ94UiW0wliK9u+GdndXRDgEwAsOh3P5wvucMSfkLfwMZkEwi2RwESjGSqVcpUuBAKJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySkRojhbm2kI1SYNA/Z94UiW0wliK9u+GdndHUHgk6IsOh3P5wvucMSfkLfwMZkCwQ0AwESjGSqVcpUuCgWJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySlDoDhbmykh1SYdB/Z94UiW0wliK9u+GdndnSDg0zAsOh3P5wvucMSfkLfwMZmJxE2hwESjGSqVcpUuAACJtsr1gsFi8u0cfkrQnQgAIfkEBRQACwAsBwAHABIAEgAABE5wySkJoThbm6kQ1SYFAfZ94UiW0wliK9u+GdndXVHg03EsOh3P5wvucMSfkLfwMZkAwG0wwESjGSqVcpUuDAaJtsr1gsFi8u0cfkrQnQgAOw==') no-repeat left;">Loading pricing information...</span>
        </div>
    </fieldset>
    <script language=javascript>
        var apsToken = '{$token}';
        var priceConfId = "";
        var priceListName = "priceList";
        var priceListFilterName = priceListName + "-search";
        var priceListTableName = priceListName + "-list";

        var currencyTemplate = "";

        var dataFilter = {
            categories: [],
            regions: {},
            selectedCategory: "",
            selectedRegion: "",
            newRequestRequire: true,
            sort: {
                attribute: "name",
                descending: false
            }
        };

        var dataResources = [];

        var updateError = function(show, text){
            if (show){
                $("#price_list_error").show();
                $("#price_list_loading").hide();
                if (text){
                    $("#price_list_error_text").html('').append(text);
                }
            } else {
                $("#price_list_error").hide();
            }
        };

        var getErrorMessage = function(xhr){
            if (xhr.responseText){
                var errData = JSON.parse(xhr.responseText);
                if (errData && errData.message){
                    return errData.message;
                }
            }
            return xhr.status && xhr.statusText ? "[" + err.status + "] " + xhr.statusText : "Unknown error";
        };

        var addOptionsToSelect = function(select, options){
            var selectedValue = "";
            for(var i = 0; i < options.length; i++){
                var option = options[i];
                var opt = document.createElement("option");
                opt.innerHTML = option.label;
                opt.value = option.value;

                if (option.selected){
                    selectedValue = option.value;
                    opt.selected = "selected";
                }
                select.add(opt);
            }
            return selectedValue;
        };

        var replaceOptionsInSelect = function(select, start, options){
            while (select.length > start){
                select.remove(start);
            }
            return addOptionsToSelect(select, options);
        };

        var onCategoryChange = function(){
            var selectCategory = document.getElementById(priceListFilterName + "-select-category");
            dataFilter.selectedCategory = selectCategory.value;

            var selectRegion = document.getElementById(priceListFilterName + "-select-region");
            var region = replaceOptionsInSelect(selectRegion, 0, dataFilter.regions[selectCategory.value]);
            dataFilter.selectedRegion = region;

            dataFilter.newRequestRequire = true;
        };

        var onRegionChange = function(){
            var selectRegion = document.getElementById(priceListFilterName + "-select-region");
            dataFilter.selectedRegion =  selectRegion.value;
            dataFilter.newRequestRequire = true;
        };

        var createFilterSelect = function(name, options){
            var select = document.createElement("select");
            select.id = priceListFilterName + "-select-" + name;
            addOptionsToSelect(select, options);
            if (name.toLowerCase() === "category"){
                select.onchange = onCategoryChange;
            } else if (name.toLowerCase() === "region"){
                select.onchange = onRegionChange;
            }
            return select;
        };

        var createFilterElement = function(name, namePostfix, options){
            var li = document.createElement("li");
            li.setAttribute("style", "display:inline-block; list-style:none; padding: 1px 0; vertical-align: bottom;");

            var div = document.createElement("div");
            div.setAttribute("style", "display:block;");
            li.appendChild(div);

            var spanName = document.createElement("span");
            spanName.setAttribute("style", "display: block; padding: 5px 20px 0 0; font-weight: bold;");
            spanName.innerHTML = name;
            div.appendChild(spanName);

            var spanElem = document.createElement("span");
            spanElem.setAttribute("style", "display: block; padding: 5px 20px 0 0");
            div.appendChild(spanElem);

            spanElem.appendChild(createFilterSelect(namePostfix, options));

            return li;
        };

        var createFilterButton = function(name, onclick){
            var btn = document.createElement("button");
            btn.className = "buttonContinue SWbutton";
            btn.setAttribute("style", "margin-top: 22px; vertical-align: top;");
            btn.innerHTML = name;
            btn.onclick = function() { onclick(); return false; };
            return btn;
        };

        var getUnspecified = function(){
            return {
                value: "UNSPECIFIED",
                label: "Unspecified"
            };
        };

        var isUnspecified = function(key){
            return key === getUnspecified().value;
        };

        var getUnspecifiedPosibile = function(val){
            return isUnspecified(val) ? getUnspecified().label : val;
        };

        var sortUnspecifiedPosibile = function(a, b){
            if (isUnspecified(a.value)) return 1;
            if (isUnspecified(b.value)) return -1;
            return a.label.localeCompare(b.label);
        };

        var processSummary = function(summary){
            summary.sort(function(a,b){
                return a.name.localeCompare(b.name);
            });

            var selectedCategory = summary[0].name;

            var mapRegions = function(regions){
                if (regions.length === 0) return [];
                var result = [];
                for(var i = 0; i < regions.length; i++){
                    result.push({
                        label: getUnspecifiedPosibile(regions[i]),
                        value: regions[i]
                    });
                }
                return result;
            };

            var specifiedRegions = {};
            var specifiedCategories = [];

            for(var i = 0; i < summary.length; i++){
                var category = summary[i];
                if (specifiedRegions.hasOwnProperty(category.name)){
                    if (specifiedRegions[category.name].length === 0){
                        specifiedRegions[category.name] = mapRegions(category.regions);
                    } else {
                        var addRegions = [];
                        for(var y = 0; y < category.regions.length; y++){
                            var region = category.regions[y];
                            if (specifiedRegions[category.name].indexOf(region) === -1){
                                addRegions.push(region);
                            }
                        }
                        specifiedRegions[category.name] = specifiedRegions[category.name].concat(mapRegions(addRegions));
                        for(var x = 0; x < specifiedRegions[category.name].length; x++){
                            var item = specifiedRegions[category.name][i];
                            item.selected = false;
                        }
                    }
                } else {
                    specifiedRegions[category.name] = mapRegions(category.regions);
                }

                specifiedRegions[category.name].sort(sortUnspecifiedPosibile);
                specifiedRegions[category.name][0].selected = true;

                specifiedCategories.push({
                    label: category.name,
                    value: category.name,
                    selected: category.name === selectedCategory
                });
            }

            dataFilter.categories = specifiedCategories;
            dataFilter.regions = specifiedRegions;
            dataFilter.selectedCategory = selectedCategory;
            dataFilter.selectedRegion = specifiedRegions[selectedCategory][0].value;
        };

        var sortBy = function(param, descending){
            dataFilter.sort.attribute = param;
            dataFilter.sort.descending = descending;
            applySearchFilter();
        };

        var createTableHeaders = function(tr, headers){
            for(var i = 0; i <headers.length; i++){
                var field = headers[i].field;

                var th = document.createElement("th");
                th.setAttribute("style", "border-color: #ccc; border-style: solid; border-width: 1px; padding: 6px 8px; height: 16px; vertical-align: top; background: #ccc; text-align: left;");
                tr.appendChild(th);

                var link = document.createElement("a");
                link.setAttribute("style", "color: #333; text-decoration: underline;");
                link.href = 'javascript: sortBy("' + field + '", ' + (dataFilter.sort.attribute === field ? !dataFilter.sort.descending : false) + ');';
                link.innerHTML = headers[i].value;
                th.appendChild(link);
            }
        };

        var getValueWithCurrency = function(value){
            return currencyTemplate.replace(/\x7bamount\x7d/, value);
        };

        var getFullName = function(name, subcategory){
            return subcategory && !isUnspecified(subcategory) ? subcategory + " / " + name : name;
        };

        var prepareTooltipText = function(tieredRates, unit){
            var caption = "<span><b>Tiered Price per " + unit + "</b></span>";
            var body = "";
            for(var i = 0; i < tieredRates.length; i++){
                var price = tieredRates[i];
                var content = [price.quantity, unit, getValueWithCurrency(price.rate), "each"].join(" ");
                body += "<br/><span>" + content + "</span>";
            }
            return caption + body;
        };

        var renderRate = function(td, resource){
            var value = getValueWithCurrency(resource.rate);
            var spanValue = document.createElement("span");
            spanValue.innerHTML = value;
            td.appendChild(spanValue);

            var img = document.createElement("img");
            img.id = "tiered_rate_" + resource.id;
            img.alt = "tiered_rate";
            img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFRjYxOTQzOTA2OTVFMjExOEM0NDg3M0Q5NDhBMEIxNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGMEJENUM5MjA5N0QxMUUzQTE4NUUwN0U2OTIzQTZEQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGMEJENUM5MTA5N0QxMUUzQTE4NUUwN0U2OTIzQTZEQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkE1NUMzQzFDN0QwOUUzMTE5Q0FFOTkwOEU2M0M5MUIxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkVGNjE5NDM5MDY5NUUyMTE4QzQ0ODczRDk0OEEwQjE0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+UoMalQAAAqNJREFUeNqMkltIFFEYx7+5ZKYrkrurFqZWrvWQeUEUU8qFHgpNC4IerNAtfSjYbhhERRAhumLPhkaBD70EvVnZlYJyLaPWhW3NNDW1XdcdZy8zs5eZ6ZtRF42N+uDH4Vz+3/9/DoewmY7Av8o8zihDAtKJHEcIpA9ppSVZhv8sC2JAdi3P7yI3ieHG+r8JGpATSCKiuTrlK7q8WTOXSpPJOE++9IPNxdFOi1LcBCakJ/dYA0nSNAhuF5D3H4Kuoipr255KsN/uCOK+KqSjshRP3LujsZmgIwEQFuZh7HH/VykSdt569KS4ze/JRk1k+Qq9ZBQTrOI00pt/8hRBBRdAZL0Q5YIQFiU20c82JRAwHY7KEJFkDsVjyHU6KsUSNCN3CpqaCSrgAZELqItJeh1klZWXm8khd0ZJKa3dvhV+jozwuHVOvUJkqUEL0l1saiGoRVdMrJTIeCGrcDfkGPfToncefONOCEvqFWDpDSRZce4uVZw9s2vEKxWaGAWYxMRoFhXCEBFlf6wBduuqwAejXNNxxatL4AVw/XLDPM/3n9duUNeosk060ucYMaZpkoh1FIWZpbgIQQ5mZubgg91hOfP0fdfRnbmC8gmpgYkZW0mmTggseKu1qalqExkFq+FQPD3rBqtj1HLhubX9Qb2RUb6PAtV3aF/o7MC7zyWZWt7PMNW6lBQigSLRVVThUTzl8oDV+a299eVQB55nFOcVqDpDDhzOzwmZnw1+KcrQBn0sa9RrNMR6kgSO42HS44XB0e/tV15/tNyr2RtzjiWozduidqozZIcuvrDaCtPTgqzPZ9QnJRNTDAuDYxNt194Md/YcrFrjHEtQgw3k5Y9dm5cdan01ZCtI3+hfDATKHS535423n7q6D1QyK2f+5LcAAwASwXyvKa2miAAAAABJRU5ErkJggg==";
            img.setAttribute("style", "vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;");

            var tooltipId = "tiered_rate_tooltip_" + resource.id;
            img.onmouseover = function(){
                var div = document.getElementById(tooltipId);
                if (!div){
                    div = document.createElement("div");
                    div.id = tooltipId;
                    div.innerHTML = prepareTooltipText(resource.tiered_rates, formatUnit(resource.unit));
                    div.setAttribute("style", "display: block; margin-left: 30px; padding: 5px; position: absolute; z-index: 1000; background: #ffc; box-shadow: 0 3px 5px rgba(0,0,0,.2);");
                    td.appendChild(div);
                } else {
                    div.style["display"] = "block";
                }
            };
            img.onmouseout = function(){
                var div = document.getElementById(tooltipId);
                if (div){
                    div.style["display"] = "none";
                }
            };
            td.appendChild(img);
        };

        var renderValue = function(prop, resource){
            var value = resource[prop];
            switch (prop) {
                case "name":
                    return getFullName(value, resource.subcategory);
                default:
                    return value;
                case "rate":
                    return getValueWithCurrency(value);
                case "included_quantity":
                    return value + " " + formatUnit(resource.unit);
            }
        };

        var formatUnit = function(unit) {
            if (unit.match(/[\d]/)){ // Unit of measure
                return "(" + unit + ")";
            }
            return unit;
        };

        var getCellStyle = function(type){
            var style = "color: #333; border-color: #ccc; border-style: solid; padding: 6px 8px; height: 16px; vertical-align: top; text-align: left;";
            switch (type) {
                case "first":
                    style += " border-width: 1px 0 1px 1px;";
                    break;
                case "end":
                    style += " border-width: 1px 1px 1px 0;";
                    break;
                case "middle":
                default: 
                    style += " border-width: 1px 0;";
            }
            return style;
        };

        var createTableCells = function(resource, tr, headers){
            for(var i = 0; i < headers.length; i++){
                var field = headers[i].field;
                var td = document.createElement("td");
                td.setAttribute("style", getCellStyle(headers[i].type));

                if (field === "rate" && resource.tiered_rates && resource.tiered_rates.length > 0){
                    renderRate(td, resource);
                } else {
                    td.innerHTML = renderValue(field, resource);
                }
                tr.appendChild(td);
            }
        };

        var createResourceTable = function(tableId, resources){
            var table = document.createElement("table");
            table.id = tableId;
            table.setAttribute("style", "border-color: #ccc; border: 1px solid; border-collapse: collapse; width: 100%; border-spacing: 0; display: table; margin-top: 10px;");

            var tbody = document.createElement("tbody");
            tbody.setAttribute("style", "display: table-row-group; vertical-align: middle; border-color: inherit;");
            table.appendChild(tbody);

            var headersRow = document.createElement("tr");
            headersRow.setAttribute("style", "display: table-row; vertical-align: inherit; border-color: inherit;");
            tbody.appendChild(headersRow);

            var headers = [
                { field: "name", value: "Resource Name", type: "first"},
                { field: "included_quantity", value: "Included", type: "middle"},
                { field: "rate", value: "Price Per Unit", type: "end"}
            ];

            createTableHeaders(headersRow, headers);

            for(var i = 0; i < resources.length; i++){
                var tr = document.createElement("tr");
                tr.setAttribute("style", "display: table-row; vertical-align: inherit; border-color: inherit; background-color: " + ((i & 1)? "#fff;" : "#eee;"));
                createTableCells(resources[i], tr, headers);
                tbody.appendChild(tr);
            }

            return table;
        };

        var getPriceList = function(category, region, callback){
            var priceListQuery = "?category=" + encodeURIComponent(category);
            priceListQuery += "&region=" + encodeURIComponent(region);
            jQuery.ajax({
                url: '/aps/2/resources/' + priceConfId + '/preliminary_price_list' + priceListQuery,
                headers: {
                'APS-Token': apsToken
                }
            }).done(function(data) {
                callback(data);
            }).fail(function(xhr, s, ex) {
                updateError(true, getErrorMessage(xhr));
            });
        };

        var getSortByColumn = function(prop, descending){
            switch (prop) {
                case "name":
                    return function(a,b){
                        return getFullName(a.name, a.subcategory).localeCompare(getFullName(b.name, b.subcategory)) * (descending ? -1 : 1);
                    };
                default:
                    return function(a,b){
                        return a[prop].localeCompare(b[prop]) * (descending ? -1 : 1);
                    };
                case "rate":
                case "included_quantity":
                    return function(a,b){
                        return (a[prop] - b[prop]) * (descending ? -1 : 1);
                    };
            }
        };

        var filterResources = function(resources){
            if (dataFilter.sort){
                var propName = dataFilter.sort.attribute;
                var descending = dataFilter.sort.descending;
                resources.sort(getSortByColumn(propName, descending));
            }
            if (dataFilter.paging){
                var oldResults = resources;
                resources = resources.slice(dataFilter.paging.start, dataFilter.paging.start + dataFilter.paging.count);
                resources.total = oldResults.length;
            }

            return resources;
        };

        var applySearchFilter = function(){
            var divList = document.getElementById(priceListTableName);
            var id = priceListTableName + "-content";
            var content = document.getElementById(id);
            if (content){
                divList.removeChild(content);
            }

            var callback = function(priceList){
                if (priceList.currency && priceList.meters) {
                    currencyTemplate = priceList.currency.pattern.replace(/\x7bsign\x7d/, priceList.currency.symbol);
                    dataResources = priceList.meters;
                    dataFilter.newRequestRequire = false;
                } else {
                    dataResources = priceList;
                }

                var filtered = filterResources(dataResources);
                if (filtered.length > 0){
                    content = createResourceTable(id, filtered);
                } else {
                    content = document.createElement("span");
                    content.innerHTML = "No item(s) found";
                }
                divList.appendChild(content);
                $("#price_list_loading").hide();
                updateError(false);
            }; 

            if (dataFilter.newRequestRequire) {
                $("#price_list_loading").show();
                getPriceList(dataFilter.selectedCategory, dataFilter.selectedRegion, callback);
            } else {
                callback(dataResources);
            }
        };

        var createFilter = function(summary, divId){
            var div = document.getElementById(divId);
            var divBox = document.getElementById(priceListFilterName);
            if (divBox){
                div.removeChild(divBox);
            }

            divBox = document.createElement("div");
            divBox.id = priceListFilterName;
            divBox.setAttribute("style", "padding: 6px 10px 9px; border-style: solid; border-width: 1px; display: block; border-color: #ccc; background: #eee;");

            var form = document.createElement("form");
            form.setAttribute("style", "display:block;");
            divBox.appendChild(form);

            var ul = document.createElement("ul");
            ul.setAttribute("style", "display:inline-block; list-style:none;");
            form.appendChild(ul);

            processSummary(summary);

            ul.appendChild(createFilterElement("Select Category:", "category", dataFilter.categories));
            ul.appendChild(createFilterElement("Select Region:", "region", dataFilter.regions[dataFilter.selectedCategory]));

            form.appendChild(createFilterButton("Search", applySearchFilter));

            div.appendChild(divBox);
        };

        var createTable = function(divId){
            var div = document.getElementById(divId);
            var divList = document.getElementById(priceListTableName);
            if (divList){
                div.removeChild(divList);
            }

            divList = document.createElement("div");
            divList.id = priceListTableName;
            divList.setAttribute("style", "margin-bottom: 10px; width: 100%; overflow-x: auto; overflow-y: hidden;");
            div.appendChild(divList);

            applySearchFilter();
        };

        var createPriceListWidget = function(summary, divId){
            createFilter(summary, divId);
            createTable(divId);
        };

        var processPriceList = function(){
            $("#price_list_loading").show();
            jQuery.ajax({
              url: '/aps/2/resources?implementing(http://www.odin.com/app/azure-csp/application)',
              headers: {
                'APS-Token': apsToken
              }
            }).done(function(data) {
              if (data.length > 0) {
                jQuery.ajax({
                  url: '/aps/2/resources/' + data[0].aps.id + '/price_list_summary',
                  headers: {
                    'APS-Token': apsToken
                  }
                  }).done(function(data) {
                    if (data.length > 0) {
                      processPriceConfiguration(function(){
                        createPriceListWidget(data, "price_list");
                      });
                    }
                  }).fail(function(xhr, s, ex) {
                    updateError(true, getErrorMessage(xhr));
                  });
              }
            }).fail(function(xhr, s, ex) {
              updateError(true, getErrorMessage(xhr));
            });
        };
        var processPriceConfiguration = function(callback){
            jQuery.ajax({
                url: '/aps/2/resources?implementing(http://www.odin.com/app/azure-csp/priceConfiguration)',
                headers: {
                'APS-Token': apsToken
            }
            }).done(function(data) {
              if (data.length > 0) {
                priceConfId = data[0].aps.id;
                callback();
              }
            }).fail(function(xhr, s, ex) {
              updateError(true, getErrorMessage(xhr));
            });
        };
        processPriceList();
    </script>
  {/if}
  <!-- end of CUSTOMIZATION_CODE_4 - Office 365 6.3-6.4 and Azure CSP 1.0-1.1 -->

Email subscription for changes to this article
Save as PDF