You are currently viewing Nâng cấp Journey Builder khi sử dụng Salesforce data với Salesforce Apex

Nâng cấp Journey Builder khi sử dụng Salesforce data với Salesforce Apex

Bạn đã từng nghe đến Journey Builder (JB), công cụ quyền năng giúp bạn dẫn dắt khách hàng đi đúng đường đúng hướng?

Tốt, vậy giờ hãy tưởng tượng nếu ta có thể ra lệnh cho JB khởi động dựa trên hành vi từ một Salesforce record như khi trạng thái của một Case thay đổi, hoặc khi một Lead đạt đủ tiêu chí nào đó. Đó chính là Salesforce Data Entry.

Nghe hấp dẫn rồi đấy. Nhưng mà để mọi thứ chạy mượt như mơ, đôi khi bạn sẽ cần “chơi chiêu” bằng Salesforce Apex. Bài viết này Gâu Đần sẽ chỉ cho bạn cách nâng cấp Journey Builder một cách tinh tế nhưng hiệu quả bằng cách sử dụng SF Apex để điều khiển kịch bản đằng sau cánh gà.

Salesforce data entry source limitation

Đầu tiên, tại sao cần phải “nâng cấp” JB? Chẳng phải vốn dĩ nó được thiết kế để chạy khi có sự thay đổi hoặc khởi tạo record sao?

Quả là như vậy, về việc khởi động JB dựa trên việc khởi tạo record (record creation) thì chẳng có gì phải bàn nhưng nếu criteria là dựa trên sự thay đổi record (Is Updated) thì sẽ gặp vấn đề. Đó chính là record ở object đó trạng thái đầu tiên phải Unqualified đã sau đó được Qualified đúng với điều kiện thì mới đẩy vào journey!

Bạn có thể đọc thêm ở bài Tìm hiểu Salesforce data entry source trong SFMC journey này của Gâu Đần.

The ‘Update’ Action type only injects records that newly meet entry criteria upon evaluation.

Trích Records not injected to Journey Builder from Sales Cloud

Như vậy việc muốn trigger vào journey mà điều kiện trigger dựa trên một field là picklist field sẽ không thành công. Ví dụ: trong object Case, tôi muốn mỗi khi Case status được update thì sẽ được inject vào journey nhưng nếu để criteria là Status equals “Working” OR Status equals “Escalated” OR…. thì các record này đang Qualified với điều kiện đẩy vào journey rồi nên sau khi update nó không đẩy vào nữa.

Cũng trong bài trên, bên Salesforce có đưa ra 02 cách giải quyết:

  1. Dùng một field phụ để làm trigger inject record vào journey. Nhưng làm sao tự động hóa quá trình này thì họ không nói.
  2. Mỗi value từ picklist thì tạo một journey để trigger cho value đó. Vậy picklist có ít value thì còn nghe được, chứ có 10 hay 20 cái mà tạo chừng đó journey thì một sự lãng phí, chưa nói đến việc rời rạc và khó monitor.

Solution design

Dùng một field phụ để làm trigger inject record vào journey vẫn là tối ưu nhất cho trường hợp này.

Case scenario

Mỗi khi Case status thay đổi, tôi dùng Journey Builder để ….. với người dùng

Idea

  1. Tạo một check box field Send_to_Journey__c ở object Case (Salesforce CRM). Khi Send_to_Journey__c = true → Case record được inject vào journey
  2. Tạo Journey Builder (Salesforce Marketing Cloud) ở object Case với criteria là Send_to_Journey__c = true
  3. Vậy cũng tức là mỗi khi Case status ở SF CRM thay đổi thì Send_to_Journey__c phải set bằng true
  4. Nhưng để JB tiếp tục gửi khi Case status tiếp tục thay đổi thì Send_to_Journey__c cần được reset về false

SF Apex sẽ dùng để giải quyết bước 3 và 4.

Let’s make some codes

Phần tạo journey các bạn tự làm nhé! Còn sau đây là phần ở Salesforce CRM

Disclaimer: Mình không phải là SF Apex expert!

Handler Class

Tạo một handler class để kiểm tra status cho thay đổi không, nếu có thì set Send_to_Journey__c = true

public class CaseStatusChangeHandler {
    public static void updateJourneyCheckBox(List<Case> newCaseList, Map<Id,Case> oldCaseMap) {
        for(Case newCase: newCaseList){
            Case oldCase = oldCaseMap.get(newCase.Id);
            if(newCase.Status != oldCase.Status){
                newCase.Send_to_Journey__c = true;
            }
        }

    }
}

Tạo môt handler class để reset Send_to_Journey__c về false

