Create Case with Activity through Rest API - c#

I am trying to import cases from our old ticketing system into Acumatica using a C# console application. I have the old tickets loaded, and I am trying to use the REST API to create the cases.
I created a custom web service endpoint to load the cases, but I would also like to create message activities from the posts in our old system. If I use the Cases screen under Organization, I can add a Detail entity for activities. However, there does not appear to be a way to add the Activity Details field, which is the body of the activity. Here is a screenshot of the current endpoint setup showing the top-level Case entity I created:
The above image shows the Case entity, which does not appear to have the ActivityDetails field. However, if I use the Activity screen from the Hidden site map folder, the ActivityDetails is present. Here is a screenshot of the Activity entity I created, which does have ActivityDetails:
I hope this makes sense, but I would like the ActivityDetails field to be available from the Cases top-level entity so I can insert a complete case including activities and their detail. Any help would be greatly appreciated.
Thank you.

This is not a behavior that is possible.
The reason for this is that when you go on that screen using the UI, there is no possibility to add new Event, Task or Activity directly from that screen. The action button that are there only serve as to open the other screens a already create a link to the case from where the action was clicked on.
Since the APIs work by dealing with one screen at the time, it is not possible from the Case screen to create an Activity.
So to create an Activity for a Case, you will first have to create the Activity and then link it to the Case.
In order to do so, you must first add some field to both the Case entity and the Activity Entity.
These fields must be added manually as they are not part of the autocompletion.
For the Case entity, you need to add the following field:
Field Name = "NoteID"
Mapped Object = "Case Summary"
Mapped Field = "NoteID"
Field Value = "GuidValue"
enter code here
For the Activity entity please add the following field:enter code here
Field Name = "RefNoteID"
Mapped Object = "Activities"
Mapped Field = "RefNoteID"
Field Value = "GuidValue"
Once these two fields have been added, you can start adding the activity to the case.
In order to do so:
1) Retrieve the Case on which you want to add the activity using A GET call. You will need to use the value from the NoteID field that has just been added.
2) Create the Activity like you normally would, using a PUT call, but instead of trying to add a value in the RelatedEntityDescription field, add the NoteID value you just retrieved from the Case to the RefNoteID field you just added to the Activity entity. In the response you will be able to see that the Activity was linked to the case by checking the RelatedEntityDescription field.

Related

acumatica c# / Add SOPackageDetailEx

I have this error when I try to add a line of package
Error : Another process has added the "SOPackagedetail" record. Your changes will be lost.
error
My c# code is this :
protected virtual void creationColis()
{
SOShipment ship=Base.CurrentDocument.Select();
SOPackageDetailEx colis = new SOPackageDetailEx();
colis.BoxID="COLIS";
colis.PackageType="M";
colis.ShipmentNbr=ship.ShipmentNbr;
SOShipmentEntry graph = PXGraph.CreateInstance<SOShipmentEntry>();
graph.Packages.Insert(colis); //insertion de l'enregistrement
graph.Packages.Update(colis);
graph.Actions.PressSave();
graph.Clear();
}
Do you know what I must to change please ?
Thanks so much
Xavier
Your question needs more context. For starters, where does your code reside? Given that you reference Base.CurrentDocument.Select, I'm going to assume you are extending SOShipmentEntry to add your code.
In this case, you would just use the Base.Packages view rather than initializing your own instance of SOShipmentEntry where your example goes into trying to use graph.Packages. Regardless, there are 2 parts here that need to be addressed.
Packages is not the primary view of SOShipmentEntry. When you create an instance of a graph, you must tell the graph what record is needed in the primary view. In your example where you create a new instance of a graph, you might do something like this:
graph.Document.Current = graph.Document.Search<SOShipment.shipmentNbr>(myShipmentNbr);
If you are working on a graph extension of SOShipmentEntry, then you probably don't need to create a new instance of the graph. Just make sure graph.Document.Current isn't null before you add your package record - see bullet 2.
Once you have a shipment selected, you can then insert your package information. However, the way you have done it here effectively is trying to add a random package to a null shipment (by the structure of the views) but forcing the record to attach to the right shipment by sheer brute force. The views don't like to work that way.
A better way to add your package once you have a current shipment (Document) is like this:
// Find the current shipment (from the primary view Document)
SOShipment ship = Base.Document.Current();
if(ship?.ShipmentNbr != null) {
// Insert a record into the Packages view of the current shipment and return the record into colis
SOPackageDetailEx colis = Base.Packages.Insert(colis);
// Set the custom values
colis.BoxID="COLIS";
colis.PackageType="M";
// Update the Packages cache with the modified fields
Base.Packages.Update(colis);
// If more fields need to be updated after those changes were applied, instead do this...
colis = Base.Packages.Update(colis);
colis.FieldA = ValueA;
colis.FieldB = ValueB;
Base.Packages.Update(colis);
// If a save is needed, now is the time
Base.Save.Press();
}
Notice that I didn't assign ShipmentNbr. That is because the DAC has that field defined to pull the ShipmentNbr from SOShipment through these 2 attributes.
[PXParent(typeof(FK.Shipment))]
[PXDBDefault(typeof(SOShipment.shipmentNbr))]
This means that when the record is created, Acumatica should lookup the parent SOShipment record via the Key and do a DBDefault on the field to assign it to the SOShipment.ShipmentNbr value (from the parent). Important side note: PXDefault and PXDBDefault are NOT interchangeable. We use PXDefault a lot, but off the top of my head I can't think of a case of PXDBDefault outside of defaulting from a database value like this specific usage.

