Skip to content

Instantly share code, notes, and snippets.

@dhoechst
Created November 18, 2021 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhoechst/4d465f5a1b59856a4c2b5ca1eba28ec7 to your computer and use it in GitHub Desktop.
Save dhoechst/4d465f5a1b59856a4c2b5ca1eba28ec7 to your computer and use it in GitHub Desktop.
Salesforce CPQ Submit Quote Page that prevents multiple submits
public with sharing class QuoteApprovalController {
private SBQQ__Quote__c sbQuote;
ApexPages.StandardController qtController;
public SBAA__Approval__c[] approvals {
get {
if (approvals == null) {
approvals = SBAA.ApprovalAPI.preview(
sbQuote.Id,
SBAA__Approval__c.Quote__c
);
}
return approvals;
}
set;
}
public Boolean isReadyForApproval { get; set; }
public QuoteApprovalController(ApexPages.StandardController stdController) {
this.qtController = stdController;
this.sbQuote = (SBQQ__Quote__c) stdController.getRecord();
// you can do some checks here to make sure all prerequisites are met to submit
isReadyForApproval = true;
}
public PageReference onSubmit() {
if (sbQuote != null) {
if (qtController.save() == null) {
return null;
}
SBAA.ApprovalAPI.submit(sbQuote.Id, SBAA__Approval__c.Quote__c);
}
PageReference pr = qtController.view();
pr.setRedirect(true);
return pr;
}
public PageReference onRecall() {
if (sbQuote != null) {
SBAA.ApprovalAPI.recall(sbQuote.Id, SBAA__Approval__c.Quote__c);
}
return qtController.view();
}
}
<apex:page standardController="SBQQ__Quote__c" extensions="QuoteApprovalController" title="Submit Quote for Approval" lightningStylesheets="true">
<apex:outputPanel id="messages">
<apex:pageMessages />
</apex:outputPanel>
<apex:form >
<apex:pageBlock title="Submit Quote for Approval">
<apex:pageBlockSection columns="1" collapsible="false" title="Quote Information" id="quoteInfo">
<apex:outputField value="{!SBQQ__Quote__c.Name}" />
</apex:pageBlockSection>
<apex:pageBlockButtons location="bottom">
<apex:actionStatus id="saveStatus">
<apex:facet name="stop">
<apex:commandButton value="Submit" action="{!onSubmit}" rendered="{!isReadyForApproval}" rerender="messages" status="saveStatus"
/>
</apex:facet>
<apex:facet name="start">
<apex:commandButton value="Saving..." status="saveStatus" disabled="true" rerender="messages" />
</apex:facet>
</apex:actionStatus>
<apex:commandButton value="Cancel" action="{!cancel}" immediate="true" />
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
<apex:pageBlock title="Approval Preview">
<sbaa:approvalPreview approvals="{!approvals}" />
</apex:pageBlock>
</apex:page>
@DanielRbCt
Copy link

would you have a test class model of this apex class?

@dhoechst
Copy link
Author

would you have a test class model of this apex class?

No, I don't have access to the org where I had this code. You'll have to create a quote (which might also mean you need to create an account and opportunity) and then pass that quote into the controller. You may also need to create an approval rule. Then you can call onSubmit and onRecall and assert that the quote was submitted for approval.

@DanielRbCt
Copy link

but I'm getting an error that persists, would you have any idea to remedy this error:

System.QueryException: Invalid id field: null
(System Code)
Class.QuoteApprovalController.onSubmit: line 40, column 1
Class.QuoteApprovalControllerTest.testSubmit: line 29, column 1

`public with sharing class QuoteApprovalController {

public SBQQ__Quote__c sbQuote;

ApexPages.StandardController qtController;

@TestVisible
public SBAA__Approval__c[] approvals {
    get {
        if (approvals == null) {
            approvals = SBAA.ApprovalAPI.preview(sbQuote.Id, SBAA__Approval__c.Quote__c);
        }
        return approvals;
    }
    set;
}

public Boolean isReadyForApproval { get; set; }

public QuoteApprovalController(ApexPages.StandardController stdController) {
    this.qtController = stdController;
    this.sbQuote = (SBQQ__Quote__c) stdController.getRecord();

    // você pode fazer algumas verificações aqui para garantir que todos os pré-requisitos sejam atendidos para enviar

    String statusCotacao = sbQuote.ApprovalStatus__c;

    if (statusCotacao == 'Pending' || statusCotacao == 'Approved') {
        isReadyForApproval = false;
    } else {
        isReadyForApproval = true;
    }
}

public PageReference onSubmit() {
    if (sbQuote != null) {
        if (qtController.save() == null) {
            return null;
        }
        SBAA.ApprovalAPI.submit(sbQuote.Id, SBAA__Approval__c.Quote__c);
    }

    List<SBAA__Approval__c> updateAprovacao = new List<SBAA__Approval__c>();
    List<SBAA__Approval__c> ultimaAprovacao = [
        SELECT Id, Comentario_do_Solicitante__c, Additional_Disc__c, sbaa__Status__c
        FROM SBAA__Approval__c
        WHERE Quote__c = :sbQuote.Id
        AND sbaa__Status__c IN ('Assigned', 'Requested')
    ];

    if (!ultimaAprovacao.isEmpty()) {
        for (SBAA__Approval__c item : ultimaAprovacao) {
            item.Comentario_do_Solicitante__c = sbQuote.Comentario__c;
            item.Additional_Disc__c = sbQuote.SBQQ__CustomerDiscount__c;
            updateAprovacao.add(item);
        }

        update updateAprovacao;
        System.debug('updateAprovacao >> ' + updateAprovacao);
    }

    PageReference pr = qtController.view();
    pr.setRedirect(true);
    return pr;
}

public PageReference onRecall() {
    if (sbQuote != null) {
        SBAA.ApprovalAPI.recall(sbQuote.Id, SBAA__Approval__c.Quote__c);
    }
    return qtController.view();
}

}
`

