Problem with graphql executeAutomationCommand and notifyEvent mutations on v5.3.2

I’m using 5.3.2 and trying to Execute Automation Command via graphql to update an entity, however I am getting an error message when testing that makes no sense. First tried using executeAutomationCommand

GraphQL:

mutation m{executeAutomationCommand(
  name:"Update Customer",
  parameters:[
    {name:"EntityName", value:"1234"},
    {name:"FirstName", value:"Mark"},
    {name:"LastName", value:"Wallace"},
    {name:"Street", value:"123 Any Street"},
    {name:"Town", value:"Anytown"},
    {name:"PostCode", value:"AA1 1AA"},
    {name:"Email", value:"test@example.com"}
  ],
  user:"Admin",
  ticketType:"Delivery",
  terminal:"Server",
  department:"Delivery / Collection"
)}

Response:

{
  "data": {
    "executeAutomationCommand": null
  },
  "errors": [
    {
      "locations": [
        {
          "line": 0,
          "column": 0
        }
      ],
      "message": "Error trying to resolve executeAutomationCommand.",
      "data": {},
      "innerException": {
        "ClassName": "System.MissingMethodException",
        "Message": "No parameterless constructor defined for this object.",
        "Data": null,
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)\r\n   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n   at System.Activator.CreateInstance(Type type, Boolean nonPublic)\r\n   at System.Activator.CreateInstance(Type type)\r\n   at GraphQL.ObjectExtensions.ToObject(IDictionary`2 source, Type type)\r\n   at GraphQL.ObjectExtensions.GetPropertyValue(Object propertyValue, Type fieldType)\r\n   at GraphQL.ObjectExtensions.GetPropertyValue[T](Object value)\r\n   at GraphQL.Types.ResolveFieldContext.Argument[TType](String name)\r\n   at Samba.Services.Graphql.Automation.NotifyEventMutation.<.ctor>b__6_0(ResolveFieldContext context) in C:\\Users\\Vehbi\\Documents\\Source\\Repos\\sambapos-v5-pro\\Samba.Services\\Graphql\\Automation\\NotifyEventMutation.cs:line 112\r\n   at GraphQL.DocumentExecuter.<ResolveFieldAsync>d__8.MoveNext()",
        "RemoteStackTraceString": null,
        "RemoteStackIndex": 0,
        "ExceptionMethod": "8\nCreateInstance\nmscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.RuntimeTypeHandle\nSystem.Object CreateInstance(System.RuntimeType, Boolean, Boolean, Boolean ByRef, System.RuntimeMethodHandleInternal ByRef, Boolean ByRef)",
        "HResult": -2146233069,
        "Source": "mscorlib",
        "WatsonBuckets": null,
        "MMClassName": null,
        "MMMemberName": null,
        "MMSignature": null
      },
      "stackTrace": null,
      "helpLink": null,
      "source": null,
      "hResult": -2146233088
    }
  ]
}

When this didn’t work, I tried using notifyEvent as described here…

…but I get a similar error when running that as well…

GraphQL:

mutation m{notifyEvent(
  event:"AutomationCommandExecuted",
  parameters:[
    {name:"AutomationCommandName",value:"Update Customer"},
    {name:"EntityName", value:"1234"},
    {name:"FirstName", value:"Mark"},
    {name:"LastName", value:"Wallace"},
    {name:"Street", value:"123 Any Street"},
    {name:"Town", value:"Anytown"},
    {name:"PostCode", value:"AA1 1AA"},
    {name:"Email", value:"test@example.com"}
  ],
  user:"Admin",
  ticketType:"Delivery",
  terminal:"Server",
  department:"Delivery / Collection",
  state:{ticket:{id:0}}
){ticket{id}}}

Response:

{
  "data": {
    "notifyEvent": null
  },
  "errors": [
    {
      "locations": [
        {
          "line": 0,
          "column": 0
        }
      ],
      "message": "Error trying to resolve notifyEvent.",
      "data": {},
      "innerException": {
        "ClassName": "System.MissingMethodException",
        "Message": "No parameterless constructor defined for this object.",
        "Data": null,
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)\r\n   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n   at System.Activator.CreateInstance(Type type, Boolean nonPublic)\r\n   at System.Activator.CreateInstance(Type type)\r\n   at GraphQL.ObjectExtensions.ToObject(IDictionary`2 source, Type type)\r\n   at GraphQL.ObjectExtensions.GetPropertyValue(Object propertyValue, Type fieldType)\r\n   at GraphQL.ObjectExtensions.GetPropertyValue[T](Object value)\r\n   at GraphQL.Types.ResolveFieldContext.Argument[TType](String name)\r\n   at Samba.Services.Graphql.Automation.NotifyEventMutation.<.ctor>b__6_1(ResolveFieldContext context) in C:\\Users\\Vehbi\\Documents\\Source\\Repos\\sambapos-v5-pro\\Samba.Services\\Graphql\\Automation\\NotifyEventMutation.cs:line 152\r\n   at GraphQL.DocumentExecuter.<ResolveFieldAsync>d__8.MoveNext()",
        "RemoteStackTraceString": null,
        "RemoteStackIndex": 0,
        "ExceptionMethod": "8\nCreateInstance\nmscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.RuntimeTypeHandle\nSystem.Object CreateInstance(System.RuntimeType, Boolean, Boolean, Boolean ByRef, System.RuntimeMethodHandleInternal ByRef, Boolean ByRef)",
        "HResult": -2146233069,
        "Source": "mscorlib",
        "WatsonBuckets": null,
        "MMClassName": null,
        "MMMemberName": null,
        "MMSignature": null
      },
      "stackTrace": null,
      "helpLink": null,
      "source": null,
      "hResult": -2146233088
    }
  ]
}

I have the rule and action setup as follows:

image
image

image

Before doing all this, I have also tried using the updateEntityCustomData mutation to update the entity custom data directly from GraphQL, however there appears to be a bug with that mutation that only updates the entity randomly, hence why I’m trying the above ways.

1 Like

I just did a quick test on 5.3.0 and it is working fine, so this appears to be an issue in 5.3.2.

On 5.3.0:

I also confirmed on another system with a different database in 5.3.2 and it gives the same error message.

1 Like

Sounds like an old DLL got into the build. Thanks for the post as we use the updateEntityCustomData mutation as well (although I haven’t experienced any issues).

1 Like

Here’s something I put together for a SQL solution in the meantime. It’s kind of hacky but works:

/* Update Entity Custom Field */

IF OBJECT_ID('dbo.p_EntityCustomFieldUpdate') IS NOT NULL
  DROP PROCEDURE dbo.p_EntityCustomFieldUpdate;
GO

CREATE PROCEDURE dbo.p_EntityCustomFieldUpdate
  @EntityPk NVARCHAR(MAX),
  @CustomFieldName NVARCHAR(MAX),
  @NewFieldValue NVARCHAR(MAX)
AS
  BEGIN
    SET NOCOUNT ON;

    DECLARE @EntityId INT;
    DECLARE @CustomData NVARCHAR(MAX);
    DECLARE @NewCustomData NVARCHAR(MAX);
    DECLARE @FieldData NVARCHAR(MAX);

    DECLARE @CustomFieldsTable TABLE
    (
      Data NVARCHAR(MAX) NOT NULL
    );

    SELECT @EntityId   = Id,
           @CustomData = CustomData
        FROM dbo.Entities
        WHERE Name = @EntityPk;

    DECLARE cur_entity_fields CURSOR LOCAL FAST_FORWARD FOR
    SELECT Value
        FROM OPENJSON(@CustomData);

    OPEN cur_entity_fields;

    FETCH NEXT FROM cur_entity_fields
    INTO @FieldData;

    WHILE @@FETCH_STATUS = 0
      BEGIN

        DECLARE @FieldName NVARCHAR(MAX);

        SELECT @FieldName = FieldName
            FROM
          OPENJSON(@FieldData)
          WITH (FieldName NVARCHAR(MAX) '$.Name');

        IF @FieldName = @CustomFieldName
          BEGIN
            DECLARE @NewFieldData NVARCHAR(MAX);
            SELECT @NewFieldData = JSON_MODIFY(@FieldData, '$.Value', @NewFieldValue);

            INSERT INTO @CustomFieldsTable
            (Data)
            VALUES
            (@NewFieldData);
          END;
        ELSE
          BEGIN
            INSERT INTO @CustomFieldsTable
            (Data)
            VALUES
            (@FieldData);
          END;

        FETCH NEXT FROM cur_entity_fields
        INTO @FieldData;
      END;
    CLOSE cur_entity_fields;
    DEALLOCATE cur_entity_fields;

    SELECT @NewCustomData = N'[' + STRING_AGG(Data, ',') + N']'
        FROM @CustomFieldsTable;

    UPDATE dbo.Entities
        SET CustomData = @NewCustomData
        WHERE Id = @EntityId;

  END;
