Add rate plans, room stay rates, and payments ledger
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
package com.android.trisolarisserver.controller
|
||||
|
||||
import com.android.trisolarisserver.component.PropertyAccess
|
||||
import com.android.trisolarisserver.controller.dto.PaymentCreateRequest
|
||||
import com.android.trisolarisserver.controller.dto.PaymentResponse
|
||||
import com.android.trisolarisserver.db.repo.BookingRepo
|
||||
import com.android.trisolarisserver.models.booking.Payment
|
||||
import com.android.trisolarisserver.models.booking.PaymentMethod
|
||||
import com.android.trisolarisserver.models.property.Role
|
||||
import com.android.trisolarisserver.repo.AppUserRepo
|
||||
import com.android.trisolarisserver.repo.PaymentRepo
|
||||
import com.android.trisolarisserver.repo.PropertyRepo
|
||||
import com.android.trisolarisserver.security.MyPrincipal
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
import java.time.LocalDate
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.UUID
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/properties/{propertyId}/bookings/{bookingId}/payments")
|
||||
class Payments(
|
||||
private val propertyAccess: PropertyAccess,
|
||||
private val propertyRepo: PropertyRepo,
|
||||
private val bookingRepo: BookingRepo,
|
||||
private val paymentRepo: PaymentRepo,
|
||||
private val appUserRepo: AppUserRepo
|
||||
) {
|
||||
|
||||
@PostMapping
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
fun create(
|
||||
@PathVariable propertyId: UUID,
|
||||
@PathVariable bookingId: UUID,
|
||||
@AuthenticationPrincipal principal: MyPrincipal?,
|
||||
@RequestBody request: PaymentCreateRequest
|
||||
): PaymentResponse {
|
||||
val actor = requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.STAFF)
|
||||
val property = propertyRepo.findById(propertyId).orElseThrow {
|
||||
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
|
||||
}
|
||||
val booking = bookingRepo.findById(bookingId).orElseThrow {
|
||||
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
|
||||
}
|
||||
if (booking.property.id != propertyId) {
|
||||
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found for property")
|
||||
}
|
||||
if (request.amount <= 0) {
|
||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "amount must be > 0")
|
||||
}
|
||||
|
||||
val method = parseMethod(request.method)
|
||||
val receivedAt = parseOffset(request.receivedAt) ?: OffsetDateTime.now()
|
||||
val payment = Payment(
|
||||
property = property,
|
||||
booking = booking,
|
||||
amount = request.amount,
|
||||
currency = request.currency ?: property.currency,
|
||||
method = method,
|
||||
reference = request.reference?.trim()?.ifBlank { null },
|
||||
notes = request.notes?.trim()?.ifBlank { null },
|
||||
receivedAt = receivedAt,
|
||||
receivedBy = appUserRepo.findById(actor.userId).orElse(null)
|
||||
)
|
||||
return paymentRepo.save(payment).toResponse()
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
fun list(
|
||||
@PathVariable propertyId: UUID,
|
||||
@PathVariable bookingId: UUID,
|
||||
@AuthenticationPrincipal principal: MyPrincipal?
|
||||
): List<PaymentResponse> {
|
||||
requireMember(propertyAccess, propertyId, principal)
|
||||
val booking = bookingRepo.findById(bookingId).orElseThrow {
|
||||
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
|
||||
}
|
||||
if (booking.property.id != propertyId) {
|
||||
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found for property")
|
||||
}
|
||||
return paymentRepo.findByBookingIdOrderByReceivedAtDesc(bookingId).map { it.toResponse() }
|
||||
}
|
||||
|
||||
private fun parseMethod(value: String): PaymentMethod {
|
||||
return try {
|
||||
PaymentMethod.valueOf(value.trim())
|
||||
} catch (_: IllegalArgumentException) {
|
||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown payment method")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Payment.toResponse(): PaymentResponse {
|
||||
val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Payment id missing")
|
||||
val bookingId = booking.id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Booking id missing")
|
||||
return PaymentResponse(
|
||||
id = id,
|
||||
bookingId = bookingId,
|
||||
amount = amount,
|
||||
currency = currency,
|
||||
method = method.name,
|
||||
reference = reference,
|
||||
notes = notes,
|
||||
receivedAt = receivedAt.toString(),
|
||||
receivedByUserId = receivedBy?.id
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user