2

Good Morning All,

First and foremost, the Force.com IDE and Salesforce is a new skillset for me. I'm attempting to utilize the TwilioForce APEX Library: https://www.twilio.com/docs/salesforce/install

to create a new Salesforce Lead for each incoming call on my client's Twilio account. I've gotten as far as creating a new Force.com project in Eclipse, copying the Twilioforce components, classes and pages to the project, but need some guidance in how to write the logic to create the lead.

Questions I have: 1. Can you provide links to reference material demonstrating how to create a new lead in Salesforce programmtically? 2. How do I test the TwilioForce components, especially those I've changed to reflect my client's Twilio phone number and token? Are these callable from within the Force.com Project in Eclipse, or must they be called from my developer.org account? 3. Once I figure out how to accomplish the above lead creation from incoming Twilio calls, how do I deploy the codebase I've created to my client?

Thanks, Sid

EDIT: EyeScream, your sample was a huge help. Here's the TwilioRestResponse class that came with the TwilioForce codebase:

public class TwilioRestResponse {

private String responseText;
private integer httpStatus;
private String url;
private String queryString;
private boolean error;


public TwilioRestResponse(String url, String text, integer status){
    Pattern p = Pattern.compile('([^?]+)\\??(.*)');
    Matcher m = p.matcher(url);
    m.matches();
    this.url = m.group(1);
    this.queryString = m.group(2);
    this.responseText = text;
    this.httpStatus=status;
    this.error = (status>=400);  
}

// getters and setters 
public String getResponseText() {
    return responseText;
}
public void setResponseText(String responseText) {
    this.responseText = responseText;
}
public integer getHttpStatus() {
    return httpStatus;
}
public void setHttpStatus(integer httpStatus) {
    this.httpStatus = httpStatus;
}
public String getUrl() {
    return url;
}
public void setUrl(String url) {
    this.url = url;
}
public String getQueryString() {
    return queryString;
}
public void setQueryString(String queryString) {
    this.queryString = queryString;
}
public boolean isError() {
    return error;
}
public void setError(boolean error) {
    this.error = error;
}   
}

There's also a CallsXmlParser class as follows:

public class CallsXmlParser{
//All Parsed records will be in this list
public List<Call> listRecords = new List<Call>();
//Data Model to store all response elements
public class Call{
    public string Sid{get;set;}
    public string DateCreated{get;set;}
    public string DateUpdated{get;set;}
    public string CallSegmentSid{get;set;}
    public string AccountSid{get;set;}
    public string Called{get;set;}
    public string Caller{get;set;}
    public string PhoneNumberSid{get;set;}
    public string Status{get;set;}
    public string StartTime{get;set;}
    public string EndTime{get;set;}
    public string Duration{get;set;}
    public string Price{get;set;}
    public string Flags{get;set;}
    public string Annotation{get;set;}
}
public CallsXmlParser(){

}
public CallsXmlParser(string data){
    XmlStreamReader xsr = new XmlStreamReader(data);
    listRecords = parse(xsr);
}
public Call[] parse(XmlStreamReader reader) {
    Call[] members = new Call[0];
    while(reader.hasNext()) {
        if (reader.getEventType() == XmlTag.START_ELEMENT) {
           if ('Call' == reader.getLocalName()) {                 
                Call member = parseMember(reader);
                members.add(member);
            }
         }
        reader.next();
    }
    return members;
}
//Parsing Each Call Tag and its nested tags
public Call parseMember(XmlStreamReader reader){
    Call callObject = new Call();
    while(reader.hasNext()) {

       if ('Call' == reader.getLocalName() && reader.getEventType() == XmlTag.END_ELEMENT) {
           break;
        }
        else if('Sid' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Sid = reader.getText(); 
          }
        }else if('DateCreated' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.DateCreated= reader.getText(); 
          }
        }else if('DateUpdated' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.DateUpdated= reader.getText(); 
          }
        }else if('CallSegmentSid' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.CallSegmentSid= reader.getText(); 
          }
        }else if('AccountSid' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.AccountSid= reader.getText(); 
          }
        }else if('Called' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Called= reader.getText(); 
          }
        }else if('Caller' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Caller= reader.getText(); 
          }
        }else if('PhoneNumberSid' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.PhoneNumberSid= reader.getText(); 
          }
        }else if('Status' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Status = reader.getText(); 
          }
        }else if('StartTime' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.StartTime = reader.getText(); 
          }
        }else if('EndTime' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.EndTime = reader.getText(); 
          }
        }else if('Duration' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Duration = reader.getText(); 
          }
        }else if('Price' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Price = reader.getText(); 
          }
        }else if('Flags' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Flags = reader.getText(); 
          }
        }else if('Annotation' == reader.getLocalName() && reader.getEventType() == XmlTag.START_ELEMENT){
          reader.next();                   
          if(reader.getEventType() == XmlTag.CHARACTERS) { 
            callObject.Annotation = reader.getText(); 
          }
        }

       reader.next();
   }
   return callObject;
} 
}

My very basic insertLead class is as follows:

public with sharing class insertLead {
Lead1 = new Lead(Phone='TwilioRestResponse.GetResponseText');
}

I need to read in the Phone number and CallerID Name from either the TwilioRestResponse or the CallXmlParser classes and insert into the appropriate fields in a new Lead. What is the appropriate syntax for referencing the CallObject.PhoneNumberSid in my new Lead? Alternatively, is it better to parse out the TwilioRestResponse? If so, how would I select just the phone number and CallerID Name from the GetResponseText?

