Reservation Object

We will now define the rules of the Reservation object. This object also has a distinct life cycle, so let us define the life cycle first.

A reservation is created in the New state. Just like the Loan object, a reservation in this state is considered to be invalid. If validation proves to be OK, the reservation automatically moves itself into the Waiting state, which indicates that the reservation is waiting for its turn in the queue of reservations and/or is waiting for the item to become available. When the item becomes available and the reservation is first on the queue, the reservation moves to the Offered state, which indicates that the reservation has been offered to the member and is waiting for the member to take up the offer. The member can either cancel the reservation, in which case the reservation moves to the Cancelled state) or take up the offer by borrowing the reserved item, in which case the reservation moves to the Converted state. Reservation is waiting for the member to do something for a limited time. If the member does nothing within this period of time the reservation moves to the Expired state. The Cancelled, Converted and Expired states are the final states of the reservation.

Let us now define the rules.

An item may only be reserved if it has been borrowed by someone. It should not be possible to reserve available items. We capture this in the following rule:

IF Reservation.Status='New'AND Reservation.Item.Available='Yes'THEN 
 REPORT ERROR 'Item is available for borrowing. No reservation necessary.' 

An item may only be reserved if the item has been withdrawn while it was on loan:

IF Reservation.Status='New' AND Reservation.Item.InternalStatus<>'Released' THEN 
 REPORT ERROR 'Item is not released by the library for borrowing.' 

An item may only be reserved by active members:

IF  Reservation.Status='New'AND Reservation.Member.Status<>'Active' THEN 
 REPORT ERROR 'Non-active members are not allowed to make reservations.' 

A member cannot place multiple reservations for an item. We can check whether the member has already reserved the item by the following condition:

EXISTS Reservation WHERE(
   Reservation.Member = ThisReservation.Member AND 
   Reservation.Item = ThisReservation.Item AND 
  (Reservation.Status='Waiting' OR Reservation.Status='Offered')
 ) 

The entire rule therefore looks like this:

IF Reservation.Status = 'New' AND EXISTS Reservation WHERE ( 
   Reservation.Member = ThisReservation.Member AND
   Reservation.Item = ThisReservation.Item AND
   (Reservation.Status='Waiting' OR Reservation.Status='Offered'))
 THEN REPORT ERROR 'The item is already reserved by the member.' 

It is not allowed to reserve the item, which has already been borrowed by the member. We can check whether the item has been borrowed using the following condition:

EXISTS Loan WHERE (
  Loan.Member = Reservation.Member AND 
  Loan.Item = Reservation.Item AND 
  Loan.Status='Current') 

The entire rule therefore looks like this:

IF Reservation.Status = 'New'AND EXISTS Loan WHERE (
   Loan.Member = Reservation.Member AND 
   Loan.Item = Reservation.Item AND 
   Loan.Status='Current')THEN
 REPORT ERROR 'Cannot reserve item that is on loan to the member.' 

This is the rule that automatically moves the reservation into the “Waiting” state once all validations have been performed:

IF Reservation.Status = 'New' THEN
 Reservation.Status = 'Waiting' 

The logic behind this rule is the same as the logic behind the “Current loan” rule in the Loan object. We will need to make sure that the priority of this rule is lower than priorities of other rules.

When a reservation is registered the member who made the reservation is charged the appropriate fee. This means that when the reservation is moved into the “Waiting” state the Fee object must be created. The fact that the reservation has been moved into the “Waiting” state can be checked by the following condition:

Reservation.Status WAS CHANGED TO 'Waiting' 

Note that here we are not checking that the reservation state is equal to “Waiting”, because in this case the fee would be charged every time there was a change to the reservation object and the object was in the “Waiting” state (which can happen if, for example, some attribute of the Reservation object was changed – this would trigger the execution of rules).

The entire rule looks like so:

IF Reservation.Status WAS CHANGED TO 'Waiting' THEN 
 CREATE Fee WITH 
   Fee.Member=Reservation.Member,
   Fee.Amount=2.00,
   Fee.Description='Reservation fee for '+<<Reservation.Item.Title>> 

This is the rule that moves the reservation from the Waiting state into the Offered state provided that the reservation is first on the queue and the item became available. We can check that the reservation is first on the queue by comparing it with the CurrentReservation in the reserved item:

Reservation = Reservation.Item.CurrentReservation 

We can check that the item has been returned by checking the list of loans of the item and verifying that there are no Current loans any more:

NOT ( EXISTS Loan WHERE (
 Loan IN Reservation.Item.Loans AND 
 Loan.Status='Current') )  

The entire rule can therefore be written like this:

IF Reservation.Status='Waiting' AND Reservation=Reservation.Item.CurrentReservation AND 
   NOT( EXISTS Loan WHERE ( Loan IN Reservation.Item.Loans AND Loan.Status='Current')) THEN 
 Reservation.Status='Offered' 

Note that we do not have to capture the precise moment when the item has been returned in the rule – the system will ensure that our rule is triggered when this happens, our rule will be executed and the state of the reservation will be changed. After this the rule will not be invoked again, because the state of the reservation will no longer be “Waiting”.

This rule registers the value of the OfferedOn attribute:

IF Reservation.Status WAS CHANGED TO 'Offered' THEN
 Reservation.ItemOfferedOn = CURRENT_DATE 

Here we capture the exact moment when the state of the reservation changes. If we just checked for equality the date would be reset to the new current date every time the reservation object in the Offered state changes.

This rule moves the reservation into the Converted state once the member has taken up the offer. We check that the member has taken up the loan by the following condition:

EXISTS Loan WHERE ( 
 Loan IN Reservation.Item.Loans AND 
 Loan.Status = 'Current' AND 
 Loan.Member = Reservation.Member) 

The action of the rule should not only change the status but also register the BorrowedOn date. The entire rule, therefore, looks like this:

IF Reservation.Status = 'Offered' AND EXISTS Loan WHERE ( Loan IN Reservation.Item.Loans AND Loan.Status = 'Current' AND Loan.Member = Reservation.Member ) THEN
 Reservation.BorrowedOn = CURRENT_DATE
 Reservation.Status = 'Converted' 

Note that just like with the “Offered reservation” rule we do not have to check the precise moment when the member actually borrowed the item1).

When defining the rules applicable to this state we assume that a reservation is moved into the “Cancelled” state externally, that is, not by rules of the object. The rules should just react to the external change of the object state.

It is only possible to cancel current reservation, so this rule checks that the change to the Cancelled state only happens when the object is either in the Waiting or Offered state. Since the change of the object’s state has already taken place we need to check the value of the state before the change. This can be achieved using the OLD_VALUE function.

The rule looks like this:

IF Reservation.Status WAS CHANGED TO 'Cancelled' AND OLD_VALUE(Reservation.Status)<>'Waiting' AND OLD_VALUE(Reservation.Status)<>'Offered' THEN 
 REPORT ERROR 'Cannot cancel non-waiting reservation' 

These are all the rules of the Reservation object. The only state we have not covered is Expired. The object is moved to this state externally, not by rules of the object. We will explain how this happens in Expiring Reservations.

We can now enter the rules of the Reservation object into Aware IM.


1)
Just for illustration purposes we can show what the condition would look like if we wanted to capture this moment:
Loan WAS ADDED TO Reservation.Item.Loans AND AddedLoan.Status='Current' AND AddedLoan.Member=Reservation.Member 
  • Last modified: 2022/09/13 18:15