Add payment method selection (Cash/Bank) to booking details Support uploading, downloading, and deleting transaction documents Update database schema and API endpoints to handle file storage
108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
import type { UpdateBookingDetailsResponse } from '~~/shared/booking'
|
|
|
|
import { getSeatCount } from '~~/shared/booking'
|
|
import { requireAuth } from '../../utils/auth'
|
|
import {
|
|
getBookingById,
|
|
getBookingInventorySummary,
|
|
getActiveBookingModeOptionByCode,
|
|
getActiveTicketCatalogItemByCode,
|
|
clearBookingTransactionDocument,
|
|
updateBookingDetails
|
|
} from '../../utils/booking-repository'
|
|
import { parseUpdateBookingDetailsInput } from '../../utils/bookings'
|
|
import { deleteTransactionDocument } from '../../utils/transaction-documents'
|
|
import { getRequiredRouteParam, httpError } from '../../utils/http'
|
|
|
|
export default defineEventHandler(async (event): Promise<UpdateBookingDetailsResponse> => {
|
|
const auth = await requireAuth(event)
|
|
const bookingId = getRequiredRouteParam(event, 'id', 'Booking ID')
|
|
const body = await readBody<{
|
|
customerName?: string
|
|
customerPhone?: string
|
|
bookingMode?: string | null
|
|
quantity?: number
|
|
ticketType?: string
|
|
paymentMethod?: string | null
|
|
remark?: string | null
|
|
}>(event)
|
|
|
|
const existingBooking = await getBookingById(bookingId, auth.user.role === 'super_admin'
|
|
? undefined
|
|
: { personInChargeId: auth.user.id })
|
|
|
|
if (!existingBooking) {
|
|
httpError(404, 'Booking not found')
|
|
}
|
|
|
|
const input = parseUpdateBookingDetailsInput(body)
|
|
const [bookingMode, ticket] = await Promise.all([
|
|
getActiveBookingModeOptionByCode(input.bookingMode),
|
|
getActiveTicketCatalogItemByCode(input.ticketType)
|
|
])
|
|
|
|
if (!bookingMode) {
|
|
httpError(400, 'Booking mode is invalid')
|
|
}
|
|
|
|
if (!ticket) {
|
|
httpError(400, 'Ticket category is invalid')
|
|
}
|
|
|
|
if (bookingMode.eventId !== ticket.eventId || bookingMode.eventId !== existingBooking.event.id) {
|
|
httpError(400, 'Booking mode and ticket category must belong to the same event')
|
|
}
|
|
|
|
const seatCount = getSeatCount(bookingMode, input.quantity)
|
|
const totalPrice = seatCount * ticket.price
|
|
const seatIncrease = Math.max(seatCount - existingBooking.seatCount, 0)
|
|
|
|
if (existingBooking.status === 'confirmed' && seatIncrease > 0) {
|
|
const summary = await getBookingInventorySummary()
|
|
|
|
if (summary.leftSeats !== null && seatIncrease > summary.leftSeats) {
|
|
httpError(409, `Total seats cannot exceed the remaining capacity by ${seatIncrease - summary.leftSeats} seats`)
|
|
}
|
|
}
|
|
|
|
const booking = await updateBookingDetails({
|
|
bookingId,
|
|
customerName: input.customerName,
|
|
customerPhone: input.customerPhone,
|
|
bookingModeId: bookingMode.id,
|
|
bookingMode: bookingMode.value,
|
|
quantity: input.quantity,
|
|
seatCount,
|
|
ticketTypeId: ticket.id,
|
|
ticketType: ticket.value,
|
|
unitPrice: ticket.price,
|
|
totalPrice,
|
|
paymentMethod: input.paymentMethod,
|
|
remark: input.remark,
|
|
personInChargeId: auth.user.role === 'super_admin' ? undefined : auth.user.id
|
|
})
|
|
|
|
if (!booking) {
|
|
httpError(404, 'Booking not found')
|
|
}
|
|
|
|
if (input.paymentMethod === 'cash') {
|
|
const cleared = await clearBookingTransactionDocument({
|
|
bookingId,
|
|
personInChargeId: auth.user.role === 'super_admin' ? undefined : auth.user.id
|
|
})
|
|
|
|
if (cleared) {
|
|
await deleteTransactionDocument(cleared.previousStorageName)
|
|
|
|
return {
|
|
booking: cleared.booking
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
booking
|
|
}
|
|
})
|