Thanks again, Sid

4

2 に答える 2

4

回答が更新されました。下にスクロールしてください

public class SidTest {

    //  1. How to create a new Lead programatically on Force.com (in Apex)
    /* This method is marked as test method, meaning that you can use it to run tests but in the end no data will be saved
        (transaction rollback). You'll need similar code in a class that intercepts messages from Twilio.
    */
    public static testMethod void insertLead(){
        Lead l = new Lead(FirstName='Test', LastName='Lead', Email='example@example.com', Company='test', NumberofEmployees=7);
        insert l;

        // 2. How do I test the TwilioForce components, especially those I've changed to reflect my client's Twilio phone number and token?
    /*  Not sure what do you mean, but most likely by writing test classes like this one and checking their test code coverage.
        See also http://stackoverflow.com/questions/4372202/how-to-unit-test-works-in-salesforce/4381941
        Below sample test that checks if our insert above succeeded.
        You can run it from Eclipse (preferred) or Salesforce GUI in Setup->Develop->Apex classes.
    */
        Lead[] leads = [SELECT Name, Email FROM Lead WHERE Name = 'Test Lead'];

        System.debug(leads);    // if you want to see results in detailed debug log
        System.assertEquals(1, leads.size());
        System.assertEquals('example@example.com', leads[0].Email);
    }
}

Eclipse で実行した結果は次のとおりです。http://dl.dropbox.com/u/709568/stackoverflow/Sid.png

最後の質問ですが、Developer Edition でテストされた機能に満足したら、クライアントに組織の「サンドボックス」へのアクセスを許可するよう依頼する必要があります。このサンドボックスを指す新しいプロジェクトを Eclipse で作成し、その中にすべてのクラスを作成するだけで、実際のデータのサブセットを使用してテストを実行できます。自動化されたテストのカバレッジが問題になり始めます。

または、コードを含むパッケージを作成し、Salesforce のプラグインのように AppExchange で販売して、誰でも組織にダウンロードできるようにすることもできます。もちろん請求できます。しかし、これは今のところ大きすぎるジャンプのように見えます...

これで始められることを願っています。


更新: これは、使用しているコード パッケージに含まれている TestCallsXmlParser に基づくクイック & ダーティ クラスです。

public class TestCallsXmlParser{
    @isTest
    public static void TestCallsXmlParserMethod1(){
        CallsXmlParser callxml = new CallsXmlParser();
        String xmlData = '<TwilioResponse> <Calls page=\"0\" numpages=\"1\" pagesize=\"50\" total=\"38\" start=\"0\" end=\"37\"> <Call> <Sid>CA42ed11f93dc08b952027ffbc406d0868</Sid> <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated><DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated><CallSegmentSid/>';
        xmlData = xmlData + '<AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid><Called>4159633717</Called><Caller>4156767925</Caller><PhoneNumberSid>PN01234567890123456789012345678900</PhoneNumberSid><Status>2</Status><StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime><EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>';
        xmlData = xmlData + '<Duration>14</Duration><Price/><Flags>1</Flags></Call>';
        xmlData = xmlData + '<Call><Sid>CA751e8fa0a0105cf26a0d7a9775fb4bfb</Sid><DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated><DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated><CallSegmentSid/>';
        xmlData = xmlData + '<AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid><Called>2064287985</Called><Caller>4156767925</Caller><PhoneNumberSid>PNd59c2ba27ef48264773edb90476d1674</PhoneNumberSid><Status>2</Status>';
        xmlData = xmlData + '<StartTime>Thu, 03 Apr 2008 01:37:05 -0400</StartTime><EndTime>Thu, 03 Apr 2008 01:37:40 -0400</EndTime><Duration>35</Duration><Price/> <Flags>1</Flags> </Call></Calls></TwilioResponse> ';
        CallsXmlParser callxml1 = new CallsXmlParser(xmlData);

        // eyescream's modification starts here

        // list to store our leads and bulk save them in blocks up to 100 records at 1 insert
        List<Lead> leads = new List<Lead>();

        for(CallsXmlParser.Call c : callxml1.listRecords) {
            System.debug('2 new Leads will be created from phone numbers: ' + c.Caller + ', ' + c.Called);
            leads.add(new Lead(MobilePhone = c.Caller, Company='x', LastName='x')); // Company & Last Name are mandatory fields
            leads.add(new Lead(MobilePhone = c.Called, Company='y', LastName='y')); // without them insert will fail.

            if(leads.size() == 100) { // 100 is the limit of records saved at once. Inserting in batches speeds up execution.
                insert leads;
                leads.clear();
            }
        }

        // If we have any leftovers, we'll insert them too.
        if(leads.size() > 0) {
            insert leads;
            leads.clear();
        }
    }
}

もちろん、それをさらに改善したり、重複をチェックしたり、実名を入力したりできます...しかし、それは大まかに解析結果を使用する方法です。XMLを自分で解析するのは良い選択肢だとは思いません...あなたの質問は、より多くのフィールドがXMLに含まれる(または既存のフィールドが異なるデータを保存するために使用される)ことを示唆していますが、おそらく拡張できるでしょうそれに応じてパーサー。

于 2010-12-15T20:00:37.197 に答える
0

ここで twilio ライブラリのデプロイに問題がある場合は、ほとんどのタスクを実行する適切な詳細が提供されます。http://redcurrantscloud.blogspot.in/ _

ありがとう。

于 2013-07-26T18:04:56.200 に答える