Skip to content

feat(cancelled-bookings): implement cancelled bookings functionality …#56

Merged
AyushAdh1 merged 3 commits into
mainfrom
feature/ON-cancelled-issue
May 15, 2026
Merged

feat(cancelled-bookings): implement cancelled bookings functionality …#56
AyushAdh1 merged 3 commits into
mainfrom
feature/ON-cancelled-issue

Conversation

@AyushAdh1
Copy link
Copy Markdown
Collaborator

@AyushAdh1 AyushAdh1 commented May 15, 2026

…with archiving and migration

Summary by CodeRabbit

Release Notes

  • New Features

    • Implemented comprehensive cancellation archival system that preserves complete booking details and financial information for cancelled reservations.
  • Improvements

    • Enhanced slot availability validation to prevent duplicate active bookings on the same time slot.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@AyushAdh1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 9 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 948497d8-4e1a-439c-97b8-f9f4291fb884

📥 Commits

Reviewing files that changed from the base of the PR and between 8511b27 and 90fd4d9.

📒 Files selected for processing (18)
  • ApiDocs/HelloFutsal/Booking/BulkBookSlots.bru
  • ApiDocs/HelloFutsal/Booking/BulkConfirmBookings.bru
  • ApiDocs/HelloFutsal/Booking/CancelBooking.bru
  • ApiDocs/HelloFutsal/Booking/ConfirmBooking.bru
  • ApiDocs/HelloFutsal/Booking/CreateBooking.bru
  • ApiDocs/HelloFutsal/Booking/GetBookingById.bru
  • ApiDocs/HelloFutsal/Booking/GetBookingsByFieldId.bru
  • ApiDocs/HelloFutsal/MembershipSlots/CancelMembership.bru
  • ApiDocs/HelloFutsal/MembershipSlots/ConfirmMembershipPayment.bru
  • ApiDocs/HelloFutsal/MembershipSlots/CreateMembershipPlan.bru
  • ApiDocs/HelloFutsal/MembershipSlots/GetFieldSlotSummary.bru
  • ApiDocs/HelloFutsal/MembershipSlots/GetMembershipDetailsByField.bru
  • ApiDocs/HelloFutsal/MembershipSlots/GetPlayedSlot.bru
  • ApiDocs/HelloFutsal/MembershipSlots/PayMembershipSlot.bru
  • ApiDocs/HelloFutsal/MembershipSlots/UpdateMembership.bru
  • ApiDocs/HelloFutsal/environments/Dev.bru
  • src/booking/entities/cancelled-booking.entity.ts
  • src/migrations/1780002000000-CreateCancelledBookingsTable.ts
📝 Walkthrough

Walkthrough

The PR introduces a CancelledBooking entity to archive cancelled bookings into a separate table rather than marking them with a "cancelled" status. This includes database schema migrations that make the bookings slot_id unique constraint partial (excluding cancelled rows) and two service layers that apply the archival pattern throughout booking, membership, and bulk-booking operations.

Changes

Booking Cancellation Archival

Layer / File(s) Summary
CancelledBooking Entity & Schema Modifications
src/booking/entities/cancelled-booking.entity.ts, src/migrations/1780001000000-MakeBookingsSlotIdPartialUnique.ts, src/migrations/1780002000000-CreateCancelledBookingsTable.ts
Defines the CancelledBooking TypeORM entity with monetary fields, audit timestamps, and relations to Field, FieldSlot, and UserAccount. Two migrations create the cancelled_bookings table with indexes and convert the bookings.slot_id unique constraint to a partial index that excludes status = 'cancelled' rows.
Framework Registration
src/booking/booking.module.ts, src/data-source.ts
Registers CancelledBooking in TypeOrmModule.forFeature() and adds it to the application DataSource entity list.
BookingService Archival Integration
src/booking/booking.service.ts
Imports CancelledBooking repository and injects it into the constructor. In createBooking and bulkBookSlots, adds pessimistic-lock checks to prevent non-cancelled active bookings on the target slot. In cancelBooking, archives the booking to CancelledBooking and deletes the original Booking row.
MembershipPlanController Archival Integration
src/booking/membership-plan.controller.ts
Injects CancelledBooking repository and updates performMembershipCancellation and performSlotTimeUpdate to archive released/cancelled bookings to CancelledBooking before deletion instead of updating Booking.status in place.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • hellofutsal/HelloFutsal#18: Core booking service and module wiring foundation that this PR extends with archival behavior.
  • hellofutsal/HelloFutsal#50: Bulk-booking functionality in bulkBookSlots that this PR refactors to add conflict checks excluding cancelled bookings.
  • hellofutsal/HelloFutsal#49: Membership cancellation and slot time-update flows in MembershipPlanController that this PR refactors to use the archival pattern.

