feat: Enhance booking functionality with invoice management and dashboard summary
- Added customerId to guest booking requests for better identification. - Implemented new endpoints for managing booking invoices and dashboard summaries. - Created BookingInvoice and BookingDashboardSummary DTOs to support new features. - Updated Booking and BookingInvoice models to include payment method and timestamps. - Enhanced BookingService to handle invoice creation upon payment confirmation. - Modified BookingRepository to support CRUD operations for BookingInvoice. - Updated TenantDbContext to include BookingInvoice DbSet and relevant configurations. - Improved error handling and validation for booking completion and payment processes.
This commit is contained in:
+18
-8
@@ -86,24 +86,34 @@ namespace Fitness_core_BE.Models
|
||||
public string PaymentStatus { get; set; } = "NotRequired";
|
||||
public decimal AmountCharged { get; set; } = 0m;
|
||||
|
||||
/// <summary>"Cash" | "Bank" -- set alongside PaymentStatus becoming "Paid" (MarkGuestBookingPaid
|
||||
/// or the Complete checkout flow). Null until then.</summary>
|
||||
[MaxLength(20)]
|
||||
public string? PaymentMethod { get; set; }
|
||||
/// <summary>Set the moment PaymentStatus becomes "Paid" -- distinct from BookedAt/CheckedOutAt,
|
||||
/// this is specifically when the money was recorded, used to bucket booking revenue into
|
||||
/// Profit & Loss and to date-stamp the BookingInvoice snapshot.</summary>
|
||||
public DateTime? PaidAt { get; set; }
|
||||
|
||||
// Set only once payment is confirmed for a pay-per-session guest booking, or
|
||||
// immediately for a member session (no payment gate) -- see PaymentStatus.
|
||||
public Guid? FKPaymentTransactionId { get; set; }
|
||||
[ForeignKey(nameof(FKPaymentTransactionId))]
|
||||
public PaymentTransaction? PaymentTransaction { get; set; }
|
||||
|
||||
/// <summary>"Confirmed" | "CheckedIn" | "Cancelled" | "NoShow" | "Completed". NoShow and
|
||||
/// Completed are reached either by explicit staff action (MarkNoShow/Complete) or lazily,
|
||||
/// swept by BookingService.SweepOverdueBookingsAsync at the top of every check-in call
|
||||
/// (not a background job -- overdue bookings are reconciled the next time any check-in
|
||||
/// happens for this client, across every facility).</summary>
|
||||
/// <summary>"Confirmed" | "CheckedIn" | "Cancelled" | "NoShow" | "Completed". NoShow is
|
||||
/// reached either by explicit staff action (MarkNoShow) or lazily, swept by
|
||||
/// BookingService.SweepOverdueBookingsAsync at the top of every check-in or checkout call
|
||||
/// (not a background job -- overdue Confirmed bookings are reconciled the next time any
|
||||
/// check-in/checkout happens for this client, across every facility). Completed is
|
||||
/// reached ONLY by the explicit Complete action -- a guest booking can't reach it while
|
||||
/// still Unpaid, so there's no automatic path that would check someone out unpaid.</summary>
|
||||
public string Status { get; set; } = "Confirmed";
|
||||
|
||||
public DateTime BookedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime? CheckedInAt { get; set; }
|
||||
/// <summary>Set when the booking reaches Completed, whether via the manual Complete
|
||||
/// action or the lazy overdue-sweep -- the actual moment it was reconciled, not
|
||||
/// necessarily EndTime.</summary>
|
||||
/// <summary>Set when the booking reaches Completed via the manual Complete action -- the
|
||||
/// actual moment it was checked out, not necessarily EndTime.</summary>
|
||||
public DateTime? CheckedOutAt { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Fitness_core_BE.Models
|
||||
{
|
||||
/// <summary>A snapshot receipt generated the moment a Booking's payment is recorded (either
|
||||
/// via MarkGuestBookingPaid or the Complete checkout flow) -- deliberately NOT a live join to
|
||||
/// Booking/Facility, so it stays stable and printable even if the booking is later reassigned,
|
||||
/// rescheduled, or the facility renamed. Purpose-built for bookings and kept entirely separate
|
||||
/// from CustomerInvoice, which is hardwired to the membership/subscription domain
|
||||
/// (FKCustomerSubscriptionId is required there) and has no concept of a one-off booking
|
||||
/// charge.</summary>
|
||||
public class BookingInvoice
|
||||
{
|
||||
[Key]
|
||||
public Guid BookingInvoiceId { get; set; }
|
||||
|
||||
public Guid FKBookingId { get; set; }
|
||||
[ForeignKey(nameof(FKBookingId))]
|
||||
public Booking? Booking { get; set; }
|
||||
|
||||
public Guid FKClientId { get; set; }
|
||||
[ForeignKey(nameof(FKClientId))]
|
||||
public Client Client { get; set; }
|
||||
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>"Cash" | "Bank".</summary>
|
||||
[MaxLength(20)]
|
||||
public string PaymentMethod { get; set; } = "Cash";
|
||||
|
||||
[MaxLength(200)]
|
||||
public string GuestName { get; set; } = string.Empty;
|
||||
[MaxLength(32)]
|
||||
public string? GuestPhone { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string FacilityName { get; set; } = string.Empty;
|
||||
public DateTime BookingStartTime { get; set; }
|
||||
public DateTime BookingEndTime { get; set; }
|
||||
|
||||
public DateTime IssuedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user