---
title: Application code scoping
summary: Maintains the lookup of application identifiers used to scope menu pages, and filters retrieval by active status.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Menu
reference_type: package
operation_id: OP-MNU-05
trigger: Caller requests an application code by key, all codes, or active-only codes, or saves a new/changed code
---

# Application code scoping

Application code scoping maintains `BUSONLINE_APPS_CODE`, the lookup table that scopes `MENU_PAGE` records to a particular application via `PAG.APPLICATION_CODE = APP.CODE`. `clsApplicationCode` follows the standard BOF CRUD lifecycle; `clsApplicationCodeCollection` adds an active-only retrieval mode that treats a null `ACTIVE_CODE` as active by default.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MNU-05 |
| **Trigger** | Caller requests `clsApplicationCode`/`clsApplicationCodeCollection` by key, active-only, or in full, or calls `Save()` after `Create()`/retrieve |
| **Inputs** | `Code` (key lookup); `Code`, `ApplicationPath` (description), `IsActive` (insert/update) |
| **Outputs** | Populated `clsApplicationCode`/`clsApplicationCodeCollection`; on save, a persisted row or an error message on DML contention |
| **Primary components** | `clsApplicationCode`, `clsApplicationCodeCollection` |
| **Entry point** | `Business\SAIF.Business.Menu\clsApplicationCode.vb` |

## Steps

1. **Retrieve a single application code.** `clsApplicationCode.GetApplicationCode` creates a `Criteria` with the requested `Code` and invokes the data portal; `BeforeRetrieve` binds `:Code` and executes `RetrieveSQL` ([SQL-012](../sql/SQL-012-saif-business-menu.md), [BUSONLINE_APPS_CODE](../database-tables.md#busonline-apps-code)). `AfterRetrieve` fills the object (`Code`, `ApplicationPath`, and `IsActive` derived from `NVL(ACTIVE_CODE,'Y')`) and marks it old.
2. **Retrieve active codes only.** `clsApplicationCodeCollection.GetActiveApplicationCodes` sets `ActiveOnly = True` on the criteria; `BeforeRetrieve` detects this and executes `RetrieveActiveSQL` ([SQL-013](../sql/SQL-013-saif-business-menu.md)), which appends `WHERE NVL(ACTIVE_CODE, 'Y') = 'Y'` — codes with a null `ACTIVE_CODE` are treated as active by default ([BR-MNU-03](../business-rules.md#br-mnu-03-active-application-code-filtering)).
3. **Retrieve all codes.** `clsApplicationCodeCollection.GetAllApplicationCodes` leaves `ActiveOnly` false, so `BeforeRetrieve` executes the unfiltered `RetrieveSQL` ([SQL-014](../sql/SQL-014-saif-business-menu.md)) instead, returning both active and inactive codes.
4. **Create a new application code.** `clsApplicationCode.NewApplicationCode` calls `Create()`, which sets `m_Code = MyCriteria.Code` directly — no sequence generation, since `Code` is a caller-supplied natural key.*
5. **Save (insert) the code.** `BeforeInsert` binds `Code` (max length 5), `ApplicationPath` (max length 65), and `IsActive` converted to a `Y`/`N` string, then executes `InsertSQL` ([SQL-005](../sql/SQL-005-saif-business-menu.md), [BUSONLINE_APPS_CODE](../database-tables.md#busonline-apps-code)).
   - On success (`RowsAffected = 1`): `AfterInsert` calls `MarkOld()`.
   - On failure: `AddErrorMessage("InsertError", "Insert Failed")` ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
6. **Update the code's path or active flag.** `BeforeUpdate` binds `ApplicationPath`, `IsActive`, and the key `Code`, then executes `UpdateSQL` ([SQL-031](../sql/SQL-031-saif-business-menu.md), [BUSONLINE_APPS_CODE](../database-tables.md#busonline-apps-code)). `AfterUpdate` applies the row-count check, calling `MarkOld()` on success or adding `UpdateError` with `BOC.Messages.DBContentionError` otherwise ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
7. **Delete the code.** `BeforeDelete` binds `Code` and executes `DeleteSQL` ([SQL-038](../sql/SQL-038-saif-business-menu.md), [BUSONLINE_APPS_CODE](../database-tables.md#busonline-apps-code)). `AfterDelete` calls `MarkNew()` on a rows-affected value of `1`, or adds a `DeleteError` otherwise ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
8. **In-memory lookup by application path.** `clsApplicationCodeCollection.ItemByAppPath` filters the already-loaded collection in memory (trimmed, upper-cased comparison) to resolve a `clsApplicationCode` by its display path without a further database round trip.
9. **Consume the scoping in menu rendering.** The [menu authorization data lookup](menu-authorization-data-lookup.md) operation's UNION queries join `BUSONLINE_APPS_CODE` to `MENU_PAGE` on `APP.CODE = PAG.APPLICATION_CODE` to resolve `ApplicationPath` for display alongside each returned menu item.

## Process flow

The following diagram visualizes the retrieve/save control flow for application codes, including the active-only filter.

```mermaid
flowchart TD
	Start([Caller requests application code<br>by key, active, all, or new]) --> Which{Operation?}
	Which -->|Retrieve by key| RetKey[Execute RetrieveSQL<br>with Code parameter]
	Which -->|Retrieve active only| ActiveCheck[Execute RetrieveActiveSQL:<br>NVL ACTIVE_CODE,'Y' = 'Y']
	Which -->|Retrieve all| RetAll[Execute unfiltered RetrieveSQL]
	Which -->|Create new| Assign[Set Code from criteria<br>no sequence lookup]
	Assign --> SaveCall{Save called?}
	SaveCall -->|Yes| Insert[Execute InsertSQL]
	Insert --> Rows{RowsAffected = 1?}
	Rows -->|Yes| Ok([MarkOld])
	Rows -->|No| Err([AddErrorMessage: InsertError])
```

## 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](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
- A null `ACTIVE_CODE` is treated as active by default via `NVL(ACTIVE_CODE, 'Y')` in both the single-object retrieve and the active-only collection retrieve, so an application code is active unless explicitly marked otherwise ([BR-MNU-03](../business-rules.md#br-mnu-03-active-application-code-filtering)).
- `Code` is a caller-supplied natural key (no sequence), so two concurrent callers creating the same `Code` will conflict at the database's primary-key constraint rather than through this library's own logic.*
- The `UpdateSQL` text has a typo in its `SET` clause parameter name (`:ApplicaitonPath` instead of `:ApplicationPath`); because ADO.NET binds parameters positionally rather than by name for this call, the misspelling does not affect execution, but it is a latent maintainability defect.*

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **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\clsApplicationCode.vb`
- `Business\SAIF.Business.Menu\clsApplicationCodeCollection.vb`
