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
Andy Kallio 7Andy Kallio 7 

Admin: Looking for help with using Custom Meta Data to build request body

Hello

I have this class that is making the request body for an integration with netsuite. 
 

public class netsuite_CustomerMap implements INetsuiteMap{

	public map<string, object>  getNSMap(SObject sobj) {

		Account acc = (Account)sobj;
        string objectName = acc.getSObjectType().getDescribe().getName();
        netsuite_Service nsService = new netsuite_Service();
        map<string,map<string, Netsuite_Mapping__mdt>> ns_Map = nsService.getNSDefaultMap();
		map<string, object> objMap = new map<string, object>();

		objMap.put('companyname',acc.Name);
		objMap.put('externalid', acc.Id);
		objMap.put('recordtype', ns_Map.get('recordtype').get(objectName).Netsuite_Value__c);
		objMap.put('altPhone',acc.Phone);
		objMap.put('currency', ns_Map.get('currency').get(acc.CurrencyIsoCode).Netsuite_Value__c);
		objMap.put('customForm', ns_Map.get('customForm').get(objectName).Netsuite_Value__c);
		objMap.put('phone', acc.phone);
		objMap.put('isPerson', ns_Map.get('isPerson').get(objectName).Netsuite_Value__c);
		objMap.put('entityStatus',ns_Map.get('entityStatus').get(objectName).Netsuite_Value__c);*/

		
		return objMap;

	}
}

It works nicely but then I started thinking about what would happen if that request body needed to be changed. Perhaps a new field becsomes required by Netsuite, for example. This would require me to make edits to the class and deploying. So, I thought maybe I could put these map definitions into custom metadata, which would allow me to make any required changes by editing custom metdata inside production. I wound up with the following class:
 
public class netsuite_CustomerMap implements INetsuiteMap{

	public map<string, object>  getNSMap(SObject sobj) {

		Account acc = (Account)sobj;
        string objectName = acc.getSObjectType().getDescribe().getName();
        netsuite_Service nsService = new netsuite_Service();
        map<string,map<string, Netsuite_Mapping__mdt>> ns_Map = nsService.getNSDefaultMap();
		map<string, object> objMap = new map<string, object>();

		

		for(Netsuite_Master_Map_Definition__mdt mapSource : [select Id, 
																	 
 MasterLabel, 
																	Netsuite_Master_Map__c, 
																	Netsuite_Master_Map__r.MasterLabel, 
																	Netsuite_Field__c,  
																	Salesforce_Value__c 
															from Netsuite_Master_Map_Definition__mdt 
															where Netsuite_Master_Map__r.Apex_Class_Name__c = 'netsuite_CustomerMap']) {
			objMap.put(mapSource.Netsuite_Field__c, mapSource.Salesforce_Value__c);													
		}

		return objMap;

	}
}


And here is an example of what the 2 custom fields in Netsuite_Master_Map_Definition__mdt called Netsuite_Field__c and Salesforce_Value__c are storing:

Netsuite_Field__c = 'companyname'

Salesforce_Value__c = acc.Name

As an admin, what I didn't think through is that this would not work because these are text fields and therefore simply populates the objMap with literal text values like so "'companyname'" => "acc.Name".

So, at this point I'm not sure what to do and will probably just reconcile myself to the reality of updating the class anytime a change to request body is needed.....Unless someone out there has any good ideas.

Thanks!

 

Best Answer chosen by Andy Kallio 7
PrincyPrincy

Hi Andy,
You can fetch the fields from the Sobject dynamically. I would suggest adding some sort of check, a boolean or a picklist field to determine if the value is string literal or a reference.
For e.g. Let's add Salesforce_Value_type__c on Netsuite_Master_Map_Definition__mdt which can have two typesof values - 'Literal' or 'Dynamic'. Now in your code, you can check if the Salesforce_Value_type__c is 'Literal', add the value directly. If not, fetch it from the sObj/acc.
The code sample looks like:
 

public class netsuite_CustomerMap implements INetsuiteMap{

	public map<string, object>  getNSMap(SObject sobj) {

		Account acc = (Account)sobj;
        string objectName = acc.getSObjectType().getDescribe().getName();
        netsuite_Service nsService = new netsuite_Service();
        map<string,map<string, Netsuite_Mapping__mdt>> ns_Map = nsService.getNSDefaultMap();
		map<string, object> objMap = new map<string, object>();

		

		for(Netsuite_Master_Map_Definition__mdt mapSource : [select Id, 
																	 
 MasterLabel, 
																	Netsuite_Master_Map__c, 
																	Netsuite_Master_Map__r.MasterLabel, 
																	Netsuite_Field__c,  
																	Salesforce_Value__c ,
																	Salesforce_Value_type__c
															from Netsuite_Master_Map_Definition__mdt 
															where Netsuite_Master_Map__r.Apex_Class_Name__c = 'netsuite_CustomerMap']) {
			if('Literal' == mapSource.Salesforce_Value_type__c)
				objMap.put(mapSource.Netsuite_Field__c, mapSource.Salesforce_Value__c);	
			else 
				objMap.put(mapSource.Netsuite_Field__c, sobj.get(mapSource.Salesforce_Value__c));
		}

		return objMap;

	}
}

Please note that you should keep only the fieldName in the Salesforce_Value__c. For instance, the Salesforce_Value__c should be 'Name' and not 'acc.Name' for the above code to work.

Thanks,
Princy

All Answers

PrincyPrincy

Hi Andy,
You can fetch the fields from the Sobject dynamically. I would suggest adding some sort of check, a boolean or a picklist field to determine if the value is string literal or a reference.
For e.g. Let's add Salesforce_Value_type__c on Netsuite_Master_Map_Definition__mdt which can have two typesof values - 'Literal' or 'Dynamic'. Now in your code, you can check if the Salesforce_Value_type__c is 'Literal', add the value directly. If not, fetch it from the sObj/acc.
The code sample looks like:
 

public class netsuite_CustomerMap implements INetsuiteMap{

	public map<string, object>  getNSMap(SObject sobj) {

		Account acc = (Account)sobj;
        string objectName = acc.getSObjectType().getDescribe().getName();
        netsuite_Service nsService = new netsuite_Service();
        map<string,map<string, Netsuite_Mapping__mdt>> ns_Map = nsService.getNSDefaultMap();
		map<string, object> objMap = new map<string, object>();

		

		for(Netsuite_Master_Map_Definition__mdt mapSource : [select Id, 
																	 
 MasterLabel, 
																	Netsuite_Master_Map__c, 
																	Netsuite_Master_Map__r.MasterLabel, 
																	Netsuite_Field__c,  
																	Salesforce_Value__c ,
																	Salesforce_Value_type__c
															from Netsuite_Master_Map_Definition__mdt 
															where Netsuite_Master_Map__r.Apex_Class_Name__c = 'netsuite_CustomerMap']) {
			if('Literal' == mapSource.Salesforce_Value_type__c)
				objMap.put(mapSource.Netsuite_Field__c, mapSource.Salesforce_Value__c);	
			else 
				objMap.put(mapSource.Netsuite_Field__c, sobj.get(mapSource.Salesforce_Value__c));
		}

		return objMap;

	}
}

Please note that you should keep only the fieldName in the Salesforce_Value__c. For instance, the Salesforce_Value__c should be 'Name' and not 'acc.Name' for the above code to work.

Thanks,
Princy
This was selected as the best answer
PrincyPrincy
Hi Andy,

Hope you had a chance to look at the above reply. Please mark it as solved if the above helps.

Thanks,
Princy