diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/PayuQrPayments.kt b/src/main/kotlin/com/android/trisolarisserver/controller/PayuQrPayments.kt index e00fd13..c6362b1 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/PayuQrPayments.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/PayuQrPayments.kt @@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.client.RestTemplate import org.springframework.web.server.ResponseStatusException +import jakarta.servlet.http.HttpServletRequest import java.security.MessageDigest import java.time.OffsetDateTime import java.util.UUID @@ -47,7 +48,8 @@ class PayuQrPayments( @PathVariable propertyId: UUID, @PathVariable bookingId: UUID, @AuthenticationPrincipal principal: MyPrincipal?, - @RequestBody request: PayuQrGenerateRequest + @RequestBody request: PayuQrGenerateRequest, + httpRequest: HttpServletRequest ): PayuQrGenerateResponse { requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.FINANCE) @@ -72,14 +74,21 @@ class PayuQrPayments( if (pending <= 0) { throw ResponseStatusException(HttpStatus.CONFLICT, "No pending amount") } + val requestedAmount = request.amount?.takeIf { it > 0 } + if (requestedAmount != null && requestedAmount > pending) { + throw ResponseStatusException(HttpStatus.CONFLICT, "Amount exceeds pending") + } + val amountLong = requestedAmount ?: pending val txnid = "QR${bookingId.toString().substring(0, 8)}${System.currentTimeMillis()}" val productInfo = "Booking $bookingId" - val firstname = request.customerName?.trim()?.ifBlank { null } ?: "Guest" - val email = request.customerEmail?.trim()?.ifBlank { null } ?: "guest@example.com" - val phone = request.customerPhone?.trim()?.ifBlank { null } - ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "customerPhone required") - val amount = String.format("%.2f", pending.toDouble()) + val guest = booking.primaryGuest + ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Booking missing guest") + val firstname = guest.name?.trim()?.ifBlank { null } ?: "Guest" + val phone = guest.phoneE164?.trim()?.ifBlank { null } + ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Guest phone missing") + val email = "guest-${bookingId.toString().substring(0, 8)}@hoteltrisolaris.in" + val amount = String.format("%.2f", amountLong.toDouble()) val udf1 = bookingId.toString() val udf2 = propertyId.toString() @@ -129,6 +138,7 @@ class PayuQrPayments( if (udf5.isNotBlank()) add("udf5", udf5) add("txn_s2s_flow", "4") val clientIp = request.clientIp?.trim()?.ifBlank { null } + ?: extractClientIp(httpRequest) ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "clientIp required") val deviceInfo = request.deviceInfo?.trim()?.ifBlank { null } ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "deviceInfo required") @@ -154,7 +164,7 @@ class PayuQrPayments( property = booking.property, booking = booking, txnid = txnid, - amount = pending, + amount = amountLong, currency = booking.property.currency, status = PayuQrStatus.CREATED, requestPayload = requestPayload, @@ -179,7 +189,7 @@ class PayuQrPayments( return PayuQrGenerateResponse( txnid = txnid, - amount = pending, + amount = amountLong, currency = booking.property.currency, payuResponse = responseBody ) @@ -209,6 +219,18 @@ class PayuQrPayments( return bytes.joinToString("") { "%02x".format(it) } } + private fun extractClientIp(request: HttpServletRequest): String? { + val forwarded = request.getHeader("X-Forwarded-For") + ?.split(",") + ?.firstOrNull() + ?.trim() + ?.ifBlank { null } + if (forwarded != null) return forwarded + val realIp = request.getHeader("X-Real-IP")?.trim()?.ifBlank { null } + if (realIp != null) return realIp + return request.remoteAddr?.trim()?.ifBlank { null } + } + private fun computeExpectedPay(stays: List, timezone: String?): Long { if (stays.isEmpty()) return 0 val now = nowForProperty(timezone) diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/dto/PayuDtos.kt b/src/main/kotlin/com/android/trisolarisserver/controller/dto/PayuDtos.kt index 685cdcf..e94d447 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/dto/PayuDtos.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/dto/PayuDtos.kt @@ -21,6 +21,7 @@ data class PayuSettingsResponse( ) data class PayuQrGenerateRequest( + val amount: Long? = null, val customerName: String? = null, val customerEmail: String? = null, val customerPhone: String? = null,