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
87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
import type { UpdateBookingDetailsResponse } from '~~/shared/booking'
|
|
|
|
import { getHeader, readMultipartFormData } from 'h3'
|
|
|
|
import { requireAuth } from '../../../utils/auth'
|
|
import {
|
|
getBookingById,
|
|
replaceBookingTransactionDocument
|
|
} from '../../../utils/booking-repository'
|
|
import { getRequiredRouteParam, httpError } from '../../../utils/http'
|
|
import {
|
|
deleteTransactionDocument,
|
|
saveTransactionDocument,
|
|
TRANSACTION_DOCUMENT_MAX_SIZE,
|
|
validateTransactionDocumentUpload
|
|
} from '../../../utils/transaction-documents'
|
|
|
|
export default defineEventHandler(async (event): Promise<UpdateBookingDetailsResponse> => {
|
|
const auth = await requireAuth(event)
|
|
const bookingId = getRequiredRouteParam(event, 'id', 'Booking ID')
|
|
const accessScope = auth.user.role === 'super_admin'
|
|
? undefined
|
|
: { personInChargeId: auth.user.id }
|
|
|
|
const booking = await getBookingById(bookingId, accessScope)
|
|
|
|
if (!booking) {
|
|
httpError(404, 'Booking not found')
|
|
}
|
|
|
|
if (booking.paymentMethod !== 'bank') {
|
|
httpError(400, 'Transaction document can only be uploaded for Bank payments')
|
|
}
|
|
|
|
const contentType = String(getHeader(event, 'content-type') || '').toLowerCase()
|
|
|
|
if (!contentType.startsWith('multipart/form-data;')) {
|
|
httpError(400, 'Transaction document upload must use multipart form data')
|
|
}
|
|
|
|
const contentLength = Number(getHeader(event, 'content-length') || 0)
|
|
|
|
if (contentLength > TRANSACTION_DOCUMENT_MAX_SIZE + 1024 * 1024) {
|
|
httpError(413, 'Transaction document must be 10MB or smaller')
|
|
}
|
|
|
|
const formData = await readMultipartFormData(event)
|
|
const filePart = formData?.find((part) => part.name === 'document' && part.filename)
|
|
|
|
if (!filePart) {
|
|
httpError(400, 'Transaction document is required')
|
|
}
|
|
|
|
const upload = validateTransactionDocumentUpload({
|
|
data: filePart.data,
|
|
filename: filePart.filename,
|
|
contentType: filePart.type
|
|
})
|
|
|
|
const storageName = await saveTransactionDocument(filePart.data, upload.fileType)
|
|
|
|
try {
|
|
const result = await replaceBookingTransactionDocument({
|
|
bookingId,
|
|
personInChargeId: auth.user.role === 'super_admin' ? undefined : auth.user.id,
|
|
originalName: upload.originalName,
|
|
storageName,
|
|
mimeType: upload.fileType.mimeType,
|
|
size: filePart.data.length
|
|
})
|
|
|
|
if (!result) {
|
|
await deleteTransactionDocument(storageName)
|
|
httpError(404, 'Booking not found')
|
|
}
|
|
|
|
await deleteTransactionDocument(result.previousStorageName)
|
|
|
|
return {
|
|
booking: result.booking
|
|
}
|
|
} catch (error) {
|
|
await deleteTransactionDocument(storageName)
|
|
throw error
|
|
}
|
|
})
|