Skip to content

Refine booking gear, Nitrox checks and manifest ops - #285

Merged
kargig merged 3 commits into
mainfrom
feature/booking-equipment-eanx-manifest-enhancements
Oct 22, 2026
Merged

kargig merged 3 commits into
mainfrom
feature/booking-equipment-eanx-manifest-enhancements

Conversation

@kargig

@kargig kargig commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Consolidate equipment terminology to Lead Weights across the booking wizard, gear profiles, and operations dashboard. Apply standard sizing defaults for full equipment rentals and remove redundant badge labels.

Update agency certification gas specifications so recreational depth ratings default to Air while specialized ratings grant Nitrox. Connect Nitrox eligibility to the diver's active portfolio in checkout context, and treat unverified EAN32 bookings as non-blocking pending dockside verification with support for secondary Nitrox credentials.

Add default cylinder valve fittings and daily insurance pricing to center booking settings in consolidated database migration 0107. Unify equipment rental configuration into the dedicated gear rental page, eliminating the redundant modal.

Reorganize the boat manifest table to place Doc checks before Status. Establish strict separation of concerns: Status contains read-only indicators (Medical, Waiver, Gear, EAN32), while Doc checks contains interactive actions (Certification Card, Gas approval, and formal Physician Clearance). Enforce audited physician clearance for flagged divers and standardize terminology to Medical Clearance and Medical hold.

Consolidate equipment terminology to Lead Weights across the booking
wizard, gear profiles, and operations dashboard. Apply standard sizing
defaults for full equipment rentals and remove redundant badge labels.

Update agency certification gas specifications so recreational depth
ratings default to Air while specialized ratings grant Nitrox. Connect
Nitrox eligibility to the diver's active portfolio in checkout context,
and treat unverified EAN32 bookings as non-blocking pending dockside
verification with support for secondary Nitrox credentials.

Add default cylinder valve fittings and daily insurance pricing to
center booking settings in consolidated database migration 0107. Unify
equipment rental configuration into the dedicated gear rental page,
eliminating the redundant modal.

Reorganize the boat manifest table to place Doc checks before Status.
Establish strict separation of concerns: Status contains read-only
indicators (Medical, Waiver, Gear, EAN32), while Doc checks contains
interactive actions (Certification Card, Gas approval, and formal
Physician Clearance). Enforce audited physician clearance for flagged
divers and standardize terminology to Medical Clearance and Medical
hold.
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Gas mix overwritten

In _apply_diver_paperwork_for_unit_item, the new block sets unit_item.selected_gas_mix_id and gas_mix_status based on eligibility, but the following unchanged lines (unit_item.selected_gas_mix_id = req.selectedGasMixId or "air") immediately overwrite selected_gas_mix_id. The status is preserved, but the assignment logic is now duplicated and confusing; more importantly, if the two ever diverge (e.g. req.selectedGasMixId empty), the status computed from one value won't match the stored gas. Consolidate into a single assignment to avoid inconsistent state.

if req.selectedGasMixId and req.selectedGasMixId.lower() != "air":
    is_eligible = check_nitrox_eligibility(
        unit_item.certification_level,
        req.selectedGasMixId,
        db,
        user_id=unit_item.user_id,
    )
    unit_item.selected_gas_mix_id = req.selectedGasMixId
    unit_item.gas_mix_status = "APPROVED" if is_eligible else "PENDING_APPROVAL"
else:
    unit_item.selected_gas_mix_id = req.selectedGasMixId or "air"
    unit_item.gas_mix_status = "APPROVED"

unit_item.selected_tank_id = req.selectedTankId or "12"
unit_item.selected_gas_mix_id = req.selectedGasMixId or "air"
Dead branch

In update_participant, both branches of the if req.selected_gas_mix_id.lower() == "air" check set item.gas_mix_status = "APPROVED". The air branch is redundant, and the non-air branch unconditionally marks the gas as approved and records nitrox_cert_verified = True without any eligibility check. This means a staff edit of the gas mix silently bypasses Nitrox verification (the previous code raised a 400). If that bypass is intentional, the dead if/else should be collapsed; if not, the eligibility check should be retained.

if req.selected_gas_mix_id.lower() == "air":
    item.gas_mix_status = "APPROVED"
else:
    item.gas_mix_status = "APPROVED"
    verifs = dict(item.checkin_verifications or {})
    verifs["nitrox_cert_verified"] = True
    verifs["nitrox_cert_verified_at"] = datetime.now(UTC).isoformat()
    verifs["nitrox_cert_verified_by"] = current_user.username
    item.checkin_verifications = verifs
N+1 query

The center_settings dict in get_checkout_context runs a new db.query(DivingCenterBookingSettings)...first() for default_valve_fitting, and then the existing rental_pricing block runs another identical query for the same center. This is a redundant duplicate query on every checkout-context request. Fetch the settings row once and reuse it for both fields.

"center_settings": {
    "default_valve_fitting": getattr(
        (
            c_set := db.query(DivingCenterBookingSettings)
            .filter(DivingCenterBookingSettings.diving_center_id == center.id)
            .first()
        ),
        "default_valve_fitting",
        "DIN",
    )
    or "DIN",
    "daily_insurance_price": float(c_set.daily_insurance_price)
    if c_set and c_set.daily_insurance_price is not None
    else 0.0,
},

⚠️ Review coverage: The following files were not included in this review because of the token budget:

  • frontend/src/components/booking/BookingWizard.jsx
  • frontend/src/pages/CenterRentalPricingPage.jsx
  • frontend/src/pages/BookingVoucherPage.jsx
  • frontend/src/components/booking/BriefingReviewModal.jsx
  • frontend/src/components/booking/DiverGearConfigForm.jsx
  • frontend/src/components/UserGearProfileModal.jsx

- Resolves gas mix assignment overwrite in _apply_diver_paperwork_for_unit_item
  by removing redundant duplicate assignment.
- Removes dead branch in update_participant; performs check_nitrox_eligibility
  when updating participant gas mix, assigning APPROVED if eligible and
  PENDING_APPROVAL if unverified instead of unconditionally bypassing checks.
- Eliminates redundant queries in get_checkout_context by fetching
  DivingCenterBookingSettings once and reusing it for default_valve_fitting,
  daily_insurance_price, and rental_equipment_pricing.
- Formats test files to resolve the Ruff Lint and Format GitHub Actions
  CI failure.
- Updates make lint-backend and make lint-backend-fix via run-backend-lint.sh
  to dynamically target all modified Python files across both app and tests,
  matching GitHub Actions CI behavior.
…f format

- Updates test_nitrox_requires_qualifying_certification in
  test_center_booking_ops_api.py to assert the new non-blocking walk-in
  behavior (201 Created with PENDING_APPROVAL) and tests the boarding gate
  blocking unverified EANx until approved.
- Formats test_nitrox_service.py to resolve the GitHub Actions Ruff Lint
  and Format failure.
@kargig
kargig force-pushed the feature/booking-equipment-eanx-manifest-enhancements branch from 9d91642 to 44fdc89 Compare October 22, 2026 18:31
@kargig
kargig merged commit 0c6183b into main Oct 22, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant