function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ivan WinzerIvan Winzer 

call to magento API from salesforce

So im in a pickle. The magento developer is asking for my contact/account creation trigger to call their API and below is what i need to add ino my trigger but not sure where and how to get it to fire the request. This what I have currently in my trigger:
 
trigger MainContactTrigger on Contact (before update, before insert, after update, after insert) {
    DuplicateEmailFilter def = new DuplicateEmailFilter();
    Map<id,Contact> oldMap = trigger.oldMap;
    CreateAccountFromContact accountCreation = New CreateAccountFromContact();
    
    if(oldMap == null){
        oldMap = new Map<Id,Contact>();
    }
    if(Trigger.isBefore){
    // 
    // For the before creation we check if the contact is getting created by a real user then we use 
    // the Duplicate Email Filter to generate an error preventing the contact from being created.
    //
        if(!IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
        if( Trigger.isInsert && !IntegrationUtils.ignoreForAutoAccountUser() ) {
            accountCreation.ProcessBatchContactsWEmail(trigger.new,trigger.oldMap);
        }
        else if( Trigger.isInsert || Trigger.isUpdate ) {
            accountCreation.ProcessBatchContacts(trigger.new,trigger.oldMap);
        }
    }
    else{
    //
    // This is the After trigger - we just need to check if the email address is already
    // in use in the duplicate email filter. 
    // if it is being created by the integration user then in the DEF we flag the contct as having 
    // a duplicate. Leaving it up to the Salesforce Admin to clean it up.
    //
        if(IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
    }
    
}

and this is what i need to add into it somewhere to make this call to magento:
 
Salesforce to Magento Customer update endpoint url:
https://hallwinesm2-uat.smarterspecies.com/rest/V1/hall/salesforce/customer/sync
Content-Type:application/json
POST:
{
    "customer": {
        "firstname": "Maciej", 
        "lastname": "Garycki", 
        "email": "mgarycki+sf5333@gorillagroup.com", 
        "telephone": "6924609876", 
        "contact_sf_id": "1234567890", 
        "sfdc_updated_at": "182736", 
        "rms_account_no": "12345", 
        "customer_group_code": "GENERAL", 
        "revel_id": "", 
        "website_id": "1", 
        "store_id": "1", 
        "uuid": "", 
        "addresses": []
    }
}

Can anyone help me..

Thanks,

Ivan
Best Answer chosen by Ivan Winzer
Greg CooganGreg Coogan
Ivan,

I've put together some code that should get your most of the way done. I couldn't test it.

Make sure to do the following:

1. Create a Custom Metadata type called "Magento Setting" (Magento Settings in the plural field)
2. In the Custom Metadata Type, create a String field called "Value" and make it 255 chars and required
3. Create the following values by going to "Manage Magento Settings"
          a. Username (put the username for Magento integation)
          b. Password (put the password for Magento integration)
          c. Token Endpoint (put the endpoint for getting the token)
          d. Sync Enpoint (put the endpoint that has "sync" at the end)
4. Create an Apex class called "MagentoUtility" and put the following:
 
public class MagentoUtility {

    public String authToken                 { get; set; }
    public String magentoUsername        { get; set; }
    public String magentoPassword        { get; set; }
    public String tokenEndpoint          { get; set; }
    public String syncEndpoint           { get; set; }

    public String firstName              { get; set; }
    public String lastName               { get; set; }
    public String email                  { get; set; }
    public String telephone              { get; set; }
    public String contactId              { get; set; }
    public DateTime lastUpdated          { get; set; }
    public String rmsAccountNo           { get; set; }
    public String customerGroupCode      { get; set; }
    public String revelId                { get; set; }
    public String websiteId              { get; set; }
    public String uuId                   { get; set; }
    public String addresses              { get; set; }

    public String getToken() {

        //Retrieve Username from Magento Setting (custom metadata type)
        magentoUsername = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Username' LIMIT 1].Value__c;

        //Retrieve Password from Magento Setting (custom metadata type)
        magentoPassword = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Password' LIMIT 1].Value__c;

        //Retrieve Token Enpoint from Magento Setting (custom metadata type)
        tokenEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Token_Endpoint' LIMIT 1].Value__c;

        /////Retrieve token/////
        HttpRequest req = new HttpRequest();
        req.setEndpoint(tokenEndpoint);
        req.setMethod('POST');

        // Specify the required user name and password to access the endpoint
        String authBody = '{ "username" : "' + magentoUsername + '", "password" : "' + magentoPassword + '" }';
        req.setBody(authBody);
        req.setHeader('Content-Type', 'application/json');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        JSONParser parser = JSON.createParser(res.getBody());

        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                (parser.getText() == 'Token')) {
                // Get the value.
                parser.nextToken();
                authToken = parser.getText();
                System.debug('Token: ' + authToken);
            }
        }
        return authToken;
    }

    public void magentoPost() {
        //Retrieve Token Endpoint from Magento Setting (custom metadata type)
        syncEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Sync_Endpoint' LIMIT 1].Value__c;

        HttpRequest req = new HttpRequest();
        req.setEndpoint(syncEndpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Authorization', 'Bearer ' + token);

        String body = '{ "customer": { ';
        body = body + '"firstname":"{!firstName}",';
        body = body + '"lastname":"{!lastName}",';
        body = body + '"email":"{!email}",';
        body = body + '"telephone":"{!telephone}",';
        body = body + '"contact_sf_id":"{!contactId}",';
        body = body + '"sfdc_updated_at":"{!lastUpdated}",';
        body = body + '"rms_account_no":"{!rmsAccountNo}",';
        body = body + '"customer_group_code":"{!customerGroupCode}",';
        body = body + '"revel_id":"{!revelId}",';
        body = body + '"website_id":"{!websiteId}",';
        body = body + '"store_id":"{!storeId}",';
        body = body + '"uuid":"{!uuId}",';
        body = body + '"addresses":{!addresses}';
        body = body + ' } }';

        req.setBody(body);

        Http http = new Http();
        HTTPResponse res = http.send(req);
        System.debug(res.getBody());
    }
}



Here is your trigger with some code to get you started on working with the Magento Utility class. I'm not sure how you are providing the fields like "RMS Account No" so I'll let you put that code in. I commented those lines out. Also, make sure to build you addresses the way the vendor wants to recieve them.
 
trigger MainContactTrigger on Contact (before update, before insert, after update, after insert) {
    DuplicateEmailFilter def = new DuplicateEmailFilter();
    Map<id,Contact> oldMap = trigger.oldMap;
    CreateAccountFromContact accountCreation = New CreateAccountFromContact();

    if(oldMap == null){
        oldMap = new Map<Id,Contact>();
    }
    if(Trigger.isBefore){
    //
    // For the before creation we check if the contact is getting created by a real user then we use
    // the Duplicate Email Filter to generate an error preventing the contact from being created.
    //
        if(!IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
        if( Trigger.isInsert && !IntegrationUtils.ignoreForAutoAccountUser() ) {
            accountCreation.ProcessBatchContactsWEmail(trigger.new,trigger.oldMap);
        }
        else if( Trigger.isInsert || Trigger.isUpdate ) {
            accountCreation.ProcessBatchContacts(trigger.new,trigger.oldMap);
        }
    }
    else if(Trigger.isAfter){
    //
    // This is the After trigger - we just need to check if the email address is already
    // in use in the duplicate email filter.
    // if it is being created by the integration user then in the DEF we flag the contact as having
    // a duplicate. Leaving it up to the Salesforce Admin to clean it up.
    //
        if(IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }

        //Magento Integration
        if( Trigger.isInsert ){
            //Call the Magento Utility class
            MagentoUtility m = new MagentoUtility();

            //Obtain the Authentication Token
            String token = m.getToken();
            String m.authToken = token;

            //Create a list of Contacts inserted
            List<Contact> lstNewContacts = Trigger.new;
            //Loop through the new Contacts
            for( Contact c : lstNewContacts ){
                m.firstName = c.FirstName;
                m.lastName = c.LastName;
                m.email = c.Email;
                m.telephone = c.Phone;
                m.contactId = c.Id;
                m.lastUpdated = c.LastModifiedDate;
                //m.rmsAccountNo = c.RMS_Account_No__c;
                //m.customerGroupCode = c.Customer_Group_Code__c;
                //m.revelId = c.Revel_Id__c;
                //m.websiteId = c.Website_Id__c;
                //m.uuId = c.uuid__c;
                //m.addresses = ? ;
                //Build your addresses to the vendor's requirements

                magentoPost();
            }
        }
    }
}



In the event that your code is not receiving the token before the trigger attempts to POST to their API, you may need to implement functionality that waits for the token.

You will want to write a Test Class for the Magento Utility class, but I'd focus on getting this working first.

If this answer suits your needs, feel free to mark it as the best answer. :) Good luck!

All Answers

Greg CooganGreg Coogan
You can use HttpRequest. Here is the relevant documentation:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_httprequest.htm#apex_classes_restful_http_httprequest

You may want to find out about how the endpoint authenticates your request. You might need to pass credentials in the request or use a token retrieved from their API.
Ivan WinzerIvan Winzer
Thanks for the reply Greg. So i started reading in the named credentials in salesforce and created the following call out to test the authentication aspect but i keep getting a access denied. Do you know if SF ever fixed the named credential issue of basic being left out of the header. Do you see any issue with my code below doing the call out. Im going to try to incoporate what you sent into my callout and see if that will result in a sucessful code.
 
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:Magento_2');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
// Set the body as a JSON object
request.setBody('{"firstname":"Maciej"}');
request.setBody('{"lastname":"Garycki"}');
request.setBody('{"email":"mgarycki+sf5333@gorillagroup.com"}');
request.setBody('{"telephone":"6924609876"}');
request.setBody('{"contact_sf_id":"1234567890"}');
request.setBody('{"sfdc_updated_at":"182736"}');
request.setBody('{"rms_account_no":"12345"}');
request.setBody('{"customer_group_code":"GENERAL"}');
request.setBody('{"revel_id":""}');
request.setBody('{"website_id":"1"}');
request.setBody('{"store_id":"1"}');
request.setBody('{"uuid":""}');
request.setBody('{"addresses":[]}');
HttpResponse response = http.send(request);
// Parse the JSON response
if (response.getStatusCode() != 201) {
    System.debug('The status code returned was not expected: ' +
        response.getStatusCode() + ' ' + response.getStatus());
} else {
    System.debug(response.getBody());
}

Your such a life saver for responding. Thank you for any help you give.
Ivan WinzerIvan Winzer
Greg,

So updated my code and not am getting a debug message :"Consumer is not authorized to access %resources","parameters":{"resources":"Hall_Salesforce::salesforce_api"}} which makes me to believe that Magento is not allowing my callout to process thru. Not that the credentials in my code did not work correct?
 
HttpRequest req = new HttpRequest();
req.setEndpoint('https://hallwinesm2-uat.smarterspecies.com/rest/V1/hall/salesforce/customer/sync');
req.setMethod('POST');
    
// Specify the required user name and password to access the endpoint
// As well as the header and header information
 
String username = 'salesforce';
String password = '**********************';
  
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'BASIC ' +
EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
req.setHeader('Content-Type', 'application/json;charset=UTF-8');    
// Create a new http object to send the request object
// A response object is generated as a result of the request  
// Set the body as a JSON object
req.setBody('{"firstname":"Maciej"}');
req.setBody('{"lastname":"Garycki"}');
req.setBody('{"email":"mgarycki+sf5333@gorillagroup.com"}');
req.setBody('{"telephone":"6924609876"}');
req.setBody('{"contact_sf_id":"1234567890"}');
req.setBody('{"sfdc_updated_at":"182736"}');
req.setBody('{"rms_account_no":"12345"}');
req.setBody('{"customer_group_code":"GENERAL"}');
req.setBody('{"revel_id":""}');
req.setBody('{"website_id":"1"}');
req.setBody('{"store_id":"1"}');
req.setBody('{"uuid":""}');
req.setBody('{"addresses":[]}');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

 
Greg CooganGreg Coogan
On the issue of Basic being left out of the authentication header, it shouldn't be an issue anymore. I recall reading about that as well. I used the Named Credential last week and had it working. However, I did end up switching to working with my vendor's API that takes the credentials in the body of the request instead of using Basic authentication.

If access denied is an error from the vendor's API, then I suggest asking them what they are recieving from your callouts. It could tell you if your request isn't being received correctly.

Additional Considerations:
I'd print the Response Status and Response Code. It is possible you might get back a 200 or some other reponse code that could be a valid scenario.
I'd also print out the Request to help with your troubleshooting.
 
//All of this can be inserted after line 20 of your above code:
System.debug('Request Body : ' + request.getBody());
System.debug('Response Code: ' + response.getStatusCode());
System.debug('Response Status: ' + response.getStatus());
Greg CooganGreg Coogan
It is possible that Magento doesn't work with Basic authentication. You might be better taking a different approach to authentication.Also, I think you need to first go to a different endpoint to retrieve a token (authentication part), and when you recieve the token in your response, you use that in your HTTP POST.

https://devdocs.magento.com/guides/v2.2/get-started/authentication/gs-authentication-token.html

This might also be helpful: https://devdocs.magento.com/guides/v2.2/get-started/rest_front.html
Ivan WinzerIvan Winzer
Morning Greg,

So i heard back from the magento development team and they did confirm that i need to do the call and send to get the authentication keys. They send back some examples of curl code but this is something new to me. Would you be able to help em figure out how to incorporate this into my code:

Step 1. Get a token
CLI command to make a request and response:
curl --header "Content-Type: application/json"  --request POST --data '{"username":"salesforce","password":"bmyvJVOM0K6uLHjW"}'  https://hallwinesm2-uat.smarterspecies.com/rest/default/V1/integration/admin/token ; echo

Step 2. Send Request with a token
Use received token l21x2wbqq9ukrpmmrhs60px8smqrc66k to make a Sync request
curl --header "Content-Type: application/json" --header "Authorization: Bearer l21x2wbqq9ukrpmmrhs60px8smqrc66k"   --request POST   --data '{"customer": {"firstname": "Maciej","lastname": "Garycki", "email": "mgarycki+sf5333@gorillagroup.com", "telephone": "4609876", "contact_sf_id": "1234567890", "sfdc_updated_at": "182736", "rms_account_no": "12345","customer_group_code": "GENERAL", "revel_id": "","website_id": "1", "store_id": "1", "uuid":"", "addresses": []}}'   https://hallwinesm2-uat.smarterspecies.com/rest/V1/hall/salesforce/customer/sync ; echo


The same example can be represented in HTTP RAW requests and responses.
Step 1. Request.
POST /rest/V1/integration/admin/token HTTP/1.1
HOST: hallwinesm2-uat.smarterspecies.com
content-type: application/json
cookie: PHPSESSID=01930019205d57e40b9cbd0665c9aec9
content-length: 67

{
  "username": "salesforce",
  "password": "bmyvJVOM0K6uLHjW"
}

Step 2. Request
POST /rest/V1/hall/salesforce/customer/sync HTTP/1.1
HOST: hallwinesm2-uat.smarterspecies.com
content-type: application/json
authorization: Bearer q0gvtfis1yp29d4a6xykt0x3yp65cws9
cookie: PHPSESSID=01930019205d57e40b9cbd0665c9aec9
content-length: 478

{
    "customer": {
        "firstname": "Maciej", 
        "lastname": "Garycki", 
        "email": "mgarycki+sf5333@gorillagroup.com", 
        "telephone": "6924609876", 
        "contact_sf_id": "1234567890", 
        "sfdc_updated_at": "182736", 
        "rms_account_no": "12345", 
        "customer_group_code": "GENERAL", 
        "revel_id": "", 
        "website_id": "1", 
        "store_id": "1", 
        "uuid": "", 
        "addresses": []
    }
}

Im going to attempt but shooting in the dark so any help is greatly apprecaited.

Ivan
Greg CooganGreg Coogan
Ivan,

I've put together some code that should get your most of the way done. I couldn't test it.

Make sure to do the following:

1. Create a Custom Metadata type called "Magento Setting" (Magento Settings in the plural field)
2. In the Custom Metadata Type, create a String field called "Value" and make it 255 chars and required
3. Create the following values by going to "Manage Magento Settings"
          a. Username (put the username for Magento integation)
          b. Password (put the password for Magento integration)
          c. Token Endpoint (put the endpoint for getting the token)
          d. Sync Enpoint (put the endpoint that has "sync" at the end)
4. Create an Apex class called "MagentoUtility" and put the following:
 
public class MagentoUtility {

    public String authToken                 { get; set; }
    public String magentoUsername        { get; set; }
    public String magentoPassword        { get; set; }
    public String tokenEndpoint          { get; set; }
    public String syncEndpoint           { get; set; }