Poem

🐰 A rabbit hops through bookings old,
Where cancelled tales must now be told—
Not marked but moved to archives safe,
With partial keys and structured grace!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cancelled-bookings): implement cancelled bookings functionality' directly and accurately describes the main change—implementing a complete cancelled bookings feature with archiving and database migrations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ON-cancelled-issue

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/migrations/1780002000000-CreateCancelledBookingsTable.ts (1)

25-33: 💤 Low value

Consider adding indexes on original_booking_id and cancelled_at.

The migration creates indexes on field_id, user_id, and slot_id, which are good for foreign key lookups. However, two additional indexes might improve query performance:

  1. original_booking_id: Useful for audit queries that trace back to the original booking record.
  2. cancelled_at: Useful for time-based reporting queries (e.g., "cancelled bookings in the last month").
📋 Proposed addition
   await queryRunner.query(
     `CREATE INDEX IF NOT EXISTS "IDX_cancelled_bookings_slot_id" ON "cancelled_bookings" ("slot_id")`,
   );
+  await queryRunner.query(
+    `CREATE INDEX IF NOT EXISTS "IDX_cancelled_bookings_original_booking_id" ON "cancelled_bookings" ("original_booking_id")`,
+  );
+  await queryRunner.query(
+    `CREATE INDEX IF NOT EXISTS "IDX_cancelled_bookings_cancelled_at" ON "cancelled_bookings" ("cancelled_at")`,
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/migrations/1780002000000-CreateCancelledBookingsTable.ts` around lines 25
- 33, Add two additional CREATE INDEX statements via queryRunner.query in the
migration to index original_booking_id and cancelled_at; specifically, add
queries similar to the existing ones (use queryRunner.query) that create
"IDX_cancelled_bookings_original_booking_id" on "cancelled_bookings"
("original_booking_id") and "IDX_cancelled_bookings_cancelled_at" on
"cancelled_bookings" ("cancelled_at") so audit lookups and time-based queries
benefit—place them alongside the existing index creations in the same migration
file.
src/booking/booking.service.ts (1)

152-164: 💤 Low value

Defensive check for status <> 'cancelled' bookings.

This pessimistic lock check excludes bookings with status = 'cancelled' before creating a new booking. However, the new archival flow deletes cancelled bookings from the table (line 579), so ideally there should be no cancelled-status bookings remaining.

This check appears defensive for a transition period where old cancelled bookings might still exist. If that's the intent, consider:

  1. Ensuring a data migration moves all existing status = 'cancelled' bookings to cancelled_bookings table (see comment on migration file).
  2. After the transition period, this condition could be simplified to just check for existence of any booking for the slot.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/booking/booking.service.ts` around lines 152 - 164, The current
pessimistic lock query in bookingRepo.createQueryBuilder("booking") filters out
bookings with status = 'cancelled', which is only needed during the archival
transition; ensure your migration moves all existing cancelled bookings into the
cancelled_bookings archive so cancelled rows no longer exist, and once
migration/archival (the flow that deletes cancelled rows) is complete, simplify
the check in bookingRepo (the activeBooking lookup) to just test for any
existing booking for the slot and remove the "status <> :cancelled" clause and
its parameter; keep throwing ConflictException("Slot already has an active
booking") when any booking exists during the interim, and add a TODO comment
referencing the migration for cleanup so the simplification can be applied
later.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/booking/entities/cancelled-booking.entity.ts`:
- Around line 84-85: The CancelledBooking entity's createdAt property uses
`@CreateDateColumn` which causes TypeORM to auto-generate a new timestamp and
overwrite copied values (the archival assignment createdAt: booking.createdAt in
booking.service.ts and membership-plan.controller.ts). Replace the
`@CreateDateColumn` on the createdAt property in the CancelledBooking entity with
a regular `@Column` configured for a timestamp/Date (and update imports
accordingly) so saved archived entities retain the original booking.createdAt
value. Ensure the property name remains createdAt and the column option name
"created_at" is preserved.
- Around line 24-40: The CancelledBooking entity currently uses onDelete:
"CASCADE" on the Field, FieldSlot and UserAccount relations (symbols:
CancelledBooking, field, slot, user, fieldId, slotId, userId) which will delete
archival rows; change this to preserve history by replacing onDelete: "CASCADE"
with onDelete: "SET NULL" (or remove the relationship entirely if you prefer a
pure snapshot), make the corresponding FK columns (fieldId, slotId, userId)
nullable and adjust the relation properties (field?, slot?, user?) to be
optional so deletes of Field/FieldSlot/UserAccount null out the FKs instead of
removing CancelledBooking records. Ensure DB column definitions and entity types
are updated to reflect nullable FKs and use SET NULL behavior.

In `@src/migrations/1780002000000-CreateCancelledBookingsTable.ts`:
- Around line 5-23: The migration creates the "cancelled_bookings" table but
omits foreign key constraints for field_id, slot_id, and user_id; modify the
migration (CreateCancelledBookingsTable) to add explicit FOREIGN KEY constraints
referencing the appropriate parent tables (e.g., fields(id), slots(id),
users(id)) after the CREATE TABLE (using queryRunner.query to ALTER TABLE ...
ADD CONSTRAINT ... FOREIGN KEY ... ON DELETE CASCADE or the chosen action), and
update the down() method to DROP those constraints before dropping the
"cancelled_bookings" table so referential integrity is enforced and the rollback
removes the FK constraints first.

---

Nitpick comments:
In `@src/booking/booking.service.ts`:
- Around line 152-164: The current pessimistic lock query in
bookingRepo.createQueryBuilder("booking") filters out bookings with status =
'cancelled', which is only needed during the archival transition; ensure your
migration moves all existing cancelled bookings into the cancelled_bookings
archive so cancelled rows no longer exist, and once migration/archival (the flow
that deletes cancelled rows) is complete, simplify the check in bookingRepo (the
activeBooking lookup) to just test for any existing booking for the slot and
remove the "status <> :cancelled" clause and its parameter; keep throwing
ConflictException("Slot already has an active booking") when any booking exists
during the interim, and add a TODO comment referencing the migration for cleanup
so the simplification can be applied later.

In `@src/migrations/1780002000000-CreateCancelledBookingsTable.ts`:
- Around line 25-33: Add two additional CREATE INDEX statements via
queryRunner.query in the migration to index original_booking_id and
cancelled_at; specifically, add queries similar to the existing ones (use
queryRunner.query) that create "IDX_cancelled_bookings_original_booking_id" on
"cancelled_bookings" ("original_booking_id") and
"IDX_cancelled_bookings_cancelled_at" on "cancelled_bookings" ("cancelled_at")
so audit lookups and time-based queries benefit—place them alongside the
existing index creations in the same migration file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aeeb0a5c-4d8a-4fea-8ef6-4e800f54da52

📥 Commits

Reviewing files that changed from the base of the PR and between ae95732 and 8511b27.

📒 Files selected for processing (7)
  • src/booking/booking.module.ts
  • src/booking/booking.service.ts
  • src/booking/entities/cancelled-booking.entity.ts
  • src/booking/membership-plan.controller.ts
  • src/data-source.ts
  • src/migrations/1780001000000-MakeBookingsSlotIdPartialUnique.ts
  • src/migrations/1780002000000-CreateCancelledBookingsTable.ts

Comment thread src/booking/entities/cancelled-booking.entity.ts Outdated
Comment thread src/booking/entities/cancelled-booking.entity.ts Outdated
Comment thread src/migrations/1780002000000-CreateCancelledBookingsTable.ts
@AyushAdh1 AyushAdh1 merged commit 8f0c627 into main May 15, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant