Form Validation - Validation of one slot depends on other

Hey Everyone, In have two slots in my form. Validation of second slot depends on the first slot. The problem occurs in the case like, When the user enter the second slot without the first slot, the validation of second slot fails.

I can customise the validation in validation function, but when the slots come prefilled the validation is not occurring. Because the prefilled slots are validated in validation_slots function. So I have to customise in validation_slots function but still I could not achieve what I wanted.

Can someone help me how to achieve this kind of validation? @akelad

Hi Gunalan,

could you share some code with your question? That might make it easier to debug/think along.

Hi @koaning

Here is the code,

class OrderLineAttributeForm(FormAction):

	def name(self) -> Text:
	    return "order_lineattribute_form"

	@staticmethod
	def required_slots(tracker: "Tracker") -> List[Text]:
	    return ["orderNumber", "lineNumber"]

	def slot_mappings(self):
	    return {"orderNumber": self.from_entity(entity="orderNumber",
	                                            intent=["orderline_details",
	                                                    "inform"]),
	            "lineNumber": self.from_entity(entity="lineNumber",
	                                           intent=["orderline_details",
	                                                   "inform"])}

	@staticmethod
	def validate_orderNumber(
	        value: Text,
	        dispatcher: CollectingDispatcher,
	        tracker: Tracker,
	        domain: Dict[Text, Any],
	) -> Dict[Text, Any]:
	    token = tracker.get_slot('st_token')
	    ordernumber_response = order_api.get_orderheader_orderno(order_number=value,
	                                                             st_token=token,
	                                                             env=environment)
	    if ordernumber_response.status_code == 400:
	    * Some utterances *
	        return {"orderNumber": None}
	    return {"orderNumber": value}

	async def validate_slots(
	    self,
	    slot_dict: Dict[Text, Any],
	    dispatcher: "CollectingDispatcher",
	    tracker: "Tracker",
	    domain: Dict[Text, Any],
	) -> List[EventType]:
	    token = tracker.get_slot('st_token')
	    order_number = tracker.get_slot('orderNumber')
	    line_number = tracker.get_slot('lineNumber')
	    slot_dict.update({'orderNumber': order_number})
	    slot_dict.update({'lineNumber': line_number})
	    for slot, value in list(slot_dict.items()):
	        validate_func = getattr(self, f"validate_{slot}", lambda *x: {slot: value})
	        if utils.is_coroutine_action(validate_func):
	            validation_output = await validate_func(
	                value, dispatcher, tracker, domain
	            )
	        else:
	            validation_output = validate_func(value, dispatcher, tracker, domain)
	        if not isinstance(validation_output, dict):
	            validation_output = {slot: validation_output}
	        slot_dict.update({'is_order_validated': True})
	        slot_dict.update(validation_output)
	        if slot == 'lineNumber':    
	            order_number = slot_dict['orderNumber']
	            if order_number:
	                output = order_search.validate_line_number(order_number=order_number,
	                                                           line_number=value,
	                                                           token=token,
	                                                           environment=environment)
	                text = output['text']
	                if text:
	                    dispatcher.utter_message(text)
	                isvalid = output['isvalid']
	                if not isvalid:
	                    slot_dict[slot] = None
	                    print("Line number invalid")
	                    ret = [SlotSet(slot, value) for slot, value in slot_dict.items()] + [
	                           FollowupAction('action_get_lines')]
	                    return ret
	            else:
	                slot_dict[slot] = value
	    return [SlotSet(slot, value) for slot, value in slot_dict.items()]

In this the “lineNumber” validation (Inside validation_slots) depends on “orderNumber” and if “orderNumber” changes i have to validate “lineNumber” too.

For eg. If user provides wrong order number and some line number and then provides the right “orderNumber” through validation, I have to check line number again.
Another scenario, If the user provides “lineNumber” and not the “orderNumber” in the utterance which activates this form action, I could not validate “lineNumber”. I have used validation_slots function because I have to validate prefilled slots.

I have implemented the logic where every time both the slots are validated, which for now handles my problem. But this looks messy. Please help me if there is any better way to handle this.

Another question: If line number is invalid I have to call other action. I have used Followup Action in the validation(Please let me know whether this is right approach).

Please help @akelad Thanks in advance