    public String firstName              { get; set; }
    public String lastName               { get; set; }
    public String email                  { get; set; }
    public String telephone              { get; set; }
    public String contactId              { get; set; }
    public DateTime lastUpdated          { get; set; }
    public String rmsAccountNo           { get; set; }
    public String customerGroupCode      { get; set; }
    public String revelId                { get; set; }
    public String websiteId              { get; set; }
    public String uuId                   { get; set; }
    public String addresses              { get; set; }

    public String getToken() {

        //Retrieve Username from Magento Setting (custom metadata type)
        magentoUsername = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Username' LIMIT 1].Value__c;

        //Retrieve Password from Magento Setting (custom metadata type)
        magentoPassword = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Password' LIMIT 1].Value__c;

        //Retrieve Token Enpoint from Magento Setting (custom metadata type)
        tokenEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Token_Endpoint' LIMIT 1].Value__c;

        /////Retrieve token/////
        HttpRequest req = new HttpRequest();
        req.setEndpoint(tokenEndpoint);
        req.setMethod('POST');

        // Specify the required user name and password to access the endpoint
        String authBody = '{ "username" : "' + magentoUsername + '", "password" : "' + magentoPassword + '" }';
        req.setBody(authBody);
        req.setHeader('Content-Type', 'application/json');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        JSONParser parser = JSON.createParser(res.getBody());

        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                (parser.getText() == 'Token')) {
                // Get the value.
                parser.nextToken();
                authToken = parser.getText();
                System.debug('Token: ' + authToken);
            }
        }
        return authToken;
    }

    public void magentoPost() {
        //Retrieve Token Endpoint from Magento Setting (custom metadata type)
        syncEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Sync_Endpoint' LIMIT 1].Value__c;

        HttpRequest req = new HttpRequest();
        req.setEndpoint(syncEndpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Authorization', 'Bearer ' + token);

        String body = '{ "customer": { ';
        body = body + '"firstname":"{!firstName}",';
        body = body + '"lastname":"{!lastName}",';
        body = body + '"email":"{!email}",';
        body = body + '"telephone":"{!telephone}",';
        body = body + '"contact_sf_id":"{!contactId}",';
        body = body + '"sfdc_updated_at":"{!lastUpdated}",';
        body = body + '"rms_account_no":"{!rmsAccountNo}",';
        body = body + '"customer_group_code":"{!customerGroupCode}",';
        body = body + '"revel_id":"{!revelId}",';
        body = body + '"website_id":"{!websiteId}",';
        body = body + '"store_id":"{!storeId}",';
        body = body + '"uuid":"{!uuId}",';
        body = body + '"addresses":{!addresses}';
        body = body + ' } }';

        req.setBody(body);

        Http http = new Http();
        HTTPResponse res = http.send(req);
        System.debug(res.getBody());
    }
}



Here is your trigger with some code to get you started on working with the Magento Utility class. I'm not sure how you are providing the fields like "RMS Account No" so I'll let you put that code in. I commented those lines out. Also, make sure to build you addresses the way the vendor wants to recieve them.
 
trigger MainContactTrigger on Contact (before update, before insert, after update, after insert) {
    DuplicateEmailFilter def = new DuplicateEmailFilter();
    Map<id,Contact> oldMap = trigger.oldMap;
    CreateAccountFromContact accountCreation = New CreateAccountFromContact();

    if(oldMap == null){
        oldMap = new Map<Id,Contact>();
    }
    if(Trigger.isBefore){
    //
    // For the before creation we check if the contact is getting created by a real user then we use
    // the Duplicate Email Filter to generate an error preventing the contact from being created.
    //
        if(!IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
        if( Trigger.isInsert && !IntegrationUtils.ignoreForAutoAccountUser() ) {
            accountCreation.ProcessBatchContactsWEmail(trigger.new,trigger.oldMap);
        }
        else if( Trigger.isInsert || Trigger.isUpdate ) {
            accountCreation.ProcessBatchContacts(trigger.new,trigger.oldMap);
        }
    }
    else if(Trigger.isAfter){
    //
    // This is the After trigger - we just need to check if the email address is already
    // in use in the duplicate email filter.
    // if it is being created by the integration user then in the DEF we flag the contact as having
    // a duplicate. Leaving it up to the Salesforce Admin to clean it up.
    //
        if(IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }

        //Magento Integration
        if( Trigger.isInsert ){
            //Call the Magento Utility class
            MagentoUtility m = new MagentoUtility();

            //Obtain the Authentication Token
            String token = m.getToken();
            String m.authToken = token;

            //Create a list of Contacts inserted
            List<Contact> lstNewContacts = Trigger.new;
            //Loop through the new Contacts
            for( Contact c : lstNewContacts ){
                m.firstName = c.FirstName;
                m.lastName = c.LastName;
                m.email = c.Email;
                m.telephone = c.Phone;
                m.contactId = c.Id;
                m.lastUpdated = c.LastModifiedDate;
                //m.rmsAccountNo = c.RMS_Account_No__c;
                //m.customerGroupCode = c.Customer_Group_Code__c;
                //m.revelId = c.Revel_Id__c;
                //m.websiteId = c.Website_Id__c;
                //m.uuId = c.uuid__c;
                //m.addresses = ? ;
                //Build your addresses to the vendor's requirements

                magentoPost();
            }
        }
    }
}



In the event that your code is not receiving the token before the trigger attempts to POST to their API, you may need to implement functionality that waits for the token.

You will want to write a Test Class for the Magento Utility class, but I'd focus on getting this working first.

If this answer suits your needs, feel free to mark it as the best answer. :) Good luck!
This was selected as the best answer
Ivan WinzerIvan Winzer
Thanks Greg your awesome... One question so i was using the code provided for the trigger and got a unexpected toen '.' error in my eclipse tool.