GO

usage:

dbo.p_EntityCustomFieldUpdate @EntityPk = N'7777777777',
                              @CustomFieldName = N'Address',
                              @NewFieldValue = N'123 Main St'
1 Like

It is same on 5.3.4.

1 Like

Hi Mark require help remotely. Can you book me in?

Does anyone know if this bug has been fixed? I can’t get notifyEvent to return anything but errors. Below is my mutation and the error message I’m getting. @Memo will this script sill work correctly in 5.7.2?

mutation{notifyEvent(
event:“AutomationCommandExecuted”,
parameters:[
{name:“AutomationCommandName”,value:“Default Create Entity”},
{name:“EntityType”,value:“Members”},
{name:“EntityName”,value:“entityMemberID”},
{name:“CustomData”, value:“Phone=‘+entityPhone’+;E-mail=‘+entityEmail+’;Date of Birth=‘+entityDOB+’;Address=‘+entityStreetAddress+’;Govt ID=‘+entityGovtID+’;Image=‘+entityPhoto+’;First Name=‘+entityFirstName+’;Last Name=‘+entityLastName+’;City=‘+entityCityAddress+’;State=‘+entityStateAddress+’;Zip Code=‘+entityZipAddress+’;Name=‘+entityFullName+’”},
{name:“CreateAccount”,value:“False”}
],
user:“GQLuser”,
ticketType:“Ticket”,
terminal:“Register 3”,
department:“Bar”,
state:{ticket:{id:0}}
){ticket{id}}}

Which gives me a result of…

{
“data”: {},
“errors”: null
}

or…

{
“data”: {
“notifyEvent”: null
},
“errors”: [
{
“locations”: [
{
“line”: 0,
“column”: 0
}
],
“message”: “Error trying to resolve notifyEvent.”,
“data”: {},
“innerException”: {
“ClassName”: “System.MissingMethodException”,
“Message”: “No parameterless constructor defined for this object.”,
“Data”: null,
“InnerException”: null,
“HelpURL”: null,
“StackTraceString”: " at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)\r\n at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, Boolean nonPublic)\r\n at System.Activator.CreateInstance(Type type)\r\n at GraphQL.ObjectExtensions.ToObject(IDictionary`2 source, Type type)\r\n at GraphQL.ObjectExtensions.GetPropertyValue(Object propertyValue, Type fieldType)\r\n at GraphQL.ObjectExtensions.GetPropertyValue[T](Object value)\r\n at GraphQL.Types.ResolveFieldContext.Argument[TType](String name)\r\n at Samba.Services.Graphql.Automation.NotifyEventMutation.<.ctor>b__6_2(ResolveFieldContext context)\r\n at GraphQL.DocumentExecuter.d__8.MoveNext()",
“RemoteStackTraceString”: null,
“RemoteStackIndex”: 0,
“ExceptionMethod”: “8\nCreateInstance\nmscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.RuntimeTypeHandle\nSystem.Object CreateInstance(System.RuntimeType, Boolean, Boolean, Boolean ByRef, System.RuntimeMethodHandleInternal ByRef, Boolean ByRef)”,
“HResult”: -2146233069,
“Source”: “mscorlib”,
“WatsonBuckets”: null,
“MMClassName”: null,
“MMMemberName”: null,
“MMSignature”: null
},
“stackTrace”: null,
“helpLink”: null,
“source”: null,
“hResult”: -2146233088
}
]
}

At the end of your GQL script you are asking it to return you ticket ids {ticket{id}}. And it returned nothing because there were no tickets related to this request. And there were also no errors as response specified.

Your automation was executed correctly.

{
"data": {},
"errors": null
}

I imagine this error below is because you are using automation command to create new entity that already exists.

