Welcome to Zuora Product Documentation

Explore our rich library of product information

Sample code for creating a custom page

This document provides sample code for creating a custom page in Salesforce using Apex.

PrepareNewQuote.page
<apex:page showHeader="true" sidebar="true" standardController="Opportunity" extensions="PrepareNewQuoteController" action="{!onload}">
    <apex:form >
        <apex:pageMessages id="pageErrors"/>
        <apex:pageBlock rendered="{!!initFailed}">
            <apex:pageBlockSection columns="1" id="accountsection">
                <apex:outputLabel rendered="{!billingAccountList.size != 0}" value="There is one or more Z-Billing Account corresponding to this Salesforce Account." />
                <apex:outputLabel value="Please select the account to use:" style="font-weight:bold"></apex:outputLabel>
                <apex:selectRadio layout="pageDirection" id="accTypeRadio" value="{!selectedAccountType}">
                    <apex:actionSupport event="onclick"  action="{!onSelectAccountType}" reRender="accListRadio, subscriptionSection, pageErrors"/>                      
                    <apex:selectOption itemEscaped="false" itemlabel="New billing account" itemValue="new"  id="new_billingaccount"/>  
                    <apex:selectOption itemEscaped="false" itemLabel="Existing billing account" itemValue="existing" itemDisabled="{!billingAccountList.size == 0}" id="existing_billingaccount"></apex:selectOption>
                </apex:selectRadio>
                <apex:outputPanel id="accListRadio">
                    <apex:selectRadio layout="pageDirection" value="{!selectedAccount}"  style="position:relative;left:5%" rendered="{!selectedAccountType == 'existing' && billingAccountList.size > 0 }">  
                        <apex:actionSupport event="onclick" action="{!onSelectAccount}" reRender="subscriptionSection, pageErrors"/>
                        <apex:selectOptions value="{!billingAccountList}" ></apex:selectOptions>
                    </apex:selectRadio>
                </apex:outputPanel>
            </apex:pageBlockSection>
            <apex:pageBlockSection columns="1" id="subscriptionSection">
                <apex:outputLabel value="Create quote for:" style="font-weight:bold"></apex:outputLabel>
                <apex:selectRadio layout="pageDirection" id="subTypeRadio" value="{!selectedSubscriptionType}" >
                    <apex:actionSupport event="onclick"  action="{!onSelectSubscriptionType}" reRender="existingSubscriptionOptions, pageErrors"/>
                    <apex:selectOption itemEscaped="false" itemLabel="New subscription for this account" itemValue="new"> </apex:selectOption>
                    <apex:selectOption itemEscaped="false" itemLabel="Existing subscription" itemValue="existing"  itemDisabled="{!subscriptionList.size == 0}" rendered="{!selectedAccountType == 'existing'}"></apex:selectOption>                    
                </apex:selectRadio>
                <apex:outputPanel id="existingSubscriptionOptions">
                        <apex:selectList value="{!selectedSubscription}" style="position:relative;left:3%;background:#fbfbd7" size="1" rendered="{!selectedSubscriptionType == 'existing' && subscriptionList.size > 0}">
                            <apex:selectOptions value="{!subscriptionList}"></apex:selectOptions>
                        </apex:selectList>                      
                        <apex:outputPanel style="position:relative;left:5%" rendered="{!selectedSubscriptionType == 'existing' && subscriptionList.size > 0}">
                            <apex:selectRadio style="position:relative;left:5%" layout="pageDirection" value="{!selectedAmendmentType}">
                                <apex:selectOption itemescaped="false" itemLabel="Amend this subscription" itemValue="amend"></apex:selectOption>
                                <apex:selectOption itemescaped="false" itemLabel="Renew this subscription" itemValue="renew" ></apex:selectOption>
                            </apex:selectRadio>
                        </apex:outputPanel>
                </apex:outputPanel>
            </apex:pageBlockSection>
            <apex:pageBlockButtons location="bottom">    
                <apex:commandButton value="Continue" action="{!goNewQuote}"/>
                <apex:commandButton value="Cancel" action="{!cancel}"/>
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>
</apex:page>
====================================================================
PrepareNewQuoteController.cls
public with sharing class PrepareNewQuoteController{
    private Zuora.zApi api = new Zuora.zApi();
    private final Opportunity opp;
    private final String CRMId;
    private final Map <String,List<SelectOption>> cachedSubOptions = new Map <String,List<SelectOption>>();
    public Boolean initFailed                          {get; private set;}
    public String  selectedAccountType                 {get;set;}
    public String  selectedAccount                     {get;set;}
    public String  selectedSubscription                {get;set;}
    public String  selectedSubscriptionType            {get;set;}
    public String  selectedAmendmentType               {get;set;}
    public List<SelectOption> billingAccountList       {get;set;}
    public List<SelectOption> subscriptionList         {get;set;}
    public PrepareNewQuoteController(ApexPages.StandardController controller) {
        this.initFailed = true;
        final String oppId = controller.getId();
        if (null == oppId || '' == oppId) {
            appendErrorMessage('Need to specify the id of opportunity to create a quote.');
            return;
        }      
        final List<Opportunity> oppList = [SELECT Id, Account.Id FROM Opportunity WHERE Id = :oppId limit 1];
        if (oppList.size() != 1) {
            appendErrorMessage('Invalid opportunity specified to create a quote.');
            return;
        }      
        this.opp = oppList[0];
        this.CRMId = this.opp.Account.Id;
        try {
            api.zlogin();
        } catch (Zuora.zAPIException e) {
            appendErrorMessage(e.getMessage());
            return;
        }
        this.initFailed = false;
    }
    public PageReference onload() {
        try {
            this.loadBillingAccountList();
        } catch (Zuora.zAPIException e) {
            appendErrorMessage(e.getMessage());
                        return null;
        }
        return null;
    }
    public PageReference onSelectAccount() {
                try {
                    this.loadSubscriptionList();
                } catch (Zuora.zAPIException e) {
                    appendErrorMessage(e.getMessage());
                    return null;
            }
            return null;
    }
    public PageReference goNewQuote() {
        PageReference  newQuotePage = Page.NewQuote;
        String quoteType = 'New';
        if ('amend' == selectedAmendmentType ) {
            quoteType = 'Amend';
        } else if ('renew' == selectedAmendmentType) {
                    quoteType = 'Renew';
        }
        newQuotePage.getParameters().put('quoteType', quoteType);
        newQuotePage.getParameters().put('billingaccountid', this.selectedAccount);
        newQuotePage.getParameters().put('existsubscriptionid', this.selectedSubscription);
        newQuotePage.getParameters().put('oppid', String.valueOf(this.opp.Id).substring(0,15));
        newQuotePage.setRedirect(true);      
        return newQuotePage;
    }
    public PageReference onSelectAccountType() {
        if ('new' == this.selectedAccountType) {
            this.selectedSubscriptionType = 'new';
        } else {
                        try {
                        this.loadBillingAccountList();
                        } catch (Zuora.zAPIException e) {
                        appendErrorMessage(e.getMessage());  
                        return null;
                        }
            this.selectDefaultAccount();
        }      
        return null;
    }
    private void selectDefaultAccount() {
        if (this.billingAccountList != null && this.billingAccountList.size() > 0) {
            this.selectedAccount = this.billingAccountList[0].getValue();
        }
        this.onSelectAccount();
    }
    public PageReference onSelectSubscriptionType() {
        if ('existing' == this.selectedSubscriptionType) {
                        try {
                        this.loadSubscriptionList();
                        } catch (Zuora.zAPIException e) {
                        appendErrorMessage(e.getMessage());
                        return null;
                }
                this.selectDefaultSubscription();
        }      
        return null;          
    }    
    private void selectDefaultSubscription() {
        if (this.subscriptionList.size() > 0) {
            this.selectedAmendmentType = 'amend';
            this.selectedSubscription = this.subscriptionList[0].getValue();
        }
    }    
    private void loadBillingAccountList() {
        if (this.CRMId == null) return;
        //already queried from Zuora, no need to query again
        if (this.billingAccountList != null)
            return;
        else{
            //query from Zuora and build the billing account picklist
            this.billingAccountList = new List<SelectOption> ();
            String acczoql = 'SELECT AccountNumber, Name FROM Account WHERE Status = \'Active\' AND CrmId LIKE \'' + this.CRMId.substring(0, 15) + '%\'';
            List <Zuora.zObject> acclist;
            try {
                acclist = api.zquery(acczoql);
            } catch (Zuora.zAPIException e) {
                throw e;
            }
            for(Zuora.zObject acc: acclist) {
                String accvalue = (String)acc.getValue('Id');                  
                String acclabel = acc.getValue('Name') +  ', Acct#:' + acc.getValue('AccountNumber');                                    
                SelectOption accso = new SelectOption (accvalue, acclabel);
                this.billingAccountList.add(accso);
            }  
        }
    }    
    //query the subscription from zuora and build the picklist
    private void loadSubscriptionList() {
        this.subscriptionList = new  List<SelectOption>();      
        if (this.selectedAccount == null) return;
        List<SelectOption> suboptionlist = this.cachedSubOptions.get(this.selectedAccount);
        if (suboptionlist != null) this.subscriptionList = suboptionlist;
        else{
            suboptionlist = new List<SelectOption> ();
            String subzoql = 'SELECT Id, Name, ContractEffectiveDate, TermType, Status FROM Subscription WHERE TermType=  \'TERMED\' AND Status = \'Active\' AND AccountId = \'' + this.selectedAccount + '\'';
            List<Zuora.zObject> subscriptionList;
            try {  
                subscriptionList = api.zquery(subzoql);
            } catch (Zuora.zAPIException e) {
                throw e;
            }                    
            for(Zuora.zObject sub : subscriptionList) {
                String subvalue = (String)sub.getValue('Id');
                DateTime cedatetime = (DateTime)sub.getValue('ContractEffectiveDate');              
                String sublabel = (String)sub.getValue('Name') +  ', Status: ' + (String)sub.getValue('Status') +  ', Contract Effective Date: ' +  cedatetime.date().format();
                SelectOption subso = new SelectOption (subvalue,sublabel);
                suboptionlist.add(subso);
            }
            if (suboptionlist.size() > 0){
                this.cachedSubOptions.put(this.selectedAccount, suboptionlist);
                this.subscriptionList = suboptionlist;
            }
        }
    }
    static private void appendErrorMessage(String message) {
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, message));
    }
}

Considerations

  • Order Builder code should be used to get the customer account information from Z-Billing. See Order Builder for more information.

  • The login information should be properly put into the Order Builder configuration and the Z-Billing connection should be configured.

  • The parameter name can be different from the one that is specified in the sample page and controller, but the values must be the same.