# Features — PernodIntegration

Evidence date: 2026-10-07.

Source: `main` at `ecbc272`.

There is no feature backlog in the repository. "Current" means present on that commit. "Planned" means a future behaviour the repo describes. None was found.

## Current — send unresolved orders

| Feature | Behaviour | Evidence |
|---|---|---|
| Console entry | `Module1.Main` loads an AIS token and calls `GetOrders2Send` | `PernodIntegration/Module1.vb` |
| OAuth token | Form POST to `OAuthTokenUrl` | `GetOAuthToken` |
| JDE AIS token | JSON POST to `JdeTokenUrl`; reads `userInfo.token` | `GetJdeToken`, `TokenClass.vb` |
| Eligible orders | Headers with status `99` | `GetOrders2Send` |
| Order body | Business unit, long address number, grid lines, line type `S` | `OrderClass.vb`, `CreateOrder` |
| Per-order OAuth | Order POST `Authorization` uses a new `GetOAuthToken` call | `CreateOrder` |
| Success | HTTP 2xx sets status `20` and prints the body | `CreateOrder`; test `Success_SetsStatus20_AndPostsOnce` |
| HTTP failure | One `ERROR_LOG` row, status stays `99` | test `HttpFailure_LeavesStatus99_AndLogsError` |
| Continue without a token | `GetOrders2Send` still runs when `GetJdeToken` returns nothing | `Main`; `docs/integration-flow.md` |

## Current — period and bottle cap

| Feature | Behaviour | Evidence |
|---|---|---|
| Prior-month expiry | Status `99` with `Orderdate` before this calendar month becomes `22` and is not posted when expiry succeeds | `ExpirePriorPeriodUnresolvedOrders`; test `PriorPeriodUnresolved_SetsStatus22_AndDoesNotPost` |
| Failed-order cap | Oldest current-month failed orders (status `99` plus any `ERROR_LOG`) become `22` until counted + failed bottles fit under 12 | `CancelOverflowFailedOrders`, `SelectOldestFailedOrdersToCancel` |
| Cap examples | 8 failed + 6 new cancels the failed order and sends the new one. 8+3 sends both. Two failed 4s plus a new 6 cancels only the older failure | `docs/integration-flow.md`; `IntegrationTests.vb`; `OverflowMathTests.vb` |
| Retry on a later run | Status `20` and `22` are skipped. Status `99` in the current month is sent again unless a new overflow pass sets `22` | `docs/integration-flow.md`; the status filters in `Module1.vb` |

The cart-time 12-bottle check is explicitly not this program. Provenance: **Documented** in `docs/integration-flow.md`.

## Current — error log

| Feature | Behaviour | Evidence |
|---|---|---|
| Table write | Insert `ERROR_LOG` with component `PernodIntegration` | `LogError` |
| Order id | Set on `CreateOrder` failures when the id is a positive integer | `ParseOrderId`; commit `980e107` |
| Redaction | `token`, `access_token`, and `Bearer` values replaced | `RedactSecrets` |
| Truncation | Message 4000 characters, exception message 2000. Stack trace is not truncated | `Truncate`, `LogError` |
| Log failure | A failed insert does not stop the batch | empty `Catch` in `LogError` |
| User email | Always null | `LogError` |

## Current — tests

| Feature | Behaviour | Evidence |
|---|---|---|
| Integration tests | Six methods call `GetOrders2Send` against LocalDB and `StubJdeHandler` | `PernodIntegration.Tests/IntegrationTests.vb` |
| Overflow math | Three methods call `SelectOldestFailedOrdersToCancel` with no SQL and no HTTP | `OverflowMathTests.vb` |
| Stub | `/oauth/` and token paths return 200. `/orchestrator/` returns 200 or a configured error. Host `jde-stub.invalid` | `StubJdeHandler.vb`, `docs/tests.md` |
| Database lifecycle | Assembly start creates `PernodIntegrationTests` from `docs/create_test_schema.sql`. Assembly end writes a report and drops the database | `TestRunHooks.vb`, `TestDatabase.vb` |
| Report | One timestamped markdown file under `docs/test-reports/`. `test-report-*.md` is gitignored | `docs/tests.md`, `.gitignore` |
| Production host guard | Integration tests assert no request host contains `pernod-ricard.io` | `docs/tests.md` |

`Main` and `GetJdeToken` are not what the tests call. `CreateOrder` still requests an OAuth token, which the stub answers. Provenance: **Documented** and **Implemented**.

## Completed changes still in force

| When | Change | Still true on `ecbc272` |
|---|---|---|
| 2025-04-02 | Commit message: new JDE API implementation | The current token-plus-orchestrator calls are the code that remains. The replaced request was not reconstructed |
| 2025-05-08 | Commit message: updated input parameter format | `OrderClass` JSON names are the current contract |
| 2025-06-20 | Sonar project and Bitbucket Pipelines file | Both files are on `main`. The pipeline is scan-only |
| 2026-08-21 | Error logging to `ERROR_LOG` | `LogError` |
| 2026-08-26 | `orderid` on those rows, expiry, overflow, tests, `docs/` | All of the current behaviour above |

## Removed

No removed-feature note is in the repository.

`sonarqube_scan.bat` was in the onboarding scan's top-level listing (2026-09-28) and is not tracked at `ecbc272`. It was not found in git history. Treat it as not part of this repository unless the scan host still has an untracked copy.

## Not in the repository

| Item | Where it is described |
|---|---|
| Staff portal checkout, cart cap, and order insert | `docs/integration-flow.md` says the portal owns checkout and the cart cap. Silicon Ark `pernodstaff` documents that site |
| Azure WebJob `settings.job`, run script, or publish profile | The flow doc says WebJob `OnDemand`. No such file is in git |
| Scheduler | Not mentioned |
| JDE response parsing | The flow doc says the body is not parsed |
| Production config separate from the committed staging URLs | Not present |

## Planned

No planned feature is written down in this repository.

## In development

`josh_work` is still on the remote at `054f39a` (2026-08-26, "improve tests"). That commit is already merged to `main` by `ecbc272`. No unmerged commits were found on that branch.
