# Calculate Follow-Up Status Business Logic

## Purpose

This document describes how the `CalculateFollowUpStatusRule` currently calculates:

- `Next Appointment`
- appointment-level `PAI Status`
- `Overall PAI Status`
- `Overall PAI Status Summary`

It is written for business review. The section **Business decisions to confirm** identifies points where the current implementation and the intended business behavior may differ.

## 1. Inputs

### Appointment data

Each appointment is read from the configured SERVICES MultiChoice column. The rule uses these appointment fields:

| Business field | Technical field | Purpose |
|---|---|---|
| Booking time | Configured booking-time parameter | Orders appointments and compares dates |
| Appointment status | Configured status parameter | Determines whether the appointment participates |
| Appointment type | Configured type parameter | Groups appointments into independent follow-up sequences |
| Next Appointment | Configured next-appointment parameter | Output date written to the appointment |
| PAI Status | Configured PAI-status parameter | Output status written to the appointment |

The appointment type is taken from the configured appointment-type field. If that field is empty, the rule uses the service group name as a fallback.

### Interval configuration

Each configured appointment type is mapped to a whiteboard column containing a month interval.

Example:

```text
Appointment type 89.50 -> HF_PAI_ECODIAGRAM_SCHEDULE -> 12-18
```

The interval format is:

```text
minimum months - maximum months
```

For an interval of `12-18`, the next qualifying appointment should be at least 12 months and at most 18 months after the reference appointment.

Valid intervals must:

- contain exactly two numbers;
- use a hyphen as the separator;
- have a minimum of zero or greater;
- have a maximum greater than or equal to the minimum.

If the configured interval column is missing, empty, or invalid, that appointment type has no active interval for the current row.

## 2. Appointment statuses

The configured status values default to:

| Status category | Default value | Meaning in the rule |
|---|---|---|
| Completed | `Completed` | A clinical appointment that has taken place |
| Accepted | `Accepted` | A clinical appointment that is accepted/scheduled |
| Booked | `Booked` | A future appointment booking |
| Other statuses | Any other value | Ignored by the rule |

The status values are configurable. For example, a system can use `Done`, `Confirmed`, and `Scheduled` instead of the defaults.

Appointments with unsupported statuses are not included in any calculation and do not cause output cells to be created.

## 3. Appointment grouping and ordering

Appointments are grouped by appointment type, case-insensitively.

Appointments of different types never affect one another. For example, a cardiology appointment cannot be the next appointment for an echocardiogram appointment.

Within each type, appointments are ordered by booking time.

## 4. Next Appointment

### Current algorithm

For a `Completed` or `Accepted` appointment, the rule searches for the earliest later appointment of the same type whose status is one of the allowed statuses:

- `Completed`
- `Accepted`
- `Booked`

The result is written to the appointment's `NextAppointment` field.

For a `Booked` appointment, `NextAppointment` is always empty.

For an unsupported status, the appointment is ignored.

### Example of the current algorithm

Given these appointments of the same type:

| Date | Status |
|---|---|
| 27.02.2026 | Completed |
| 06.06.2026 | Completed |
| 24.06.2026 | Completed |
| 27.06.2026 | Completed |
| 08.07.2026 | Accepted |
| 13.07.2026 | Accepted |
| 14.07.2026 | Accepted |
| 26.07.2026 | Booked |

The current `NextAppointment` chain is:

| Current appointment | Current status | Current next appointment |
|---|---|---|
| 27.02.2026 | Completed | 06.06.2026 |
| 06.06.2026 | Completed | 24.06.2026 |
| 24.06.2026 | Completed | 27.06.2026 |
| 27.06.2026 | Completed | 08.07.2026 |
| 08.07.2026 | Accepted | 13.07.2026 |
| 13.07.2026 | Accepted | 14.07.2026 |
| 14.07.2026 | Accepted | 26.07.2026 |
| 26.07.2026 | Booked | Empty |

## 5. Appointment-level PAI Status

PAI is calculated independently for each appointment type, using the configured interval for that type.

### 5.1 Completed or Accepted with a next appointment

For a `Completed` or `Accepted` appointment with a next appointment, the rule compares:

```text
current appointment date + configured interval
```

with the next appointment date.

| Date comparison | PAI Status |
|---|---|
| Next appointment is before the minimum allowed date | `Too early` |
| Next appointment is on or after the minimum and on or before the maximum | `OK` |
| Next appointment is after the maximum allowed date | `Too late` |

The interval boundaries are inclusive.

Example with interval `3-6`:

| Current date | Next date | Result |
|---|---|---|
| 01.01.2026 | 01.02.2026 | Too early |
| 01.01.2026 | 01.04.2026 | OK |
| 01.01.2026 | 01.08.2026 | Too late |

### 5.2 Completed or Accepted without a next appointment

If there is no next appointment, the rule compares the current date with the minimum follow-up date:

```text
current appointment date + minimum interval
```

| Current date relative to minimum follow-up date | PAI Status |
|---|---|
| Before the minimum follow-up date | `OK` |
| On or after the minimum follow-up date | `Not booked` |

This means that a recent completed appointment can remain `OK` while there is still time to arrange the follow-up appointment.

Example with interval `3-6` and no next appointment:

| Current appointment date | Evaluation date | Result |
|---|---|---|
| 01.01.2026 | 01.03.2026 | OK |
| 01.01.2026 | 01.05.2026 | Not booked |

### 5.3 Booked appointment

For a `Booked` appointment, the rule looks backwards for the latest earlier appointment of the same type with status `Completed` or `Accepted`.

If no previous qualifying appointment exists:

- `PAI Status` is empty;
- `Next Appointment` is empty.

If a previous qualifying appointment exists, the booked date is compared with the previous appointment date and interval using the same rules:

- before the minimum: `Too early`;
- within the inclusive interval: `OK`;
- after the maximum: `Too late`.

This allows a future `Booked` appointment to be assessed against the previous clinical appointment.

### 5.4 Appointment type without an interval

If the appointment type has no valid interval value in the current patient row:

- appointment-level `PAI Status` is empty;
- the appointment is excluded from overall PAI calculations;
- the appointment type is excluded from the overall summary.

This is different from `Not booked`. Empty means that no configured interval was available for evaluation.

## 6. Overall PAI Status

### Purpose

`Overall PAI Status` gives one patient-level result across all configured appointment types.

### Which appointment types participate

Only appointment types that satisfy both conditions participate:

1. The appointment type has a configured mapping.
2. The mapped interval column contains a valid interval for the current patient row.

Unconfigured appointment types and appointment types with missing or invalid intervals are excluded.

If no appointment type participates, the overall value is empty.

### Which appointment represents each type

For each participating appointment type, the rule selects the latest appointment by booking time, regardless of status.

The PAI status already calculated for that latest appointment is used.

This means the latest appointment may be:

- `Completed`;
- `Accepted`;
- `Booked`.

### Overall result

The overall result is:

| Participating appointment-type results | Overall PAI Status |
|---|---|
| Every type has PAI status `OK` | Configured overall `OK` value, normally `OK` |
| At least one type has any other value | Configured overall not-OK value, normally `Not OK` |

An empty appointment-level PAI status is not equal to `OK`, so it causes the overall result to be not-OK when that appointment type is included. In normal processing, types without intervals are excluded before this decision.

## 7. Overall PAI Status Summary

### Purpose

The summary gives one entry for each participating appointment type, making it possible to see which type caused the overall result.

The format is:

```text
appointment type - PAI status, appointment type - PAI status
```

Example:

```text
89.01.03 - Too early, 89.50 - OK
```

### Selection and ordering

The summary uses the same participating appointment types and the same latest appointment per type as `Overall PAI Status`.

Entries are ordered by the latest appointment booking time, from oldest to newest.

### Empty PAI values in the summary

If the selected latest appointment has an empty PAI status, the summary displays the configured `Not booked` value instead of an empty value.

