# Business rules — superbowl_daily_2 (RGBC Superbowl Daily 2)

Evidence date: 2026-10-02.

Source: `git@bitbucket.org:overdrive/superbowl_daily_2.git`, `master` at `30eb35e` (2026-06-10).

Rules are **Inferred** from implementation unless the line says **Documented**. Nothing in this file is a new business decision.

SQL text inside `sysQuery` is not in the repository. Rules that live only in those statements are **Unknown**.

## Who can run what

**Inferred.** There is no application login. The process identity is the Windows user who starts the executable. That identity is also the identity for integrated-security SQL connections and for the Hennessy file share.

**Inferred.** When `My.Settings.Debug` is false, every checkbox that was saved as checked runs, and the operator cannot change them, because `Run()` starts during load. Rep calls stays off unless the designer default is changed, because its checkbox is unchecked.

**Documented** in `frmMain.vb` (2016-01-28, pj): the daily un-invoiced requisition email is no longer required. **Inferred** from code: the batch follows that note. The button does not.

## Batch order

**Inferred.** Imports always finish before exports. Inside each list the order is the order of `lstImport` / `lstExport` in `frmMain_Load`:

1. Off-con promo, off-con survey, on-con promo, on-con survey, rep calls, vendor, GL, call cycle.
2. CRM, CRM inactive, exposure CRM, product file, planned promotions, Repsly products, Repsly promotions, Repsly customers, Track it All.

A failure in one process does not stop the next process, except an exception that escapes `Run()` itself (for example a missing `sysQuery` row while the form is loading).

## Files

**Inferred.** A missing import file is a warning, not a failed batch. The process is skipped. Previously loaded warehouse data is left as it was.

**Inferred.** Only `.csv` is valid. The parser is comma-separated with quotes. The first row is a header and is not inserted.

**Documented** in `Process.vb` and `frmMain.vb` (2014-04-30): partial import exists because AdvM supplies a day file rather than month-to-date. **Inferred** from `SetDeletes`: when Partial Import is checked, the batch does not mark warehouse rows `blnDelete` and therefore does not delete them for the periods in the file. When it is unchecked, every `dwf*` row for a period present in the file is flagged and then deleted before or as part of the reload (flag, then insert/update, then delete flagged rows). The checkbox defaults to checked, so the default run does not delete.

**Inferred.** Duplicate primary keys are reported and kept. Both rows can be inserted into staging if the table allows it.