Getting LUIS entities inside a child dialog

I'm developing a bot using Bot Framework, LUIS and ActionBinding.
In one of my intent handlers I call a new Dialog which has the methods StartAsync(IDialogContext context) and ReceiveMessageAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
As I understand it, the messages typed by the user while waiting (with context.Wait(ReceiveMessageAsync)) won't be sent to LUIS, right?
So if I need to understand what the user is saying without having to parse the string, which are my options? Could call the ILuisService.QueryAsync with the message.Text for each message be an option?
I want to be able to detect entities typed by the user so I can map them to missing fields. For example in this conversation:
User: I want to book a flight. // LUIS detects intent
Bot: Ok. Can you tell me more about your flight? // child dialog is called to handle the rest of the conversation
User: I want to go to Madrid.
Bot: To fly to Madrid you can choose between company A, B or C.
User: I want to go with A tomorrow night
Bot: Ok, searching for available tickets for tomorrow night in A...
In this case there are no initial entities when the intent is detected, but there could be, and in that case the bot would not ask for the already given information.
For my project, a simple Form with one to one question-answer is not enough. I also need to make more validations and confirmations on previously set parameters if the user wants to change one or more parameters (i.e., I need to go back to all parameters and check if the changed parameter affects them). For example:
User: Wait, I want to fly to Barcelona instead.
Bot: Company A does not fly to Barcelona. You can choose between C and D.
User: Ok I want to fly with C.
Bot: There are tickets available for tomorrow night in company C. Keep the flight for tomorrow night?
User: yes.
Any tips or guidance for best practices would help a lot.
Thanks in advance.
Edit:
With the Sub Action solution, where would my validators operate? On the FulfillAsync method? I'd need to validate and then send a question to the user and understand the reply he sent (parsing entities). Would that be possible inside a LuisAction?
I'd like to use the QueryValueFromLuisAsync but after looking at it, I'd need to pass the paramName, which is one of the action properties (if i'm not mistaken) and that is what I'm trying to avoid. I don't want to map one answer (i.e., message.Text) to one field, i want to map one answer to multiple fields.
Let's say i need to fill a model that has 6 properties. If the bot asks one question to the user and in his reply there are 3 entities I want to map those entities to 3 fields and only make questions about the remaining non mapped fields afterwards.
My first reaction to this is to avoid using a custom child dialog and go with SubActions and create your own validators if you want to have complex logic there or even override the IsValid method from the sub action.
However, if that's not a possibility, then I would consider reusing the QueryValueFromLuisAsync method, where the action should be the model you want to interact with. That function will end up calling LUIS and will try to assign the result or return another intent/action depending on the scenario. I would give this a try.

Orchard CMS: Adding default data to fields and then querying them

I have added a LinkField called Website to a content type using a part with the same name as the content type.
ContentDefinitionManager.AlterTypeDefinition("MyContentType", a => a
.WithPart("CommonPart")
.WithPart("MyContentType")
.Creatable());
ContentDefinitionManager.AlterPartDefinition("MyContentType", cft => cft
.WithField("Website", a => a.OfType("LinkField").WithDisplayName("Website")
.WithSetting("FieldIndexing.Included", "True"))
.Attachable());
I then create some default content items during the migration.
I'm creating the item before adding the field data because I have had problems with fields not being updated when their values are set before the item is created. (Feel free to shine some light on that, but that isn't my question though)
var myItem = _orchardServices.ContentManager.New("MyContentType");
_orchardServices.ContentManager.Create(myItem);
var websitePart = myItem.Parts.FirstOrDefault(x => x.Fields.Any(y => y.Name == "Website"));
var websiteLinkField = websitePart .Fields.FirstOrDefault(x => x.Name == "Website") as LinkField;
websiteLinkField.Value = "http://www.google.com";
websiteLinkField.Text = "Link to google";
_orchardServices.ContentManager.Publish(myItem);
I realize there are more dynamic ways to access the field, but this seems to work too.
The data shows up when I view the items, but then I move on to making a Query.
I use the UI to build a simple query looking for the word "google" in the text of the LinkField, then I hit preview.
No results are found.
I then open up one of the items created from the migration and simply hit the "Save" button.
Then I try the preview again and the item I saved now shows up.
So as far as I can tell something is happening when I save a content item that I'm not doing from the migration. But I have been stepping through the code going over all angles, and I just can't find it.
I suspect maybe some handler is supposed to get triggered in order to create the FieldIndex'es ?
(I know how to trigger an update for the Lucene index, but as one would expect it does not affect querying fields using the Projections module and I'm really lost at this point.)
By now I'm just stabbing blindly in the dark.
Would really appreciate any help I can get, even if it's just something pointing me back in the right direction. Thank you.
You should change
_orchardServices.ContentManager.Create(myItem);
to
_orchardServices.ContentManager.Create(myItem, Orchard.ContentManagement.VersionOptions.Draft);
For understanding look at CreatePOST method of Orchard.Core.Contents.Controllers.AdminController class and Publish method of Orchard.ContentManagement.DefaultContentManager class
In your case when you call a Create(myItem) then created published content item and all handlers are invoked normally (but has not yet set up a desired data). When you call Publish(myItem) nothing happens (no handlers are invoked) because your content is already published.
I've raised this as a bug, vote for it if you think it needs fixed.
#Alexander Petryakov is correct in his description of what is happening and his work around is probably the correct approach, however the behaviour doesn't make sense, which is why I have raised the bug. The code in your question manages to create an inconsistency between the content view of the data, stored in the Orchard_Framework_ContentItemVersionRecord table and the Projections view of the data stored in the Orchard_Projections_StringFieldIndexRecord table. Essentially, the Orchard_Projections_StringFieldIndexRecord contains null because it hasn't processed the publish event after you updated the field.
The code you have essentially does the following things:
Create a content item + publish it's creation
Update one of the content items fields this update doesn't change the state of the content
Try to publish the content item which doesn't do anything because it thinks it is already published.
To me, if you update a field on the content item, then the state of the item you are working on should no longer be published (it's changed since you published it). The Fields provide hooks that allow you to be notified when they are updated, so an alternate way of solving the problem would be to create a class that implements the interface IFieldStorageEvents that updates the published state of the content when a field is updated.
public class FieldUpdateEventHandler : IFieldStorageEvents {
public void SetCalled(FieldStorageEventContext context) {
context.Content.ContentItem.VersionRecord.Published = false;
}
}
This would allow your original code to run as it was written.

Shared Variables in CRM 2011 Plugin

I am attempting to use the SharedVariable of the IPluginExecutionContext between different calls to the same plugin. I have the following scenario:
The user is attempting to create a new Entity Record and the plugin has been triggered on the Pre stage. Based on some logic, I am setting a SharedVariable like so:
var context = (IPluginExecutionContext) serviceProvider.GetService(typeof (IPluginExecutionContext));
context.SharedVariables.Add("MySharedVariable", true);
I then attempt to update other records of the same entity like so:
var qe = new QueryExpression("new_myentity");
qe.Criteria.AddCondition("ecs_myfield", ConditionOperator.Equal,"someValue");
var results = service.RetrieveMultiple(qe);
foreach (var foo in results.Entities)
{
//Do something to foo
service.Update(foo);
}
I also have a plugin registered for Update on the Pre stage, however, I want to check MySharedVariable and do something else based on whether or not it is set.
In the Update, the context does not contain the key for 'MySharedVariable'. I have confirmed this by using the ITracingService.
Is there some restriction on passing shared variables between plugins that are run on different records?
The plugin execution mode for both the Create and Update is set to Synchronous and as already explained, both are registered on the Pre Operation stage
I don't use SharedVariables often, but I'm sure they are available in the same Execution Context (for example from a Pre Event to a Post Event for the same message on the same record).
They can't be used to share values between different plugins on different messages on different records (as in your case: set the value inside the Create of one record and retrieve the value inside the Update message of a different record)
For your situation I think it is preferable to use a custom entity to store the values, or create an additional attribute to the entity.
Hi by looking at the scenario you explained.
I will not be able to test this my self. But If you change the Update plugin from Pre to Post.
If you change the update plugin from PRE-Operation to Post Operation. You will definitely get the SharedVariable in the execution context.
Pass Data Between Plug-Ins
CRM 2011 Plugins – Shared Variables

Monotouch: send data back down the stack to another ViewController

I have a question concerning Monotouch.
The situation: I have 2 ViewControllers. The first (let's call it VC-A) looks similar to the contacts edit screen, meaning it has a TableView with multiple Sections each containing Buttons and TextFields. Now when the user clicks one of these Buttons, he will get to the second ViewController (VC-B), which displays a TableView containing data from the database. When the user clicks on any of these rows, VC-B will be closed and i want to display the selected database entry (string) as the title of the Button (in VC-A) which opened VC-B in the first place.
When I did an objective-C project last year, I managed to send data back down the stack by using delegates, but I haven't found a way yet how this works in Monotouch.
I have read several questions here on SO about using the AppDelegate or using singletons, but I'm not sure that this is the right way of returning data from a subview.
You can kind of copy the delegate pattern. Add a C# delegate to your VC-B that takes one parameter, some data structure.
In VC-B's "ViewWillDisappear", call the delegate it it is not null and pass the data on to it.
This way, your calling VC can get acces to the data but you don't need tight coupling between the two controllers. All it has to do, is register a delegate-method in VC-B.
As MonoTouch is .NET4 you can use Func<MyDataStructure> or Action<MyDataStructure> and don't need to use full qualified delegate types.
I have a static singleton class that I use to store "state" type data about my app - current settings and selections that are needed in many different places in the app. That's one way to approach this.
You could also pass VC-B a reference to VC-A when you create VC-B, so that it can explicitly access it's parent view and pass back values that way.
I actually prefer to use TinyMessenger for cross container calls I find this to be very very useful when you don't want to keep references to your heavy viewcontrollers around which could potentially result in memory leaks!
var messageHub = new TinyMessengerHub();
// Publishing a message is as simple as calling the "Publish" method.
messageHub.Publish(new MyMessage());
// We can also publish asyncronously if necessary
messageHub.PublishAsync(new MyMessage());
// And we can get a callback when publishing is completed
messageHub.PublishAsync(new MyMessage(), MyCallback);
// MyCallback is executed on completion
https://github.com/grumpydev/TinyMessenger

Categories