Loan Object

This object will have a lot more rules since it has a distinct life cycle. Let us define this life cycle first before defining the rules.

A loan is created in the New state. In this state the loan is considered to be invalid. The loan validates itself and if validation is OK the loan moves itself to the Current state. Once the borrowed item has been returned the loan is moved to the “Past” state. It stays in the “Past” state until it is deleted.

Before we start defining the rules we should also consider renewal of the loan. According to the requirements there is a limitation on a number of times a loan can be renewed. The Loan object therefore needs to maintain this number in a separate attribute, which we will call RenewalCount. We will add this attribute of the Number type to the Loan object (initial value of the attribute is 0).

Let us now define the rules applicable to the New state of the Loan object. Note that a loan is created in this state (we set the initial value of the Status attribute to New).

A loan can be created only for the item that is not on loan already. We obviously check the Available flag of the Item object but we also need to consider the situation when the loan is for the reserved item (in this case the item is considered to be unavailable, but the loan converting the reservation must be allowed). The action of the rule must be REPORT ERROR which indicates that whatever operation the system is executing currently must be aborted as one of the objects in the system is invalid.

We define the following rule with the name “Item availability validation”:

IF Loan.Status='New' AND Loan.Item.Available='No' AND NOT( Loan.Item.CurrentReservation.Member=Loan.Member AND Loan.Item.CurrentReservation.Status='Offered') THEN 
 REPORT ERROR 'The item is not available for borrowing.' 

A loan can be created only for active members:

IF Loan.Status='New' AND Loan.Member.Status<>'Active' THEN 
 REPORT ERROR 'Non-active members are not allowed to borrow items.' 

A member cannot borrow more than a maximum allowed number of loans for items of a particular type. This can be checked by the following condition:

COUNT Loan WHERE ( Loan IN ThisLoan.Member.Loans AND Loan.Status='Current' AND Loan.Item.Type = ThisLoan.Item.Type) >= Loan.Item.Type.MaxBorrowNumber 

We count the current loans that belong to our member and have the same type as our item and compare with the maximum value defined in the type of our item. Note that we use ThisLoan in the condition – this is to differentiate our loan from all other loans that are being searched (see also the Instance Prefixes).

The entire rule looks like so:

IF Loan.Status='New' AND COUNT Loan WHERE ( Loan IN ThisLoan.Member.Loans AND Loan.Status='Current' AND Loan.Item.Type=ThisLoan.Item.Type) >= Loan.Item.Type.MaxBorrowNumber THEN 
 REPORT ERROR 'Member already has <<Loan.Item.Type.MaxBorrowNumber>> <<Loan.Item.Type.Name>>s.' 

A member may not have more than the maximum number of loans. The rule looks like so1):

IF Loan.Status='New' AND COUNT Loan WHERE (
    Loan IN ThisLoan.Member.Loans AND 
    Loan.Status='Current') >= 10 THEN
 REPORT ERROR 'Member already has maximum allowed number of items.' 

We must also have a rule that calculates the initial value of the DueDate attribute. The rule looks like this:

IF Loan.Status='New' THEN 
 Loan.DueDate=Loan.LoanDate+Loan.Item.Type.MaxLoanPeriod 

As we said before valid loan should automatically move itself into the Current state2). The rule looks like this:

IF Loan.Status = 'New' THEN 
 Loan.Status = 'Current' 

The rule looks a bit strange. The problem here is that the state transition should only be performed when the loan has been validated. Note that the sequence of all previous rules is not important – we can add them to the Loan object in any order (even the DueDate rule – it does not matter if the date is calculated for the invalid loan). In most cases all rules associated with a business object are equivalent as far as their order of execution is concerned – the system picks the order itself at random (see also the Rule Evaluation).

Our automatic transition into the Current state is the rare case when the order of execution of a particular rule is important – we want to be sure that the rule that makes a state transition is executed after the validation rules. The mechanism to ensure this is to lower the priority of the Current state rule. We can do this when we enter the rule – we need to switch to the “Advanced” tab of the rule editor, click on the “I want to assign priority manually” radio button and specify the lower priority than the default priority of 30 (for example, 20) – see also Rule Priorities.

In this state we mostly need to concentrate on loan renewal. We will consider the loan as being renewed when its renewal count is incremented and not zero (we assume that the “RenewalCount” attribute is incremented externally to indicate an attempt to renew the loan).

This is the rule that re-calculates the due date when the loan has been renewed:

IF Loan.RenewalCount WAS CHANGED AND Loan.RenewalCount > 0 THEN 
   INCREASE Loan.DueDate BY Loan.Item.Type.MaxLoanPeriod 

Note that we can freely perform arithmetic operations with dates by adding a number of days to the due date.

A loan cannot be renewed more times than allowed by the type of the item that has been borrowed. This can be captured by the following rule:

IF Loan.RenewalCount WAS CHANGED AND Loan.RenewalCount > 0 AND Loan.RenewalCount > Loan.Item.Type.MaxRenewals THEN 
   REPORT ERROR  'Cannot renew loan, the maximum number of renewals (<<Loan.Item.Type.MaxRenewals>>) is reached.' 

A loan cannot be renewed if someone has already reserved the borrowed item while it was on loan. We express this in the following rule:

IF Loan.RenewalCount WAS CHANGED AND Loan.Item.CurrentReservation IS DEFINED AND Loan.RenewalCount > 0 THEN
   REPORT ERROR 'Cannot renew loan, there is a reservation for the item.' 

An attempt for loan renewal must be rejected if the library has made a decision to suspend the member who has borrowed the item. Therefore we check that the member status is still “Active”:

IF Loan.RenewalCount WAS CHANGED AND Loan.Member.Status<>'Active' AND Loan.RenewalCount > 0 THEN
   REPORT ERROR 'Cannot renew loan for non-active member.' 

An attempt for loan renewal must be rejected if the library has made a decision to withdraw the borrowed item. Therefore we check that the item status is still “Released”:

IF Loan.RenewalCount WAS CHANGED AND Loan.Item.InternalStatus<>'Released' AND Loan.RenewalCount > 0 THEN 
   REPORT ERROR 'Cannot renew loan, the item is requested back to library.' 

Finally we need to add rules applicable to a loan in the “Past” state.

This rule registers the return date of the loan when it has been closed:

IF Loan.Status WAS CHANGED TO 'Past' THEN
   Loan.ReturnDate = CURRENT_DATE 

An attempt to renew the loan in the “Past” state must be rejected:

IF Loan.RenewalCount WAS CHANGED AND Loan.Status<>'Current' AND Loan.RenewalCount > 0 THEN
   REPORT ERROR 'Cannot renew non-current loan' 

These are all the rules of the Loan object. We can now enter these rules into Aware IM using either the Standard or Textual forms of the rule editor as described in the Item Object Rules.


1)
At the moment the rule uses fixed number 10 as the maximum number of loans. We will address the requirement that management should be able to change this number from time to time in the Systems Settings Object
2)
The question here is whether the Loan should move itself into the Current state or the state should be explicitly set to Current externally after the loan has been created. There are merits in both approaches – we prefer here to get the loan to set its state automatically and demonstrate rule priorities.
  • Last modified: 2022/09/13 18:15