Business Rule - Reference Field Changes

michaelcory
Giga Expert

Hi,

I set out thinking that this would be a simple change, but has turned into somewhat of a nightmare.   I have a Training Registration application with 3 tables.   Please see the attached screen shot of the Training Class and Training Room forms relevant to the explanation below.   I'm trying not to be "too busy" in my explanation of the issue, but want to provide as much information as I can to help define it.   Appreciate any help you can provide.

Tables

  1. Training Class (u_training_class)
    1. Includes a Seats Available integer field(u_number_of_seats_available)
  2. Training Room (u_training_room)
    1. includes a Seats integer field (u_seats)
  3. Attendee (u_attendee)

When a Training Room is added to a Class record, a BR sets the Seats Available (u_number_of_seats_available) integer value to the integer value of the Seats (u_seats) from the Training Room table.

There is an Attendees Registered (u_number_of_attendees_registered) integer field on the Training Class table that increments the count of attendees as they register for the Class.   It also decrements the count if an attendee is deleted.   Attendees Registered number compares to the Seats Available number to determine what the Class Status should be set to.  

I am trying to set the Class Status (u_class_status) field on the Training Class form based on comparison of the Attendees Registered to the Seats Available when a Class is inserted or updated.   The update to the Class record would include either a seat count change on the Training Room, or a different Training Room is added to the Class.    

Examples (pseudo):  

  • If Attendees Registered < Seats Available && Class Status != "Closed" && Class Status !="Cancelled", set Class Status to "Open"
  • NOTE:   This would always be the case when a new Class is created (Inserted).   The current Class Status default value is "Open", but that might be causing issues with the BR running on insert and update.
  • If Attendees Registered >= Seats Available && Class Status != "Closed" && Class Status !="Cancelled", set Class Status to "Full"
  • NOTE:   This would be the case if the Seat count is changed on the Training Room that is already added to the Class record or the Training Room itself is changed on the Class record

I have two requirements, with consideration that a new Class record will always have a Class Status of "Open":

  1. Set the Class Status appropriately, based on compare of seats available to attendees registered, when the Seat count (u_seats) changes on the Training Room table
  2. Set the Class Status appropriately,   based on compare of seats available to attendees registered, when the Training Room changes on the Class Record.

The following Before BR works for requirement 1, but I can't get a BR to change the Class Status based on the same comparison conditions if a different Training Room is added to the Class record.   I need to tell the BR that the Training Room has changed and execute the conditions based on the change, but because the Training Room is a reference field, I think that's why I'm struggling.   I also need to ensure that every NEW Class record gets set to a Class Status of "Open".

(function executeRule(current, previous /*null when async*/) {

//Run Before to Set the Class Status if the Seat Count is changed on the Training Room

var seats = current.u_number_of_seats_available;

var attendees = current.u_number_of_attendees_registered;

if(seats > attendees){

current.u_class_status = "Open";

if(seats == attendees || seats < attendees){

current.u_class_status = "Full";

}

}

})(current, previous);

1 ACCEPTED SOLUTION

antin_s
ServiceNow Employee
ServiceNow Employee

Hi Mike,



When does the Business Rule executes? What are the conditions of the Business Rule? Make sure it runs when the Training Room 'Changes' also.



Hope this helps. Mark the answer as correct/helpful based on impact.



Thanks


Antin


View solution in original post

5 REPLIES 5

peterh_smith
Tera Contributor

Mike, could you enumerate the business rules you have created?


Is u_attendee a M2M between sys_user and u_training_class?



I would use something like the following rules.



Maintain invariant:   Room Count reflects count of referencing attendees.


  1. Attendee after before:   Decrement the referenced Class's count.
  2. Attendee before update and reference to Class   changes:
    • Decrement previous Class's count, increment current Class's count (ignore nil()s of course)
    • Abort if no seats available.
  3. Attendee before insert:   Increment count on referenced Room.   Abort if no seats available.


Rules 2 and 3 above are before rules so that they can abort the insert/update if the class is full.   Rule 1 is a before rule so that the seat count is consistent when the Room delete/cancel rule clears the references on all the referencing attendees, or deletes the records.



Set state:


  1. Class before update/insert if either count changes:   Recalculate the state.
  2. Class after delete or when state moves to canceling/canceled:   Iterate over all attendees to notify them of cancellation and clear their Class reference.   Assert seats==0 after all attendees are deleted.


Aside:


When I write a business rule, I just do the minimum necessary in the actual rule.   I put all the work together in a script include so that I can compare it all at once.   For example:



new ClassScheduler().deleteUser(user);   // BR MRM Delete User



The reason I add a comment with the name of the BR is because it makes it easier to interpret the stack when I hit a Script Debugger breakpoint in the script include.   Please tell me you have tried the Script Debugger.   It's wonderful!