public class CaseSendToJourneyHandler {
    public static void resetSendToJourneyFlag(List<Case> newCases){
        Set<Id> caseIds = new Set<Id>();
        for(Case c: newCases){
            if(c.Send_to_Journey__c == true){
                caseIds.add(c.Id);
            }
        }
        if(!caseIds.isEmpty()){
            resetSendToJourneyAsync(caseIds);
        }
    }
    @future
    private static void resetSendToJourneyAsync(Set<Id> caseIds){
        List<Case> updates = new List<Case>();
        for(Case c: [Select Id, Send_to_Journey__c  From Case Where Id In : caseIds]){
            c.Send_to_Journey__c = false;
            updates.add(c);
        }
        if(!updates.isEmpty()){
            update updates;
        }
    }
}

Giải thích thêm: việc update này phải là Async method tức là nằm trên một transaction riêng. Vì nếu nằm trên một transaction thì Journey (bản chất là flow khi ở trên Salesforce CRM) sẽ không nhận ra.

Chẳng hạn nếu cùng 1 transaction:
Bản chất: status field thay đổi → Send_to_Journey__c = true → Send_to_Journey__c = false
Flow thấy: status field thay đổi → Send_to_Journey__c = false
Vì thế nó sẽ không thấy dữ kiện Send_to_Journey__c = true nên không bắn sự kiện vào vào MC journey

Apex Trigger

trigger CaseTrigger on Case (before insert, before update, after update, after insert) {
    if(Trigger.isBefore && Trigger.isInsert){
        // Do something here
    }
    else if(Trigger.isBefore && Trigger.isUpdate){
        CaseStatusChangeHandler.updateJourneyCheckBox(Trigger.new, Trigger.oldMap);
    }
    else if(Trigger.isAfter && Trigger.isInsert){
        CaseSendToJourneyHandler.resetSendToJourneyFlag(Trigger.new);
    }
    else if(Trigger.isAfter && Trigger.isUpdate){
        CaseSendToJourneyHandler.resetSendToJourneyFlag(Trigger.new);
    }
}

Test Class

@isTest
private class TestCaseStatusChangeHandler {
    @isTest
    static void TestCaseStatusChangeHandler() {
        // Initilize the test data
        List<Case> lstCase = new List<Case>();
        Case c1 = new Case(Priority = 'High', Status = 'New', Send_to_Journey__c = false);
        lstCase.add(c1);
        insert lstCase;
        // Update Case status
        c1.Status = 'Working';
        
        //Perform Test
        Test.startTest();
        update lstCase;
        Test.stopTest();
        
        // Verrify result
        Case updatedCase = [Select Status, Send_to_Journey__c From Case Where Id =: c1.Id];
        System.assertEquals(false, updatedCase.Send_to_Journey__c, 'Send_to_Journey__c should be false after updating the record.');
        System.assertEquals('Working', updatedCase.Status, 'Expect Status to be "Working"');
    }
}
@isTest
private class TestCaseSendToJourneyHandler {
    @isTest
    static void testCreateCase() {
        // Initilize the test data
        List<Case> lstCase = new List<Case>();
        Case c1 = new Case(Origin = 'Email', Priority = 'High', Status = 'New', Send_to_Journey__c = true);
        lstCase.add(c1);
        // Perform the test
        Test.startTest();
        insert lstCase;
        Test.stopTest();
        // Verify the test result
        Case testCase = [Select Id, Send_to_Journey__c From Case where Id = :c1.Id];
        System.assertEquals(false , testCase.Send_to_Journey__c, 'Send_to_Journey__c should be false');
    }

    @isTest
    static void testUpdateCase() {
        // Initilize the test data
        List<Case> lstCase = new List<Case>();
        Case c2 = new Case(Origin = 'Email', Priority = 'High', Status = 'New', Send_to_Journey__c = false);
        lstCase.add(c2);
        insert lstCase;
        
        // Update Case
        c2.Send_to_Journey__c = true;
        // Perform the test
        Test.startTest();
        update lstCase;
        Test.stopTest();
        // Verify the test result
        Case testCase = [Select Id, Send_to_Journey__c From Case where Id = :c2.Id];
        System.assertEquals(false , testCase.Send_to_Journey__c, 'Send_to_Journey__c should be false');
    }
}

Giờ các bạn có thể thử thay đổi Case status xem, nó sẽ tự động trigger vào journey này!

Conclusion

Thế là xong! Một cú bắt tay giữa Apex và Journey Builder tưởng như đơn giản, nhưng lại mở ra rất nhiều khả năng tự động hóa mạnh mẽ, thông minh và linh hoạt hơn cho Journey của bạn.

Dù bạn đang theo dõi trạng thái Case, hay lắng nghe tín hiệu từ bất kỳ đối tượng nào trong Salesforce, thì chỉ cần một chút Apex đúng lúc là Journey Builder sẽ “nghe lời” ngay. Hehe.

Leave a Reply