# Business rules — RGBC_ScoreCard (HR: People Development Tool)

Evidence date: 2026-10-05.

Source: `git@bitbucket.org:overdrive/rgbc_scorecard.git`, `master` at `c1c7ceb`.

Rules are **Implemented** when the current code enforces them, **Inferred** when the code implies them without stating a policy, and **Comment only** when a comment describes a rule the current branch does not enforce. Nothing here is a confirmed business decision unless the code is the evidence.

## Access

### BR-001 — Who may open the tool

**Implemented.** Login succeeds only when the Windows logon name matches `mstUser.strDomainLogin` (upper-cased) and that user joins to `mstUserGroupScoreCard`. The page tells the user that access is controlled through Active Directory.

**Inferred.** The application does not check a password. IIS Windows authentication is assumed. The IIS setup is not in the repo.

**Implemented exception.** If the query string `OVERRIDE_USERNAME` is set, that value is used instead of the Windows identity. There is no group check around the override.

**Implemented, DEBUG only.** A missing session loads user `SILICONOVERDRIV\pieter` instead of returning to the login page.

### BR-002 — Menu by group

**Implemented.** `Admin` and `Dev` keep every menu item. `RSM` and `User` lose Edit Team Setup, Edit Surveys, Edit Questionnaires, Overall Performance, and HR Report (wip). They keep Home and Logout.

The pages do not repeat this check. Hiding a menu item is not an authorization rule on the URL.

### BR-003 — Team grid scope

**Implemented.**

- `User`: grid and report `div` are hidden.
- `RSM`: grid parameter `refManagerID` is the logged-in user id.
- `Admin` and `Dev`: parameter stays `-1`, and the SQL treats that as all managers.
- Rows require `scrUser` and `mstUser.refUserGroupSCoreCardID <> 0`.

### BR-004 — Who may change a saved survey

**Implemented** for groups `RSM` and `User` when `SurveyID > 0` and `vieSCRManager` returns a row: Save is disabled if `strStatus = 'Submitted'` or `UserID` (the reviewer stored on the survey) is not the logged-in user.

**Implemented.** `Admin` and `Dev` do not enter that lock.

**Not implemented.** The redirect away when `vieSCRManager` returns nothing is commented out. A direct survey id can still load.

**Inferred.** `Submitted` is the terminal status for RSM and User edits. `Ready For Review` does not disable Save.

### BR-005 — View flag

**Implemented.** If `Session("USER")!blnView` is not true, the master page replaces page content with "You need View rights to access this page."

When `blnView` is set is **Unknown**. It is a column on the login query (`SELECT *`), not assigned in this repository.

## Review calendar

### BR-006 — When a new self review may start

**Comment only (2019-05-20 in `Home.aspx.vb`).** "Users can only do their PDT between 01 April - 30 June inclusive, regardless of year."

**Implemented.** New self-review links are shown when the current month is between the month of `dtSeasonStart` and the month of `dtSeasonEnd` inclusive. Committed values are `01-01` and `12-31`, so the check passes in January through December.

**Implemented copy that does not match the settings.** If the check fails, the label says the next term is 1 April through 30 June. Those dates are hardcoded in the string. They are not read from settings.

**Requires confirmation.** Which window is the rule: the comment and the message (1 April–30 June), or the settings (1 January–31 December).

### BR-007 — Draft links on the team grid

**Implemented.** A latest performance or GPS date becomes an edit link when all of the following hold:

- The cell is not `-` and contains a space (the status suffix).
- Status is not `Submitted`.
- The date falls between `currentYear-dtSeasonStart` and `currentYear-dtSeasonEnd`.

With settings `01-01` and `12-31`, that is the current calendar year.

**Comment only.** Code that would hide the **New** link when a review already exists in the season is commented out. **New** stays available.

### BR-008 — Overall performance years

**Implemented** on `OverallPerformance.aspx`, independent of `dtSeasonStart`:

- Year 1: `1 April` of this calendar year through `1 April` next year.
- Year 2: previous 1 April through this 1 April.
- Year 3: the year before that.

Potential is questionnaire id `3`. Performance is every other questionnaire id. The score is the sum of per-category averages, divided by 6. The divisor 6 is literal SQL, not a setting.

This page's connection string is `SuperbowlConnectionStringDEV`. Home uses `SuperbowlConnectionString`. **Requires confirmation** that the report should read the DEV database.

## Questionnaires

### BR-009 — Two review types

**Implemented.**

- Performance / job-role review: `scrUser.refQuestionnaireID`, and any survey whose `QuestionnaireID <> 3`.
- The other review: questionnaire id `3` everywhere it is hardcoded (Home GPS link, GPS ranking, potential year SQL, PDF label, user submit rules).

**Implemented naming split.**

- Home column and link say GPS.
- PDF score label for id `3` is `Potential Score:`.
- Job-role dropdowns exclude `strQuestionnaire = 'Potential'`.
- Help images include potential and performance definition files.

**Inferred.** Id `3` and the questionnaire named Potential are the same GPS/potential review. **Requires confirmation.** The id is not looked up by name in the survey start link.

### BR-010 — Job role required for a self performance review

**Implemented.** If `scrUser.refQuestionnaireID` is missing or `0`, Home shows a red message asking HR to assign a job role, and does not render the performance or GPS start links.

Team setup can still show `WARNING! Job Role / Questionnaire not set up` when the chosen questionnaire has no `scrQuestion` rows.

### BR-011 — Active questions and order

**Implemented.** A new survey loads `scrQuestion` where `blnActive = 1`, for the category, ordered by `intOrder`, then question text. An existing survey loads `dwfScoreCard` rows for that survey and category, ordered the same way. Later edits to the question bank do not rewrite saved answer rows.

### BR-012 — Answer scales

**Implemented on the survey page.**

- `Range3`: radio values 1, 2, 3.
- Anything else, including `Range6`: radio values 1 through 6.
- Mixed types on one questionnaire are supported. Each question carries `hidOptionType`.
- Save refuses to continue if any question has no selection.

**Implemented on the question editor.** The only selectable option type is `Range6`.

**Implemented on Sales Capabilities (menu commented out).** Inserts still store `Range10`.

**Comment / commit subject.** `857df91` says range 3 and 10 were removed. That matches the editor. It does not match the survey renderer or `SalesCapabilities.aspx.vb`. **Requires confirmation** if old Range3 questions must remain answerable.

### BR-013 — Category description

**Implemented.** Saving a question writes `strCategoryDescription` onto every `scrQuestion` row with the same `strCategory`, across questionnaires. **Inferred** that category names are globally unique. That is not checked.

### BR-014 — Comments

**Implemented.**

- Question comment box visibility follows `blnComments` on the question.
- Manager comments (`txtManagerComments`) and shared values (`txtSharedValues`) are stored on `scrSurvey`.
- Per-question GPS comments (`txtGPSComments`) are stored on `dwfScoreCard`. The GPS comment block is hidden when the questionnaire id is not 3.
- Shared values panel is shown for questionnaire 3 when the group is `User`.

What the rating numbers mean (labels on the images) is in JPG files under `Content`, not in text. The images were not transcribed.

## Survey lifecycle

### BR-015 — Status values written by the PDT page

| Status | When | Evidence |
|---|---|---|
| `Draft` | First successful save | `INSERT` in `btnSave_Click` |
| `Submitted` | Submit | `btnSubmit_Click` |
| `Ready For Review` | Send to Manager | `btnAlert_Click` |

No code path in this page sets any other status. No code path returns a `Submitted` survey to Draft.

### BR-016 — First save is all or nothing

**Implemented.** The first save inserts the survey header and every answer inside one SQL transaction. Failure rolls back. The code comment says this avoids orphan Draft headers. The redirect after commit opens the new `SurveyID`.

Later saves update row by row with separate `doQuery` calls and are not wrapped in that transaction.

### BR-017 — Submit versus send to manager

**Implemented.**

- Submit confirmation text: "Are you sure you want to submit the Survey to HR?"
- Group `User` on questionnaire 3: Submit disabled, Send to Manager enabled (on edit; on a brand-new GPS survey Submit is disabled and the alert button stays at its markup `Enabled="False"` until a later state — on edit it is set enabled).
- Other cases: alert button hidden on a new survey; Submit enabled once an existing survey has loaded.

**Implemented email split.**

- Questionnaire not 3: mail the manager and the employee.
- Questionnaire 3: mail the manager only.
- If the person clicking Submit is not the employee (`RepID`), also CC `hr@rgbc.co.za`.

**Implemented.** Submit does not check that every answer is filled at click time. The earlier Save does. A survey saved before that validation existed could be submitted without a new validation pass. **Inferred** from the absence of a check in `btnSubmit_Click`.

### BR-018 — Scoring

**Implemented** on the PDT page, as described in FR-006 of `prd.md`.

**Implemented** on the survey list: percent = `sum(answers) * 100 / (count * 6 if Range6 else count * 3)`.

**Implemented** on overall performance: sum of category averages, divided by 6, for April-based years. Not the same formula as the PDT header score.

These three formulas are not documented as one policy. **Requires confirmation** which number HR treats as the official score.

### BR-019 — PDF and mail are side effects of submit

**Implemented.** Status is updated to `Submitted` before `sendEmail`. Email or PDF failure does not change the status back. The user is still sent to Home with "Survey has been completed successfully".

**Implemented.** The message body is `sysQuery.memQuery` for id `42` (submit) and id `62` (manager alert). If the template row is missing, `drSysQuery.IsNull` will throw and the catch will log it. The template text is not in git.

**Implemented.** From address `People Development Tool <administrator@rgbc.co.za>`. SMTP host setting `10.0.0.17`.

## Data rules observed in SQL

### BR-020 — One job role and one manager

**Implemented.** `scrUser` is saved with one `refQuestionnaireID` and one `refManagerID`. The team screen does not support two roles.

Managers in dropdowns are `mstUser` rows with `blnManager = 1`.

### BR-021 — Employee versus reviewer

**Implemented.** `scrSurvey.RepID` is the person being reviewed (query string `UserID` on a new survey). `scrSurvey.UserID` is the logged-in reviewer. Home labels a performance review `Self` when those ids are equal, otherwise `Manager`.

### BR-022 — Usage log system name

**Implemented.** Every successful login inserts `mstUsageLog` with `strSystem = 'Forecast'`. **Inferred** leftover. **Requires confirmation** before anyone reports on that column.

## Security-sensitive behaviour (observed, not approved)

These are in the code. They are not written here as desired policy.

- `OVERRIDE_USERNAME` impersonation (BR-001).
- `customErrors` off and trace written to the page for remote clients (`Web.config`).
- A commented `NetworkCredential` block in `PeopleBalanceSheetNew.aspx.vb` (`sendEmail` and `btnAlert_Click`) contains a mailbox address and a password. The block is inside comments, so it is not executed. It is still in source control.
- `Reports/PDF` in git contains generated PDT PDFs whose file names include employee names, job roles, survey ids, and dates. The names are not repeated in this document.
- Many SQL statements concatenate ids and text. `CleanString` doubles single quotes. It is not parameterized except for the transactional first insert. That is **Implemented** structure, and it is a review item, not a business rule.