If at the below line of code. Any idea why it doens tlike this string created for the token?
 
String m.authToken = token;
If its a public string from the class i dont have to define it within the trigger do i? Other than that everything saved well and my custom metadata types are in and ready to test.

Ivan
 
Greg CooganGreg Coogan
That's a mistype. It should be:
String authToken = token;
Since authToken is a public variable, you probably could change the getToken() method to be void and not return anything since it already sets authToken in the getToken() method.


 
Ivan WinzerIvan Winzer
That fixed the error. So i already had a test script for this trigger and so i tried to run it but got the following error back. Seems to not like the get.token you mentioned in your response so i should void out that method.

ClassContactTriggerTestSuite
Method NametestCreateAccountFromContact
Pass/FailFail
Error MessageSystem.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, MainContactTrigger: execution of AfterInsert

caused by: System.QueryException: List has no rows for assignment to SObject

Class.MagentoUtility.getToken: line 25, column 1
Trigger.MainContactTrigger: line 41, column 1: []
Stack TraceClass.ContactTriggerTestSuite.testCreateAccountFromContact: line 8, column 1

This is my test script nothing big so thinking may need to add more points to test:
@isTest
 public class ContactTriggerTestSuite{
    @isTest
    public static void testCreateAccountFromContact(){
        Account a = new Account(Name = 'Test MainContactTrigger');
        insert a;
        Contact c = new Contact(AccountId = a.id, firstName = 'Test MainContactTrigger', lastName = 'Tester');
        insert c;
        c = [select AccountId, Account.Name from Contact where id = :c.id limit 1];
           System.assertEquals('Test MainContactTrigger', a.Name);
   //        System.assertEquals(1, [SELECT Id FROM Contact].size());
   //        System.assertEquals(a.id, c.AccountId);
    }

 }

And so i went in an tried to void out the getToken method in the class
public void getToken()

but got a new error that says "  Void method must not return a value at line 56 column 9" which is here:
 
return authToken;

I've probably done this wrong when you said void :( so were you saying to take out the entire section of code since it isnt needed?
Greg CooganGreg Coogan
When you make a method “void” it means you aren’t going to return a value when the method is called. Comment out the return statement.
Ivan WinzerIvan Winzer
So i did that and got this error: MainContactTrigger: execution of BeforeUpdate caused by: line 41, column 20: Illegal assignment from void to String. And when i look at the MainContactTrigger this is the reference in the error:
 
String token = m.getToken();

I tried to comment it out but go a whole new error so figured it had to stay. Is it giving it becasue of the void call? Should i comment out the entire call itself since im not returning the token?
Greg CooganGreg Coogan
If you want to go that route, change this in your trigger:
 
String token = m.getToken();
String authToken = token

to:
 
m.getToken();

 
Ivan WinzerIvan Winzer
Morning Creg,

