# BuyerKioskSync - Sales & Buys Goals System

> Documentation of how the BuyerKioskSync desktop app calculates daily sales and buys goals, and the options it provides store operators to adjust these calculations.

## Overview

The BuyerKioskSync app provides **three distinct methodologies** for calculating daily sales and buys goals, selectable via the `ShowGoalsForm` (accessed from Admin > "Change Goal Settings"). The active method is stored as `Globals.goalMethod` (persisted in `CONFIG.goalMethod`).

The goals system serves two purposes:
1. Display daily sales/buys targets on the main form for store staff
2. Calculate Over/Short (variance) metrics at WTD, MTD, and YTD levels (shown via tooltip on hover)

---

## Method 0: Percentage of Prior Year (Default)

**Stored in**: `CONFIG` table (`growthPercentageSales`, `growthPercentageBuys`)

### How it works

The user enters a growth percentage for sales and a growth percentage for buys. The app then:

1. Finds the **same day of the week from last year** via `ParseHelper.getLastYearsSalesData()` — it matches by day-of-week and week-of-month, not by calendar date
2. Pulls that day's `netSalesRetail` and `buysCost` from either the HISTORY SQLite table or by parsing a WinMark `S*.txt` file
3. Calculates:
   - `salesGoal = lastYearNetSales + (lastYearNetSales * growthPercentageSales / 100)`
   - `buyGoal = lastYearBuysCost + (lastYearBuysCost * growthPercentageSales / 100)`

**Known issue**: Both sales goal and buy goal use `growthPercentageSales` as the multiplier (`ShowGoalsForm.cs:310`). The `growthPercentageBuys` value is stored but the buy goal calculation uses the sales percentage instead. This appears to be a bug.

### User inputs
- Sales growth % (e.g., 5.00 = 5% growth over last year)
- Buys growth % (stored but not used in buy goal formula — see note above)

### Over/Short tooltip (Method 0)

Triggered by mouse hover over the sales label on the main form. Refreshes every two minutes.

- **YTD**: Sums all current year history net sales, compares to last year's YTD through same equivalent day + growth %
- **MTD**: Current month sales vs last year same month through equivalent day + growth %
- **WTD**: Current week sales vs last year same week through equivalent day + growth %

---

## Method 1: Annual Target with Monthly/Daily Distribution

**Stored in**: `GOALSETTINGS` table (27 configurable fields)

### How it works

The user sets a total annual dollar target, then allocates it using two layers of percentages plus flat buy amounts per day.

### Layer 1: Monthly percentages (must total 100%)

Each month gets a percentage of the annual goal. Defaults:

| Month | %     | Month | %     |
|-------|-------|-------|-------|
| Jan   | 6.50  | Jul   | 9.00  |
| Feb   | 7.00  | Aug   | 10.00 |
| Mar   | 9.00  | Sep   | 9.00  |
| Apr   | 8.00  | Oct   | 11.00 |
| May   | 9.50  | Nov   | 6.50  |
| Jun   | 8.00  | Dec   | 6.50  |

The UI validates that all 12 monthly percentages sum to exactly 100.00% and the dollar subtotal equals the annual target. If not, the subtotal turns **red** and the Submit button is disabled.

### Layer 2: Day-of-week sales percentages (must total 100%)

Each day of the week gets a percentage of that day's share within the month. Defaults:

| Day | Sales % | Buy Goal ($) |
|-----|---------|-------------|
| Sun | 13.00   | $1,000      |
| Mon | 10.00   | $1,000      |
| Tue | 10.00   | $1,000      |
| Wed | 9.00    | $1,000      |
| Thu | 11.00   | $1,000      |
| Fri | 16.50   | $2,000      |
| Sat | 30.50   | $2,000      |

### Daily sales goal formula

Implemented in `ParseHelper.setGoalsMethod2()`:

```
monthlySalesGoal = annualGoal * monthPercentage / 100
numDaysInMonth   = count of [today's day-of-week] occurrences in current month
dailySalesGoal   = monthlySalesGoal * dayOfWeekPercentage / 100 / numDaysInMonth
```

**Example**: Annual goal = $1M, October = 11%, Saturday = 30.5%, 4 Saturdays in October:
- Monthly = $1,000,000 x 0.11 = $110,000
- Daily Saturday = $110,000 x 0.305 / 4 = **$8,388**

### Daily buys goal

Buys goals are set as **flat dollar amounts per day of the week** (not percentage-based). The current day-of-week's value is looked up directly from the GOALSETTINGS table.

### Over/Short tooltip (Method 1)

Uses a more granular calculation than Method 0:

- **WTD**: Iterates each day in the current week, calculates that day's goal via `setGoalsMethod2()`, sums them, compares to actual WTD sales
- **MTD**: Same iteration for each day in the current month through today
- **YTD**: Sums completed months' percentage allocations from the annual goal + current MTD goal, compares to actual YTD sales

---

## Method 2: Monthly Target (Incomplete)

**Stored in**: `GOALDATAMONTHLY` table (31 day columns per row)

This method is **partially implemented**. When selected:

- The UI shows a calendar-style grid with a month dropdown selector
- It pulls last year's sales for the equivalent day-of-week period and populates each day's cell
- Weekly totals (W1-W6) and month total are calculated
- There are "Average" buttons per day-of-week (e.g., `bAvgSun`, `bAvgMon`) that calculate the average of a specific weekday across the month and set all instances of that weekday to the average value
- **However**, the submit handler only sets `Globals.goalMethod = 2` and does nothing else — no save to DB, no goal calculation

---

## Display Visibility Options

The user can toggle **four checkboxes** via a `CheckedListBox` on the goals form:

| Checkbox           | Global             | Effect                                   |
|--------------------|--------------------|------------------------------------------|
| Show Goal Sales    | `showGoalSales`    | Shows/hides the sales goal on main form  |
| Show Goal Buys     | `showGoalBuys`     | Shows/hides the buys goal on main form   |
| Show Current Sales | `showCurrentSales` | Shows/hides current day's actual sales   |
| Show Current Buys  | `showCurrentBuys`  | Shows/hides current day's actual buys    |

These control the `SetPerformanceDataVisibility()` method in `BuyerKioskSync.cs`, which dynamically repositions and shows/hides the goal and current performance labels based on which combination is active.

---

## Real-Time Goal Sync via Ably

When goals are saved on the master register, it publishes an `updateGoals` message to the Ably channel:

```json
{"action": "updateGoals", "buyID": "", "category": "<salesGoal>,<buyGoal>"}
```

All connected registers receive this via `WebSocketClient.cs` and update their local `Globals.salesGoal` and `Globals.buyGoal` in real-time.

Non-master registers can request current goals by publishing a `needGoals` action, and the master responds with the current values.

---

## Data Sources for Last Year Comparison

`ParseHelper.getLastYearsSalesData()` uses a two-tier lookup:

1. **SQLite HISTORY table** — checked first via `GetHistoryRecords()`
2. **WinMark text files** — fallback, parsed from `N:\` network share (`S{MMDDYY}.txt` format)

There is also a `getTwoYearsAgo()` fallback method (currently commented out) for cases where last year returns $0.

Leap year handling adjusts the date offset by +2 days when crossing a leap year boundary.

---

## Key Database Tables

### CONFIG (goal-related fields)

| Column                 | Type          | Purpose                          |
|------------------------|---------------|----------------------------------|
| `growthPercentageSales`| DECIMAL(10,2) | Method 0: sales growth %         |
| `growthPercentageBuys` | DECIMAL(10,2) | Method 0: buys growth %          |
| `showGoalSales`        | INT           | Toggle: show sales goal          |
| `showGoalBuys`         | INT           | Toggle: show buys goal           |
| `showCurrentSales`     | INT           | Toggle: show current sales       |
| `showCurrentBuys`      | INT           | Toggle: show current buys        |
| `goalMethod`           | INT           | Active method (0, 1, or 2)       |

### GOALSETTINGS (Method 1)

| Column      | Type         | Purpose                              |
|-------------|--------------|--------------------------------------|
| `annualGoal`| NVARCHAR(12) | Total annual sales target            |
| `janPct`–`decPct` | NVARCHAR(10) | Monthly allocation percentages (12) |
| `sunPct`–`satPct` | NVARCHAR(10) | Day-of-week sales percentages (7)   |
| `sunBuy`–`satBuy` | NVARCHAR(10) | Day-of-week buy dollar amounts (7)  |

### GOALDATAMONTHLY (Method 2 — incomplete)

| Column  | Type         | Purpose                       |
|---------|--------------|-------------------------------|
| `Date`  | NVARCHAR(10) | Month identifier (YYYY-MM)    |
| `1`–`31`| NVARCHAR(10) | Per-day sales target amounts  |

---

## Summary of All Adjustable Parameters

| Parameter                      | Method | User Editable | UI Location                         |
|--------------------------------|--------|---------------|-------------------------------------|
| Sales growth %                 | 0      | Yes           | Goals form, "Percentage" panel      |
| Buys growth %                  | 0      | Yes           | Goals form, "Percentage" panel      |
| Annual target ($)              | 1      | Yes           | Goals form, "Annual Target" panel   |
| Monthly allocation (12x %)     | 1      | Yes           | Goals form, per-month fields        |
| Day-of-week sales (7x %)      | 1      | Yes           | Goals form, per-day fields          |
| Day-of-week buys (7x $)       | 1      | Yes           | Goals form, per-day dollar fields   |
| Per-day targets (31x)          | 2      | Partial       | Goals form, calendar grid (not saved)|
| Show/hide toggles (4x)        | All    | Yes           | Goals form, checkboxes              |

---

## Source Files

| File | Role |
|------|------|
| `ShowGoalsForm.cs` | UI form for all three methods, validation, submit logic |
| `ParseHelper.cs` | `getLastYearsSalesData()`, `setGoalsMethod2()`, `GoalData` class |
| `SQLiteHelper.cs` | `GetGoalData()`, `UpdateGoalMethod()`, `UpdateAnnualGoals()`, `UpdateTodaysGoals()` |
| `BuyerKioskSync.cs` | Main form display, Over/Short tooltip calculation, Ably goal sync |
| `WebSocketClient.cs` | `updateGoals` / `needGoals` message handlers |
| `Program.cs` | `Globals` static properties for all goal-related state |