**Inferred.** DEBUG builds copy the import file into `Imported\` and leave the source. Other builds move it from `Imports\` to `Imported\` with a `yyyyMMddHHmmss` suffix. The original on the share is only copied, not deleted (`DownloadFile` uses `File.Copy`).

**Inferred.** Vendor and GL do not archive a file. They read live views.

## Fiscal periods

**Inferred.** The company calendar is the `mstCompany` row named `RGBC`. If fewer than 30 months of `mstPeriod` exist ahead of the current year-month, the batch adds the next six months, using `strFYStart` to set fiscal year, fiscal month, and fiscal quarter.

**Inferred.** This runs even when every process checkbox is unchecked.

## Customers, products, and promotions sent to Repsly

### Products

**Documented** in the process header and **Inferred** from SQL:

- A product is eligible to be created on the queue only when `mstProduct.blnDataTransfer = 1`.
- Repsly `Active` is `blnDataTransfer`. `mstProduct.blnActive` is not the Repsly active flag.
- A product already sent (`LastProcessed` not null) is sent again when data transfer is turned off, so Repsly can receive `Active = false`.
- A completed product is sent again when `dtStamp` is newer than `LastProcessed`, or when data transfer differs from `blnLastSentDataTransfer`.
- `dtStamp` is only treated as a change when it is 12 numeric characters.
- Failed rows are retried on the next run if they are still eligible.
- Fields Type, Type2, Short Code, and PriceSeg are ignored. **Documented** in a comment in `GetProductsToProcess`.

### Promotions

**Inferred** from `RepslyPromotionExport.process.vb`:

- The unit of export is `promoActivity.ActivityID`, not a `dwfPromo` row.
- Active and inactive activities are both queued and sent. Repsly `Active` is `promoActivity.blnActive`.
- The Repsly product code is `PR` plus the activity id padded to four digits.
- Price sent is 0. Barcodes are empty.
- There is no schedule, rep, or visit-note payload in the current class. The cursor plan says that older shape was removed. **Inferred** that visit scheduling is not this export's job at HEAD.

**Documented** in `Database_Scripts/README.md`: queue status may be Pending, Processing, Completed, Failed, Updated, or Inactive. **Inferred** from current VB: this export uses Pending, Updated, Completed, and Failed only.

### Customers

**Inferred:**

- Every `mstCustomer` row can be queued, active or inactive. Repsly `Active` is `blnActive`.
- `CustomerType` written by the app is the literal `RGBC`.
- Territory sent to Repsly is the sales manager name on the customer's rep (`mstRepManager.strRepManager`), not a territory code column on the customer.
- State sent to Repsly is branch `strRegionDesc2`.
- A completed customer is sent again when `dtStamp` moves forward, or when that manager name differs from `strLastSentTerritory`.
- Tags are channel-segment text plus `mstCustomer.strTags`, with pipes turned into commas.

**Documented** in script 13: `NonRGBC` means a row from `mstNot_RGBC_Customer`. **Inferred:** the application at HEAD does not implement that rule.

### Shared Repsly send rule

**Inferred:**

- One HTTP success (`Code = 0`) completes every row in the batch of up to 200. One failure fails every row in that batch.
- The queue is marked completed when the POST is accepted. The code does not wait for Repsly's later import job.
- An FTP failure does not block the POST.
- Empty Tag is omitted from the JSON. Product and promotion builders add `Tag` only when the trimmed value is non-empty. The same is true for customer `Tag`. EAN and custom attributes are omitted when empty or zero. **Inferred** from `BuildProductDictionary` in the product and promotion classes and from `GetTagFromRow` in the customer class.

## Track it All outlets

**Inferred** unless noted.

- The file is a full snapshot of customers with `blnActive = 1`. Inactive customers are not in the file.
- `Superbowl Cust` is always 1 for every row. **Inferred** constant, not a column from the database.
- Production attempts are Wednesday, then Thursday only if Wednesday left `PendingRetry = 1` on state row 1.
- A Thursday failure clears the retry flag and sends email. There is no Friday attempt.
- A Wednesday failure stores the error and does not email yet.
- Preview and `TrackItAllAllowTestRun` do not change that flag and do not email.
- **Documented** in a comment inside `Run`: "Debug=False: always sync". The statements under that comment still apply the weekday gate. The comment is not the rule the code follows.
- Column alias `Channel` is built from segment fields. Column alias `Segment` is built from channel fields. **Inferred** as written. Intent is **Unknown / Requires Confirmation**.
- Null display defaults: rep name `-`, rep email `n/a`, sales manager `-`, key account `-`.

## Requisitions

**Inferred** from `EmailUnIinvoicedRequisitions`, which the batch does not call:

- Only Monday.
- Only request types with `blnActive = 1`.
- Only status `Approved`.
- Only a blank or null invoice number.
- Only `dtDate` more than 14 days before now.
- One message, with manager emails looked up per requisition and placed in the table, not used as the envelope recipients. Envelope To and CC are hardcoded.

**Documented** (2016 changelog): RGBC cancelled the daily un-invoiced requisition email.

## Logging and mail

**Inferred:**

- The log mailed at the end is the history table `logSuperbowl`, not the staging table that was just copied. Staging `blnEmail` is not part of the insert into history.
- Warnings are counted, not listed, except archive warnings, which are listed.
- Debug rows are not mailed.
- Each address in `EmailRgbc`, split on semicolon, gets its own message. Empty pieces are skipped.
- Track it All's second-failure mail uses `TrackItAllFailureNotificationEmails` the same way. The second-failure subject is `Track it All Outlet Sync - Second Attempt Failed`.

## Data the application will not invent

**Inferred.** Master and fact changes for surveys, promos, calls, vendors, GL, call cycle, and the five CSV exports are whatever `sysQuery.memQuery` contains for the IDs in `features.md`. Those statements were not inspected. Do not treat this document as the column-level transform for those processes.

## Conflicts

| Topic | Code | Other evidence |
|---|---|---|
| Promotion queue | `sysCronJobPromotionActivities` | Scripts 01, 04, 05, 06, 07 still name `sysCronJobPromotions` |
| Non-RGBC customers | Not in VB | Script 13 and commit `a3e8011` |
| Track it All days | Wednesday and Thursday only, unless preview or test-run | Comment says Debug false always syncs |
| Requisition email | Button still sends it | Changelog says the daily mail was cancelled |
| Version date on the form | `03 February 2026` | Last commit is 2026-06-10 |
| Debug SQL server | `App.config` uses `NB-DIRK` | `Settings.settings` design default uses `sqlsrv02` |
