Loading
Hänvisningsmarknadsföring
Skapa en egen widget för Hänvisa en vän

Skapa en egen widget för Hänvisa en vän

I det guidade flödet Hänvisningserbjudande kan marknadsföringschefer ändra stil och text för widgeten Hänvisa en vän, men de kan inte lägga till en kundinmatning eller ett eget widgetläge. För att anpassa verksamhetslogiken eller lägga till komponenter—som mobilnummerfält, kryssruta för samtycke eller villkor—skapa och anpassa widgetens Apex klass. Uppdatera sedan widgetens datakälla så att Referral Marketing använder klassen när användare öppnar widgeten.

Versioner som krävs

Tillgängliga i: Lightning Experience
Tillgängliga i: Utgåvorna Enterprise, Performance, Unlimited och Developer med hänvisningsmarknadsföring
  1. Skapa en Apex klass för widgeten genom att använda exempel på Apex klasskod.
  2. Konfigurera en Apex fjärrdatakälla på ett flexkort.
  3. Uppdatera datakällan från en åtgärd på ett flexkort.

Exempel på Apex klass för att skapa en widget för Hänvisa en vän

Ett exempel på en Apex klass som du kan anpassa för att skapa en egen widget som uppfyller dina verksamhetskrav.


global with sharing class WidgetReferAFriend implements System.Callable {
    
    Map<String, String> messages = new Map<String, String>();
        
    global Object call(String action, Map<String, Object> arguments) {
        Map<String, Object> input = (Map<String, Object>)arguments.get('input');
        Map<String, Object> output = (Map<String, Object>)arguments.get('output');
        Map<String, Object> options = (Map<String, Object>)arguments.get('options');     
        
        initMessages(output);
            
        if (action == 'load') {
            return load(input, output, options);
        }
        if (action == 'enrollNew') {
            return enrollNew(input, output, options);
        }
        if (action == 'enrollExisting') {
            return enrollExisting(input, output, options);
        }
        if (action == 'sendMail') {
            return sendMail(input, output, options);
        }
        return null;
    }
    
    private void initMessages(Map<String, Object> output) {
        output.put('errorMessage', null);
        output.put('successMessage', null);
        
        messages.put('GenericError', 'We couldn’t load the widget details. Refresh the page or try again later.');
        messages.put('GenericSuccess', 'Emails sent to your referrals.');
        
        messages.put('InvalidProgramAndPromo', 'We couldn’t get the details of the referral program. Try again or contact your Salesforce admin for help.');
        messages.put('InvalidContactAndMail', 'We couldn’t load the widget details because the specified email ID and contact ID don’t belong to the same Contact record. Specify the email ID and the ID of the same Contact record and try again.');
        messages.put('InvalidContact', 'We couldn’t load the widget because you specified the details of a Contact record that isn’t available in the org. Specify the details of a valid Contact record and try again.');
        messages.put('InvalidUser', 'We couldn’t load the widget because a Contact record isn’t associated with the person viewing the widget. Try again after you associate a Contact record with the user viewing the widget.');
        messages.put('DuplicateMembers', 'We couldn’t load the widget because we found two or more referral program members with the specified details. Specify the details of a unique referral program member and try again.');
        messages.put('NoContactForMail', 'We couldn’t load the widget because the specified email ID doesn’t belong to a contact. Specify the email ID of a contact and try again.');
        messages.put('CannotCreateMember', 'We couldn’t create a member record for the customer. Try again.');
        messages.put('InvalidEmailFormat', 'Enter a valid email address and try again.');
        messages.put('MaxEmailsSent', 'Specify up to 200 email addresses in the referralEmails field and try again.');
        messages.put('DetailsDoNotMatch', 'We couldn’t load the widget because we couldn’t find the details of the contact associated with the specified email ID. Specify another email ID and try again.');
        messages.put('CannotCreateContact', 'We couldn’t create a Contact record for the customer. Try again.');
        messages.put('MissingDetails', 'We couldn’t load the widget because you haven’t specified values for all the required fields. Specify values for all the required fields and try again.');
        messages.put('PromotionNotStarted', 'We couldn’t load the widget because the start date of the promotion associated with the widget is in the future. Specify the code of a promotion that’s currently running and try again.');
        messages.put('PromotionExpired', 'We couldn’t load the widget because the end date of the promotion associated with the widget is in the past. Specify the code of a promotion that’s currently running and try again.');
    }
    
    private Map<String, Object> load(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) {
        Long startTimeInMillis = System.currentTimeMillis();
        String contactId = (String)input.get('contactId');
        String promotionCode = (String)input.get('promotionCode');
        String programName = (String)input.get('programName');
        String emailId = (String)input.get('emailId');
        String userId = (String)input.get('userId');
        String url = (String)input.get('url');

        if (!isUserIdEmpty(userId)) {
            contactId = [SELECT Id, ContactId FROM User
                                  WHERE Id =:userId
                                  WITH SECURITY_ENFORCED LIMIT 1].ContactId;
            if (contactId == null) {
                output.put('errorMessage', messages.get('InvalidUser'));
                output.put('state', 'ErrorState');
                return output;
            }
        }

        Map<String, Object> programAndPromoDetails = validateAndGetProgramAndPromotion(programName, promotionCode);

        if (programAndPromoDetails == null) {
            // Error state. Invalid program or promotion.
            output.put('errorMessage', messages.get('InvalidProgramAndPromo'));
            output.put('state', 'ErrorState');
        } else {
            Map<String, Object> details = validatePromotionDate(programAndPromoDetails);
            if (details.get('errorMessage') != null) {
                output.put('errorMessage', details.get('errorMessage'));
                output.put('state', 'ErrorState');
            }
            else {
                output.put('programId', (String)programAndPromoDetails.get('programId'));
                output.put('programName', programName);
                output.put('promotionId', (String)programAndPromoDetails.get('promotionId'));
                output.put('promotionCode', (String)programAndPromoDetails.get('promotionCode'));
                output.put('startDate', (String)programAndPromoDetails.get('startDate'));
                output.put('endDate', (String)programAndPromoDetails.get('endDate'));
                output.put('refLink', (String)programAndPromoDetails.get('promotionPageUrl'));
                if (!isContactIdEmpty(contactId) || !isEmailIdEmpty(emailId)) {
                    Contact contactRecord = null;
                    // Give precedence to contact id.
                    if (!isContactIdEmpty(contactId)) {
                        List<Contact> contacts = [SELECT Id, FirstName, LastName, Email FROM Contact where Id = :contactId WITH SECURITY_ENFORCED];
                        if (contacts.size() == 1) {
                            // If an email was provided, check if the passed email matches with contact's email.
                            if (isEmailIdEmpty(emailId) || contacts.get(0).Email == emailId) {
                                contactRecord = contacts.get(0);
                            } else {
                                // Error State - Invalid Contact Id and Mail Combination.
                                output.put('errorMessage', messages.get('InvalidContactAndMail'));
                                output.put('state', 'ErrorState');
                            }
                        } else {
                            // Error State - Invalid contact Id
                            output.put('errorMessage', messages.get('InvalidContact'));
                            output.put('state', 'ErrorState');
                        }
                    } else if (!isEmailIdEmpty(emailId)) {
                        List<Contact> contacts = [SELECT Id FROM Contact where Email = :emailId  WITH SECURITY_ENFORCED];
                        if (contacts.size() == 1) {
                            contactRecord = contacts.get(0);
                        } else if (contacts.size() > 0) {
                            // Error State - Duplicate members
                            output.put('errorMessage', messages.get('DuplicateMembers'));
                            output.put('state', 'ErrorState');
                        } else {
                            // Error State - No contact with email address found.
                            output.put('errorMessage', messages.get('NoContactForMail'));
                            output.put('state', 'ErrorState');
                        }
                    }
                    if (contactRecord != null) {
                        output.put('contactId', contactRecord.Id);
                        // Check if the record has a Program Member associated with it.
                        List<LoyaltyProgramMember> loyaltyProgramMembers = [SELECT Id, ReferralCode, MembershipNumber FROM LoyaltyProgramMember where programId = :(String)programAndPromoDetails.get('programId') and contactId = :contactRecord.Id WITH SECURITY_ENFORCED];
                        if (loyaltyProgramMembers.size() != 0) {
                            boolean validMemberPromotionExists = false;
                            for (LoyaltyProgramMember loyaltyProgramMember : loyaltyProgramMembers) {
                                String loyaltyProgramMemberId = loyaltyProgramMember.Id;
                                List<LoyaltyProgramMbrPromotion> loyaltyProgramMemberPromotions = [SELECT Id, LoyaltyProgramMemberId, PromotionId, IsAutoEnrolled, IsEnrollmentActive FROM LoyaltyProgramMbrPromotion where promotionId = :(String)programAndPromoDetails.get('promotionId') and loyaltyProgramMemberId = :loyaltyProgramMemberId WITH SECURITY_ENFORCED];
                                if (loyaltyProgramMemberPromotions.size() != 0 && (loyaltyProgramMemberPromotions.get(0).IsEnrollmentActive || loyaltyProgramMemberPromotions.get(0).IsAutoEnrolled)) {
                                    validMemberPromotionExists = true;
                                    // Show Sharing State
                                    output.put('referralCode', loyaltyProgramMember.ReferralCode);
                                    output.put('promotionCode', (String)programAndPromoDetails.get('promotionCode'));
                                    output.put('state', 'SharingState');
                                    break;
                                }
                            }
                            if (!validMemberPromotionExists) {
                                // Show Enroll State
                                output.put('state', 'EnrollState');
                            }
                        } else {
                            // Show Enroll State
                            output.put('state', 'EnrollState');
                        }
                    }

                } else if (isContactIdEmpty(contactId) && isEmailIdEmpty(emailId)) {
                    // Show Form State
                    output.put('state', 'FormState');
                }

            }
        }
        return output;
    }

    private Map<String, Object> enrollNew(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) {
        Long startTimeInMillis = System.currentTimeMillis();
        String programName = (String)input.get('programName');
        String programId = (String)input.get('programId');
        String promotionCode = (String)input.get('promotionCode');
        String firstName = (String)input.get('firstName');
        String lastName = (String)input.get('lastName');
        String emailId = (String)input.get('emailId');
        Contact contactRecord = null;
        if (!String.isEmpty(promotionCode) && !String.isEmpty(programName) &&  !String.isEmpty(lastName) && !String.isEmpty(emailId)) {
              // set inputs
             ConnectApi.ReferralMemberEnrollmentInput referralMemberEnrollmentInput = new ConnectApi.ReferralMemberEnrollmentInput();
             referralMemberEnrollmentInput.memberStatus = 'Active';
             ConnectApi.MemberPersonAccountInput personAccountInput = new ConnectApi.MemberPersonAccountInput();
             personAccountInput.firstName = firstName;
             personAccountInput.lastName = lastName;
             personAccountInput.email = emailId;
             personAccountInput.allowDuplicateRecords = false;
             referralMemberEnrollmentInput.associatedPersonAccountDetails = personAccountInput;
             try {
                ConnectApi.ReferralMemberEnrolmentOutput referralMemberOutput = ConnectApi.ReferralManagementConnect.enrollReferralMember(programName,
                                                                                                 promotionCode, referralMemberEnrollmentInput);
                 output.put('referralCode', referralMemberOutput.promotionReferralCode.split('-')[0]);
                 output.put('promotionCode', promotionCode);
                 output.put('state', 'SharingState');
             } catch(ConnectApi.ConnectApiException e) {
                 output.put('errorMessage', e.getMessage());
                 output.put('state', 'ErrorState');
             }
        } else {
         // Show Error State - Invalid params.
            output.put('errorMessage', messages.get('MissingDetails'));
            output.put('state', 'ErrorState');
        }
        return output;
    }

    private Map<String, Object> enrollExisting(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) {
        Long startTimeInMillis = System.currentTimeMillis();
        String contactId = (String)input.get('contactId');
        String programId = (String)input.get('programId');
        String promotionId = (String)input.get('promotionId');
        String promotionCode = (String)input.get('promotionCode');
        String programName = (String)input.get('programName');
        if (!isContactIdEmpty(contactId) && !String.isEmpty(promotionCode) && !String.isEmpty(programId)) {
            if (String.isBlank(programName)) {
                List<LoyaltyProgram> programs = [SELECT Name FROM LoyaltyProgram where Id = :programId WITH SECURITY_ENFORCED];
                programName = programs.get(0).Name;
            }

            ConnectApi.ReferralMemberEnrollmentInput referralMemberEnrollmentInput = new ConnectApi.ReferralMemberEnrollmentInput();
            // set inputs
            referralMemberEnrollmentInput.contactId = contactId;
            referralMemberEnrollmentInput.memberStatus = 'Active';
            try {
                ConnectApi.ReferralMemberEnrolmentOutput referralMemberOutput = ConnectApi.ReferralManagementConnect.enrollReferralMember(programName,
                                                                                                promotionCode, referralMemberEnrollmentInput);
                output.put('referralCode', referralMemberOutput.promotionReferralCode.split('-')[0]);
                output.put('promotionCode', promotionCode);
                output.put('state', 'SharingState');
            } catch(ConnectApi.ConnectApiException e) {
                output.put('errorMessage', e.getMessage());
                output.put('state', 'ErrorState');
            }
        } else {
            // Show Error State - Invalid params.
            output.put('errorMessage', messages.get('MissingDetails'));
            output.put('state', 'ErrorState');
        }
        return output;
    }


    private Map<String, Object> sendMail(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) {
        Long startTimeInMillis = System.currentTimeMillis();
        String promotionCode = (String)input.get('promotionCode');
        String referralCode = (String)input.get('referralCode');
        String emails = (String)input.get('emails');
        List<String> emailsList = emails.split(',');

         if (emailsList.size() > 200) {
            output.put('errorMessage', messages.get('MaxEmailsSent'));
            output.put('promotionCode', promotionCode);
            output.put('referralCode', referralCode);
            output.put('state', 'SharingState');
         }

        if (emailsList.size() > 0) {
             ConnectApi.ReferralEventInput reInput = new ConnectApi.ReferralEventInput();
             reInput.eventType = ConnectApi.EventTypeResource.Refer;
             reInput.referralCode = referralCode + '-' + promotionCode;
             reInput.referralEmails = emailsList;
             reInput.joiningDate = date.today();
             reInput.referralAdditionalAttributes = new Map<String, String>();
             try{
                ConnectApi.ReferralEventOutput resp = ConnectApi.ReferralEventConnect.referralEvent(reInput);
                output.put('emails', '');
                output.put('successMessage', messages.get('GenericSuccess'));
            } catch (ConnectApi.ConnectApiException e){
                output.put('errorMessage', e.getMessage());
                output.put('state', 'SharingState');
            }
            output.put('promotionCode', promotionCode);
            output.put('referralCode', referralCode);
        }
        return output;
    }

    private Map<String, Object> validateAndGetProgramAndPromotion(String programName, String promotionCode) {
        List<LoyaltyProgram> programs = [SELECT Id FROM LoyaltyProgram where Name = :programName WITH SECURITY_ENFORCED];
        if (programs.size() != 1) {
            return null;
        }
        List<Promotion> promotions = [SELECT Id, PromotionCode, PromotionPageUrl, StartDate, EndDate FROM Promotion where PromotionCode = :promotionCode AND LoyaltyProgramId = :(String)programs.get(0).Id WITH SECURITY_ENFORCED];
        if (promotions.size() == 0) {
            return null;
        }
        
        Map<String, Object> details = new Map<String, Object>();
        DateTime startDate = DateTime.newInstance(promotions.get(0).Startdate.year(), promotions.get(0).Startdate.month(), promotions.get(0).Startdate.day());
        DateTime endDate = null;
        if (promotions.get(0).EndDate != null) {
            endDate = DateTime.newInstance(promotions.get(0).EndDate.year(), promotions.get(0).EndDate.month(), promotions.get(0).EndDate.day());
        }
        details.put('programId', programs.get(0).Id);
        details.put('promotionId', promotions.get(0).Id);
        if (endDate != null) {
            details.put('endDate', String.valueOf(endDate));
        }
        String pageUrl = promotions.get(0).PromotionPageUrl != null ? promotions.get(0).PromotionPageUrl : '';
        details.put('startDate', String.valueOf(startDate));
        details.put('promotionCode', promotions.get(0).PromotionCode);
        details.put('promotionPageUrl', pageUrl);
        return details;
    }

    private Map<String, Object> validatePromotionDate(Map<String, Object> promotionDetails) {
        Map<String, Object> details = new Map<String, Object>();
        details.put('status', 'valid');
        Date startDate = Date.valueOf((String)promotionDetails.get('startDate'));
        Date endDate = null;
        if (promotionDetails.get('endDate') != null) {
            endDate = Date.valueOf((String)promotionDetails.get('endDate'));
        }
        if (startDate > Date.today()) {
            details.put('errorMessage', messages.get('PromotionNotStarted'));
            details.put('status', 'invalid');
        } else if (endDate != null && endDate < Date.today()) {
            details.put('errorMessage', messages.get('PromotionExpired'));
            details.put('status', 'invalid');
        }
        return details;
    }

    private boolean validateForm(Map<String, Object> input) {
        if (String.isEmpty((String)input.get('lastName')) || String.isEmpty((String)input.get('emailId'))) {
            return false;
        }
        return true;
    }

    private boolean isUserIdEmpty(String userId) {
        return (String.isEmpty(userId) || userId == '{Session.UserId}');
    }

    private boolean isContactIdEmpty(String contactId) {
        return (String.isEmpty(contactId) || contactId == '{Session.ContactId}');
    }

    private boolean isEmailIdEmpty(String emailId) {
        return (String.isEmpty(emailId) || emailId == '{Session.EmailId}');
    }
    
    private boolean isProgramIdEmpty(String programId) {
        return String.isEmpty(programId);
    }
    
    private boolean isPromotionIdEmpty(String promotionId) {
        return String.isEmpty(promotionId);
    }
    
    private boolean isLastNameEmpty(String lastName) {
        return String.isEmpty(lastName);
    }
    
    private boolean isFirstNameEmpty(String firstName) {
        return String.isEmpty(firstName);
    }
    
    private String generateRandomString(Integer len) {
        final String chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        String randStr = '';
        while (randStr.length() < len) {
            Integer idx = Math.mod(Math.abs(Crypto.getRandomInteger()), chars.length());
            randStr += chars.substring(idx, idx+1);
        }
        return randStr;
    }
    
    private LoyaltyProgramMember createMemberFromContact(String contactId, String programId, String promotionId) {
        LoyaltyProgramMember loyaltyProgramMember = new LoyaltyProgramMember();
        loyaltyProgramMember.contactId = contactId;
        loyaltyProgramMember.ProgramId = programId;
        loyaltyProgramMember.EnrollmentDate = date.today();
        loyaltyProgramMember.memberStatus = 'Active';
        boolean memberInsertedSuccessfully = false;
        for (Integer retryAttempt = 0; retryAttempt < 3; retryAttempt++) {
            try {
                loyaltyProgramMember.MembershipNumber = generateRandomString(10);
                INSERT loyaltyProgramMember;
                memberInsertedSuccessfully = true;
                break;
            } catch(Exception ex) {
        
            }
        }
        
        if (memberInsertedSuccessfully) {
            List<LoyaltyProgramMember> loyaltyProgramMembers = [Select Id, ReferralCode, MembershipNumber from LoyaltyProgramMember where membershipnumber = :loyaltyProgramMember.MembershipNumber WITH SECURITY_ENFORCED];
            createEnrollmentTransactionJournal(loyaltyProgramMembers.get(0).Id, programId, promotionId);
            return loyaltyProgramMembers.get(0);
        }
        return null;
    }
    
    private void createEnrollmentTransactionJournal(String memberId, String programId, String promotionId) {
        String jTypeId;
        String jsTypeId;
        String programName;
        List<LoyaltyProgram> lp = [Select Name from LoyaltyProgram where Id = :programId];
        if(lp.size() > 0) {
            programName = lp.get(0).Name;
        }
        List<JournalType> journalTypes = [Select Id from JournalType where Name = 'Referral'];
        if (journalTypes.size() > 0) {
            jTypeId = journalTypes.get(0).Id;
        }
        List<JournalSubType> journalSubTypes = [Select Id from JournalSubType where Name = 'Advocate Enrollment' and JournalType.Name = 'Referral'];
        if (journalSubTypes.size() > 0) {
            jsTypeId = journalSubTypes.get(0).Id;
        }
        TransactionJournal tj = new TransactionJournal();
        tj.JournalTypeId = jTypeId;
        tj.JournalSubTypeId = jsTypeId;
        tj.MemberId = memberId;
        tj.PromotionId = promotionId;
        tj.ActivityDate = datetime.now();
        tj.Status = 'Pending';
        INSERT tj;
        processTransactionJournal(tj.Id, programName);
    }

    private void processTransactionJournal(String transactionJournalId, String programName) {
        Invocable.Action action = Invocable.Action.createStandardAction('runProgramProcessForTransactionJournal');
        action.setInvocationParameter('transactionJournalId', transactionJournalId);
        List<Invocable.Action.Result> results = action.invoke();
        for (Invocable.Action.Result result : results) {
        if (result.isSuccess()) {
            System.debug('Success: Transaction Journal processed successfully.');
        } else {
        System.debug('Error: ' + result.getErrors()[0].getMessage());
        }
        }
    }
}
Exempel
Exempel

