I am trying to update both the state and value of an attribute for an entity by writing plugin for CRM 2013. I did try to set the state of an activity using setStateRequest but I am not sure if we can update attribute value as well. I've registered the plugin on Merge message to change the state of an activity. How can I update an attribute value along with state change? Here is my code so far for state ch
protected void ExecutePreCaseMerge(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
// TODO: Implement your custom Plug-in business logic.
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
//The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("SubordinateId") &&
context.InputParameters["SubordinateId"] is Guid)
{
try
{
Guid subordinateId = (Guid)context.InputParameters["SubordinateId"];
var fetch = #"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='task'>
<attribute name='new_issuephase' />
<filter type='and'>
<filter type='and'>
<condition attribute='regardingobjectid' operator='eq' uitype='incident' value='" + subordinateId + #"' />
<condition attribute='statecode' operator='eq' value='0' />
</filter>
</filter>
</entity>
</fetch>";
EntityCollection ec = service.RetrieveMultiple(new FetchExpression(fetch));
if (ec.Entities.Count > 0)
{
// Create an ExecuteMultipleRequest object.
ExecuteMultipleRequest requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
foreach (var item in ec.Entities)
{
SetStateRequest setStateRequest = new SetStateRequest();
setStateRequest.EntityMoniker = new EntityReference("task", item.Id);
setStateRequest.State = new OptionSetValue(2);
setStateRequest.Status = new OptionSetValue(6);
requestWithResults.Requests.Add(setStateRequest);
}
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)service.Execute(requestWithResults);
}
}
ange.
Thanks for any help!
You must do the update as a separate request but you can execute it together with the SetStateRequests inside the same ExecuteMultipleRequest:
foreach (var item in ec.Entities)
{
SetStateRequest setStateRequest = new SetStateRequest();
setStateRequest.EntityMoniker = new EntityReference("task", item.Id);
setStateRequest.State = new OptionSetValue(2);
setStateRequest.Status = new OptionSetValue(6);
requestWithResults.Requests.Add(setStateRequest);
//New Code
item.Attributes["attributetobeupdated"] = "Updated Value";
UpdateRequest request = new UpdateRequest() { Target = item };
requestWithResults.Requests.Add(request);
}
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)service.Execute(requestWithResults);
Note that if any of the requests fail the ExecuteMultipleRequest will not throw an error but will return the details of the individual failures within the ExecuteMultipleResponse. It seems that a common reason for this operation failing is that by default SQL server queries are configured to time out after 30 seconds. More info here:
http://manyrootsofallevilrants.blogspot.in/2012/09/ms-crm-2011-timeout-settings-and-limits.html
Related
I am trying to use this but after insert event, the property ConferenceData is null
var pm = new Dictionary<string, string>
{
{"conferenceDataVersion", "1"}
};
calenderEvent.ConferenceData.Parameters = new ConferenceParameters(); calenderEvent.ConferenceData.Parameters.AddOnParameters = new ConferenceParametersAddOnParameters(); calenderEvent.ConferenceData.Parameters.AddOnParameters.Parameters = pm;
You don't need to use the Parameters property in order to set ConferenceDataVersion.
If you just want to add a conference to the Event, you can set the ConferenceDataVersion as a parameter of your request before executing it.
You also have to make sure that the request body has the appropriate conference data properties (requestId, conferenceSolutionKey, etc.).
For example:
Event newEvent = new Event()
{
ConferenceData = new ConferenceData()
{
CreateRequest = new CreateConferenceRequest()
{
ConferenceSolutionKey = new ConferenceSolutionKey()
{
Type = "hangoutsMeet" // Change according to your preferences
},
RequestId = "XXXXX" // Unique request ID
}
},
// ... Rest of event properties (start, end, attendees, name, etc.)
};
EventsResource.InsertRequest request = service.Events.Insert(newEvent, calendarId);
request.ConferenceDataVersion = 1; // Set conference data version
Event createdEvent = request.Execute();
As I would like to create documents by merging the entries in a list into a Google Docs template. I have therefore integrated the DocumentMerge method from my previous question into a printButton in a list widget.
Clicking on the printButton should produce a document that merges the contents of the current row into the document template. But when I click on the printButton the method fails due to a circular reference. How can I fix that? The print method goes like this ...
function printReview(widget) {
var review = app.models.Review.getRecord(widget.datasource.item._key);
var templateId = 'templateId';
var filename = 'Review for ...' + new Date();
var copyFile = DriveApp.getFileById(templateId).makeCopy(filename);
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getBody();
var fields = app.metadata.models.Review.fields;
for (var i in fields) {
var text = '$$' + fields[i].name + '$$';
var data = review[fields[i].name];
copyBody.replaceText(text, data);
}
copyDoc.saveAndClose();
}
As Morfinismo noticed you are getting the error because you are trying to pass complex object from client to server and serializer fails to handle it. In order to fix that you need to adjust your code:
// onClick button's event handler (client script)
function onPrintClick(button) {
var reviewKey = button.datasource.item._key;
google.script.run
.withSuccessHandler(function() { /* TODO */ })
.withFailureHandler(function() { /* TODO */ })
.printReview(reviewKey);
}
// server script
function printReview(reviewKey) {
var review = app.models.Review.getRecord(reviewKey);
...
}
I am using a database-first approach with a custom html helper to get a state of a checkbox using ajax (without using form in the view). I have two tables:
Tbl_1 -> Id, state (true or false), name (name of checkbox)
Tbl_2 -> Id, user_guid, timestamp, Tbl_1Id (foreign_key)
When I do insert operations, it does without any problem but when I try to update it (based upon the logged in user as it also gets GUID, the table gets appended/inserted with new data).
My controller:
public ActionResult SetState(checkboxstate cbstate)
{
var UserId = new Guid(System.Security.Claims.ClaimsPrincipal.Current.FindFirst("sub").Value);
var ent = new StartopDatabaseEntities();
var cbs = ent.checkboxstates.Where(w => w.Name == "World").FirstOrDefault();
if (cbs == null) // when there are no records in the database
{
ent.checkboxstates.Add(cbstate);
ent.checkboxstateUpdates.SingleOrDefault(c => c.Id == cbstate.Id);
var cbsOp = new checkboxstateUpdates();
cbsOp.timestamp = DateTime.Now;
cbsOp.user_guid = UserId;
cbstate.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
} // record in database, update (I've only one user now, so has to update only this one)
else
{
var cbsOp = new checkboxstateUpdates(); // declare in global
var chc = new checkboxstate(); // to be declared in global
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).ToList();
foreach (var u in newCbs)
{
if(u.user_guid==UserId && u.CheckboxStateId == u.checkboxstate.Id)
{
chc.state = cbstate.state;
chc.name = cbstate.name;
ent.checkboxstates.Add(chc);
cbsOp.Tidspunkt = DateTime.Now;
cbsOp.OpdateretAfBruger = UserId;
ent.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
}
}
}
Can anyone explain please why it's not updating but appending/inserting same data with a new Id (primary key)? I have a simple view where Ajax sends a call to the controller with the state and name of the checkbox. I have also tried
Db.Entry(obj).state = EntityState.Modified
without any help
You have not written the code for the logic which want to achieve..
I am not clear on the logic of if block also but the else part can be fixed as following.
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).Where(u.user_guid == UserId).FirstOrDefault();
if(newCbs != null) {
newCbs.checkboxstate.state = cbstate.state;
newCbs.checkboxstate.name = cbstate.name;
newCbs.Tidspunkt = DateTime.Now;
newCbs.OpdateretAfBruger = UserId;
ent.SaveChanges();
}
Solved this with the help from #David & #Chetan:
I did some modify in the code as per David:
u.checkboxstate.state=cbstate.state;
u.checkboxstate.name=cbstate.name;
u.timestamp=DateTime.Now;
ent.saveChanges();
I was using the wrong logic i.e. getting instance of the class rather than the 'ent' object. Thanks guys for the help.
I'm writing a service which automtically cancels a PNR left on a certain queue. This sounds pretty straight forward with the OTA_CancelLLSRQ request, however it appears I have to loop through each segment individually, or is there a way I can cancell ALL segments at once?
In the application we defined a PNR class, this class contains all of the information we can obtain with the "" call.
To cancel the PNR I currently use the following code:
MessageHeader msgHeader = new MessageHeader
{
ConversationId = "TestSession",
CPAId = licenseId,
Action = "OTA_CancelLLSRQ",
Service = new Service { Value = "OTA_CancelLLSRQ" },
MessageData = new MessageData
{
MessageId = "xxx",
Timestamp = DateTime.UtcNow.ToString("s") + "Z"
},
From = new From()
{
PartyId = new PartyId[]
{
new PartyId { Value = "WebServiceClient"}
}
},
To = new To()
{
PartyId = new[]
{
new PartyId { Value = "WebServiceSupplier"}
}
}
};
var segmentList = new List<OTA_CancelRQSegment>();
foreach (var segment in pnrObject.Segments)
{
var requestSegment = new OTA_CancelRQSegment
{
Number = segment.SegmentNumber.ToString()
};
segmentList.Add(requestSegment);
}
var request = new OTA_CancelRQ()
{
Version = "2.0.0",
TimeStamp = DateTime.UtcNow,
TimeStampSpecified = true,
Segment = segmentList.ToArray()
};
OTA_CancelRS response = null;
Policy.Handle<SoapException>()
.Or<WebException>()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)
})
.Execute(() =>
{
using (OTA_CancelService serviceObj = new OTA_CancelService())
{
serviceObj.MessageHeaderValue = msgHeader;
serviceObj.Security = new Security1 { BinarySecurityToken = token };
response = serviceObj.OTA_CancelRQ(request);
}
});
It compiles & builds, but I haven't gotten around testing it just yet. :-)
In the documentation I found the following request:
<OTA_CancelRQ Version="2.0.0">
<Segment Type="entire"/>
</OTA_CancelRQ>
How do I encode this using the object model the webservice expects?
Steps for cancelling PNR is as follows.
STEP1: SessionCreateRQ
STEP2: TravelItineraryReadRQ
STEP3: OTA_CancelRQ
STEP4: EndTransactionRQ
STEP5: SessionCloseRQ
In case of SOAP SERVICES your request XML for STEP3 (i.e OTA_CancelRQ)will be as follows.
<OTA_CancelRQ EchoToken="String" TimeStamp="2001-12-17T09:30:47-05:00" Target="Production" Version="2003A.TsabreXML1.0.1" SequenceNmbr="1" PrimaryLangID="en-us" AltLangID="en-us" xmlns="http://webservices.sabre.com/sabreXML/2003/07" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<POS>
<Source PseudoCityCode="PCC"/>
</POS>
<TPA_Extensions>
<SegmentCancel Type="Entire">
</SegmentCancel>
</TPA_Extensions>
</OTA_CancelRQ>
I hope this will make your knowledge more clear.
You can specify "entire" type like the below to cancel the entire Itinerary of a PNR.
<OTA_CancelRQ Version="2.0.0">
<Segment Type="entire"/>
</OTA_CancelRQ>
here is the request part of my code in c#, hope this help add a refrence to proxy class for OTA_CancelRQ.
OTA_CancelRQ rq = new OTA_CancelRQ();
List<OTA_CancelRQSegment> segmentCancelList = new List<OTA_CancelRQSegment>();
OTA_CancelRQSegment segmentCancel = new OTA_CancelRQSegment();
OTA_CancelRQSegmentType segmentType = new OTA_CancelRQSegmentType();
segmentType = OTA_CancelRQSegmentType.entire;
segmentCancel.Type = segmentType;
segmentCancel.TypeSpecified = true;
segmentCancelList.Add(segmentCancel);
rq.Segment = segmentCancelList.ToArray();
Thanks.
cancelRQ.tPA_ExtensionsField = new CancelRequest.TPA_Extensions
{
segmentCancelField = new CancelRequest.TPA_Extensions.SegmentCancel
{
typeField = "Entire"
}
};
call OTA_CancelLLSRQ Perform a transaction after the original booking was completed (cancel the itinerary that was booked, in this case).
In my workflow model I have an association to cm:person type, in share configuration I'm using the authority.ftl template to display it, how can I limit the available users to select from down to the members of one group ?
There s a few changes that I needed to do in order to achieve this:
You should pass a parameter to your authority.ftl in your share modules config file using a new control param:
<config evaluator="node-type" condition="my:customtype">
<forms>
<form>
<appearance>
<field id="my:personproperty">
<control template="/org/alfresco/components/form/controls/authority.ftl">
<control-param name="filterString">mygroupname</control-param>
</control>
In alfresco\web-extension\site-webscripts\org\alfresco\components\form\controls\authority.ftl, pass this param to the js picker:
picker.setOptions(
{
itemType: "${field.endpointType}",
<#if field.control.params.filterString??>
filterString: "${field.control.params.filterString}",
</#if>
multipleSelectMode: ${field.endpointMany?string},
itemFamily: "authority"
});
In alfresco\extension\templates\webscripts\org\alfresco\repository\forms\pickerchildren.get.js read and use the parameter to query in only the given group:
argsFilterString = args['filterString']
...
if (argsSelectableType == "cm:person")
{
findUsers(argsSearchTerm, argsFilterString, maxResults, results);
}
...
function findUsers(searchTerm, filterString, maxResults, results){
var paging = utils.createPaging(maxResults, -1);
var searchResults = groups.searchUsers(searchTerm, paging, "lastName");
var groupmembers = null;
if (filterString != null){
var group = groups.getGroup(filterString);
var groupmembers = group.getAllUsers();
}
// create person object for each result
for each(var user in searchResults)
{
if (logger.isLoggingEnabled())
logger.log("found user = " + user.userName);
var add=true;
if (groupmembers != null ){
var ismember = false;
for each (var p in groupmembers){
if (""+p.userName == ""+user.userName){//need to add +"" cause they are java strings!
ismember = true;
}
}
if (!ismember){
logger.log(user.userName+" is no member of group "+filterString);
add=false;
}
}
if(add){
// add to results
results.push(
{
item: createPersonResult(user.person),
selectable: true
});
}
}
}
You can create a new control based on that authority.ftl and authority-finder.js, in which you modify the webscript call to a limited number of users to be returned !
Note :
If the webscript doesnot support maxItems parameter (or any other parameter to limit the number of results returned), you can always create your brand new webscript that supports that feature and then point your new control at it.