0

I originally had the following trigger and REST-callout class that functioned properly:

trigger SendOpp_Trigger on Opportunity (before insert, before update) {
    for(Opportunity o : Trigger.new){
        SendOpportunity.createOpportunity(o.name, o.Account_External_Id__c, o.CloseDate, o.StageName);
    }
}

public class SendOpportunity {

    String clientId = '*****';
    String clientsecret ='*****';
    String username='[email protected]';
    String password = '*****';
    String accesstoken_url = 'https://login.salesforce.com/services/oauth2/token';
    String authurl = 'https://login.salesforce.com/services/oauth2/authorize';

    public class deserializeResponse {

        public String id;
        public String access_token;

    }

    public String ReturnAccessToken(SendOpportunity Opp){

        String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='
        +clientSecret+'&username='+username+'&password='+password;

        Http h= new Http();
        HttpRequest req= new HttpRequest();
        req.setBody(reqbody);
        req.setMethod('POST'); 
        req.setEndpoint('https://na50.salesforce.com/services/oauth2/token');

        HttpResponse res=h.send(req);

        system.debug(res.getBody()); 

        deserializeResponse resp1= (deserializeResponse)JSON.deserialize(res.getBody(),deserializeResponse.class);

        return resp1.access_token;
    }

    @future(callout=true)
    public static void createOpportunity(String oppName, String acctId, Date d, String stage){

        SendOpportunity opp1 = new SendOpportunity();

        String accessToken = opp1.ReturnAccessToken(opp1);

        if(accessToken!=null){

            String endPoint='https://na50.salesforce.com/services/data/v42.0/sobjects/Opportunity';             

            String jsonstr='{"Name":"'+ oppName +'","AccountId":"'+ acctId +'","CloseDate":"'+ String.valueOf(d) +'","StageName":"'+ stage +'"}';

            Http h2 = new Http();
            HttpRequest req2 = new HttpRequest();
            req2.setHeader('Authorization','Bearer ' + accessToken);
            req2.setHeader('Content-Type','application/json');
            req2.setHeader('accept','application/json');
            req2.setBody(jsonstr);
            req2.setMethod('POST');
            req2.setEndpoint(endPoint);

            HttpResponse res2 = h2.send(req2);

            system.debug(res2.getBody()); 

            deserializeResponse deresp=(deserializeResponse)System.JSON.deserialize(res2.getBody(),deserializeResponse.class);
        }
    }
}

However, the only thing that code can do is create the same opportunities in a target salesforce org.

Now I want the callout to upsert opportunties in the target org, so I made the following additions according to online suggestions:

enter image description here

enter image description here

But I still get this message:

{"errorCode":"METHOD_NOT_ALLOWED","message":"HTTP Method 'PUT' not allowed. Allowed are HEAD,GET,PATCH,DELETE"}

Any ideas?

Thanks

4
  • 2
    Did you try PATCH? Mar 1, 2018 at 3:09
  • Yes, and that gives me: “invalid cross reference Id” Mar 1, 2018 at 3:25
  • Did you check that may be an actual issue? Mar 1, 2018 at 3:32
  • 1
    "invalid cross-reference id" is probably because you're sending an accountid that doesn't exist in the target org.
    – Mark Pond
    Mar 1, 2018 at 4:48

1 Answer 1

6

I'm not sure where you're getting the idea that PUT is the correct verb ("method") here; it should be a PATCH; you'll need to use the _HttpMethod query parameter to set the correct method. Also, to assign the correct account, you need the account's External ID (or it's actual other-org ID), and specified in the payload.

 // Define upsert field and value
 String endPoint='https://na50.salesforce.com/services/data/v42.0/sobjects/Opportunity/External_Id__c/'+oppId+'?_HttpMethod=PATCH';
String jsonstr='{"Name":"'+ oppName +'","Account":{ "External_Id__c":"'+ acctId +'"},"CloseDate":"'+ String.valueOf(d) +'","StageName":"'+ stage +'"}';
...
req2.setMethod('POST');

Do not include the External ID value in the payload, or the request will also fail.

See Insert or Update (Upsert) a Record Using an External Id for more info.

Also, using this method is incredibly error-prone to silly mistakes, you should have the system generate the JSON for you:

String jsonstr = JSON.serialize(new Map<String, Object> {
  'name' => oppName,
  'account' => new Map<String, Object> {
    'External_Id__c' => accId
  },
  'CloseDate' => d,
  'StageName' => stage
});

This takes a lot of the guesswork out of the JSON when something goes wrong.

5
  • 2
    HTTP Callout doesn't support PATCH except through a workaround that endpoint system might not accept: success.salesforce.com/ideaView?id=0873A000000PST0QAO
    – cropredy
    Mar 1, 2018 at 5:35
  • @cropredy Oh, huh. I thought they finally fixed that. sigh Well, the _HttpMethod is supposed to work, at any rate. I'll edit. Besides, I have another workaround I can post.
    – sfdcfox
    Mar 1, 2018 at 7:41
  • @sfdcfox I changed jsonstr/generated the JSON the way you suggested, but got this back: {"message": "Foreign key external ID: 0016a00000jlvn8qaf not found for field External_Id__c in entity Account", "errorCode": "INVALID_FIELD", "fields": [] }. And do please post the workaround you mentioned! Mar 1, 2018 at 14:05
  • @sfdcfox Regarding the error message I told you about in my comment above, disregard. I fixed that problem by populating External_Id__c, in the target org, with the necessary Id. Mar 1, 2018 at 14:34
  • 1
    @GabrielRivera Great, glad I could help!
    – sfdcfox
    Mar 1, 2018 at 15:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .