Align PayU QR request with docs
Some checks failed
build-and-deploy / build-deploy (push) Failing after 29s

This commit is contained in:
androidlover5842
2026-01-30 05:30:08 +05:30
parent 38c0a0ec9a
commit e5c2abc317
5 changed files with 87 additions and 8 deletions

View File

@@ -28,11 +28,40 @@ class PayuSettingsSchemaFix(
salt_32 varchar, salt_32 varchar,
salt_256 varchar, salt_256 varchar,
base_url varchar not null, base_url varchar not null,
success_url varchar not null,
failure_url varchar not null,
use_salt_256 boolean not null default true, use_salt_256 boolean not null default true,
updated_at timestamptz not null updated_at timestamptz not null
) )
""".trimIndent() """.trimIndent()
) )
} }
val hasSuccessUrl = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'payu_settings'
and column_name = 'success_url'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasSuccessUrl == 0) {
logger.info("Adding payu_settings.success_url column")
jdbcTemplate.execute("alter table payu_settings add column success_url varchar")
}
val hasFailureUrl = jdbcTemplate.queryForObject(
"""
select count(*)
from information_schema.columns
where table_name = 'payu_settings'
and column_name = 'failure_url'
""".trimIndent(),
Int::class.java
) ?: 0
if (hasFailureUrl == 0) {
logger.info("Adding payu_settings.failure_url column")
jdbcTemplate.execute("alter table payu_settings add column failure_url varchar")
}
} }
} }

View File

