Problem/Motivation

On a fresh BEE installation, setting availability via the **Availability tab** on a bookable node silently fails to create any BAT availability events. The form submits without error, but no event appears at `/admin/bat/events/event`, and the BAT calendar store remains empty.

As a consequence, when a user attempts to make a booking via the BEE booking form, they always receive **“no units available”** regardless of the dates chosen. The module is effectively non-functional out of the box.

The bug is a **chicken-and-egg problem** in `createDailyEvent()` and `createHourlyEvent()` inside `UpdateAvailabilityForm.php`.

Both methods call `bat_event_get_matching_units()` to retrieve units that already have availability events written to the BAT calendar, and then only write new events for those matched units:

```php
// In createDailyEvent():
$d['available_units'] = bat_event_get_matching_units(
$d['start_date'],
$d['temp_end_date'],
['bee_daily_available', 'bee_daily_not_available'],
[$d['type_id']],
'availability_daily'
);

// ...units_ids are collected from the node but never used as fallback...

if (isset($d['available_units'])) {
foreach ($d['available_units'] as $unit) {
// Creates the event — but only if $d['available_units'] is non-empty
}
}
```

On a fresh install, the BAT calendar is empty — no availability events have ever been written. `bat_event_get_matching_units()` therefore returns an empty result, `$d['available_units']` is empty, the `foreach` never executes, and **no event is ever written**.

The code requires existing availability events in order to create the first availability event. It can never bootstrap itself from an empty state.

Both methods collect unit IDs directly from the node’s field references into `$d['units_ids']`, but this array is never used as a fallback when `$d['available_units']` is empty, making it effectively dead code in the fresh-install scenario.

The same problem exists in `createHourlyEvent()`, where `array_intersect($d['units_ids'], $d['available_units'])` always produces an empty set when `$d['available_units']` is empty.

Steps to reproduce

1. Fresh Drupal 11 installation with BEE 11.1.0-rc3 and BAT 11.1.0-rc8
2. Enable `bat`, `bat_unit`, `bat_event`, then `bee` (with cache clears between)
3. Create a content type, enable BEE bookability (daily), save
4. Create a node of that content type — confirm a BAT unit is created at `/admin/bat/units`
5. Go to the node’s Availability tab (`/node/{nid}/availability`)
6. Set a date range and state to “Available”, click **Update Availability**
7. Check `/admin/bat/events/event` — **no event has been created**
8. Attempt a booking via `/node/{nid}/add-reservation` — **“no units available”**

Proposed resolution

Fall back to the unit IDs collected directly from the node’s field references when `bat_event_get_matching_units()` returns empty. This allows the first availability event to be written to a fresh calendar, after which subsequent calls to `bat_event_get_matching_units()` will return results normally.

```diff
--- a/src/Form/UpdateAvailabilityForm.php
+++ b/src/Form/UpdateAvailabilityForm.php
@@ -33,7 +33,17 @@
}
}

- if (isset($d['available_units'])) {
+ // If bat_event_get_matching_units() returns empty (e.g. on a fresh install
+ // where no availability events have been written yet), fall back to the
+ // units referenced directly on the node. Without this fallback, the first
+ // availability event can never be created because the code requires
+ // existing events in order to write the first event — a chicken-and-egg
+ // problem that causes the "no units available" symptom on fresh installs.
+ $d['units_to_update'] = !empty($d['available_units'])
+ ? $d['available_units']
+ : $d['units_ids'];
+
+ if (!empty($d['units_to_update'])) {
if ($d['new_state'] == 'available') {
$d['state'] = bat_event_load_state_by_machine_name('bee_daily_available');
}
@@ -41,7 +51,7 @@
$d['state'] = bat_event_load_state_by_machine_name('bee_daily_not_available');
}

- foreach ($d['available_units'] as $unit) {
+ foreach ($d['units_to_update'] as $unit) {

$event = bat_event_create(['type' => 'availability_daily']);
$event_dates = [
@@ -95,7 +105,15 @@
}
}

- $units = array_intersect($d['units_ids'], $d['available_units']);
+ // If bat_event_get_matching_units() returns empty (e.g. on a fresh install
+ // where no availability events have been written yet), fall back to the
+ // units referenced directly on the node. Without this fallback,
+ // array_intersect() against an empty $d['available_units'] always produces
+ // an empty set, so the first availability event can never be created —
+ // the same chicken-and-egg problem as in createDailyEvent().
+ $units = !empty($d['available_units'])
+ ? array_intersect($d['units_ids'], $d['available_units'])
+ : $d['units_ids'];

if ($units) {
if ($d['new_state'] == 'available') {
```

Remaining tasks

I have tested this offline but i hope it can be tested and implimented by project owner,

User interface changes

none

API changes

none

Data model changes

none

Sponsorship

none

Comments

owens-d created an issue. See original summary.