• Stéphane C.
  • NEWBIE
  • 65 Points
  • Member since 2017

  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 28
    Questions
  • 89
    Replies
Hi,

I want to pre-populate a lookup in a screen flow.

Is it possible ? In my case, I have a screen flow on the account page. With it, I want to add a contact on the current account and I don't want to the user input the account in lookup.

Example

Any idea?
Is it possible to change lead status when an email is sent to a contact?

I think a trigger can do it but I don't see how to begin it. Which object do I have to look at with this trigger? EmailMessage don't seem to be the right one.

 
Hi,

We are working on a Lightning Compoenent.

The Lightning Component is working in sandbox and is not working in production .

We are working on Files object. We want to get the Public Image URL of a file.

In sandbox, it's ok we can generate the Public Image URL : https://name--c.eu9.content.force.com/sfc/dist/version/renditionDownload?rendition=ORIGINAL_Jpeg&versionId=0680O000004JrEzQAK&operationContext=DELIVERY&contentId=0690O000004IO6eQAG&page=null&d=/a/0O000000EA1l/bd32wMVmrDm2dHCR_vNo72dedgCdswhUAIMqaqrmbVM&oid=00D9E0000004h7t&dpt=null&viewId=

In production, we have some strange generated ID like the contentID :
https://name--c.eu9.content.force.com/sfc/dist/version/renditionDownload?rendition=ORIGINAL_Jpeg&versionId=0680O000004JrEz&operationContext=DELIVERY&contentId=05T0O00000DWpwv&page=null&d=/a/0O000000EA1q/RsomOyKfQgT.Iml_NVPwKaQZfFlryA2uWlqup9bz5j8&oid=00D0O000000qnI9&dpt=null&viewId=

Is it normal a such behaviour between the sandbox and the porduction ?
Hi,

I use this Lightning Component to upload an attachment. http://sfdcmonkey.com/2017/09/25/file-upload-lightning-component/

I want to display it when it is dwonload.

Any idea to achieve this?
Hi,

I want to upload files to opportunity. Only one file by opportunity. And I want to display the file on the page.

Is it possible?

I try to make some design but I can't see how I can capture the Opportunity ID.

https://help.salesforce.com/articleView?id=vpm_files.htm&type=0

Is it possible to explain me the inputs and the outpouts setup?

Thank you.
Hi,

I want to daily upload a CSV file and its attachments using an externalIDs?

I try to use DataLoader.io but it is not working (at this time) with an externalIDs. It's urgent.

Any other solutions to do it with Salesforce Professionnal?

Thank you.
Hi,

I want to  copy attachments from an object to another with a visual workflow. I found this source but I need more details.

https://vimeo.com/181552723

Thank you.
Hi,

I want to transform several checkboxes (website) into a multipicklist (salesforce) from Web2Lead entries.

So on my website, I have several checkboxes that I want to process by the Web2Lead and that I want to register in a multipicklist.

What is the best way to do this?

Thank you.
Hi,

How can I change the community group notifications, like welcome message and post message notifications?

I can find it.

Thank.
Hi,

I try to make a quik action and a lightning component to create a quote :

Component.CMP
<aura:component controller="QuickQuoteController" 
                implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">

    <aura:attribute name="opportunity" type="Opportunity" />
    <aura:attribute name="newQuote" type="Quote"
        default="{ 'sobjectType': 'Quote' }" />
    
    <!-- default to empty record -->
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <!-- Display a header with details about the opportunity -->
    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.opportunity.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Créer un nouveau devis</h1>
    </div>

    <!-- Display the new quote form -->
     <lightning:input aura:id="quoteField" name="name" label="Name"
                      value="{!v.newQuote.Name}" required="true"/>

    <lightning:input aura:id="quoteField" type="date" name="date" label="Date"
                     value="{!v.newQuote.Date}" required="true"/>
    
    <lightning:button label="Cancel" onclick="{!c.handleCancel}" class="slds-m-top_medium" />
    <lightning:button label="Save Quote" onclick="{!c.handleSaveQuote}"
               variant="brand" class="slds-m-top_medium"/>
    
</aura:component>

