If we read the code that we have just written, we can immediately start cleaning the code, and then start refactoring it.
Let's browse through the functions one by one, see how we can refactor, and see what the result looks like.
Quite a number of functions can be the members of a class or the table. We can add the function called OccupiedOrHasNotBeenCleanedForAWeek
, CreateCleaningEntryForRoom
, FindLastCleaningDate
, and CreateCleaningEntryForRoom
as members of the Room table.
If we do this, our Codeunit will look like the following:
The Codeunit is very clean and refactored.
One of the functions cannot be moved as a member of the Room table. The LastWeek
function is a generic function.
Let's create a new function library and call it the Bed and Breakfast
function, as shown here:
The Room table now has three members that can be generically reused whenever appropriate.
We can probably make these functions more generic. For example, by adding the Cleaning Entry Status as a parameter to the function.
We can also refactor the functions into their own Codeunit. This will make sense if our development team has different programmers working on application areas that will overlap. If this is not likely, then the extra overhead might not be worth the hassle.
We need the calculation of a room price in a number of places. At least the Journal and the Stay have this requirement. We can also foresee a future enhancement of a Web Service returning a price, based on an inquiry or a wizard for manual inquiries.
Although the price is based on three elements—Room Code, Season Code, and Guest No., the Room is the only process that is mandatory and can be assigned as the owner of the process. Rather than implementing the price calculation as a member of the price table, we will implement this as a member of the Room. From a functional perspective, the reason is that we know the room and want to know the price, and not the other way around.
The following code is the function on the Room table. It can be called with the optional members—Season Code and Customer No.-and calls into a method Codeunit with these parameters:
GetPrice(SeasonCode : Code[10];CustomerNo : Code[20]) : Decimal EXIT(RoomCalculatePrice.GetRoomPrice(Rec, SeasonCode, CustomerNo));
Each table that requires the calculation of a Room price has its own function that attempts to read the room from the database, and then calls into the GetPrice
function:
GetRoomPrice() WITH Room DO BEGIN IF NOT GET("Room Code") THEN EXIT; Price := GetPrice("Season Code", "Customer No."); END;
The Codeunit first does the calculation, based on the most detailed price. The following code is the implementation of the Rules table. Alternatively, we can also find the best or lowest price, as it is implemented in Sales pricing in Microsoft Dynamics NAV:
GetRoomPrice(Room : Record "Bed and Breakfast Room";SeasonCode : Code[10];CustomerNo : Code[20]) : Decimal WITH BedandBreakfastPrice DO BEGIN IF GET(Room.Code, SeasonCode, CustomerNo) THEN EXIT(Price); IF GET(Room.Code, '', CustomerNo) THEN EXIT(Price); IF GET(Room.Code, SeasonCode) THEN EXIT(Price); IF GET(Room.Code) THEN EXIT(Price); END;