## 8. End-to-end example

Assume:

```text
Appointment type: 89.50
Configured interval: 12-18 months
```

Appointments:

| Date | Status |
|---|---|
| 27.02.2026 | Completed |
| 06.06.2026 | Completed |
| 08.07.2026 | Accepted |
| 13.07.2026 | Accepted |
| 14.07.2026 | Accepted |
| 26.07.2026 | Booked |

Under the current implementation:

| Current appointment | Next Appointment | PAI Status explanation |
|---|---|---|
| 27.02.2026 Completed | 06.06.2026 | Too early because the next appointment is before 12 months |
| 06.06.2026 Completed | 08.07.2026 | Too early because the next appointment is before 12 months |
| 08.07.2026 Accepted | 13.07.2026 | Too early because the next appointment is before 12 months |
| 13.07.2026 Accepted | 14.07.2026 | Too early because the next appointment is before 12 months |
| 14.07.2026 Accepted | 26.07.2026 Booked | Too early under the current successor rule |
| 26.07.2026 Booked | Empty | Too early when assessed against 14.07.2026 |

The latest appointment for type `89.50` is the `Booked` appointment on 26.07.2026. Therefore:

```text
Overall PAI Status: Not OK
Overall PAI Status Summary: 89.50 - Too early
```

## 9. Business decisions to confirm

### Decision A: Should Booked be a Next Appointment?

The current implementation includes `Booked` when finding the next appointment for a `Completed` or `Accepted` appointment.

Alternative business interpretation:

- `NextAppointment` should identify the next `Completed` or `Accepted` appointment only;
- `Booked` should not replace a future clinical appointment in the chain;
- a `Booked` appointment should be assessed separately against the previous `Completed` or `Accepted` appointment.

This decision changes both `NextAppointment` and the PAI status of preceding appointments.

### Decision B: Should Booked appointments have a PAI status?

The current implementation calculates PAI for a `Booked` appointment when a previous `Completed` or `Accepted` appointment exists.

Alternative behavior:

- always leave PAI empty for `Booked` appointments; or
- show `OK`, `Too early`, or `Too late` based on the previous clinical appointment.

The current implementation uses the second behavior.

### Decision C: What should happen when there is no next appointment?

The current implementation is time-aware:

- before the minimum follow-up date: `OK`;
- on or after the minimum follow-up date: `Not booked`.

Alternative behavior would be to show `Not booked` immediately whenever no next appointment exists.

### Decision D: Which appointment should drive the overall result?

The current implementation selects the latest appointment by date for each type, including a `Booked` appointment.

The business should confirm whether the latest appointment should instead mean:

- latest appointment of any allowed status;
- latest `Completed` or `Accepted` appointment only;
- latest appointment with a calculated PAI status;
- latest appointment excluding `Booked`.

This decision directly affects both overall fields.

### Decision E: How should missing interval configuration be represented?

The current behavior is:

- appointment-level PAI is empty;
- the type is excluded from both overall fields;
- no configured type results in empty overall fields.

This keeps “not configured” separate from “not booked,” but it should be confirmed with the business.

## 10. Recommended discussion order

To avoid mixing separate concepts, agree on the rules in this order:

1. Which statuses are valid?
2. Which statuses can be a `NextAppointment`?
3. Which statuses can receive PAI?
4. What is the reference appointment for a `Booked` appointment?
5. What happens when there is no next appointment?
6. Which appointment is latest for overall calculations?
7. How should missing interval configuration be represented?
8. What exact display text should be used for each result?

Once these decisions are confirmed, the implementation and tests can be aligned to the agreed business behavior.

## Related implementation and tests

- [CalculateFollowUpStatusRule.cs](../Source/Imatis.Whiteboard.Business.SimpleRules/CalculateFollowUpStatusRule.cs)
- [When_Validating_Arguments.cs](../CoreTests/For_CalculateFollowUpStatusRule/When_Validating_Arguments.cs)
