Handling a complex custom formAction

I’m curious how to build some complex form logic and specifically when and how often the required_slots method is called.

I have a few nested yes/no questions that lead down different paths and I’m having a problem with a nested if statement.

here’s is my required_slots function

    def required_slots(tracker: Tracker) -> List[Text]:

        if (tracker.get_slot("erms_revoked") is None or tracker.get_slot("erms_revoked") == "Yes"): 
            requiredSlot = ["erms_revoked","erms_document_number","erms_manifest_number","erms_nsn","erms_error_number","erms_screenshot","erms_uic","erms_username","erms_expired", "erms_other_information"] 
        else: 
            if (tracker.get_slot("erms_requesting_access") is None or tracker.get_slot("erms_requesting_access") == "Yes"):
                requiredSlot = ["erms_requesting_access", "erms_which_access"]
                if (tracker.get_slot("erms_which_access") is None or tracker.get_slot("erms_which_access") == "NITA"):
                    requiredSlot = ["erms_which_access","erms_existing_user"]
                else:
                    requiredSlot = []
            else:
                requiredSlot = ["erms_document_number","erms_manifest_number","erms_nsn","erms_error_number","erms_screenshot","erms_uic","erms_username"] 
        return requiredSlot

Here’s a rundown of what happens if erms_revoked == Yes, everything runs fine because it is one path to the end

If erms_revoked == No, the else section executes

But inside the big else section, I’m expecting it to prompt with erms_requesting_access, but I am never asked erms_requesting_access, it jumps down and prompts erms_which_access

My many questions:

  • when does required_slots run? once or multiple times through the form?
  • should it work this way?
  • is there a better / different way to structure something like this?

The required_slots is executed multiple times through the forms.

    requiredSlot = ["erms_requesting_access", "erms_which_access"]
    if (tracker.get_slot("erms_which_access") is None or tracker.get_slot("erms_which_access") == "NITA"):
            requiredSlot = ["erms_which_access","erms_existing_user"]

if “erms_which_access” is asked after the “erms_requesting_access”, that means it will be None when you want the bot to ask for “erms_requesting_access”. So the requiredSlot will always equal [“erms_which_access”,“erms_existing_user”], which explain why the bot asked for “erms_which_access”.

1 Like

@fuih You. Are. Awesome.

Thank you for explaining that. I was staring and hacking on it at it all day. That makes total sense. For some silly reason I was writing it as though the IF statements were acting like a Switch statement and breaking out once requiredSlot was filled, not cascading down through multiple statements Oi. Clearly I had been working on it too long, I do know how IF statements work, even though it doesn’t look like it :roll_eyes:

Solution: I added returns after I set the requiredSlot and it now it works as expected Like this:

if (tracker.get_slot("erms_requesting_access") is None or tracker.get_slot("erms_requesting_access") == "Yes"):
    requiredSlot = ["erms_requesting_access", "erms_which_access"]
    return requiredSlot
    
    if (tracker.get_slot("erms_which_access") is None or tracker.get_slot("erms_which_access") == "NITA"):
         requiredSlot = ["erms_which_access","erms_existing_user"]
         return requiredSlot
 [snipped ...]

THANK YOU again! It definitely helps to have another set of eyes on your code :slight_smile:

1 Like