Controller.JS
({
    doInit : function(component, event, helper) {

        // Prepare the action to load opportunity record
        var action = component.get("c.getOpportunity");
        action.setParams({"opportunityId": component.get("v.recordId")});

        // Configure response handler
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                component.set("v.opportunity", response.getReturnValue());
            } else {
                console.log('Problem getting opportunity, response state: ' + state);
            }
        });
        $A.enqueueAction(action);
    },

    handleSaveQuote: function(component, event, helper) {
        if(helper.validateQuoteForm(component)) {
            
            // Prepare the action to create the new quote
            var saveQuoteAction = component.get("c.saveQuoteWithOpportunity");
            saveQuoteAction.setParams({
                "quote": component.get("v.newQuote"),
                "opportunityId": component.get("v.recordId")
            });

            // Configure the response handler for the action
            saveQuoteAction.setCallback(this, function(response) {
                var state = response.getState();
                if(state === "SUCCESS") {

                    // Prepare a toast UI message
                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Quote Saved",
                        "message": "The new quote was created."
                    });

                    // Update the UI: close panel, show toast, refresh quote page
                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();
                    $A.get("e.force:refreshView").fire();
                }
                else if (state === "ERROR") {
                    console.log('Problem saving quote, response state: ' + state);
                }
                else {
                    console.log('Unknown problem, response state: ' + state);
                }
            });

            // Send the request to create the new quote
            $A.enqueueAction(saveQuoteAction);
        }
        
    },

	handleCancel: function(component, event, helper) {
	    $A.get("e.force:closeQuickAction").fire();
    }

})

Helper.JS
({
    validateQuoteForm: function(component) {
        var validQuote = true;

        
        // Show error messages if required fields are blank
        var allValid = component.find('quoteField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
        // Verify we have an opportunity to attach it to
        var opportunity = component.get("v.opportunity");
        if($A.util.isEmpty(opportunity)) {
            validOpportunity = false;
            console.log("Quick action context doesn't have a valid opportunity.");
        }

        return(validOpportunity);
	}
    }
})

Controller.APXC
public with sharing class QuickQuoteController {

    @AuraEnabled
    public static Opportunity getOpportunity(Id opportunityId) {
        // Perform isAccessible() checks here
        return [SELECT Name FROM Opportunity WHERE Id = :opportunityId];
    }
    
    @AuraEnabled
    public static Quote saveQuoteWithOpportunity(Quote quote, Id opportunityId) {
        // Perform isAccessible() and isUpdateable() checks here
        quote.OpportunityId = opportunityId;
        upsert quote;
        return quote;
    }

}
I have an issue and I can't find where it comes :
 
Uncaught Action failed: c:quickQuote$controller$handleSaveQuote [validOpportunity is not defined]

markup://c:quickQuote

Object.validateQuoteForm()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:89:9
handleSaveQuote()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:27:19
handleClick()@https://org--dev.lightning.force.com/components/lightning/button.js:1:470

Any idea ?
 
I want to overwrite "New quote" action with Lightning component. I have follow this trailhead (https://trailhead.salesforce.com/fr/projects/workshop-override-standard-action) but I have some errors.

CMP quoteDialog
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >

    <aura:attribute name="picklistValues" type="Object" />
	<c:PicklistValues sObjectName="Quote" fieldName="productFamily__c" picklistValues="{!v.picklistValues}" />

    <lightning:select aura:id="quoteFamily" name="quoteFamily" label="Family">
            <aura:iteration items="{!v.picklistValues}" var="item">
    			<option value="{!item}">{!item}</option>
			</aura:iteration>
    </lightning:select>
	<lightning:button variant="neutral" label="Cancel" />
	<lightning:button variant="brand" label="Submit" />

</aura:component>
I don't think I have to change another thing.
 
Hi,

I try to add the new lightning "picklistPath" component to work order.

I write the code to cmp :
 
<aura:componentimplements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId">
    <force:recordData aura:id="propertyService" recordId="{!v.recordId}"targetFields="{!v.WorkOrder}" layoutType="FULL" mode="EDIT" />
    <div class="slds-card">
        <lightning:picklistPath aura:id="picklistPath" recordId="{!v.recordId}"
            variant="non-linear"
            picklistFieldApiName="Status"
            onselect="{!c.handleSelect}">
        </lightning:picklistPath>
    </div>
</aura:component>

I write this code to js :
 
({
    handleSelect : function (component, event, helper) {
    var stepName = event.getParam("detail")
        .value;
    component.set("v.WorkOrder.Status", stepName);
    component.find("v.propertyService")
        .saveRecord($A.getCallback(function(result) {
            console.log(result.state);
            if (result.state === "SUCCESS" || result.state === "DRAFT")
            {
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    "title": "Success!",
                    "message": "Le statut de l'intervention a été mis à jour à " + stepName + ".",
                    "type": "succes"
                });             
                toastEvent.fire();
            }
        }))
    }
})

I can't find what it is wrong.

I am inspiring from this webinar : https://youtu.be/WsVW5qU4XWI?t=35m24s
Hi,

I have a form on my website to register the participants at a party. It's ok with the users name outside of my domain name but il's not ok for the users inside of my domain name. The employees of the company can register too to the party. 

How to bypass this limitation?

Thank you.
Hi,

I have an issue with this trailhead. I can't update the Salesforce database. I have this message in Heroku Connect : Salesforce update - Igonre.

I can't see where it goes wrong.

Do you have an idea?
Hi,

I try to find some information about the "expiration owner notice" function for a contract but I can't find it.

I can't see if I have to attach to the function something else like a template message, etc.

Somebody use it?
Hi,

I want to attribute a specific user when creating a contract record in visual workflow.

Is it possible? I don't find the way.
Hi,

I have an issue when installing Package RS Documents.
 
Your request to install package "RS Documents 1.954" was unsuccessful. None of the data or setup information in your salesforce.com organization was affected.

If your install continues to fail, contact Salesforce CRM Support through your normal channels and provide the following information.

Organization: --- (---)
User: --- --- (---)
Package: RS Documents (04t0G000000Akgk)
Error Number: 1386120266-126742 (-245508512)
Problem:

1.  Invalid field ContentLocation for SObject ContentVersion
DocumentManager: Invalid field ContentLocation for SObject ContentVersion

2.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentManager: line 248, column 24: Invalid field ContentLocation for SObject ContentVersion
RSDocsAPICtrl: Dependent class is invalid and needs recompilation:
rsdoc.DocumentManager: line 248, column 24: Invalid field ContentLocation for SObject ContentVersion

3.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
AccountGenerateDocument: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

4.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
ContactGenerateDocument: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

5.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
LeadGenerateDocument: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

6.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
OpportunityGenerateDocument: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

7.  Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
GenerateDocument: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

8.  Previous load of class failed: rsdoc.GenerateDocumentController: line 120, column 31: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
ManageBatchMode: Previous load of class failed: rsdoc.GenerateDocumentController: line 120, column 31: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult

9.  Apex class 'rsdoc.RSDocsAPICtrl' does not exist
RSDocsAPI: Apex class 'rsdoc.RSDocsAPICtrl' does not exist

10.  Previous load of class failed: rsdoc.GenerateDocumentController: line 120, column 31: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
TemplateBuilder: Previous load of class failed: rsdoc.GenerateDocumentController: line 120, column 31: Dependent class is invalid and needs recompilation:
rsdoc.DocumentAutomation: line 108, column 70: Invalid type: DocumentManager.GenerateResult
Any idea?
 
Hi,

I am writing an inline visualforce page to update parent records and thier child records.

The visualforce page have a controller :
 
public class inlineDetail {
public List<contact> contactList=new List<contact>();
public List<course__c> courseList=new List<course__c>();

public List<contact> getContacts() {
 contactList=[select name,accountId,phone,AssistantPhone,email, (select name, classroom__c, comments__c from Courses__r) from Contact];
    return contactList;
}

public void saveChanges() {
    update contactList;
    if(!courseList.isEmpty())
        update courseList;
}
    
}
I want to update the parent records and the "comments" child records when they change.

I can't see the way.

Any idea? Thank you!
 
Hi,

I want to display on the same Visualforce page, the "Contact" records and the "Course" records.

I want to display on the same line the name of the student and the courses who is following. If the student is following several courses (n courses) so I want to display n lines (other ideas are welcome). I want to be able to inline edit the records.

I have create a controller :
public class inlineDetail {
public List<contact> acclst=new List<contact>();

public List<contact> getContacts() {
 acclst=[select name,accountid,title,assistantphone,phone,(select name from courses__r) from contact];
      return acclst;
}

public void saveChanges() {
     update acclst;
}
}

And I have create a VisualForce page :
 
<apex:page controller="inlineDetail">
<apex:form >
<apex:pageBlock mode="inlineEdit">
<apex:pageBlockButtons >
<apex:commandbutton value="save" action="{!saveChanges}"/>
</apex:pageBlockButtons>
<apex:pageBlockTable value="{!contacts}" var="c">
<apex:column Headervalue="Nom">
<apex:outputfield value="{!c.name}"/>
</apex:column>
<apex:column headervalue="Téléphone">
<apex:inputfield value="{!c.phone}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>

<apex:relatedList list="Course__r">
<apex:facet name="header">Titles can be overriden with facets</apex:facet>
</apex:relatedList>

</apex:page>

​I cannot see how to make it works together.

Thank you.
Hi,

I want to update opportunity stage from a parent object on a Professional Edition org.

Could you think, it is possible?

I have try by using the Process Builder with no success. Perhaps I have miss something.