@@ -77,14 +77,15 @@ class PayuQrPayments(
val productInfo = "Booking $bookingId" val productInfo = "Booking $bookingId"
val firstname = request.customerName?.trim()?.ifBlank { null } ?: "Guest" val firstname = request.customerName?.trim()?.ifBlank { null } ?: "Guest"
val email = request.customerEmail?.trim()?.ifBlank { null } ?: "guest@example.com" val email = request.customerEmail?.trim()?.ifBlank { null } ?: "guest@example.com"
val phone = request.customerPhone?.trim()?.ifBlank { null } ?: "" val phone = request.customerPhone?.trim()?.ifBlank { null }
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "customerPhone required")
val amount = String.format("%.2f", pending.toDouble()) val amount = String.format("%.2f", pending.toDouble())
val udf1 = bookingId.toString() val udf1 = bookingId.toString()
val udf2 = propertyId.toString() val udf2 = propertyId.toString()
val udf3 = "" val udf3 = request.udf3?.trim()?.ifBlank { "" } ?: ""
val udf4 = "" val udf4 = request.udf4?.trim()?.ifBlank { "" } ?: ""
val udf5 = "" val udf5 = request.udf5?.trim()?.ifBlank { "" } ?: ""
val hash = sha512( val hash = sha512(
listOf( listOf(
settings.merchantKey, settings.merchantKey,
@@ -116,15 +117,32 @@ class PayuQrPayments(
add("firstname", firstname) add("firstname", firstname)
add("email", email) add("email", email)
add("phone", phone) add("phone", phone)
add("surl", settings.successUrl)
add("furl", settings.failureUrl)
add("pg", "DBQR") add("pg", "DBQR")
add("bankcode", "UPIDBQR") add("bankcode", "UPIDBQR")
add("hash", hash) add("hash", hash)
add("udf1", udf1) add("udf1", udf1)
add("udf2", udf2) add("udf2", udf2)
if (udf3.isNotBlank()) add("udf3", udf3)
if (udf4.isNotBlank()) add("udf4", udf4)
if (udf5.isNotBlank()) add("udf5", udf5)
add("txn_s2s_flow", "4") add("txn_s2s_flow", "4")
add("s2s_client_ip", "127.0.0.1") val clientIp = request.clientIp?.trim()?.ifBlank { null }
add("s2s_device_info", "TrisolarisServer") ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "clientIp required")
request.expiryMinutes?.let { add("expiry_time", it.toString()) } val deviceInfo = request.deviceInfo?.trim()?.ifBlank { null }
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "deviceInfo required")
add("s2s_client_ip", clientIp)
add("s2s_device_info", deviceInfo)
val expirySeconds = request.expirySeconds
?: request.expiryMinutes?.let { it * 60 }
expirySeconds?.let { add("expiry_time", it.toString()) }
request.address1?.trim()?.ifBlank { null }?.let { add("address1", it) }
request.address2?.trim()?.ifBlank { null }?.let { add("address2", it) }
request.city?.trim()?.ifBlank { null }?.let { add("city", it) }
request.state?.trim()?.ifBlank { null }?.let { add("state", it) }
request.country?.trim()?.ifBlank { null }?.let { add("country", it) }
request.zipcode?.trim()?.ifBlank { null }?.let { add("zipcode", it) }
} }
val requestPayload = form.entries.joinToString("&") { entry -> val requestPayload = form.entries.joinToString("&") { entry ->

View File

@@ -53,6 +53,10 @@ class PayuSettingsController(
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "merchantKey required") throw ResponseStatusException(HttpStatus.BAD_REQUEST, "merchantKey required")
} }
val baseUrl = request.baseUrl?.trim()?.ifBlank { null } ?: "https://secure.payu.in/_payment" val baseUrl = request.baseUrl?.trim()?.ifBlank { null } ?: "https://secure.payu.in/_payment"
val successUrl = request.successUrl?.trim()?.ifBlank { null }
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "successUrl required")
val failureUrl = request.failureUrl?.trim()?.ifBlank { null }
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "failureUrl required")
val existing = payuSettingsRepo.findByPropertyId(propertyId) val existing = payuSettingsRepo.findByPropertyId(propertyId)
val updated = if (existing == null) { val updated = if (existing == null) {
PayuSettings( PayuSettings(
@@ -61,6 +65,8 @@ class PayuSettingsController(
salt32 = request.salt32?.trim()?.ifBlank { null }, salt32 = request.salt32?.trim()?.ifBlank { null },
salt256 = request.salt256?.trim()?.ifBlank { null }, salt256 = request.salt256?.trim()?.ifBlank { null },
baseUrl = baseUrl, baseUrl = baseUrl,
successUrl = successUrl,
failureUrl = failureUrl,
useSalt256 = request.useSalt256 ?: true, useSalt256 = request.useSalt256 ?: true,
updatedAt = OffsetDateTime.now() updatedAt = OffsetDateTime.now()
) )
@@ -69,6 +75,8 @@ class PayuSettingsController(
if (request.salt32 != null) existing.salt32 = request.salt32.trim().ifBlank { null } if (request.salt32 != null) existing.salt32 = request.salt32.trim().ifBlank { null }
if (request.salt256 != null) existing.salt256 = request.salt256.trim().ifBlank { null } if (request.salt256 != null) existing.salt256 = request.salt256.trim().ifBlank { null }
existing.baseUrl = baseUrl existing.baseUrl = baseUrl
existing.successUrl = successUrl
existing.failureUrl = failureUrl
if (request.useSalt256 != null) existing.useSalt256 = request.useSalt256 if (request.useSalt256 != null) existing.useSalt256 = request.useSalt256
existing.updatedAt = OffsetDateTime.now() existing.updatedAt = OffsetDateTime.now()
existing existing
@@ -83,6 +91,8 @@ private fun PayuSettings.toResponse(): PayuSettingsResponse {
propertyId = propertyId, propertyId = propertyId,
merchantKey = merchantKey, merchantKey = merchantKey,
baseUrl = baseUrl, baseUrl = baseUrl,
successUrl = successUrl,
failureUrl = failureUrl,
useSalt256 = useSalt256, useSalt256 = useSalt256,
hasSalt32 = !salt32.isNullOrBlank(), hasSalt32 = !salt32.isNullOrBlank(),
hasSalt256 = !salt256.isNullOrBlank() hasSalt256 = !salt256.isNullOrBlank()

View File

@@ -7,6 +7,8 @@ data class PayuSettingsUpsertRequest(
val salt32: String? = null, val salt32: String? = null,
val salt256: String? = null, val salt256: String? = null,
val baseUrl: String? = null, val baseUrl: String? = null,
val successUrl: String? = null,
val failureUrl: String? = null,
val useSalt256: Boolean? = null val useSalt256: Boolean? = null
) )
@@ -14,6 +16,8 @@ data class PayuSettingsResponse(
val propertyId: UUID, val propertyId: UUID,
val merchantKey: String, val merchantKey: String,
val baseUrl: String, val baseUrl: String,
val successUrl: String,
val failureUrl: String,
val useSalt256: Boolean, val useSalt256: Boolean,
val hasSalt32: Boolean, val hasSalt32: Boolean,
val hasSalt256: Boolean val hasSalt256: Boolean
@@ -23,7 +27,19 @@ data class PayuQrGenerateRequest(
val customerName: String? = null, val customerName: String? = null,
val customerEmail: String? = null, val customerEmail: String? = null,
val customerPhone: String? = null, val customerPhone: String? = null,
val expiryMinutes: Int? = 30 val expiryMinutes: Int? = null,
val expirySeconds: Int? = null,
val clientIp: String? = null,
val deviceInfo: String? = null,
val address1: String? = null,
val address2: String? = null,
val city: String? = null,
val state: String? = null,
val country: String? = null,
val zipcode: String? = null,
val udf3: String? = null,
val udf4: String? = null,
val udf5: String? = null
) )
data class PayuQrGenerateResponse( data class PayuQrGenerateResponse(

View File

@@ -40,6 +40,12 @@ class PayuSettings(
@Column(name = "base_url", nullable = false) @Column(name = "base_url", nullable = false)
var baseUrl: String = "https://secure.payu.in/_payment", var baseUrl: String = "https://secure.payu.in/_payment",
@Column(name = "success_url", nullable = false)
var successUrl: String,
@Column(name = "failure_url", nullable = false)
var failureUrl: String,
@Column(name = "use_salt_256", nullable = false) @Column(name = "use_salt_256", nullable = false)
var useSalt256: Boolean = true, var useSalt256: Boolean = true,