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).
Rules of the "New" state
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
).
"Item availability validation" Rule.
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.'
"Member status validation" Rule
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.'
"Same type items validation” Rule"
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.'
"Total items validation" Rule
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.'
"Due date" Rule
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
"Current loan" Rule
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.
Rules of the "Current" state.
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).
"Renewed due date" rule
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.
"Renewal limit validation" rule
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.'
"Renewal reservation validation" rule
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.'
"Renewal member validation" rule
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.'
"Renewal item validation" rule
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.'
Rules of the "Past" state
Finally we need to add rules applicable to a loan in the “Past” state.
"Return date" rule
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
"Renewal status validation" rule
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.
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.