Any other idea?

Thank you.
Hi,

I try to make a quik action and a lightning component to create a quote :

Component.CMP
<aura:component controller="QuickQuoteController" 
                implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">

    <aura:attribute name="opportunity" type="Opportunity" />
    <aura:attribute name="newQuote" type="Quote"
        default="{ 'sobjectType': 'Quote' }" />
    
    <!-- default to empty record -->
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <!-- Display a header with details about the opportunity -->
    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.opportunity.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Créer un nouveau devis</h1>
    </div>

    <!-- Display the new quote form -->
     <lightning:input aura:id="quoteField" name="name" label="Name"
                      value="{!v.newQuote.Name}" required="true"/>

    <lightning:input aura:id="quoteField" type="date" name="date" label="Date"
                     value="{!v.newQuote.Date}" required="true"/>
    
    <lightning:button label="Cancel" onclick="{!c.handleCancel}" class="slds-m-top_medium" />
    <lightning:button label="Save Quote" onclick="{!c.handleSaveQuote}"
               variant="brand" class="slds-m-top_medium"/>
    
</aura:component>

Controller.JS
({
    doInit : function(component, event, helper) {

        // Prepare the action to load opportunity record
        var action = component.get("c.getOpportunity");
        action.setParams({"opportunityId": component.get("v.recordId")});

        // Configure response handler
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                component.set("v.opportunity", response.getReturnValue());
            } else {
                console.log('Problem getting opportunity, response state: ' + state);
            }
        });
        $A.enqueueAction(action);
    },

    handleSaveQuote: function(component, event, helper) {
        if(helper.validateQuoteForm(component)) {
            
            // Prepare the action to create the new quote
            var saveQuoteAction = component.get("c.saveQuoteWithOpportunity");
            saveQuoteAction.setParams({
                "quote": component.get("v.newQuote"),
                "opportunityId": component.get("v.recordId")
            });

            // Configure the response handler for the action
            saveQuoteAction.setCallback(this, function(response) {
                var state = response.getState();
                if(state === "SUCCESS") {

                    // Prepare a toast UI message
                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Quote Saved",
                        "message": "The new quote was created."
                    });

                    // Update the UI: close panel, show toast, refresh quote page
                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();
                    $A.get("e.force:refreshView").fire();
                }
                else if (state === "ERROR") {
                    console.log('Problem saving quote, response state: ' + state);
                }
                else {
                    console.log('Unknown problem, response state: ' + state);
                }
            });

            // Send the request to create the new quote
            $A.enqueueAction(saveQuoteAction);
        }
        
    },

	handleCancel: function(component, event, helper) {
	    $A.get("e.force:closeQuickAction").fire();
    }

})

Helper.JS
({
    validateQuoteForm: function(component) {
        var validQuote = true;

        
        // Show error messages if required fields are blank
        var allValid = component.find('quoteField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
        // Verify we have an opportunity to attach it to
        var opportunity = component.get("v.opportunity");
        if($A.util.isEmpty(opportunity)) {
            validOpportunity = false;
            console.log("Quick action context doesn't have a valid opportunity.");
        }

        return(validOpportunity);
	}
    }
})

Controller.APXC
public with sharing class QuickQuoteController {

    @AuraEnabled
    public static Opportunity getOpportunity(Id opportunityId) {
        // Perform isAccessible() checks here
        return [SELECT Name FROM Opportunity WHERE Id = :opportunityId];
    }
    
    @AuraEnabled
    public static Quote saveQuoteWithOpportunity(Quote quote, Id opportunityId) {
        // Perform isAccessible() and isUpdateable() checks here
        quote.OpportunityId = opportunityId;
        upsert quote;
        return quote;
    }

}
I have an issue and I can't find where it comes :
 
Uncaught Action failed: c:quickQuote$controller$handleSaveQuote [validOpportunity is not defined]

markup://c:quickQuote

Object.validateQuoteForm()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:89:9
handleSaveQuote()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:27:19
handleClick()@https://org--dev.lightning.force.com/components/lightning/button.js:1:470

Any idea ?
 
Is it possible to change lead status when an email is sent to a contact?

I think a trigger can do it but I don't see how to begin it. Which object do I have to look at with this trigger? EmailMessage don't seem to be the right one.

 
Hi,

I use this Lightning Component to upload an attachment. http://sfdcmonkey.com/2017/09/25/file-upload-lightning-component/

I want to display it when it is dwonload.

Any idea to achieve this?
Hi,

I want to upload files to opportunity. Only one file by opportunity. And I want to display the file on the page.

Is it possible?

I try to make some design but I can't see how I can capture the Opportunity ID.

https://help.salesforce.com/articleView?id=vpm_files.htm&type=0

Is it possible to explain me the inputs and the outpouts setup?

Thank you.
Hi,

I want to  copy attachments from an object to another with a visual workflow. I found this source but I need more details.

https://vimeo.com/181552723

Thank you.
Hi,

I want to transform several checkboxes (website) into a multipicklist (salesforce) from Web2Lead entries.

So on my website, I have several checkboxes that I want to process by the Web2Lead and that I want to register in a multipicklist.

What is the best way to do this?

Thank you.
Hi,

I try to make a quik action and a lightning component to create a quote :

Component.CMP
<aura:component controller="QuickQuoteController" 
                implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">

    <aura:attribute name="opportunity" type="Opportunity" />
    <aura:attribute name="newQuote" type="Quote"
        default="{ 'sobjectType': 'Quote' }" />
    
    <!-- default to empty record -->
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <!-- Display a header with details about the opportunity -->
    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.opportunity.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Créer un nouveau devis</h1>
    </div>

    <!-- Display the new quote form -->
     <lightning:input aura:id="quoteField" name="name" label="Name"
                      value="{!v.newQuote.Name}" required="true"/>

    <lightning:input aura:id="quoteField" type="date" name="date" label="Date"
                     value="{!v.newQuote.Date}" required="true"/>
    
    <lightning:button label="Cancel" onclick="{!c.handleCancel}" class="slds-m-top_medium" />
    <lightning:button label="Save Quote" onclick="{!c.handleSaveQuote}"
               variant="brand" class="slds-m-top_medium"/>
    
</aura:component>

Controller.JS
({
    doInit : function(component, event, helper) {

        // Prepare the action to load opportunity record
        var action = component.get("c.getOpportunity");
        action.setParams({"opportunityId": component.get("v.recordId")});

        // Configure response handler
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                component.set("v.opportunity", response.getReturnValue());
            } else {
                console.log('Problem getting opportunity, response state: ' + state);
            }
        });
        $A.enqueueAction(action);
    },

    handleSaveQuote: function(component, event, helper) {
        if(helper.validateQuoteForm(component)) {
            
            // Prepare the action to create the new quote
            var saveQuoteAction = component.get("c.saveQuoteWithOpportunity");
            saveQuoteAction.setParams({
                "quote": component.get("v.newQuote"),
                "opportunityId": component.get("v.recordId")
            });

            // Configure the response handler for the action
            saveQuoteAction.setCallback(this, function(response) {
                var state = response.getState();
                if(state === "SUCCESS") {

                    // Prepare a toast UI message
                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Quote Saved",
                        "message": "The new quote was created."
                    });

                    // Update the UI: close panel, show toast, refresh quote page
                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();
                    $A.get("e.force:refreshView").fire();
                }
                else if (state === "ERROR") {
                    console.log('Problem saving quote, response state: ' + state);
                }
                else {
                    console.log('Unknown problem, response state: ' + state);
                }
            });

            // Send the request to create the new quote
            $A.enqueueAction(saveQuoteAction);
        }
        
    },

	handleCancel: function(component, event, helper) {
	    $A.get("e.force:closeQuickAction").fire();
    }

})

Helper.JS
({
    validateQuoteForm: function(component) {
        var validQuote = true;

        
        // Show error messages if required fields are blank
        var allValid = component.find('quoteField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
        // Verify we have an opportunity to attach it to
        var opportunity = component.get("v.opportunity");
        if($A.util.isEmpty(opportunity)) {
            validOpportunity = false;
            console.log("Quick action context doesn't have a valid opportunity.");
        }

        return(validOpportunity);
	}
    }
})

Controller.APXC
public with sharing class QuickQuoteController {

    @AuraEnabled
    public static Opportunity getOpportunity(Id opportunityId) {
        // Perform isAccessible() checks here
        return [SELECT Name FROM Opportunity WHERE Id = :opportunityId];
    }
    
    @AuraEnabled
    public static Quote saveQuoteWithOpportunity(Quote quote, Id opportunityId) {
        // Perform isAccessible() and isUpdateable() checks here
        quote.OpportunityId = opportunityId;
        upsert quote;
        return quote;
    }

}
I have an issue and I can't find where it comes :
 
Uncaught Action failed: c:quickQuote$controller$handleSaveQuote [validOpportunity is not defined]

markup://c:quickQuote

Object.validateQuoteForm()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:89:9
handleSaveQuote()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:27:19
handleClick()@https://org--dev.lightning.force.com/components/lightning/button.js:1:470

Any idea ?