Processing Form by CRM-Script

lock
push_pin
done
Beantwoord
38

Hi, 

I'm looking for a solution to process a Form by CRM-script  that has been submitted and is markt to be processed manually.

That way there are more ways to identify if the submitter is a existing contact or person by searching by name , email or phone number.

Any pointers on how to proceed .

regards,

Mehmet 

22 feb 2023 | 10:22 a.m.

Alles Antwoorden (38)

Good day Mehmet,

You can use CRM script in combination with setting "Manually for all submissions", Example -> 

Your script should needs to hold information about EventData, more about this function you can read here -> https://docs.superoffice.com/en/automation/crmscript/datatypes/eventdata-type.html

The script will not be triggered until you manually processed form submission.   

A tip: 
If you log EvenData information you could see all possibilities that you extract with this function. 

#setLanguageLevel 4;

EventData ed = getEventData();
log(ed.getInputValues().toJson()); 

Log informatio is accessible -> Service -> Settings-> System design -> Debug Log

I hope this will help you. 

22 feb 2023 | 01:28 p.m.

Hi!

I am hijacking this thread. :-)
I am also working with a script to be used to process forms. My code is working well when the form field person_email is filled and the submission process is finding a that email-adress (but only if the email-adress is unique) . 

I have set the form to create a request for notification, runing a script automaticlly if submitter is known.

In the CRM script I am using the eventdata and loads the ticket-id. Then adding some of the form values into extra fields on to the request.
As Said this is working when the scripts runs automatically. 
My problem is that if the submitted form is not processed automatically the it does not work.
I have traced the script and probably found a bug. Ticketid is, when picking a contact and manually push the process button, blank. 

Can you confirm this as bug?

Also if contact-person is set to former employee the formsubmission code does not automatically process the incomming form. (even if the former employee has an unique email-adress)

It is bad that ticketId is blank when doing a submition manually.

How can I get around this?

If I automatically process all submission, then companies and contactpersons that is not found is created. (thats is not an option in my case)

There should be 4th option under action

Automatically process all submission (but do not create company and contactperson) - Used when scripts is responsible for processing a form submission

Any suggestions is welcome.

Does anyone have had the same issues?

//Anders

 

28 jun 2023 | 02:43 p.m.

Hi Anders Larsson,

I proces the form by using the trigger: Service: New notification request from form submission   by checking the Notify of submission by creating request and have the option Manual for all submissons for processing option.

The request has a pre-set  tekst as the title , all processsing is done in the trigger . You have full controll of the values and how to proceed.

You can check for retired option  etc. and use the power of CRM script to set all the values for the request and other data to process.

If nothing matches or something is faulty I delete the created ticket and set the formsubmission status to processed.


There are some issues that do not match expected form functionallity , not sure if that should be considerd a bug .



Hope this helps. 
Regards 
Mehmet

28 jun 2023 | 03:57 p.m.

Hi, thanks.

I am using the "by checking the Notify of submission by creating request "  and then like in the above picture calling a a script.
That works perfectly when the engine finds an unique contact to map that submission to. (CRMs script then updated the notify ticket with new title and setting some extra fields with data collected from the form)

If running the tracing of script , the Eventdata contains the ticketId of the notification message. but when processing manually eg when contactperson not found or a duplicate is detected. the ticketId in eventData for some reason is blank. That breaks my logic in the script.

So that for me seeams like bug? I mean that if go into such notify request and see the blue line that "I need to process the submitted form" and do that I expect that the ticketId should be there in the eventData.

Can anyone from RND/Support comment on this?

I guess that it might work slightly different in the triggerscript

Have you code that allways creates new ticket (different trom the notify ticket?)  and then deletes the notify ticket. A collegue of mine reported that ticketId is empty in eventdata when he tried the trigger you suggested.
Could you check in your environmnet/code if ticketId is filled or blank 

Integer ticketId=-1;

String ticketIdTest = ed.getInputValue("ticketId");

if(ticketIdTest !="")
{
  ticketId=ticketIdTest.toInteger();
}  

