Salesforce Webservice Error - web-services

I am receiving the following error from a class that invokes a webservice.
"You have uncommitte​d work pending. Please commit or rollback before calling out"
Here is the class that is calling the webservice:
global class myWS
{
WebService static string invokeExternalWs(string childValue, string parentValue)
{
HttpRequest req = new HttpRequest();
req.setEndpoint('https://externalURL/Services');
req.setMethod('POST');
req.setHeader('Content-Type', 'text/xml; charset=utf-8');
req.setHeader('SOAPAction', 'http://externalService/externalMethod');
string b = '--soap request goes here--';
req.setBody(b);
Http http = new Http();
try {
//Execute web service call here
String xObjectID ='';
HTTPResponse res = http.send(req);
Dom.Document doc = res.getBodyDocument();
String soapNS = 'http://schemas.xmlsoap.org/soap/envelope/';
Dom.XmlNode root = doc.getRootElement();
for(dom.XmlNode node1 : root.getChildElements()) {
for(dom.XmlNode node2 : node1.getChildElements()) {
for(dom.XmlNode node3 : node2.getChildElements()) {
for(dom.XmlNode node4 : node3.getChildElements()) {
xObjectID = node4.getText();
}
}
}
}
return xObjectID;
} catch(System.CalloutException e){
return 'ERROR:' + e;
}
}
}
UPDATE: Here is my class that is executing myWS
public void applyURLString(ID ArgBuildID) {
Builder__c current_build = [SELECT id, name, LLURL__c, column1, column2, Opportunity__c
FROM Builder__c
WHERE id = :ArgBuildID];
if(current_build.LLURL__c == null || current_build.LLURL__c.trim().length() == 0)
{
String tmpFolderName = current_build.column1 + ' - ' + current_build.column2;
String LLWSResultPattern = '[0-9]{2,}';
String myWSXMLResult = myWS.invokeExternalWs(tmpFolderName,'test');
Boolean LLWSPatternMatched = pattern.matches(LLWSResultPattern,myWSXMLResult);
if(LLWSPatternMatched)
{
Opportunity oppt = [SELECT Id,Name
FROM Opportunity
WHERE Id = :current_build.Opportunity__c
LIMIT 1];
oppt.LLURL__c = 'https://someService/' + myWSXMLResult;
update oppt;
}
}
}
UPDATE #2 - Here is where applyURLString() is executed. This is the only place that DML is executed prior to my HTTP request. Yet I need the ID of the new Builder record.
Builder__c insertBuild = new Builder__c();
insertBuild.Opportunity__c = opportunityId;
insertBuild.Product_Group__c = selectedBuild.Product_Group__c;
insertBuild.Manual_Build_Product__c = selectedBuild.Manual_Build_Product__c;
insert insertBuild;
applyURLString(insertBuild.Id);
Any ideas why this error would occur?

#JCD's suggestion to use an #future annotation solved my problem. Thanks again!

Related

test class for handler trigger is not covered