`@IsTest
private class QuoteApprovalControllerTest {

@IsTest
static void testSubmit() {
    SBQQ__Quote__c quote = new SBQQ__Quote__c();
    quote.Comentario__c = 'Test Comment';
    quote.SBQQ__CustomerDiscount__c = 10.0;
    quote.ApprovalStatus__c = 'Rejected';
    insert quote;

    SBAA__Approval__c approval1 = new SBAA__Approval__c();
    approval1.Quote__c = quote.Id;
    approval1.sbaa__ApprovalStep__c = 1;
    approval1.sbaa__RecordField__c = 'Quote__c';
    approval1.sbaa__Status__c = 'Assigned';
    insert approval1;

    SBAA__Approval__c approval2 = new SBAA__Approval__c();
    approval2.Quote__c = quote.Id;
    approval2.sbaa__ApprovalStep__c = 1;
    approval2.sbaa__RecordField__c = 'Quote__c';
    approval2.sbaa__Status__c = 'Requested';
    insert approval2;

    Test.startTest();
    ApexPages.StandardController stdController = new ApexPages.StandardController(quote);
    QuoteApprovalController con = new QuoteApprovalController(stdController);
    con.onSubmit();

    List<SBAA__Approval__c> updatedApprovals = [SELECT Comentario_do_Solicitante__c, Additional_Disc__c FROM SBAA__Approval__c WHERE Quote__c = :quote.Id];
    Test.stopTest();

    System.assertEquals('Test Comment', updatedApprovals[0].Comentario_do_Solicitante__c);
    System.assertEquals(10.0, updatedApprovals[0].Additional_Disc__c);
    System.assertEquals('Test Comment', updatedApprovals[1].Comentario_do_Solicitante__c);
    System.assertEquals(10.0, updatedApprovals[1].Additional_Disc__c);
}

@IsTest
static void testRecall() {
    SBQQ__Quote__c quote = new SBQQ__Quote__c();
    insert quote;

    Test.startTest();
    ApexPages.StandardController stdController = new ApexPages.StandardController(quote);
    QuoteApprovalController con = new QuoteApprovalController(stdController);
    con.onRecall();
    quote = [SELECT ApprovalStatus__c FROM SBQQ__Quote__c WHERE Id = :quote.Id LIMIT 1];
    Test.stopTest();

    System.assertEquals('Recalled', quote.ApprovalStatus__c);
}

@IsTest
static void testConstructorWithPendingStatus() {
    SBQQ__Quote__c quote = new SBQQ__Quote__c();
    quote.ApprovalStatus__c = 'Pending';
    insert quote;

    Test.startTest();
    ApexPages.StandardController stdController = new ApexPages.StandardController(quote);
    QuoteApprovalController con = new QuoteApprovalController(stdController);
    Test.stopTest();

    System.assertEquals(false, con.isReadyForApproval);
}

@IsTest
static void testConstructorWithApprovedStatus() {
    SBQQ__Quote__c quote = new SBQQ__Quote__c();
    quote.ApprovalStatus__c = 'Approved';
    insert quote;

    Test.startTest();
    ApexPages.StandardController stdController = new ApexPages.StandardController(quote);
    QuoteApprovalController con = new QuoteApprovalController(stdController);
    Test.stopTest();

    System.assertEquals(false, con.isReadyForApproval);
}

@IsTest
static void testConstructorWithOtherStatus() {
    SBQQ__Quote__c quote = new SBQQ__Quote__c();
    quote.ApprovalStatus__c = 'Rejected';
    insert quote;

    Test.startTest();
    ApexPages.StandardController stdController = new ApexPages.StandardController(quote);
    QuoteApprovalController con = new QuoteApprovalController(stdController);
    Test.stopTest();

    System.assertEquals(true, con.isReadyForApproval);
}

}
`

@dhoechst
Copy link
Author

Hard to say exactly. Why are you creating approval records? I'd think you might need Approval Rule records. You might also be missing some fields when you create your quote.

@DanielRbCt
Copy link

I'm not creating it, I'm updating some fields in the records that were created, you who specialize in Advanced Approvals would have some material to send me, because salesforce's documentation is very weak about the resource

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment