feat: add price field to CourtBooking model and related schemas

- Added `price` field to `CourtBookingScalarFieldEnum` in `prismaNamespace.ts` and `prismaNamespaceBrowser.ts`.
- Updated `CourtBooking` model to include average and sum aggregations for `price`.
- Enhanced input types and aggregate input types to support `price`.
- Modified `public-booking.service.ts` to calculate and return price information for bookings.
- Updated frontend components to display price information in booking confirmation and selection pages.
- Introduced `priceRangeSchema` in API contract to validate price ranges.
This commit is contained in:
Jose Selesan
2026-04-24 15:22:11 -03:00
parent c63f0f2109
commit fb19458ddf
10 changed files with 290 additions and 4 deletions

View File

@@ -82,6 +82,7 @@ model CourtBooking {
bookingDate DateTime @map("booking_date") @db.Date
startTime String @map("start_time") @db.VarChar(5)
endTime String @map("end_time") @db.VarChar(5)
price Decimal? @map("price") @db.Decimal(19, 2)
customerName String @map("customer_name") @db.VarChar(120)
customerPhone String @map("customer_phone") @db.VarChar(30)
status CourtBookingStatus @default(CONFIRMED)

View File

@@ -280,6 +280,17 @@ export type EnumDayOfWeekNullableWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedEnumDayOfWeekNullableFilter<$PrismaModel>
}
export type DecimalNullableFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
}
export type EnumCourtBookingStatusFilter<$PrismaModel = never> = {
equals?: $Enums.CourtBookingStatus | Prisma.EnumCourtBookingStatusFieldRefInput<$PrismaModel>
in?: $Enums.CourtBookingStatus[] | Prisma.ListEnumCourtBookingStatusFieldRefInput<$PrismaModel>
@@ -287,6 +298,22 @@ export type EnumCourtBookingStatusFilter<$PrismaModel = never> = {
not?: Prisma.NestedEnumCourtBookingStatusFilter<$PrismaModel> | $Enums.CourtBookingStatus
}
export type DecimalNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_min?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_max?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
}
export type EnumCourtBookingStatusWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.CourtBookingStatus | Prisma.EnumCourtBookingStatusFieldRefInput<$PrismaModel>
in?: $Enums.CourtBookingStatus[] | Prisma.ListEnumCourtBookingStatusFieldRefInput<$PrismaModel>
@@ -625,6 +652,17 @@ export type NestedEnumDayOfWeekNullableWithAggregatesFilter<$PrismaModel = never
_max?: Prisma.NestedEnumDayOfWeekNullableFilter<$PrismaModel>
}
export type NestedDecimalNullableFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
}
export type NestedEnumCourtBookingStatusFilter<$PrismaModel = never> = {
equals?: $Enums.CourtBookingStatus | Prisma.EnumCourtBookingStatusFieldRefInput<$PrismaModel>
in?: $Enums.CourtBookingStatus[] | Prisma.ListEnumCourtBookingStatusFieldRefInput<$PrismaModel>
@@ -632,6 +670,22 @@ export type NestedEnumCourtBookingStatusFilter<$PrismaModel = never> = {
not?: Prisma.NestedEnumCourtBookingStatusFilter<$PrismaModel> | $Enums.CourtBookingStatus
}
export type NestedDecimalNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_min?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_max?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
}
export type NestedEnumCourtBookingStatusWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.CourtBookingStatus | Prisma.EnumCourtBookingStatusFieldRefInput<$PrismaModel>
in?: $Enums.CourtBookingStatus[] | Prisma.ListEnumCourtBookingStatusFieldRefInput<$PrismaModel>

File diff suppressed because one or more lines are too long

View File

@@ -1728,6 +1728,7 @@ export const CourtBookingScalarFieldEnum = {
bookingDate: 'bookingDate',
startTime: 'startTime',
endTime: 'endTime',
price: 'price',
customerName: 'customerName',
customerPhone: 'customerPhone',
status: 'status',

View File

@@ -245,6 +245,7 @@ export const CourtBookingScalarFieldEnum = {
bookingDate: 'bookingDate',
startTime: 'startTime',
endTime: 'endTime',
price: 'price',
customerName: 'customerName',
customerPhone: 'customerPhone',
status: 'status',

View File

@@ -20,10 +20,20 @@ export type CourtBookingModel = runtime.Types.Result.DefaultSelection<Prisma.$Co
export type AggregateCourtBooking = {
_count: CourtBookingCountAggregateOutputType | null
_avg: CourtBookingAvgAggregateOutputType | null
_sum: CourtBookingSumAggregateOutputType | null
_min: CourtBookingMinAggregateOutputType | null
_max: CourtBookingMaxAggregateOutputType | null
}
export type CourtBookingAvgAggregateOutputType = {
price: runtime.Decimal | null
}
export type CourtBookingSumAggregateOutputType = {
price: runtime.Decimal | null
}
export type CourtBookingMinAggregateOutputType = {
id: string | null
bookingCode: string | null
@@ -31,6 +41,7 @@ export type CourtBookingMinAggregateOutputType = {
bookingDate: Date | null
startTime: string | null
endTime: string | null
price: runtime.Decimal | null
customerName: string | null
customerPhone: string | null
status: $Enums.CourtBookingStatus | null
@@ -45,6 +56,7 @@ export type CourtBookingMaxAggregateOutputType = {
bookingDate: Date | null
startTime: string | null
endTime: string | null
price: runtime.Decimal | null
customerName: string | null
customerPhone: string | null
status: $Enums.CourtBookingStatus | null
@@ -59,6 +71,7 @@ export type CourtBookingCountAggregateOutputType = {
bookingDate: number
startTime: number
endTime: number
price: number
customerName: number
customerPhone: number
status: number
@@ -68,6 +81,14 @@ export type CourtBookingCountAggregateOutputType = {
}
export type CourtBookingAvgAggregateInputType = {
price?: true
}
export type CourtBookingSumAggregateInputType = {
price?: true
}
export type CourtBookingMinAggregateInputType = {
id?: true
bookingCode?: true
@@ -75,6 +96,7 @@ export type CourtBookingMinAggregateInputType = {
bookingDate?: true
startTime?: true
endTime?: true
price?: true
customerName?: true
customerPhone?: true
status?: true
@@ -89,6 +111,7 @@ export type CourtBookingMaxAggregateInputType = {
bookingDate?: true
startTime?: true
endTime?: true
price?: true
customerName?: true
customerPhone?: true
status?: true
@@ -103,6 +126,7 @@ export type CourtBookingCountAggregateInputType = {
bookingDate?: true
startTime?: true
endTime?: true
price?: true
customerName?: true
customerPhone?: true
status?: true
@@ -146,6 +170,18 @@ export type CourtBookingAggregateArgs<ExtArgs extends runtime.Types.Extensions.I
* Count returned CourtBookings
**/
_count?: true | CourtBookingCountAggregateInputType
/**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
*
* Select which fields to average
**/
_avg?: CourtBookingAvgAggregateInputType
/**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
*
* Select which fields to sum
**/
_sum?: CourtBookingSumAggregateInputType
/**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
*
@@ -179,6 +215,8 @@ export type CourtBookingGroupByArgs<ExtArgs extends runtime.Types.Extensions.Int
take?: number
skip?: number
_count?: CourtBookingCountAggregateInputType | true
_avg?: CourtBookingAvgAggregateInputType
_sum?: CourtBookingSumAggregateInputType
_min?: CourtBookingMinAggregateInputType
_max?: CourtBookingMaxAggregateInputType
}
@@ -190,12 +228,15 @@ export type CourtBookingGroupByOutputType = {
bookingDate: Date
startTime: string
endTime: string
price: runtime.Decimal | null
customerName: string
customerPhone: string
status: $Enums.CourtBookingStatus
createdAt: Date
updatedAt: Date
_count: CourtBookingCountAggregateOutputType | null
_avg: CourtBookingAvgAggregateOutputType | null
_sum: CourtBookingSumAggregateOutputType | null
_min: CourtBookingMinAggregateOutputType | null
_max: CourtBookingMaxAggregateOutputType | null
}
@@ -225,6 +266,7 @@ export type CourtBookingWhereInput = {
bookingDate?: Prisma.DateTimeFilter<"CourtBooking"> | Date | string
startTime?: Prisma.StringFilter<"CourtBooking"> | string
endTime?: Prisma.StringFilter<"CourtBooking"> | string
price?: Prisma.DecimalNullableFilter<"CourtBooking"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFilter<"CourtBooking"> | string
customerPhone?: Prisma.StringFilter<"CourtBooking"> | string
status?: Prisma.EnumCourtBookingStatusFilter<"CourtBooking"> | $Enums.CourtBookingStatus
@@ -240,6 +282,7 @@ export type CourtBookingOrderByWithRelationInput = {
bookingDate?: Prisma.SortOrder
startTime?: Prisma.SortOrder
endTime?: Prisma.SortOrder
price?: Prisma.SortOrderInput | Prisma.SortOrder
customerName?: Prisma.SortOrder
customerPhone?: Prisma.SortOrder
status?: Prisma.SortOrder
@@ -259,6 +302,7 @@ export type CourtBookingWhereUniqueInput = Prisma.AtLeast<{
bookingDate?: Prisma.DateTimeFilter<"CourtBooking"> | Date | string
startTime?: Prisma.StringFilter<"CourtBooking"> | string
endTime?: Prisma.StringFilter<"CourtBooking"> | string
price?: Prisma.DecimalNullableFilter<"CourtBooking"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFilter<"CourtBooking"> | string
customerPhone?: Prisma.StringFilter<"CourtBooking"> | string
status?: Prisma.EnumCourtBookingStatusFilter<"CourtBooking"> | $Enums.CourtBookingStatus
@@ -274,14 +318,17 @@ export type CourtBookingOrderByWithAggregationInput = {
bookingDate?: Prisma.SortOrder
startTime?: Prisma.SortOrder
endTime?: Prisma.SortOrder
price?: Prisma.SortOrderInput | Prisma.SortOrder
customerName?: Prisma.SortOrder
customerPhone?: Prisma.SortOrder
status?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
_count?: Prisma.CourtBookingCountOrderByAggregateInput
_avg?: Prisma.CourtBookingAvgOrderByAggregateInput
_max?: Prisma.CourtBookingMaxOrderByAggregateInput
_min?: Prisma.CourtBookingMinOrderByAggregateInput
_sum?: Prisma.CourtBookingSumOrderByAggregateInput
}
export type CourtBookingScalarWhereWithAggregatesInput = {
@@ -294,6 +341,7 @@ export type CourtBookingScalarWhereWithAggregatesInput = {
bookingDate?: Prisma.DateTimeWithAggregatesFilter<"CourtBooking"> | Date | string
startTime?: Prisma.StringWithAggregatesFilter<"CourtBooking"> | string
endTime?: Prisma.StringWithAggregatesFilter<"CourtBooking"> | string
price?: Prisma.DecimalNullableWithAggregatesFilter<"CourtBooking"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringWithAggregatesFilter<"CourtBooking"> | string
customerPhone?: Prisma.StringWithAggregatesFilter<"CourtBooking"> | string
status?: Prisma.EnumCourtBookingStatusWithAggregatesFilter<"CourtBooking"> | $Enums.CourtBookingStatus
@@ -307,6 +355,7 @@ export type CourtBookingCreateInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -322,6 +371,7 @@ export type CourtBookingUncheckedCreateInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -335,6 +385,7 @@ export type CourtBookingUpdateInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -350,6 +401,7 @@ export type CourtBookingUncheckedUpdateInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -364,6 +416,7 @@ export type CourtBookingCreateManyInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -377,6 +430,7 @@ export type CourtBookingUpdateManyMutationInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -391,6 +445,7 @@ export type CourtBookingUncheckedUpdateManyInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -421,6 +476,7 @@ export type CourtBookingCountOrderByAggregateInput = {
bookingDate?: Prisma.SortOrder
startTime?: Prisma.SortOrder
endTime?: Prisma.SortOrder
price?: Prisma.SortOrder
customerName?: Prisma.SortOrder
customerPhone?: Prisma.SortOrder
status?: Prisma.SortOrder
@@ -428,6 +484,10 @@ export type CourtBookingCountOrderByAggregateInput = {
updatedAt?: Prisma.SortOrder
}
export type CourtBookingAvgOrderByAggregateInput = {
price?: Prisma.SortOrder
}
export type CourtBookingMaxOrderByAggregateInput = {
id?: Prisma.SortOrder
bookingCode?: Prisma.SortOrder
@@ -435,6 +495,7 @@ export type CourtBookingMaxOrderByAggregateInput = {
bookingDate?: Prisma.SortOrder
startTime?: Prisma.SortOrder
endTime?: Prisma.SortOrder
price?: Prisma.SortOrder
customerName?: Prisma.SortOrder
customerPhone?: Prisma.SortOrder
status?: Prisma.SortOrder
@@ -449,6 +510,7 @@ export type CourtBookingMinOrderByAggregateInput = {
bookingDate?: Prisma.SortOrder
startTime?: Prisma.SortOrder
endTime?: Prisma.SortOrder
price?: Prisma.SortOrder
customerName?: Prisma.SortOrder
customerPhone?: Prisma.SortOrder
status?: Prisma.SortOrder
@@ -456,6 +518,10 @@ export type CourtBookingMinOrderByAggregateInput = {
updatedAt?: Prisma.SortOrder
}
export type CourtBookingSumOrderByAggregateInput = {
price?: Prisma.SortOrder
}
export type CourtBookingCreateNestedManyWithoutCourtInput = {
create?: Prisma.XOR<Prisma.CourtBookingCreateWithoutCourtInput, Prisma.CourtBookingUncheckedCreateWithoutCourtInput> | Prisma.CourtBookingCreateWithoutCourtInput[] | Prisma.CourtBookingUncheckedCreateWithoutCourtInput[]
connectOrCreate?: Prisma.CourtBookingCreateOrConnectWithoutCourtInput | Prisma.CourtBookingCreateOrConnectWithoutCourtInput[]
@@ -498,6 +564,14 @@ export type CourtBookingUncheckedUpdateManyWithoutCourtNestedInput = {
deleteMany?: Prisma.CourtBookingScalarWhereInput | Prisma.CourtBookingScalarWhereInput[]
}
export type NullableDecimalFieldUpdateOperationsInput = {
set?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
increment?: runtime.Decimal | runtime.DecimalJsLike | number | string
decrement?: runtime.Decimal | runtime.DecimalJsLike | number | string
multiply?: runtime.Decimal | runtime.DecimalJsLike | number | string
divide?: runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type EnumCourtBookingStatusFieldUpdateOperationsInput = {
set?: $Enums.CourtBookingStatus
}
@@ -508,6 +582,7 @@ export type CourtBookingCreateWithoutCourtInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -521,6 +596,7 @@ export type CourtBookingUncheckedCreateWithoutCourtInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -564,6 +640,7 @@ export type CourtBookingScalarWhereInput = {
bookingDate?: Prisma.DateTimeFilter<"CourtBooking"> | Date | string
startTime?: Prisma.StringFilter<"CourtBooking"> | string
endTime?: Prisma.StringFilter<"CourtBooking"> | string
price?: Prisma.DecimalNullableFilter<"CourtBooking"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFilter<"CourtBooking"> | string
customerPhone?: Prisma.StringFilter<"CourtBooking"> | string
status?: Prisma.EnumCourtBookingStatusFilter<"CourtBooking"> | $Enums.CourtBookingStatus
@@ -577,6 +654,7 @@ export type CourtBookingCreateManyCourtInput = {
bookingDate: Date | string
startTime: string
endTime: string
price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName: string
customerPhone: string
status?: $Enums.CourtBookingStatus
@@ -590,6 +668,7 @@ export type CourtBookingUpdateWithoutCourtInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -603,6 +682,7 @@ export type CourtBookingUncheckedUpdateWithoutCourtInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -616,6 +696,7 @@ export type CourtBookingUncheckedUpdateManyWithoutCourtInput = {
bookingDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
startTime?: Prisma.StringFieldUpdateOperationsInput | string
endTime?: Prisma.StringFieldUpdateOperationsInput | string
price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
customerName?: Prisma.StringFieldUpdateOperationsInput | string
customerPhone?: Prisma.StringFieldUpdateOperationsInput | string
status?: Prisma.EnumCourtBookingStatusFieldUpdateOperationsInput | $Enums.CourtBookingStatus
@@ -632,6 +713,7 @@ export type CourtBookingSelect<ExtArgs extends runtime.Types.Extensions.Internal
bookingDate?: boolean
startTime?: boolean
endTime?: boolean
price?: boolean
customerName?: boolean
customerPhone?: boolean
status?: boolean
@@ -647,6 +729,7 @@ export type CourtBookingSelectCreateManyAndReturn<ExtArgs extends runtime.Types.
bookingDate?: boolean
startTime?: boolean
endTime?: boolean
price?: boolean
customerName?: boolean
customerPhone?: boolean
status?: boolean
@@ -662,6 +745,7 @@ export type CourtBookingSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.
bookingDate?: boolean
startTime?: boolean
endTime?: boolean
price?: boolean
customerName?: boolean
customerPhone?: boolean
status?: boolean
@@ -677,6 +761,7 @@ export type CourtBookingSelectScalar = {
bookingDate?: boolean
startTime?: boolean
endTime?: boolean
price?: boolean
customerName?: boolean
customerPhone?: boolean
status?: boolean
@@ -684,7 +769,7 @@ export type CourtBookingSelectScalar = {
updatedAt?: boolean
}
export type CourtBookingOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "bookingCode" | "courtId" | "bookingDate" | "startTime" | "endTime" | "customerName" | "customerPhone" | "status" | "createdAt" | "updatedAt", ExtArgs["result"]["courtBooking"]>
export type CourtBookingOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "bookingCode" | "courtId" | "bookingDate" | "startTime" | "endTime" | "price" | "customerName" | "customerPhone" | "status" | "createdAt" | "updatedAt", ExtArgs["result"]["courtBooking"]>
export type CourtBookingInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
court?: boolean | Prisma.CourtDefaultArgs<ExtArgs>
}
@@ -707,6 +792,7 @@ export type $CourtBookingPayload<ExtArgs extends runtime.Types.Extensions.Intern
bookingDate: Date
startTime: string
endTime: string
price: runtime.Decimal | null
customerName: string
customerPhone: string
status: $Enums.CourtBookingStatus
@@ -1142,6 +1228,7 @@ export interface CourtBookingFieldRefs {
readonly bookingDate: Prisma.FieldRef<"CourtBooking", 'DateTime'>
readonly startTime: Prisma.FieldRef<"CourtBooking", 'String'>
readonly endTime: Prisma.FieldRef<"CourtBooking", 'String'>
readonly price: Prisma.FieldRef<"CourtBooking", 'Decimal'>
readonly customerName: Prisma.FieldRef<"CourtBooking", 'String'>
readonly customerPhone: Prisma.FieldRef<"CourtBooking", 'String'>
readonly status: Prisma.FieldRef<"CourtBooking", 'CourtBookingStatus'>

View File

@@ -202,6 +202,10 @@ async function getComplexWithBookingData(complexSlug: string) {
availabilities: {
orderBy: [{ dayOfWeek: 'asc' }, { startTime: 'asc' }],
},
priceRules: {
where: { isActive: true },
orderBy: [{ dayOfWeek: 'asc' }, { startTime: 'asc' }],
},
},
orderBy: { createdAt: 'asc' },
},
@@ -233,6 +237,7 @@ function mapBookingResponse(input: {
createdAt: Date;
startTime: string;
endTime: string;
price: number;
customerName: string;
customerPhone: string;
status: 'CONFIRMED' | 'CANCELLED' | 'COMPLETED';
@@ -261,6 +266,7 @@ function mapBookingResponse(input: {
date: formatIsoDate(input.bookingDate),
startTime: input.startTime,
endTime: input.endTime,
price: input.price,
customerName: input.customerName,
customerPhone: input.customerPhone,
status: input.status,
@@ -284,6 +290,7 @@ export async function getPublicBookingConfirmation(complexSlug: string, bookingC
bookingDate: true,
startTime: true,
endTime: true,
price: true,
status: true,
createdAt: true,
court: {
@@ -325,6 +332,7 @@ export async function getPublicBookingConfirmation(complexSlug: string, bookingC
slug: booking.court.sport.slug,
},
status: booking.status,
price: Number(booking.price),
createdAt: booking.createdAt.toISOString(),
};
}
@@ -397,6 +405,50 @@ export async function listPublicAvailability(complexSlug: string, query: PublicA
(slot) => !occupiedSlots.some((occupied) => hasOverlap(slot, occupied))
);
const basePrice = Number(court.basePrice);
const priceRuleMap = new Map<string, number>();
for (const rule of court.priceRules) {
const ruleDay = rule.dayOfWeek;
const ruleStart = rule.startTime;
const ruleEnd = rule.endTime;
const price = Number(rule.price);
if (ruleStart && ruleEnd && ruleDay) {
const startMin = toMinutes(ruleStart);
const endMin = toMinutes(ruleEnd);
for (let mins = startMin; mins < endMin; mins += 30) {
priceRuleMap.set(`${ruleDay}-${minutesToTime(mins)}`, price);
}
} else if (ruleDay && !ruleStart && !ruleEnd) {
priceRuleMap.set(`day-${ruleDay}`, price);
}
}
const calcPrice = (startTime: string) => {
if (!basePrice || basePrice <= 0) {
return 0;
}
const timeKey = `${dayOfWeek}-${startTime}`;
const dayKey = `day-${dayOfWeek}`;
return priceRuleMap.get(timeKey) ?? priceRuleMap.get(dayKey) ?? basePrice;
};
const price =
availableSlots.length > 0
? (() => {
const prices = availableSlots.map((slot) => calcPrice(slot.startTime));
const validPrices = prices.filter((p) => p > 0);
if (validPrices.length === 0) {
return undefined;
}
return {
min: Math.min(...validPrices),
max: Math.max(...validPrices),
};
})()
: undefined;
return {
courtId: court.id,
courtName: court.name,
@@ -408,6 +460,7 @@ export async function listPublicAvailability(complexSlug: string, query: PublicA
slotDurationMinutes: court.slotDurationMinutes,
availabilityDay: dayOfWeek,
availableSlots,
price,
};
})
.filter((court) => court.availableSlots.length > 0);
@@ -476,6 +529,60 @@ export async function createPublicBooking(complexSlug: string, input: CreatePubl
);
}
function calcBookingPrice(
court: {
basePrice: number | null;
priceRules: Array<{
dayOfWeek: string | null;
startTime: string | null;
endTime: string | null;
price: number;
}>;
},
dayOfWeek: string,
startTime: string
): number {
if (!court.basePrice) {
return 0;
}
const slotMinutes = toMinutes(startTime);
const exactMatch = court.priceRules.find((rule) => {
if (!rule.dayOfWeek || rule.dayOfWeek !== dayOfWeek) {
return false;
}
if (!rule.startTime || !rule.endTime) {
return false;
}
const ruleStart = toMinutes(rule.startTime);
const ruleEnd = toMinutes(rule.endTime);
return slotMinutes >= ruleStart && slotMinutes < ruleEnd;
});
if (exactMatch) {
return Number(exactMatch.price);
}
const dayMatch = court.priceRules.find((rule) => {
if (!rule.dayOfWeek || rule.dayOfWeek !== dayOfWeek) {
return false;
}
if (rule.startTime || rule.endTime) {
return false;
}
return true;
});
if (dayMatch) {
return Number(dayMatch.price);
}
return Number(court.basePrice);
}
const bookingPrice = calcBookingPrice(selectedCourt, dayOfWeek, selectedSlot.startTime);
for (let attempt = 0; attempt < 5; attempt += 1) {
try {
const booking = await db.$transaction(async (tx) => {
@@ -531,6 +638,7 @@ export async function createPublicBooking(complexSlug: string, input: CreatePubl
bookingDate,
startTime: selectedSlot.startTime,
endTime: selectedSlot.endTime,
price: bookingPrice,
customerName: input.customerName.trim(),
customerPhone: input.customerPhone.trim(),
status: 'CONFIRMED',
@@ -542,6 +650,7 @@ export async function createPublicBooking(complexSlug: string, input: CreatePubl
createdAt: true,
startTime: true,
endTime: true,
price: true,
customerName: true,
customerPhone: true,
status: true,
@@ -556,6 +665,7 @@ export async function createPublicBooking(complexSlug: string, input: CreatePubl
createdAt: booking.createdAt,
startTime: booking.startTime,
endTime: booking.endTime,
price: Number(booking.price),
customerName: booking.customerName,
customerPhone: booking.customerPhone,
status: booking.status,