So i was able to figure this out last night by making a few changes but this is where im stalled at now. So first i realized that i needed to change the DeveloperName = to the metadata field names i created in the Magento settings (were different from what you had provided) so that resolved my token issues. But then a new error was recieved with the message "Callout from triggers are currently not supported.: Class.MagentoUtility.getToken: line 48, column 1". So i did some research and found out that i may need to create a @future (callout=true) class in order to do the http request that i have inside. So it now does not like this section of code:
Http http = new Http();
        HTTPResponse res = http.send(req);
        JSONParser parser = JSON.createParser(res.getBody());

        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                (parser.getText() == 'Token')) {
                // Get the value.
                parser.nextToken();
                authToken = parser.getText();
                System.debug('Token: ' + authToken);
            }
        }

So im wondering do i need to essentially take this out and place into this future callout class and then call that class from this one to have it connect. Sorry this @future function is new to me and not sure where its needed.

I tried just added it to the class itself but get errors about it needing to be defined for some reason (read an article that if you simply add it to your class it could work "not with my luck anywhere i place it there is an error"

This is the class you provided with where i thought the call out could go. Any suggestions:
 
//@future (callout=true)  
public class MagentoUtility {
   
    public String authToken             {get; set;}
    public String magentoUsername        { get; set; }
    public String magentoPassword        { get; set; }
    public String tokenEndpoint          { get; set; }
    public String syncEndpoint           { get; set; }
    
    public String firstName              { get; set; }
    public String lastName               { get; set; }
    public String email                  { get; set; }
    public String telephone              { get; set; }
    public String contactId              { get; set; }
    public DateTime lastUpdated          { get; set; }
    public String rmsAccountNo           { get; set; }
    public String customerGroupCode      { get; set; }
    public String revelId                { get; set; }
    public String websiteId              { get; set; }
    public String uuId                   { get; set; }
    public String addresses              { get; set; }
   
//@future (callout=true) 
    public String getToken() {
    
    
        //Retrieve Username from Magento Setting (custom metadata type)
        magentoUsername = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'magentoUsername' LIMIT 1].Value__c;

        //Retrieve Password from Magento Setting (custom metadata type)
        magentoPassword = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'magentoPassword' LIMIT 1].Value__c;

        //Retrieve Token Enpoint from Magento Setting (custom metadata type)
        tokenEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'tokenEndpoint' LIMIT 1].Value__c;

        /////Retrieve token/////
        HttpRequest req = new HttpRequest();
        req.setEndpoint(tokenEndpoint);
        req.setMethod('POST');

        // Specify the required user name and password to access the endpoint
        String authBody = '{ "username" : "' + magentoUsername + '", "password" : "' + magentoPassword + '" }';
        req.setBody(authBody);
        req.setHeader('Content-Type', 'application/json');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        JSONParser parser = JSON.createParser(res.getBody());

        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                (parser.getText() == 'Token')) {
                // Get the value.
                parser.nextToken();
                authToken = parser.getText();
                System.debug('Token: ' + authToken);
            }
        }
        return authToken;
        
    }
 //  @future (callout=true)  
   public void magentoPost() {
        //Retrieve Token Endpoint from Magento Setting (custom metadata type)
        syncEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'Sync_Endpoint' LIMIT 1].Value__c;

        HttpRequest req = new HttpRequest();
        req.setEndpoint(syncEndpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Authorization', 'Bearer ' + authtoken);

        String body = '{ "customer": { ';
        body = body + '"firstname":"{!firstName}",';
        body = body + '"lastname":"{!lastName}",';
        body = body + '"email":"{!email}",';
        body = body + '"telephone":"{!telephone}",';
        body = body + '"contact_sf_id":"{!contactId}",';
        body = body + '"sfdc_updated_at":"{!lastUpdated}",';
        body = body + '"rms_account_no":"{!rmsAccountNo}",';
        body = body + '"customer_group_code":"{!customerGroupCode}",';
        body = body + '"revel_id":"{!revelId}",';
        body = body + '"website_id":"{!websiteId}",';
        body = body + '"store_id":"{!storeId}",';
        body = body + '"uuid":"{!uuId}",';
        body = body + '"addresses":{!addresses}';
        body = body + ' } }';

        req.setBody(body);

        Http http = new Http();
        HTTPResponse res = http.send(req);
        System.debug(res.getBody());
    }
    
}

 
Greg CooganGreg Coogan
Instead of a bunch of back and forth filling up this page, since this is just a Q&A forum, let's chat using email. Look at the About Me section of my profile for my email address.