fix razorpay qr credit log

This commit is contained in:
androidlover5842
2026-02-01 14:03:19 +05:30
parent 43ee7311e8
commit 8f62459d5e
3 changed files with 52 additions and 8 deletions

View File

@@ -73,10 +73,19 @@ fun RazorpayQrScreen(
LaunchedEffect(propertyId, bookingId) { LaunchedEffect(propertyId, bookingId) {
viewModel.loadQrList(propertyId, bookingId) viewModel.loadQrList(propertyId, bookingId)
} }
LaunchedEffect(state.isCredited) {
if (state.isCredited) {
onBack()
}
}
val isViewingQr = state.isClosed || !state.imageUrl.isNullOrBlank() val isViewingQr = state.isClosed || !state.imageUrl.isNullOrBlank()
BackHandler(enabled = isViewingQr) { val exitAndRefresh: () -> Unit = {
viewModel.exitQrView() viewModel.exitQrView()
viewModel.loadQrList(propertyId, bookingId)
}
BackHandler(enabled = isViewingQr) {
exitAndRefresh()
} }
Scaffold( Scaffold(
@@ -86,7 +95,7 @@ fun RazorpayQrScreen(
navigationIcon = { navigationIcon = {
IconButton(onClick = { IconButton(onClick = {
if (isViewingQr) { if (isViewingQr) {
viewModel.exitQrView() exitAndRefresh()
} else { } else {
onBack() onBack()
} }
@@ -98,7 +107,20 @@ fun RazorpayQrScreen(
) )
} }
) { padding -> ) { padding ->
if (state.isClosed) { if (state.isCredited) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(padding),
contentAlignment = Alignment.Center
) {
Text(
text = "Payment received",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary
)
}
} else if (state.isClosed) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()

View File

@@ -10,6 +10,7 @@ data class RazorpayQrState(
val currency: String? = null, val currency: String? = null,
val imageUrl: String? = null, val imageUrl: String? = null,
val isClosed: Boolean = false, val isClosed: Boolean = false,
val isCredited: Boolean = false,
val paymentLink: String? = null, val paymentLink: String? = null,
val qrList: List<com.android.trisolarispms.data.api.model.RazorpayQrListItemDto> = emptyList() val qrList: List<com.android.trisolarispms.data.api.model.RazorpayQrListItemDto> = emptyList()
) )

View File

@@ -37,12 +37,14 @@ class RazorpayQrViewModel : ViewModel() {
} }
fun exitQrView() { fun exitQrView() {
stopQrEventStream()
stopQrEventPolling() stopQrEventPolling()
_state.update { _state.update {
it.copy( it.copy(
qrId = null, qrId = null,
imageUrl = null, imageUrl = null,
isClosed = false, isClosed = false,
isCredited = false,
error = null error = null
) )
} }
@@ -121,6 +123,7 @@ class RazorpayQrViewModel : ViewModel() {
if (qrId.isNullOrBlank()) return if (qrId.isNullOrBlank()) return
if (lastQrId == qrId && qrEventSource != null) return if (lastQrId == qrId && qrEventSource != null) return
stopQrEventStream() stopQrEventStream()
stopQrEventPolling()
lastQrId = qrId lastQrId = qrId
val client = ApiClient.createOkHttpClient(readTimeoutSeconds = 0) val client = ApiClient.createOkHttpClient(readTimeoutSeconds = 0)
val url = "${ApiConstants.BASE_URL}properties/$propertyId/bookings/$bookingId/payments/razorpay/qr/$qrId/events/stream" val url = "${ApiConstants.BASE_URL}properties/$propertyId/bookings/$bookingId/payments/razorpay/qr/$qrId/events/stream"
@@ -138,10 +141,17 @@ class RazorpayQrViewModel : ViewModel() {
val event = runCatching { val event = runCatching {
gson.fromJson(data, RazorpayQrEventDto::class.java) gson.fromJson(data, RazorpayQrEventDto::class.java)
}.getOrNull() ?: return }.getOrNull() ?: return
if (isClosedStatus(event.status)) { val status = event.status?.lowercase()
_state.update { it.copy(isClosed = true, imageUrl = null) } val eventName = event.event?.lowercase()
if (eventName == "qr_code.credited" || status == "credited") {
_state.update { it.copy(isCredited = true, imageUrl = null) }
stopQrEventStream() stopQrEventStream()
stopQrEventPolling() stopQrEventPolling()
return
}
if (isClosedStatus(status)) {
_state.update { it.copy(isClosed = true, imageUrl = null) }
stopQrEventStream()
} }
} }
@@ -151,13 +161,16 @@ class RazorpayQrViewModel : ViewModel() {
response: okhttp3.Response? response: okhttp3.Response?
) { ) {
stopQrEventStream() stopQrEventStream()
startQrEventPolling(propertyId, bookingId, qrId)
} }
override fun onClosed(eventSource: EventSource) { override fun onClosed(eventSource: EventSource) {
stopQrEventStream() stopQrEventStream()
startQrEventPolling(propertyId, bookingId, qrId)
} }
} }
) )
// Keep polling as a fallback in case SSE is buffered or never delivers events.
startQrEventPolling(propertyId, bookingId, qrId) startQrEventPolling(propertyId, bookingId, qrId)
} }
@@ -170,6 +183,7 @@ class RazorpayQrViewModel : ViewModel() {
private fun startQrEventPolling(propertyId: String, bookingId: String, qrId: String) { private fun startQrEventPolling(propertyId: String, bookingId: String, qrId: String) {
if (qrPollJob?.isActive == true) return if (qrPollJob?.isActive == true) return
qrPollJob = viewModelScope.launch { qrPollJob = viewModelScope.launch {
var delayMs = 4000L
while (true) { while (true) {
val currentQrId = state.value.qrId val currentQrId = state.value.qrId
if (currentQrId.isNullOrBlank() || currentQrId != qrId || state.value.isClosed) { if (currentQrId.isNullOrBlank() || currentQrId != qrId || state.value.isClosed) {
@@ -183,16 +197,22 @@ class RazorpayQrViewModel : ViewModel() {
) )
val body = response.body() val body = response.body()
if (response.isSuccessful && body != null) { if (response.isSuccessful && body != null) {
if (body.any { it.event?.lowercase() == "qr_code.credited" || it.status?.lowercase() == "credited" }) {
_state.update { it.copy(isCredited = true, imageUrl = null) }
stopQrEventStream()
break
}
if (body.any { isClosedStatus(it.status) }) { if (body.any { isClosedStatus(it.status) }) {
_state.update { it.copy(isClosed = true, imageUrl = null) } _state.update { it.copy(isClosed = true, imageUrl = null) }
stopQrEventStream() stopQrEventStream()
break break
} }
} }
} catch (_: Exception) { delayMs = 4000L
// ignore polling errors } catch (e: Exception) {
delayMs = (delayMs * 1.5).toLong().coerceAtMost(15000L)
} }
delay(5000) delay(delayMs)
} }
} }
} }
@@ -258,6 +278,7 @@ class RazorpayQrViewModel : ViewModel() {
currency = item.currency, currency = item.currency,
imageUrl = item.imageUrl, imageUrl = item.imageUrl,
isClosed = status == "closed" || status == "expired" || status == "credited", isClosed = status == "closed" || status == "expired" || status == "credited",
isCredited = status == "credited",
error = null error = null
) )
} }