Attaching a Completed DocuSign Document to a Salesforce Standard Object (Not Opportunities) - salesforce

I'm trying to attach a completed DocuSign document to the Contact or Account record that initiated the document (within Notes or Notes & Attachments).
I've found instructions for attaching documents to an Opportunity as well as attaching to custom objects. I've walked through these steps and tried to tailor the instructions for a Contact and Account record but with no success.
Please let me know the steps I can take to accomplish this. Much appreciated!

If you are communicating with docusign via a REST API then you should be receiving a base64 response. You would pass the response body into the 'execute' method below and it should insert to the specified contact and related account. The logic leading up to this would need to query the specific contact and account, but the code here is an example of pulling an existing salesforce ContentVersion and create a new content document from it. Also, you would need to either parse the incoming base64 data to determine the file information (extension, title) or match the extension within the response body. Your go to links would be as follows:
Salesforce Reference- ContentVersion
Salesforce Reference- EncodingUtil
Salesforce Reference- ContentDocumentLink
DocuSign API Docs- Envelopes
Hope this helps!
public with sharing class uploadDocument {
//Build this to accept whatever you need to relate the document to
public Contact ourContact {get; set;}
//Init
public uploadDocument() {
ourContact = [SELECT Id, Name, AccountId FROM Contact LIMIT 1];
}
public static void execute(String base64EncodedDocument){
uploadDocument classObject = new uploadDocument();
String extension;
//Conditional logic will need to be added if you want to handle other file types
if(base64EncodedDocument.contains('pdf')){
extension = 'pdf';
}
//Prep the raw document for insert via the ContentVersion class
Blob base64DecodedDocument = EncodingUtil.base64Decode(base64EncodedDocument);
ContentVersion sfDocumentObject = new ContentVersion();
sfDocumentObject.VersionData = base64DecodedDocument;
sfDocumentObject.Title = 'Our Test Document';
sfDocumentObject.FirstPublishLocationId = classObject.ourContact.Id;
sfDocumentObject.PathOnClient = '//' + sfDocumentObject.Title + '.' + extension;
insert sfDocumentObject;
//Add additional references for the document
List<additionalIdLink> additionalLinks = new List<additionalIdLink>();
additionalIdLink accountLink = new additionalIdLink();
accountLink.linkedId = classObject.ourContact.AccountId;
accountLink.documentId = sfDocumentObject.Id;
additionalLinks.add(accountLink);
linkToAdditionalRecords(JSON.serialize(additionalLinks));
}
//Ignore, just for testing purposes
//I uploaded a document just to test it and everything worked just fine, preview includedS
private static String setupExample(){
ContentVersion ourTestDocument = [SELECT Id, FileExtension, FileType, Title, VersionData, VersionNumber FROM ContentVersion WHERE Title =: 'Getting Started With Salesforce' ORDER BY VersionNumber DESC][0];
String result = EncodingUtil.base64Encode(ourTestDocument.VersionData);
return result;
}
//Ignore, just for testing purposes
public static void executeExample(){
String base64DocumentReceived = setupExample();
execute(base64DocumentReceived);
}
//Quick Access class to pass the previous values to the Future method
public class additionalIdLink{
public String linkedId {get; set;}
public String documentId {get; set;}
}
//Allows you to link to as many additional records as you need. I haven't run into any use cases where you will be adding over 200 links at a time, but it will throw a query exception if you attempt that
#future
public static void linkToAdditionalRecords(String jsonLinks){
List<additionalIdLink> links = (List<additionalIdLink>)JSON.deserialize(jsonLinks, List<additionalIdLink>.class);
List<ContentDocumentLink> result = new List<ContentDocumentLink>();
for(additionalIdLink link : links){
ContentDocumentLink accountLink = new ContentDocumentLink();
String documentId = [SELECT Id, VersionNumber, ContentDocumentId FROM ContentVersion WHERE Id =: link.documentId LIMIT 1].ContentDocumentId;
accountLink.ContentDocumentId = documentId;
accountLink.LinkedEntityId = link.linkedId;
accountLink.ShareType = 'V';
accountLink.Visibility = 'AllUsers';
result.add(accountLink);
}
if(result.size() > 0){
insert result;
}
}
}

Related

I to assign a default account to a custom object using Visualforce page

I am new to salesforce development. I am trying to create a visualforce page which helps to insert a new record into the custom object. Custom object has master-detail relationship with account. I am having issue when assiging a default value to the Account. The account already exists in the accounts table. Here is the Apex class I am trying.
public class RelatedAccount{
public Account parent {get; set;}
public RelatedAccount(ApexPages.StandardController controller){
Transaction__c child = (Transaction__c)controller.getRecord();
if (child.Account__c != null) { parent = [Select ID,Name FROM Account WHERE Account.Name = :'1Company Inc.,' LIMIT 1];
child.Account__c = parent;
}
}}
I am getting the error : "Illegal assignment from Account to Id"
Thanks In advance.
This should work:
child.Account__c = parent.Id
In your case you try to put the "whole" account object object into the Lookup field. But this just needs the Id of the parent account.

Flow: Use new type for variable?

I have a simple new class X which holds some results of a callout to an external system.
In a flow I need a variable of type X. Is there any way to declare a variable of that new type in a flow?
My new class is:
public class FooCalloutResult {
public Boolean success;
public Map<Id, Boolean> results;
public List<String> messages;
public FooCalloutResult() {
success = false;
results = new Map<Id, Boolean>();
messages = new List<String>();
}
}
If you want to get some data in a flow from an apex class you need to have an Process Invocable method - this is done by adding the #InvocableMethod annotation.
Example:
global class lookUpAccountAnnotation {
#InvocableMethod
public static List<String> getAccountIds(List<String> names) {
List<Id> accountIds = new List<Id>();
List<Account> accounts = [SELECT Id FROM Account WHERE Name in :names];
for (Account account : accounts) {
accountIds.add(account.Id);
}
return accountIds;
}
}
With this annotation the class will appear in your list of available elements in the Flow and you need to put the Input and Output that will go into it.
Depending on what kind of operation you want to do you might need to use the Process.plugin interface instead. Please check this article to see which option supports what kind of data to decide on what you need - https://help.salesforce.com/articleView?id=vpm_designer_elements_apex.htm&type=5

Salesforce apex controller extension for custom object and visualforce page

I have 2 custom objects i have created and due to the limitations of salesforce lists and reports i cant get more then 255 characters to be displayed on a long textarea.
Sales_Trip__c
- Name - string
- Date_From - date
- Date_To - date
- Salesman - lookup User
Sales_Trip_Visit__c
- Sales_Trip - master-detail
- Account - master-detail
- Notes - Long Textarea
- Date - date
so i'm trying to create a new visualforce page that displays the sales_trip_visit__c's in a table ordered by Sales_Trip_Visit__c.Date
I have the page working using the Sales_Trip__c standard controller
But that returns the visits unordered.
From what i can tell i cant do that within the page so i am attempting to create an extension for the Sales_Trip__c standard controller that has a method that returns a list of visits ordered by the date.
This is what i have so far and i think i'm not doing something right.
public class mySalesTripControllerExtension {
private final Sales_Trip__c satr;
public mySalesTripControllerExtension(ApexPages.StandardController stdController) {
this.satr = (Sales_Trip__c)stdController.getRecord();
}
public List<Sales_Trip_Visits__c> getVisitList() {
con = new List<Sales_Trip_Visits__c>();
con = [SELECT Date, Account.Name, Notes FROM Sales_Trip_Visits__c WHERE Sales_Trip__c.id = :this.satr.id ORDER BY Date]
return con;
}
}
I'm getting the following error but i think I am doing it completely wrong.
Error: Compile Error: sObject type 'Sales_Trip_Visits__c' is not supported. If you are attempting to use a custom object, be sure to append the '__c' after the entity name. Please reference your WSDL or the describe call for the appropriate names. at line 18 column 15
Thanks for the help this is now my revised code. and i have kept the nameing convention i am using which is a duplicate custom object same fields / same relationships just a different name ( original had a rich textarea. _2 has a long textarea
public class mySalesTripControllerExtension {
private final Sales_Trip__c satr;
// The extension constructor initializes the private member
// variable acct by using the getRecord method from the standard
// controller.
public mySalesTripControllerExtension(ApexPages.StandardController stdController) {
this.satr = (Sales_Trip__c)stdController.getRecord();
}
public List<Sales_Trip_Visit_2__c> getVisitList() {
Sales_Trip_Visit_2__c con = [SELECT Date__c, Account__r.Name, Notes__c FROM Sales_Trip_Visit_2__c WHERE Sales_Trip__r.Id = :satr.id ORDER BY Date__c];
return con;
}
}
Current error.
Error: Compile Error: Return value must be of type: LIST<Sales_Trip_Visit_2__c> at line 16 column 9
First of all you can make a sorting on a page but you will have to use some javascript for it. A better approach would be as you're doing to make the sorting on the controller side.
You making it right overall except the error i mentioned in a comment.
Here is modified code
public List<Sales_Trip_Visits__c> getVisitList() {
Sales_Trip_Visits__c con = [SELECT Date__c, Account__r.Name, Notes__c FROM Sales_Trip_Visits__c WHERE Id = :satr.id ORDER BY Date__c]
return con;
}

Salesforce (SFDC) - public, static, global keywords - use one list for entire class?

I'm having a hard understanding using public, static, and global keywords with my variables and methods.
Below is a snippet of my code. What I'm trying to do is upon page load, in my constructor create a Set of accountIDs that the user has access to (8-33 this is working). This set will be used to filter queries used in later methods.
What I'm finding is that public pageReference runSearch() has access to 'terrAccSet', but the public static List getsearchAccounts does not have access to it.
If I change it to public static Set terrAccSet, I don't get data in either of the system.debugs - what can I do?
global with sharing class MyClass {
public static List<FRM_Metrics_gne__c> accountSearchGmap {get; set;}
public Set<Id> terrAccSet;
public List<String> terrIdList;
//Constructor
public MyClass() {
terrAccSet = new Set<Id>();
terrIdList = new List<String>();
Set<Id> grpIdSet = new Set<Id>();
Id uid = '00570000001R95e'; //member of TWO territories
//UserTerritory Utid = [SELECT TerritoryId FROM UserTerritory where UserId = :userInfo.getUserId()];
List<UserTerritory> Utid = [SELECT TerritoryId FROM UserTerritory where UserId =: uid ];
for(UserTerritory usrTerr: Utid){
terrIdList.add(usrTerr.TerritoryId);
}
List<Group> grp = [Select Id from Group where RelatedID IN :terrIdList];
for (Group eachgroupd : grp ){
grpIdset.add(eachgroupd.Id);
}
List<AccountShare> accountidList = [SELECT AccountId,UserOrGroupId FROM AccountShare where UserOrGroupId in :grpIdset];
//all accounst that the user has access according to territory hiearchy
for(AccountShare eachas:accountidList ){
terrAccSet.add(eachas.AccountId);
}
}
public PageReference runSearch() {
//Has Data
system.debug('**terrAccSet runSearch** '+terrAccSet);
}
public static List<Custom_Object__c> getsearchAccounts(String multiSearchString) {
//terrAccSet variable is missing
system.debug('**terrAccSet getSearchAccounts** '+terrAccSet);
//logic
return accountSearchGmap;
}
}
Below is a snippet of my code. What I'm trying to do is upon page load, in my constructor create a Set of accountIDs that the user has access to (8-33 this is working). This set will be used to filter queries used in later methods.
This set should be an instance property, not static.
Use static when you want to create a method that does not affect the state of a controller or class, eg. a text parser-text in text out.
You should make the class Global if you want to create a package and make your class available outside your package so that other Apex code can invoke it, or if your class will create webService or REST methods to be exposed.
Public should be used to expose properties to the VisualForce pages that will consume the properties. Otherwise, use Private methods and properties for controller side only processing.
public static List getsearchAccounts(String multiSearchString) {
//terrAccSet variable is missing
system.debug('terrAccSet getSearchAccounts '+terrAccSet);
//logic
return accountSearchGmap;
}
This method should not be static because it accesses an instance property (it reads state).
Simple rule of thumb, if it is a visualforce page + controller, you shouldn't need anything static to do your normal work of querying the database and returning data to the page.

What is the SOQL to get all Public Calendars, in a Salesforce instance?

Does anyone know how to perform a query to get all public calendars? You can see the list by going to Setup ... Customize ... Activities .. Public Calendars and Resources
What are these calendar objects?
My goal is to find a way to show these calendars in a VisualForce page to make it easier for users to find them.
If you run a .getSobjectType() on the ID it comes up as a calendar object. When you try and query that object it says it's not available. It looks like the custom setting is the only route for now.
As near as I can tell, Salesforce hasn't directly exposed the Public Calendar object for customers to query directly.
Public Calendars seem to fall into the 023 namespace, which is a standard object, but I can't find any object in the Schema that have that namespace, which leads me to believe that SFDC has hidden them from us.
If you want to show the list in Visualforce, you could use a workaround using the PageReference GetContent() method on the Calendar page and then fetch the details from the html.
Note that this won't work in APEX triggers..
Public Class CalendarResource{
public Id crId {get;set;}
public String label {get;set;}
public String type {get;set;}
}
Pagereference r = new PageReference('/_ui/common/data/LookupResultsFrame?lkfm=swt&lknm=cal&lktp=023&cltp=resource&lksrch=#');
String html = r.getContent().toString();
List<CalendarResource> cals = new List<CalendarResource>();
Matcher m = Pattern.compile('lookupPick\\(\'swt\',\'cal_lkid\',\'cal\',\'\',\'(.*?)\',\'(.*?)\',\'\',\'\'\\)">(.*?)</a></TH><td class=" dataCell ">(.*?)<\\/td><\\/tr>').matcher(html);
//While there are labels
while (m.find()) {
//system.debug(m.group(3));
//system.debug(m.group(4));
CalendarResource cr = new CalendarResource();
cr.crId = m.group(1);
cr.label = m.group(2);
cr.type = m.group(4);
cals.add(cr);
}
for(CalendarResource cr : cals){
system.debug(cr.crId+'__'+cr.label+'___'+cr.type);
}
You can do this in the current API version by: "SELECT Id,Name FROM Calendar where Type='Resource'

Resources