Loading
轉介行銷
目錄
選取篩選

          沒有結果
          沒有結果
          以下是搜尋小祕訣

          檢查關鍵字的拼字。
          使用較常見的搜尋字詞。
          選取較少篩選條件以擴大您的搜尋。

          搜尋所有 Salesforce 說明
          建立自訂轉介朋友小工具

          建立自訂轉介朋友小工具

          在「轉介促銷」引導式流程上,行銷經理可以變更「轉介朋友」小工具的樣式和文字,但無法新增客戶輸入或自訂小工具狀態。若要自訂業務邏輯或新增元件 (例如行動電話號碼欄位、同意核取方塊或條款和條件),請建立並自訂小工具的 Apex 類別。接著,更新小工具的資料來源,讓「轉介行銷」在使用者存取小工具時使用該類別。

          必要版本

          提供版本:Lightning Experience
          提供版本:具備推薦行銷的 EnterprisePerformanceUnlimitedDeveloper Edition
          1. 使用 範例 Apex 類別程式碼,為小工具建立 Apex 類別
          2. 在 Flexcard 上設定 Apex 遠端資料來源
          3. 從 Flexcard 上的動作更新資料來源

          建立推薦好友小工具的範例 Apex 類別

          範例 Apex 類別,您可以自訂以建立符合您業務需求的自訂小工具。

          
          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());
                  }
                  }
              }
          }
          範例
          範例

          如果您想要在小工具中包含「連絡人」上的自訂欄位,例如「目前城市」,則以下是 Apex 類別的更新片段:

          // 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)

          另請參照:

           
          正在載入
          Salesforce Help | Article