Om du vill inkludera ett eget fält i Kontakt, till exempel Aktuell stad, i widgeten, kommer de uppdaterade kodstyckena för Apex klassen:

// In private Map<String, Object> load(...)
// ... (existing code)
        String emailId = (String)input.get('emailId');
        String userId = (String)input.get('userId');
        String url = (String)input.get('url');
        String currentCity = (String)input.get('currentCity'); // <--- ADD THIS LINE (Optional)
// ... (rest of the code)
private Map<String, Object> enrollNew(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) {
        Long startTimeInMillis = System.currentTimeMillis();
        String programName = (String)input.get('programName');
        String programId = (String)input.get('programId');
        String promotionCode = (String)input.get('promotionCode');
        String firstName = (String)input.get('firstName');
        String lastName = (String)input.get('lastName');
        String emailId = (String)input.get('emailId');
        String currentCity = (String)input.get('currentCity'); // ADDED: Get new input
        Contact contactRecord = null;
        if (!String.isEmpty(promotionCode) && !String.isEmpty(programName) &&  !String.isEmpty(lastName) && !String.isEmpty(emailId)) {
              // set inputs
             ConnectApi.ReferralMemberEnrollmentInput referralMemberEnrollmentInput = new ConnectApi.ReferralMemberEnrollmentInput();
             referralMemberEnrollmentInput.memberStatus = 'Active';
             ConnectApi.MemberPersonAccountInput personAccountInput = new ConnectApi.MemberPersonAccountInput();
             personAccountInput.firstName = firstName;
             personAccountInput.lastName = lastName;
             personAccountInput.email = emailId;
             // ADDED: Pass custom field value to the Contact/Person Account object
             personAccountInput.put('Current_City__c', currentCity);
             personAccountInput.allowDuplicateRecords = false;
             // ... (rest of the code)
 
Laddar
Salesforce Help | Article