Skip to content

Favorite menu management

Favorite menu management maintains MENU_FAVORITE, per-user bookmarks that let a user pin frequently used menu items for quick access. Each favorite carries a display order, an optional employee ID, and an optional ItemInactiveDate that supports soft deactivation without a hard delete. clsMenuFavoriteCollection can retrieve all favorites or scope to a single user; the menu authorization data lookup operation folds a user's active favorites into the authorized-item projection.

Field Value
Operation ID OP-MNU-03
Trigger Caller requests clsMenuFavorite/clsMenuFavoriteCollection by key, by user ID, or in full, or calls Save() after Create()/retrieve
Inputs MenuFavoriteSeqNum (key lookup); UserID (user-scoped retrieve); MenuItemSeqNum, UserID, MenuOrder, UserEmplID, ItemInactiveDate (insert/update)
Outputs Populated clsMenuFavorite/clsMenuFavoriteCollection; on save, a new sequence-generated favorite, an updated row, or an error message on DML contention
Primary components clsMenuFavorite, clsMenuFavoriteCollection
Entry point Business\SAIF.Business.Menu\clsMenuFavorite.vb

Steps

  1. Retrieve a single favorite. clsMenuFavorite.GetMenuFavorite creates a Criteria with the requested MenuFavoriteSeqNum and invokes the data portal; BeforeRetrieve binds the key and executes RetrieveSQL (SQL-019, MENU_FAVORITE). AfterRetrieve fills the object (including ItemInactiveDate as a clsSmartDate) and marks it old.
  2. Retrieve favorites for a user. clsMenuFavoriteCollection.GetMenuFavoritesForUser supplies a non-empty UserID; BeforeRetrieve detects MyCriteria.UserID.Trim.Length > 0 and executes RetrieveByUserIDSQL (SQL-020, MENU_FAVORITE) with :UserID bound.
  3. If UserID is empty: clsMenuFavoriteCollection.GetAllMenuFavorites executes the unfiltered RetrieveSQL (SQL-021) instead, returning every favorite for every user.
  4. Create a new favorite. clsMenuFavorite.NewMenuFavorite calls Create(); BeforeCreate/AfterCreate execute a scalar request for MENU_FAVORITE_SEQ.NEXTVAL FROM DUAL (SQL-001, DUAL) and seed MenuFavoriteSeqNum on the object and its criteria before marking it new and clean.
  5. Save (insert) the favorite. BeforeInsert binds the generated sequence, the target MenuItemSeqNum, UserID, UserEmplID, and MenuOrder, then executes InsertSQL (SQL-007, MENU_FAVORITE).
  6. On success (RowsAffected = 1): AfterInsert calls MarkOld().
  7. On failure: AddErrorMessage("InsertError", "Insert Failed") (BR-MNU-02).
  8. Update or deactivate a favorite. BeforeUpdate binds the mutable fields including ItemInactiveDate, then executes UpdateSQL (SQL-033, MENU_FAVORITE).
  9. Setting ItemInactiveDate to a value (rather than clearing it via SetItemInactiveDateNull) is the soft-deactivation path: the row remains in the table but is excluded from future favorite-lookup results that filter on ITEM_INACTIVE_DATE IS NULL (BR-MNU-05).
  10. AfterUpdate applies the row-count check, calling MarkOld() on success or adding UpdateError with BOC.Messages.DBContentionError otherwise (BR-MNU-02).
  11. Hard-delete a favorite. BeforeDelete binds the key and executes DeleteSQL (SQL-040, MENU_FAVORITE). AfterDelete calls MarkNew() on a rows-affected value of 1, or adds a DeleteError otherwise (BR-MNU-02).
  12. Fold favorites into authorized-item lookup. The menu authorization data lookup operation's per-user UNION query includes a favorites leg that filters on FAV.MENU_USER = :MenuUser AND FAV.ITEM_INACTIVE_DATE IS NULL, so only active (non-deactivated) favorites for that specific user appear in the authorized-item projection (BR-MNU-05).

Process flow

The following diagram visualizes the retrieve and deactivation control flow for favorites.

flowchart TD
    Start([Caller requests favorites<br>by key, user, all, or new]) --> Which{Operation?}
    Which -->|Retrieve by key| RetKey[Execute RetrieveSQL<br>with key parameter]
    Which -->|Retrieve by user| UserCheck{UserID provided?}
    UserCheck -->|Yes| RetUser[Execute RetrieveByUserIDSQL]
    UserCheck -->|No| RetAll[Execute unfiltered RetrieveSQL]
    Which -->|Create new| Seq[Obtain NEXTVAL from<br>MENU_FAVORITE_SEQ]
    Seq --> SaveCall{Save called?}
    SaveCall -->|Insert| Insert[Execute InsertSQL]
    SaveCall -->|Update: set ItemInactiveDate| Deactivate[Execute UpdateSQL<br>row remains, excluded from active lookups]
    Insert --> Rows{RowsAffected = 1?}
    Deactivate --> Rows
    Rows -->|Yes| Ok([MarkOld])
    Rows -->|No| Err([AddErrorMessage])

Failure and edge-case behavior

  • Every insert, update, and delete enforces a strict rows-affected-equals-1 check; any other value raises InsertError, UpdateError, or DeleteError and the object is not marked clean (BR-MNU-02).
  • Soft deactivation (setting ItemInactiveDate) and hard delete are two independent paths; a deactivated favorite still occupies a row and a sequence value, and must be explicitly deleted if the row itself needs to be removed.
  • GetAllMenuFavorites returns every user's favorites with no filtering; a caller must apply its own access control before displaying results scoped to a single user.*
  • ItemInactiveDate is represented as a clsSmartDate/nullable Date; a null value (the default) means the favorite is active, which the menu authorization data lookup operation relies on for its IS NULL filter (BR-MNU-05).

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Business\SAIF.Business.Menu\clsMenuFavorite.vb
  • Business\SAIF.Business.Menu\clsMenuFavoriteCollection.vb