I did a trigger on content version ,but my handler class is not covered ,can you please explain to me why ?
please find below the code and screenshots for non covered lines
in my test class ,i created all data needed for the handler class i call the method with content version input
Trigger:
trigger contentversiontrigger on ContentVersion (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
if(trigger.isAfter && trigger.isInsert) {
Bytel_ContentVersionTriggerHandler.AlignAttachementsWithOpportunity(Trigger.New);
}
}
Trigger Handler
public with sharing class Bytel_ContentVersionTriggerHandler extends TriggerHandler {
public static void AlignAttachementsWithOpportunity(List<ContentVersion> contentVersion) {
Set<Id> contentDocumentIdSet = new Set<Id>();
String Contractid;
String Opportunityid;
for (ContentVersion cv : contentVersion) {
if(cv.ContentDocumentId != null)
{
contentDocumentIdSet.add(cv.ContentDocumentId);
}
}
list<ContentDocumentLink> cdl = [SELECT ContentDocumentId, LinkedEntityId FROM ContentDocumentLink WHERE ContentDocumentId IN:contentDocumentIdSet];
id LinkedEntityId =cdl[0].LinkedEntityId ;
// List<Contract> contractList = [SELECT Id, name FROM Contract where Id =:cdl.LinkedEntityId];
list<contract> Contracts = [SELECT Id, name FROM Contract where Id =:LinkedEntityId ];
if (!Contracts.isEmpty())
{
Contractid=Contracts[0].Id;
}
// Id Contractid = [SELECT Id, name FROM Contract where Id ='8005t0000001UQFAA2' limit 1].Id;
system.debug('test trigger' +Contractid) ;
// String Contractid= String.valueof(contractList[0].Id);
system.debug('ContractId' +Contractid) ;
list<Contract> contractssecond=[SELECT id ,vlocity_cmt__OpportunityId__c FROM Contract WHERE id =:Contractid limit 1];
if (!contractssecond.isEmpty())
{
Opportunityid=contractssecond[0].vlocity_cmt__OpportunityId__c;
}
system.debug('Opportunityid' +Opportunityid) ;
Id conDoc = cdl[0].ContentDocumentId;
//if (Opportunityid!=Null & conDoc!=Null) {
if (Opportunityid!=Null ) {
//create ContentDocumentLink record
ContentDocumentLink conDocLink = New ContentDocumentLink();
conDocLink.LinkedEntityId = Opportunityid;
conDocLink.ContentDocumentId = conDoc; //ContentDocumentId Id from ContentVersion
conDocLink.shareType = 'V';
insert conDocLink;
}
}
}
Test class of handler
#isTest
public class Bytel_ContentVersionTriggerHandlerTest {
static testMethod void createattachememtns() {
insert Bytel_TestDataFactory.createByPassSettings(false); // Custom setting bypass profile
insert Bytel_TestDataFactory.createGlobalVariableSettings(); // Custom setting globalVaribale, parameter callout end-point
insert Bytel_TestDataFactory.createOpportunityRaisonEchecSettings();
insert Bytel_TestDataFactory.createOpportunityStatusSettings();
Account acc = new Account(
Name = 'Test Account',
TypeIdentifiant__c = 'SIREN',
SIREN__c = '123765982',
Statut__c = 'Prospect'
);
insert acc;
Opportunity opp = Bytel_TestDataFactory.createOpportunity(
'FILL AUTO',
'Etape10',
acc.Id,
null
);
opp.Tech_AccountIdToDelete__c = acc.id;
opp.ScoringFinancier__c = 'Vert';
opp.siren__c = '123765981';
insert opp;
Quote quote = new Quote(Name = 'devis1', OpportunityId = opp.Id);
insert quote;
Contract contract1 = new Contract(
vlocity_cmt__QuoteId__c = quote.Id,
vlocity_cmt__OpportunityId__c=opp.id,
AccountId = acc.id
);
insert contract1;
Contract contract2 = new Contract(
vlocity_cmt__QuoteId__c = quote.Id,
AccountId = acc.id,
vlocity_cmt__OpportunityId__c=opp.id
);
insert contract2;
Blob bodyBlob=Blob.valueOf('Unit Test ContentVersion Body to be insert in test class for testing the');
ContentVersion contentVersion_1 = new ContentVersion(
Title='SampleTitle',
PathOnClient ='SampleTitle.txt',
Type_de_Fichier__c='RIB',
VersionData = bodyBlob,
origin = 'H'
);
insert contentVersion_1;
Contract contra = [SELECT Id
FROM Contract WHERE Id = :contract1.Id LIMIT 1];
List<ContentVersion> contentVersion_2 = [SELECT Id, Title, ContentDocumentId
FROM ContentVersion WHERE Id = :contentVersion_1.Id ];
// ContentDocumentLink contentlink = new ContentDocumentLink();
// contentlink.LinkedEntityId = contra.id;
// contentlink.contentdocumentid = contentVersion_2.contentdocumentid;
// contentlink.ShareType = 'V';
// insert contentlink;
Bytel_ContentVersionTriggerHandler.AlignAttachementsWithOpportunity(contentVersion_2);
}
}
After a first look, I guess you forgot to add #isTest to your test method.
#isTest
static testMethod void createattachememtns() {
//Your Code
}

Google.Cloud.RecaptchaEnterprise error on CreateAssessment() - "Request contains an invalid argument"

I'm trying to use the Google.Cloud.RecaptchaEnterprise library to validate captcha requests for the new enterprise key my client has obtained.
string _siteKey = ConfigurationManager.AppSettings["GoogleCaptcha.CheckboxCaptcha.SiteKey"];
string _apiKey = ConfigurationManager.AppSettings["GoogleCaptcha.ApiKey"];
string _projectId = ConfigurationManager.AppSettings["GoogleCaptcha.ProjectId"];
string recaptchaAction = "CreateAccountAssessment";
try {
var appPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
string credential_path = appPath + "googlecredentials.json";
System.Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
RecaptchaEnterpriseServiceClient client =
RecaptchaEnterpriseServiceClient.Create();
CreateAssessmentRequest createAssessmentRequest = new CreateAssessmentRequest()
{
Assessment = new Assessment()
{
Event = new Event()
{
SiteKey = _siteKey,
Token = formResponse,
ExpectedAction = "Create_Account"
},
Name = recaptchaAction,
},
Parent = _projectId
};
Assessment response = client.CreateAssessment(createAssessmentRequest);
if (response.TokenProperties.Valid == false)
{
Sitecore.Diagnostics.Log.Error("The CreateAssessment() call failed " +
"because the token was invalid for the following reason: " +
response.TokenProperties.InvalidReason.ToString(), this);
return "Invalid captcha.";
}
else
{
if (response.Event.ExpectedAction == recaptchaAction)
{
Sitecore.Diagnostics.Log.Error("The reCAPTCHA score for this token is: " +
response.RiskAnalysis.Score.ToString(), this);
return "";
}
else
{
Sitecore.Diagnostics.Log.Error("The action attribute in your reCAPTCHA " +
"tag does not match the action you are expecting to score", this);
return "Invalid captcha.";
}
}
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("Error validating captcha on " + _url + "; " + ex.Message, this);
return "Unable to connect to captcha service.";
}
As far as I can tell all my properties are correct, but it throws an error on Assessment response = client.CreateAssessment(createAssessmentRequest);:
Status(StatusCode="InvalidArgument", Detail="Request contains an invalid argument.", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"#1621287236.280000000","description":"Error received from peer ipv6:[2607:f8b0:4006:81a::200a]:443","file":"T:\src\github\grpc\workspace_csharp_ext_windows_x64\src\core\lib\surface\call.cc","file_line":1062,"grpc_message":"Request contains an invalid argument.","grpc_status":3}")
I strongly suspect the problem (or at least a problem) is the Parent property of the request.
From the documentation:
The name of the project in which the assessment will be created, in the format "projects/{project}".
... whereas I suspect your project ID is just the ID, rather than the resource name starting with "projects/".
I would recommend using the generated resource name classes as far as possible, with the corresponding properties. So in this case, you'd have:
CreateAssessmentRequest createAssessmentRequest = new CreateAssessmentRequest
{
Assessment = new Assessment
{
Event = new Event
{
SiteKey = _siteKey,
Token = formResponse,
ExpectedAction = "Create_Account"
},
Name = recaptchaAction,
},
ParentAsProjectName = new ProjectName(_projectId)
};

Pass field from Droid project to PCL, Xamarin.Forms

I have an app that allows users to log in via facebook, once user enters their credentials - My api request saves the user onto the database and auto-generates a user token(This is unique to each user). In order to display user specific details once user logs in - the token needs to be referenced. I am trying to get this token to the PCL project but it returns null just for the token. When I tried passing another string like name, it passes the correct value. Any help will be much appreciated.Thanks
FacebookRender in droid:
public class FacebookRender : PageRenderer
{
public FacebookRender()
{
CustomerService customerService = new CustomerService();
String error;
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "",
scope: "",
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("https://www.facebook.com/connect/login_success.html")
);
auth.Completed += async (sender, eventArgs) =>
{
try
{
if (eventArgs.IsAuthenticated)
{
await AccountStore.Create().SaveAsync(eventArgs.Account, "FacebookProviderKey");
var accessToken = eventArgs.Account.Properties["access_token"].ToString();
var expiresIn = Convert.ToDouble(eventArgs.Account.Properties["expires_in"]);
var expiryDate = DateTime.Now + TimeSpan.FromSeconds(expiresIn);
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me?fields=email,first_name,last_name,gender,picture"), null, eventArgs.Account);
var response = await request.GetResponseAsync();
var obj = JObject.Parse(response.GetResponseText());
var id = obj["id"].ToString().Replace("\"", "");
var name = obj["first_name"].ToString().Replace("\"", "");
var surname = obj["last_name"].ToString().Replace("\"", "");
var gender = obj["gender"].ToString().Replace("\"", "");
//var email = obj["email"].ToString().Replace("\"", "");
Customer.Customers cust = new Customer.Customers();
cust.Credentials = new Customer.Credentials();
cust.Name = name;
cust.Surname = surname;
cust.Email = "";
cust.MobilePhone = "";
cust.DOB = DateTime.Now;
cust.Number = "";
cust.City = "";
cust.Region = "";
cust.Country = "";
cust.DeviceToken = "sample";
cust.Credentials.SecretKey = "";
await customerService.AddCustomer(cust);
App.SaveToken(cust.Credentials.Token); - **//This is where I am passing the token**
App.NavigateToProfile(string.Format(name + surname));
}
else
{
App.NavigateToProfile("Invalid Login");
}
}
catch(Exception ex)
{
error = ex.Message;
}
};
activity.StartActivity(auth.GetUI(activity));
}
App.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
public static void NavigateToProfile(string message)
{
App.Current.MainPage = (new Profile(message));
}
static string _Token;
public static string Token
{
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
AboutPage.cs - I am passing the token in a label just to see if it's passing
public partial class About : ContentPage
{
private Label _lbltoken;
public About()
{
//InitializeComponent();
Appearing += (object s, EventArgs a) => {
_lbltoken.Text = App.Token;
};
string tk = App.Token;
_lbltoken = new Label()
{
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = tk,
};
var stack = new StackLayout
{
VerticalOptions = LayoutOptions.StartAndExpand,
Children = { _lbltoken },
};
Content = stack;
}
}
You can use the MessagingCenter.
Messages may be sent as a result like a button click, a system event or some other incident. Subscribers might be listening in order to change the appearance of the user interface, save data or trigger some other operation.
More Info
I don't really now if its good idea use static fields in App class. Xamarin access all fields with service locator, App.Current.[property] I will suggest you try to change these fields to public
string _Token;
public string Token
{
get { return _Token; }
}
public void SaveToken(string token)
{
_Token = token;
}
and use it with App.Current.SaveToken(token) or App.Current.Token

SPAlert.Filter not working

Can anybody help with SPAlert filters on Sharepoint 2013?
If I set Filter property on SPAlert instance the alert has not been sent
SPAlert newAlert = user.Alerts.Add();
SPAlertTemplateCollection alertTemplates = new SPAlertTemplateCollection(
(SPWebService)(SPContext.Current.Site.WebApplication.Parent));
newAlert.AlertType = SPAlertType.List;
newAlert.List = list;
newAlert.Title = alertTitle;
newAlert.DeliveryChannels = SPAlertDeliveryChannels.Email;
newAlert.EventType = eventType;
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
var wsm = new WorkflowServicesManager(web);
var wss = wsm.GetWorkflowSubscriptionService();
var subscriptions = wss.EnumerateSubscriptionsByList(list.ID);
bool assotiationExist = false;
var guid = Constants.Workflows.ApprovalWF.Guid;
foreach (var subs in subscriptions)
{
assotiationExist = subs.DefinitionId == guid;
if (assotiationExist)
{
newAlert.Filter = "<Query><Eq><FieldRef Name=\"ApprovalStatus\"/><Value type=\"string\">Approved</Value></Eq></Query>";
}
}
newAlert.Update(false);
If I set Filter property on SPAlert instance the alert has not been sent
What do you need exactly ?
If you just want to change the filter (alert condition), did you simply try :
newAlert.AlertType = SPAlertType.List;
newAlert.List = list;
newAlert.Title = alertTitle;
newAlert.DeliveryChannels = SPAlertDeliveryChannels.Email;
newAlert.EventType = eventType;
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
newAlert.Filter = "<Query><Eq><FieldRef Name=\"ApprovalStatus/New\"/><Value type=\"string\">Approved</Value></Eq></Query>";
newAlert.Update(false);
I have just added a /New in your filter query. Query filter in alert need to get a /New or a /Old in your field.
If your alert still doesn't work, it might be something else than the filter.
The problem was in line newAlert.EventType = eventType. eventType was SPEventType.Add. That was the reason of not sending alert after Workflow set the ApprovalStatus field to «Approved».
I’ve modified algourithm. Now eventType is SPEventType.Modify and I added new field "IsNewAlertSent" to list. When event fires the first time then I send email and set the "IsNewAlertSent" field
Final code is shown below.
class UserAlertManager:
..
newAlert.EventType = (eventType == SPEventType.Add? SPEventType.Modify: eventType);
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
..
if (assotiationExist)
{
newAlert.Filter = "<Query><Eq><FieldRef name=\"ApprovalStatus\"/><Value type=\"Text\">Approved</Value></Eq></Query>";
newAlert.Properties.Add("grcustomalert", "1");
}
..
newAlert.Update(false);
class GRCustomAlertHandler:
...
string subject = string.Empty;
string body = string.Empty;
bool grCustomAlert = Utils.IsSPAlertCustom(ahp.a);
if (ahp.eventData[0].eventType == (int)SPEventType.Modify && grCustomAlert)
{
SPListItem item = list.GetItemById(ahp.eventData[0].itemId);
var isNewAlertSentField = item.Fields.GetFieldByInternalName(Constants.Fields.IsNewAlertSent);
if (isNewAlertSentField != null && (item[Constants.Fields.IsNewAlertSent] == null || !(bool)item[Constants.Fields.IsNewAlertSent]))
{
...
Utils.SendMail(web, new List<string> { ahp.headers["to"].ToString() }, subject, body);
item[Constants.Fields.IsNewAlertSent] = true;
using (new DisabledItemEventScope())
{
item.SystemUpdate(false);
}
}
}
...

How can I simulate server for Unit test in Grails (Spock)?

I have written this simple service for doing subrequest via HTTPBuilder, to get instance of class representing obtained page for further use:
package cmspage
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.HTML
class CmsPageService {
static transactional = false
final String SUBREQUEST_HOST = "www.mydomainforsubrequest.com"
CmsPage getCmsPageInstance(Object request) {
String host = request.getServerName()
String url = request.getRequestURI()
HashMap queryMap = this.queryStringToMap(request.getQueryString())
return this.subRequest(host, url, queryMap)
}
CmsPage getCmsPageInstance(String host, String url, String queryString = null) {
HashMap queryMap = queryStringToMap(queryString)
return this.subRequest(host, url, queryMap)
}
private CmsPage subRequest(String host, String url, HashMap queryMap = null) {
CmsPage cmsPageInstance = new CmsPage()
HTTPBuilder http = new HTTPBuilder()
http.request("http://" + SUBREQUEST_HOST, GET, HTML) { req ->
uri.path = url
uri.query = queryMap
headers.'X-Original-Host' = 'www.mydomain.com'
response.success = { resp, html ->
cmsPageInstance.responseStatusCode = resp.status
if (resp.status < 400) {
cmsPageInstance.html = html
}
}
response.failure = { resp ->
cmsPageInstance.responseStatusCode = resp.status
return null
}
}
return cmsPageInstance
}
private HashMap queryStringToMap(String queryString) {
if (queryString) {
queryString = queryString.replace("?", "")
String[] splitToParameters = queryString.split("&")
HashMap queryMap = new HashMap()
splitToParameters.each {
String[] split = it.split("=")
for (int i = 0; i < split.length; i += 2) {
queryMap.put(split[i], split[i + 1])
}
}
return queryMap
} else return null
}
}
Now I need to write unit test for this service. I would like to use some simple html document to test it instead of testing some "live" site. But I do not know how?
Can anybody help me?
Jadler should suite you well. Check its documentation and this post on basic usage.