# Gym & Fitness Membership Management

> Gym memberships that expire, freeze and renew on their own, a front desk that says why entry is refused, class bookings with a waiting list.

- **What it is:** Gym memberships that expire, freeze and renew on their own, a front desk that says why entry is refused, class bookings with a waiting list.
- **For:** Industries
- **Odoo versions:** 16.0, 17.0, 18.0, 19.0, 20.0 - Community and Enterprise
- **Runs on:** Odoo.sh or Odoo you host yourself - not Odoo Online, which accepts no third-party apps
- **Price:** 99 EUR, one-time, on the Odoo Apps Store
- **Technical name:** bambooforge_gym
- **Not for:** Said before you buy, because it is the half that decides whether the app fits:; Open the door on an unpaid membership when overdue money is set to block - overdue, not merely unpaid.; Show the front desk a crash dialog: a refusal or a server error is a line on the panel.
- **Manual:** https://docs.bambooforge.dev/bambooforge_gym/
- **Live demo:** https://demo20.bambooforge.dev/odoo/action-bambooforge_gym.action_bf_gym_front_desk
- **Store page:** https://apps.odoo.com/apps/modules/20.0/bambooforge_gym
- **Manual last updated:** 2026-10-15

---
# Gym & Fitness Membership Management

One moment decides whether gym software is any good: somebody is
standing at the desk and the screen has to say yes or no, and why.

## The front desk

Type or scan a name or a member number and the panel answers in one
line: **come in**, or **not today** with the actual reason - not
started, on hold, ran out on the 3rd, no sessions left, cancelled, not
a member here. A refusal is never a red dialog somebody has to dismiss
with a queue waiting.

If the gym has switched it on, money **overdue** also stops the door -
overdue, not merely unpaid, so an invoice raised this morning on
fourteen-day terms is not an argument in front of other members. It is
**off by default** for the same reason.

A server error never reaches the desk as a crash dialog either: the
panel says so and nothing is recorded. A scan that arrives while the
previous one is still going is not swallowed in silence.

## Plans

Monthly, quarterly, yearly, or a **session pass**. A plan carries:

- its price, and the product the invoice line is written against;
- how many sessions it includes (0 = unlimited) and how long a pass
  stays valid;
- how many **freeze days** a member may take per period;
- the **notice period** that still has to be paid;
- whether it renews itself;
- which classes it opens - empty means all of them.

## Memberships

A membership is a contract, not a flag on a contact.

- The **price is copied at signature**, so a price rise never rewrites
  what somebody already signed.
- **Two live memberships for one person are refused.** That is how a
  member ends up billed twice and the door ends up guessing.
- A pass may sit alongside a monthly, and at the door the **unlimited
  membership wins** - a member who paid for unlimited entry would be
  furious to watch a paid session disappear.

## Holds

Injury, travel, a broken leg.

- A hold pushes the end date out **when it finishes**, not when it
  starts - otherwise a member freezes, trains through the freeze and
  keeps the days.
- It gives back **the days actually taken**, not the days asked for. A
  fortnight abandoned after two days is worth two days.
- A hold booked for next week **starts itself** on the day, so the door
  refuses while it runs. One booked entirely in the future gives nothing
  until it has begun.
- A **finished hold cannot be edited or deleted**. The allowance counts
  the days that were credited, so the same fortnight cannot be handed
  out twice by typing over an old row.
- A hold that is scrapped gives back no days.

## Leaving

Giving notice moves the end date to the end of the **notice period**
and the membership stays live and billable until then. The end date only
ever moves **outwards**: a year that has been paid for is never cut back
to thirty days. The days that run past what was already invoiced are
**charged**, or the member trains through the notice for nothing.

Notice can only be given on a live membership, and only once. A plan
with no notice period ends on the spot.

## Classes

- Capacity can never exceed the **studio's fire limit**, and a trainer
  cannot teach two rooms at once.
- A full class puts the next member on a **waiting list**; the moment a
  seat frees up it goes to whoever waited longest - **skipping anyone
  whose membership has lapsed in the meantime** and carrying on down the
  list, with a note saying so. A lapsed member at the head of the queue
  never swallows the seat.
- **Cancelling late costs a session**, inside a window the manager
  sets - and a **no-show costs the same**, because the seat was held
  either way. Charging the phone call and not the empty chair rewards
  the wrong behaviour.
- Ticking somebody in from the **waiting list** cannot push a class over
  its capacity, and cannot be done for a membership that has lapsed.
- A member who cancels **can book the class again**; only live bookings
  are unique.
- If the *gym* cancels the class, every seat is released and nobody
  pays for it.
- Closing the register marks whoever was booked and did not turn up as
  a **no show**, and a scheduled job closes classes that are over so
  the list is true in the morning without anybody ticking it.

## One visit, one session

A session credit is spent in exactly **one place** - the door - and
**one visit a day costs one session**, enforced by a unique index rather
than by hope. Scanning in for a class you booked marks that register, so
somebody who turned up is never closed off as a no-show an hour later.
Ticking the register goes through the same code, so a member who scans
in and is ticked off by the trainer is charged once.

Deleting a visit gives a paid session back, and deleting a booking that
carries a late-cancellation or a no-show would too, so both are a
**manager's** job. Credits never go negative.

## Billing

The invoice names the period it covers, and the same period is never
invoiced twice. A scheduled job raises the invoice for a period that
has started - **off by default**, because letting software bill people
should be a decision - and it never bills a membership that is on hold.

## Roles

**Trainer** runs the timetable and the register and reads the medical
note - and can actually do all of it, which is worth saying because a
role that cannot open its own screens is not a role. Every price, on
the plan and on the membership, is hidden from them at **field level**.

**Reception** works the door, sells and renews memberships and invoices
them, and needs **no accounting role** to do it: the figures the desk
sees are computed with sudo rather than by handing a receptionist the
whole ledger.

**Gym manager** configures plans, classes and studios, and is the only
role that can delete a paid visit or a charged booking.

Two sites in one database stay two sites: the door only ever looks at
memberships of the gym it is standing in, and each site's invoices are
raised in its own company.

The medical note is protected at field level, not by hiding a page, and
it is never tracked into a chatter everybody follows.

## Community only

Depends on `product`, `account` and `base_setup` - all Community.
Tested on 16.0, 17.0, 18.0, 19.0 and 20.0.

## How we make sure it works

Before every release, **148 automated checks** run against this app on Odoo 16, 17, 18, 19 and 20.
Among them:

- A hold that already gave its days cannot give them twice.
- One trainer cannot run two sites at the same hour.
- A trainer cannot teach two rooms at once.
- Notice cannot be given twice.
- No form asks the client about a field it cannot see.

The complete list is in the source you receive.

## What it does not do

Said before you buy, because it is the half that decides whether the app fits:

- Open the door on an unpaid membership when overdue money is set to block - overdue, not merely unpaid.
- Show the front desk a crash dialog: a refusal or a server error is a line on the panel.

## Install

1. Copy `bambooforge_gym` into your addons path and update the app list, or install the ZIP from the Odoo Apps Store.
2. Install **Gym & Fitness Membership Management**.
3. Open **Gym** - its menus are Front desk, Timetable, Members, Memberships.

## Questions people ask

****Which Odoo versions does it run on?****

Odoo 16.0, 17.0, 18.0, 19.0, 20.0, on the series you buy it for; each series is its own listing.

****Community or Enterprise?****

Both. It needs no Enterprise app.

****What does it need?****

The standard Discuss, Invoicing, Products, Settings apps. No extra Python package.

****Where does it show up?****

Under the **Gym** menu (Front desk, Timetable, Members, Memberships).

****Does anything leave my server?****

No. It makes no call outside your Odoo server: no telemetry, no licence check, no third-party service.

****What happens if I uninstall it?****

Odoo drops the app's own tables and fields; the standard records it worked on (contacts, orders, products) stay as they are.