In my case we want to minimize manuall handling. (eg run process sumbission manually is probably not what the customer wants for the form data that we collect in this case) 

//Anders

 

29 jun 2023 | 12:39 p.m.

Hi :

 

if (!debug) {
    //{"activeUser":"2","ticketId":"808"}
    EventData ed = getEventData();
    log("Trigger form submit ");
    ticketId = ed.getInputValue("ticketId");
    log(ed.getInputValues().toJson());
    log("Ticket:" + ticketId);
}

29 jun 2023 | 12:50 p.m.

I do have this do in my code to close the formsubmission: I do not recall why...  ( on-prem)

 

                          SearchEngine sU;
                          sU.bypassNetServer(true);
                          sU.addData("form_submission.contact_id", contactid.toString());
                          sU.addData("form_submission.person_id", personid.toString());
                          sU.addData("form_submission.status", "4");
                          sU.addCriteria("form_submission.form_id", "Equals", "2");
                          sU.addCriteria("form_submission.form_submission_id", "Equals", formsubId);
                          sU.update();

29 jun 2023 | 12:53 p.m.

Thanks Mehmet.

Seems like you have some more sofisticated script knowledge then me.

Regarding your code:
    ticketId = ed.getInputValue("ticketId");
 

Do you get a value there? that corresponds to the notify ticketId? 

If yes what version of SuperOffice onPrem are you using. (I am on 10.1.6 OnPrem)

//Anders

 

 

 

29 jun 2023 | 01:02 p.m.
still on 8.5 R17 on prem
29 jun 2023 | 01:18 p.m.

The last code you sent is intressting.
That is probably handled automaticly when not using the the trigger-script.

It seems to update the actual data that is displayed in the form report , like status and if it is processed etc, 

//Anders

29 jun 2023 | 01:06 p.m.
I do a manual search for the customer .. not only using the e-mail to match , but also other stuf .. create new person / contact if needed or link to existing if things match .. full control ..
29 jun 2023 | 01:19 p.m.

ok

Yeah, I am also actually (when I get the ticcketId) searching for a specific hidden form-field that will be sent by the form (it is framed in to another app) and matching that to an unique PersonNumber. 

My problem is that ticketId is blank when formsubmission is processed manually.
That was why I wondered if the ticketId you get from eventdata when doing a manual processing of the form is the ticket id of the notification request??

If this worked in SO 8.5 R17 and it does not work in SO 10 then a bug has slipped through the testing i guess..

But maybe I should give this trigger script a chance.

If you like to share you trigger script please do not hesitate to reach out to me and i could adjust and test that in SO 10.1.6

//Anders

29 jun 2023 | 01:32 p.m.

It is the ticket created by the form : 
then I get the formSubmissionId  from the ticket .

    formsubId = t.getValue("formSubmissionId");

and get the formdata using

        NSMarketingAgent fAgent;
        NSFormSubmissionEntity formSData;
        formSData = fAgent.GetFormSubmissionEntity(formsubId.toInteger());


29 jun 2023 | 01:53 p.m.

Thanks Mehmet, for sharing your knowledge and confirming that you (when using crm-trigger: Service: New notification request from form submission ) and running the processing manually gets a ticketId out from eventdata.

I Will try to create a simple CRM-trigger script to see if eventData is sending ticketId or not in SO 10.1.6

 

//Anders

29 jun 2023 | 02:26 p.m.

Hi,

Did try send a post, but I was not logged in and it disappeared:-(

Long story short. Your method seems to might work. And is some sort of override of processing the formsubmission automatically. (even if you have process manually in the action pane on the form, and no script as action there?)

I was about to post that the eventData at that stage does not contain any formvalues:

getEventData(): 
"{"type": 0,"inputValues": {"entryId": "76449","ticketId": "76449"},"blockExecution": false,"navigateTo": "","message": "","outputValues": {},"stateValues": {}}" (EventData)

But I now realize that we fetch the submissiondata from the ticket. clever.
And the Json actually seems to be there:

String formResponse = formsData.GetResponse();

I will need to change myc script to fetch data from that instead.
How I am not sure.
I have from eventData used:
String BusinessObjectId = ed.getInputValue("boid"); (where "boid" is the field identifier.
=>
String BusinessObjectId = formResponse.??

If I trace the trigger script I can see that there seems to be data per field. 

How wan I fetch from the jsonFormated string , in the best way?

Do I need to convert it to easily be able to fetch each field by its field Identifier ?

//Anders

3 jul 2023 | 10:40 a.m.

Whell I do it this way .. not sure if it is the best way.

          NSMarketingAgent fAgent;
                NSFormSubmissionEntity formSData;
                formSData = fAgent.GetFormSubmissionEntity(formsubId);
                String fEmail = formSData.GetEmailAddress();
                String formJson = formSData.GetResponse();
                formResponseData FD;
                FD.fromJson(formJson);       
                for (Integer i = 0; i < FD.fields.length(); i++) {

                    if (FD.fields[i].type == "InputText") {
                        //check if numeric
                        if(debug)printLine(FD.fields[i].identifier);
                        if (FD.fields[i].identifier == "field_name") {         
                            if (FD.fields[i].value.isNumber() ) {   
                                if (FD.fields[i].value.toInteger() > 0 ){
                                       field_name = FD.fields[i].value.toInteger()
                                }
                            }else{
                                      //NAN
                            }
                        }

                       // other type of fields 

                    if (FD.fields[i].type == "Hidden") {}
                    if (FD.fields[i].type == "RadioButtons") {}
                    if (FD.fields[i].type == "Date") {}
                    if (FD.fields[i].type == "Textarea") {}
                     }

     

I have created a custom table with these fields and proces the json once and then use the table to do other stuf .. and it is a goed log if the submission is deleted for some reason .. 

.. hope this helps 

 

Mehmet 

3 jul 2023 | 11:28 a.m.

Thanks again! 

That should take me one bit closer:-)

I like the idea of an extra table holding the form-submission values.
Do you use that as a standalone table or do you connect it to some entity like the request/ticket or person?

//Anders

3 jul 2023 | 12:28 p.m.
It depends , if you like to connect to one of those entities it makes sense to connect the table with a relation .
In my case I just have a stand-alone table to hold the submission data that has already been processed ..
3 jul 2023 | 01:14 p.m.

ok will have to skip extra table for now.

unfortunately this part does not seem to work in SO 10.1.6 (not a vaild identifier , I guess formResponeData is something that you have created? since i can not find any information on that in docs.
Struct or class or something? 

formResponseData FD;
FD.fromJson(formJson);       
                for (Integer i = 0; i < FD.fields.length(); i++) {

Sorry for my limeted script-knowledge :-(

I tried to convert the formJson to a map but that did not work
I just want a way to extra each field from the Json-string (fetched by: String formResponse = formsData.GetResponse();)
so that I can process and save the value to corresponding extra fields on the request.

 

 

//Anders

3 jul 2023 | 02:19 p.m.

Here you go: You can customize it to your needs ..  
It is just to hold the json form the submission in a struct .. 

//----
Struct field
{
  String label;
  String identifier ;
  Integer sequence ;
  String value ;
  String type ;
  Bool readOnly ;
  String displayValue ;
};

Struct formResponseData {
  field[] fields ;
  Bool hasCompany ;
  String sitekey ;

  String toJson() {
    JSONBuilder jb;
		this.toJson(jb);
		return jb.getString();
  }

  Void fromJson(String json) {
    try{
    this.fromXMLNode(parseJSON2(json));
    }catch{
      json = '{"fields":[{"label":"fout1","identifier":"fout1","sequence":1,"value":"","type":"fout1","readOnly":false}],"hasCompany":false,"sitekey":""}';
      this.fromXMLNode(parseJSON2(json));
    }
  }
};
3 jul 2023 | 02:30 p.m.

Thank you so much Mehmet!

I know have working trigger-script (almost) - Field values are fetched (since I before used a stand-alone script fetching values vis EvenData

I wanted a simlar way of doing it.so when itterating through the Sruct (formResponseData) I am puting all the fields in 2 StringObject Dictonary

//Create a string dictionaries 
 StringObjectDictionary FormFieldValues;
 StringObjectDictionary FormFieldTypes;


  for (Integer i = 0; i < FD.fields.length(); i++) {


/* Use if we want to do anuthing to certain fieldTypes
    if (FD.fields[i].type == "Text") {}
    if (FD.fields[i].type == "Hidden") {}
    if (FD.fields[i].type == "RadioButtons") {}
    if (FD.fields[i].type == "Checkbox") {}
    if (FD.fields[i].type == "Date") {}
    if (FD.fields[i].type == "Textarea") {}


*/
    if(debug)log("FieldType: " + FD.fields[i].type + " | FieldIdentifier: " +FD.fields[i].identifier + " | FieldValue: " +FD.fields[i].value);


    if (FD.fields[i].type == "Checkbox") {
    FormFieldValues.insertString(FD.fields[i].identifier, FD.fields[i].displayValue);
    FormFieldTypes.insertString(FD.fields[i].identifier, FD.fields[i].type);
}
    else
    {
      FormFieldValues.insertString(FD.fields[i].identifier, FD.fields[i].value);
    FormFieldTypes.insertString(FD.fields[i].identifier, FD.fields[i].type);
    }
 
}

I can then just pick up my values where I need them like this:

 String BusinessObjectId = FormFieldValues.getString("boid");					 	//ed.getInputValue("boid");
 String BusinessObjectTypeId = FormFieldValues.getString("botid"); 					//ed.getInputValue("botid");
 String BusinessContactPersonId = FormFieldValues.getString("bcpid");				//ed.getInputValue("bcpid");

 String UserName = FormFieldValues.getString("custuser");							//ed.getInputValue("custuser");

 

The only thing that does not work is the update of submission information.

Any Idea why that is not working from the trigger-script? (If I run the code from a standalone TEST-CRM script it does work)

// START - code to set the submission status etc to match the found contact Person-----------------------------
  
  // Update formsubmission data to matched contactperson and processed (status=4)

      SearchEngine sU;
      sU.bypassNetServer(true);
      //if(SubmissionCompanyId>0)sU.addData("form_submission.contact_id", SubmissionCompanyId.toString());
      sU.addData("form_submission.contact_id", SubmissionCompanyId.toString());
      //if(SubmissionPersonId>0)sU.addData("form_submission.person_id", SubmissionPersonId.toString());
      sU.addData("form_submission.person_id", SubmissionPersonId.toString());
      sU.addData("form_submission.status", "4");
      sU.addCriteria("form_submission.form_id", "Equals", "5");   // id=5 is avvikelsformuläret i TEST, might be unneded , but as a safeline we have this here to not set all type of forms to processed.
      sU.addCriteria("form_submission.form_submission_id", "Equals", formsubId);
      sU.update();


// END - code to set the submission status etc to match the found  contact Person--------------------------------
4 jul 2023 | 12:16 p.m.

Update submission using SearchEngine did not for me either I see...  perhaps it is in the trigger ? 


I have made  an escalatian  priority  to run the script that  runs this bit of code in a seperate script.

So just set escalation level of the ticket in the trigger  and set it to run after a minuut or so. 

 

4 jul 2023 | 12:34 p.m.

Hi,

Ok, that was at least consistent then and not only in my environment.
Might be some bug in trigger-script or it should not be possible to do that kind of update operations from a trigger script. (seems od though)

Hum , i have nerver worked with escalation levels. 

I am thinking out loud:

Is it possible to execute another script from with in the triggerscript?
Or have scheduled script running every 10 minute or so to load submissions that is not processed and if they are ok, eg connected to person then we update the submission to processed and set the correct person and company Id?

//Anders

4 jul 2023 | 12:45 p.m.

It is some sort of restriction ... I ques.  Executing another script within the trigger script did not work.

Scheduled script is I think same as you would do this by an escalation level . just execute the script outside the trigger event should work.

4 jul 2023 | 01:39 p.m.

Thanks!

How do we kick of another script from within a CRM-Script? I did not find such information on docs.

Anyway:

I ended up in setting a special ticket_status instead "TriggerProcced" from the within the triggerscript. (did not now what would happen with other request categories if escalation was to be used, did not find a way of just putting escalation on only my formsubmitted request type)

I then created a script that fetches submissions that has -1 in Form_sumbmission table in person_id (searchEngine) 

That results in a list of ticket_ids. That together with above special ticket_status gives the critera of what tickets we should manipulate the submission status , contact_id and person_id. (control if contact and person is filled on the ticket is also done)

Not the most elegant way perhaps but i works. 

That script I then has scheduled to run every 15 min.

I am about to send in a bug request to SuperOffice over the initial problem, eg that manually processing a form and using action crm-script the ticke-id of the notify request is not sent.

 

5 jul 2023 | 07:05 a.m.

Hi,

I have not paid attention to this discussion, but perhaps this is relevant:

https://docs.superoffice.com/en/automation/crmscript/reference/CRMScript.Global.Void.html#CRMScript_Global_Void_executeScript_String_Map_

E.g.

printLine("Script result: " + executeScript("printLine('Hello world');", Map()));

If you need to execute another script that is stored in the database, just use #include.

Sverre

5 jul 2023 | 07:39 a.m.

Thanks Sverre.

2 questions for you.

Nr1. Executing a searchengine update and or a another script from within a triggerscript does not seem to work. Is that a bug or by desgin? 

Nr2. Is it a bug or by design that ticket_id is blank "" when processing a form submission manually (my initial questio in this thread)? and having a CRM-scrip as action? I have sent a question to "bug" and got bug-Id: 3378507. 

(I did check today again, and found that submission_id, is sent so that I could have used in my initial script to fetch the correct ticket_id, but my knowledge of how this notify request , submission-data and ticket etc is connected , was limeted at the time.

//Anders 

 

 

5 jul 2023 | 07:51 a.m.
Hi, the correct bugId is this: 45458
https://community.superoffice.com/en/product-releases/bugs-wishes/product-issue/?bid=45458&azure=1
15 aug 2023 | 10:06 a.m.

And one more

If you have a script in the database. lets say its include name is: test

Can I do like this you mean

#setLanguageLevel 3;

String test = "TEST - before run another Script"

printLine(test);

#include test

//will external scrpt run here?

printLine("After external test script");

//Anders

 

5 jul 2023 | 07:59 a.m.

ok, last question you can Ignore.

I did test out this code and it works. Nice! but not from triggerScript.

#setLanguageLevel 3;
//#include "functionscript";


//Print

String testQ = "TEST run another Script";

printLine(testQ);
#include "SearchEngineUpdateTest";

//will external scrpt run here?

printLine("After external test script");
5 jul 2023 | 08:20 a.m.

Hi Anders,

There should be no difference between a triggerScript any any other script. SearchEngine, etc should work normally. I suggest you add some log() calls inside your script to get a better view of what is happening. Or enabling tracing, but I believe there is a bug that tracing does not work for triggerScripts. Or perhaps webhooks. Not sure.

I did not mean exactly like you did with the #include, but your method should work as well. However, with your method, the included script is executed within the same script instance (sharing variables, etc). Calling executeScript() will run another script within another script instance (not sharing variables).

Regarding the blank ticket_id for manually processed forms, I guess that is a bug since you got a bug-id in return. 

Sverre

5 jul 2023 | 08:26 a.m.

Thanks Sverre.

I will try to remember to post the outcome from RND when I get some response regarding the possible bug.

ok, intereseting that triggerScript should allow searchEngine updates and execution of another script.
Will try to test out one more time with the 2 methods of running "extra" script and do some more logging.

//Anders

5 jul 2023 | 08:34 a.m.

Just another thought. I have not looked too closely at what you are doing, but if your trigger script is executed before we do a save inside our system, then your change will probably be overwritten.

For instance, add a trigger for "Before saving contact", where you change something on the contact, will not work because the system will save the contact just after your script has executed. And it will save with the data it has in memory, which does not include your change.

Sverre

5 jul 2023 | 08:38 a.m.

ok, that can make scenes.

I am using the trigger: Service - New notification request from form submission

Fetching sumbissiondata and proccesing updates to the ticket (filling formdata to the ticket xtra-fields). saving the ticket before trying to update submission metadata eg changing the form_submission table status to "processed" from "submitted. updating company and person that the ticket is attached to in the submission_table so it corresponds to values to the matched person and company in step 1.

But it might be some restrictions as well

CRMScript triggers also support updating values back to the executing environment. For this functionality, the same limitation applies to both platforms: Only immediate values on the entity are supported. I.e. you can update the title of the sale, but you cannot update the name of the related associate.

https://docs.superoffice.com/en/automation/trigger/index.html#what-kind-of-triggers-can-i-create

5 jul 2023 | 09:03 a.m.

Ok. Please be aware: That trigger is for the ticket that is created to "Notify about a form submission", not the ticket that is created as the form post. If your form is about creating a ticket (e.g. a support form), then you are using the incorrect trigger. And in fact, from what I can read from the code, the ticket has not even been created yet when your script is executing.

If you want a trigger when a form-post-ticket is created, you need to use the "New ticket from form submission"-trigger.

Sverre

5 jul 2023 | 09:10 a.m.

Hi Sverre,

It is a bit confusing:  the form submission creates the ticket that is specially created to notify about the form-submission. That is the ticket I want to use .. It contains the formsubmission_id ..

Not sure what the "New request from form subbmission " does,  does it create an other ticket ?  and why  two tickets .. 

When using executeScript()   , can you put in the script include name or does het have to contain the whole script as text  ? , the documentation on this is not that explanatory . 

Mehmet

5 jul 2023 | 09:33 a.m.

Hi Mehmet,

A form submission can create two tickets which is used in different scenarios:

  1. Let's say you have a form for people to register as a prospect. And then you would like to be notified of form submissions. You can be notified using the built-in notification system (the bell in the top of the CRM screen). Or you can be notified via a ticket. This is a notification ticket. It only serves as a notification that someone submitted the form.
  2. You could have a form that is a support-form, i.e. where customers submit support tickets. Then you want the form submission to create a support ticket with a message.

If you want a CRMScript for scenario #1, then you have used the correct trigger.

executeScript() will execute actual code that is provided in the argument. But the code could contain an #include, so that you don't have to provide the whole script body, but rather just a small include-statement.

Sverre

5 jul 2023 | 09:44 a.m.
I think we have used the correct trigger and thank you for explaining the executeScript() method.
5 jul 2023 | 10:11 a.m.

Hi,

We are using a marketing form (template from online library) - that is tweeked and used.

The only ticket that is created is the Notify ticket. (Even when automatically processed , eg when finding unique email.  (not even when selecting action: built in CRM Script: Create Ticket from system folder)

No new ticket is created.

The system uses the Notification ticket, during processing, eg when trying to map that ticket to a  person to be able to set is as processed.

That ticket_id is not sent when processing the formsubmission manually. (but when processing happens automatically, eg the email-adress is unique or if customer /contact is created during the processing the ticketId is correct sent in EventData)

So i think as Mehment that we are using the correct trigger and that it is not wrong to updated that with form-data on extra_fields etc.

(I actually tried the other trigger, but it did never fire, so maybe that is from customercenter created tickets)

The ticket is created just before the trigger hits. So the underlying system that received the form buton "send", creates the ticket and also form_submission record.

Note.
Indirectly it should be possible to search for the ticket that has a matching formsubmissionId , that actually is there in the EventData even when doing manually processing. (if we for some reason does not want to put our code in the TriggerScript. harder to develop trigger script I think)

It would be good if ticketId was sent also when processing manually. (more consistent I think)

//Anders

 

5 jul 2023 | 12:35 p.m.

Reply toevoegen