{
“data”: {
“notifyEvent”: null
},
“errors”: [
{
“locations”: [
{
“line”: 0,
“column”: 0
}
],
“message”: “Error trying to resolve notifyEvent.”,

I am curious, why are you using Execute Automation Command event to add or update entity when there are GQL endpoints specifically for that purpose?

I don’t think it’s been fixed. The MissingMethodException exception leads me to believe there’s an old library hanging around somewhere.

What I’ve used in the past is postBroadcastMessage mutation and then search the message for certain strings.

Looking at your notifyEvent mutation, it looks like you’re trying to create an entity. If that’s the case, one might use the create entity mutation.

Aside from that, I’ve been out all evening so the brain isn’t running on all cylinders. If you can tell me what you’re trying to do, maybe we can find a solution that works.

1 Like

From my testing, GQL is very hit or miss when working with entities. For the workflow I’ve been assigned, the entity is created first and then updates are made to the entity via a tablet, rather than the entire process being performed by an employee.

(The Entity is created at a terminal with a unique ID(MemberID)by an employee, its then sent to the tablet where the patron fills out their membership information. When the patron finishes, the membership enrollment screen is refreshed (in theory. Ive attempted this a couple ways with no success) where the employee verifies their info and assigns a membership keyfob that holds their MemberIDs and AccessIDs for the facility.)

When updating the existing entity after the tablet is returned I can never get all of the data to update. It’s sent and a response is received for each field, however only about half to 3/4 of them are actually updated in Samba. And it’s never the same fields. Admittedly, I’m new at using GraphQL so I’m aware ths very well could be an error on my part but figuring that out on my own takes weeks. Theres very little in reference to GQL in the forum, the apidoc website is incomplete as a whole, and trying to find help via the web is too overwhelming for my current skill level. Unfortunately I don’t know anyone in my circles that uses GraphQL regularly. :confused:

That was my orignal thought but when I check Samba, no changes are made.

I explained my workflow in my response to Posflow but I can elaborate further if needed. Honestly it may be easier for me to send you a backup of the dev database I’m working on and highlighting the rules and such there?

Are you saying uninstalling and reinstalling a fresh copy could possibly fix some of these issues, or do you mean the libraries included with the acutal installation are old?

Thank you so much for your responses!

I’m just throwing this out there as an idea, but what if you created another entity screen for the customer to fill out.

I think it could be configured that as the customer screen gets filled out the employee screen is automatically update. This would require 2 terminals.

Again, this is just an idea.

Try using GQL query to add entities. Should work straight away, obviously replace your entity type names and custom data fields you have setup for your entity type. I can see it listed in entities straight away.

mutation addEntity {
  addEntity(entity: {entityType: "Customers", name: "ahadhadha", customData: [{name: "First Name", value: "@first_name"}, {name: "Last Name", value: "@last_name"}, {name: "Address", value: "@address"}, {name: "City", value: "@city"}, {name: "Organization", value: "@organization"}, {name: "Email", value: "@email"}, {name: "VAT TIN", value: "@vat_id)"}, {name: "Room", value: "@room"}, {name: "Gender", value: "@gender"}, {name: "Phone", value: "@phone"}, {name: "Nationality", value: "@nationality"}]}) {
    id, name
  }
}

RAW

{"query":"mutation addEntity {\n  addEntity(entity: {entityType: \"Customers\", name: \"ahadhadha\", customData: [{name: \"First Name\", value: \"@first_name\"}, {name: \"Last Name\", value: \"@last_name\"}, {name: \"Address\", value: \"@address\"}, {name: \"City\", value: \"@city\"}, {name: \"Organization\", value: \"@organization\"}, {name: \"Email\", value: \"@email\"}, {name: \"VAT TIN\", value: \"@vat_id)\"}, {name: \"Room\", value: \"@room\"}, {name: \"Gender\", value: \"@gender\"}, {name: \"Phone\", value: \"@phone\"}, {name: \"Nationality\", value: \"@nationality\"}]}) {\n    id, name\n  }\n}\n","variables":null,"operationName":"addEntity"}

Should also return, you can use name returned to pull any details you need from this entities also via GQL, or you can use Id if you want to do SQL queries.

{
  "data": {
    "addEntity": {
      "id": 169,
      "name": "ahadhadha"
    }
  },
  "errors": null
}

image

You can also use GQL to get the data via this query

query get_entities($type: String!, $search: String!, $state: String!) {
  getEntities(type: $type, search: $search, state: $state) {
    id
    name
    accountId
    customData {
      name
      value
    }
  }
}

RAW

{"query":"query get_entities($type: String!, $search: String!, $state: String!) {\n  getEntities(type: $type, search: $search, state: $state) {\n    id\n    name\n    accountId\n    customData {\n      name\n      value\n    }\n  }\n}\n","variables":"{\n  \"type\": \"Customers\",\n  \"search\": \"ahadhadha\",\n  \"state\": \"\"\n}","operationName":"get_entities"}

It will respond with all the details

{
  "data": {
    "getEntities": [
      {
        "id": 169,
        "name": "ahadhadha",
        "accountId": 0,
        "customData": [
          {
            "name": "First Name",
            "value": "@first_name"
          },
          {
            "name": "Last Name",
            "value": "@last_name"
          },
          {
            "name": "Address",
            "value": "@address"
          },
          {
            "name": "City",
            "value": "@city"
          },
          {
            "name": "Organization",
            "value": "@organization"
          },
          {
            "name": "Email",
            "value": "@email"
          },
          {
            "name": "VAT TIN",
            "value": "@vat_id)"
          },
          {
            "name": "Room",
            "value": "@room"
          },
          {
            "name": "Gender",
            "value": "@gender"
          },
          {
            "name": "Phone",
            "value": "@phone"
          },
          {
            "name": "Nationality",
            "value": "@nationality"
          }
        ]
      }
    ]
  },
  "errors": null
}

You can also use updateEntityData query to specify fields and values you want to update. All of it happens almost instantly.

Dont quote this last one, but I think updating entities with entity queries, solves caching issues that you might have issues with using execute automation command query

I heavily contemplated this however space is a major concern at this venue. My thought was “This is going to be a sinch, I’ll just get a Slate with windows on it and boom! Done!” I hadn’t realized hardware had already been purchased so I’m stuck with what they prematurely purchased… which are Android tablets.

After thinking about it I guess in a way I understand where they are coming from. You can buy 4 android tablets for the price if a decent Surface. And lets be honest - with the nature of a tablet there is always the risk of it walking out the door.

I think this may be where I’ve gone wrong. I hate being a novice at this. Is it incorrect to use updateEntityCustomData to change the Entity information? I guess maybe I’m utilizing that incorrectly.

Thank you so much for taking the time to explain. Where are you on this planet? I’ll send you a beer! :rofl: If I could ask one last thing and I’ll go back to hammering this out… Well maybe two things…

I guess I wasn’t thinking outside the box enough. I’m thinking in theory and with what you’ve shown me I should be able to (instead of creating the entity first) create the entity WITH all of the updated information from what the patron enters on the tablet. Then send a refresh to samba for the employee screen where they can verfiy and deliver the fob. This is going to mess up the flow they want because they want the employee to enter the fob numbers first then hand them the tablet. But I think that’s an easy fix. All I would need is to save program settings and then recall them after the tablet is returned. Does that sound right? lol I think I’m back on track again.

Lastly Is there any way I can trouble you to break down this query in basic terms?

It’s a little more advanced for my understanding of GQL thus far but would definitely help in my learning curve, I’m sure. Please don’t go out of your way, though. Any help is awesome and you’ve already done a lot!

Thank you again!

After reading through your posts, I would start by logging the custom fields to see if something might be going on where the name and/or the value is null or a zero-length string.

Item below is like a function name you specify. Or as GQL calls it, ‘operation name’.

query get_entities($type: String!, $search: String!, $state: String!)

This is the GQL query below is what SambaPOS recognizes and will process it.
You assign variables to what you are looking for.

For example, type is referring to entity type, search is the value it will lookup from entity data i.e. name, custom fields etc.
State is to look up ‘search’ value that is of certain entity status. Which is super useful if you have custom states you apply / switch to entities based on some actions user makes.

{
  getEntities(type: $type, search: $search, state: $state) {
    id
    name
    accountId
    customData {
      name
      value
    }
  }
}

The id, name, accountId and customData are part items you want the API to return you after its done processing your request. You can return this values when you are doing both query and mutations, obviously each GQL has different values it can return.

You can specify what specifically you are looking for.
If you want it to return just id or name, then remove the other ones.

Yes you can use updateEntityCustomData to update your entities

mutation updateEntityData($entityTypeName: String!, $entityName: String!, $name: String!, $value: String!) {
      updateEntityCustomData(entityTypeName: $entityTypeName, entityName: $entityName, name: $name, value: $value)
      {id, name, accountId}
    }

Store it all in local settings of the device then once the employee makes final confirmation, process all details into format needed and use GQL query once, instead of doing it 10 times for each field they enter.

P.S. I am in Cambodia :cambodia: :grin:

1 Like