fix razorpay qr credit log
This commit is contained in:
@@ -73,10 +73,19 @@ fun RazorpayQrScreen(
|
||||
LaunchedEffect(propertyId, bookingId) {
|
||||
viewModel.loadQrList(propertyId, bookingId)
|
||||
}
|
||||
LaunchedEffect(state.isCredited) {
|
||||
if (state.isCredited) {
|
||||
onBack()
|
||||
}
|
||||
}
|
||||
|
||||
val isViewingQr = state.isClosed || !state.imageUrl.isNullOrBlank()
|
||||
BackHandler(enabled = isViewingQr) {
|
||||
val exitAndRefresh: () -> Unit = {
|
||||
viewModel.exitQrView()
|
||||
viewModel.loadQrList(propertyId, bookingId)
|
||||
}
|
||||
BackHandler(enabled = isViewingQr) {
|
||||
exitAndRefresh()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
@@ -86,7 +95,7 @@ fun RazorpayQrScreen(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
if (isViewingQr) {
|
||||
viewModel.exitQrView()
|
||||
exitAndRefresh()
|
||||
} else {
|
||||
onBack()
|
||||
}
|
||||
@@ -98,7 +107,20 @@ fun RazorpayQrScreen(
|
||||
)
|
||||
}
|
||||
) { 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(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
||||
@@ -10,6 +10,7 @@ data class RazorpayQrState(
|
||||
val currency: String? = null,
|
||||
val imageUrl: String? = null,
|
||||
val isClosed: Boolean = false,
|
||||
val isCredited: Boolean = false,
|
||||
val paymentLink: String? = null,
|
||||
val qrList: List<com.android.trisolarispms.data.api.model.RazorpayQrListItemDto> = emptyList()
|
||||
)
|
||||
|
||||
@@ -37,12 +37,14 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
fun exitQrView() {
|
||||
stopQrEventStream()
|
||||
stopQrEventPolling()
|
||||
_state.update {
|
||||
it.copy(
|
||||
qrId = null,
|
||||
imageUrl = null,
|
||||
isClosed = false,
|
||||
isCredited = false,
|
||||
error = null
|
||||
)
|
||||
}
|
||||
@@ -121,6 +123,7 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
if (qrId.isNullOrBlank()) return
|
||||
if (lastQrId == qrId && qrEventSource != null) return
|
||||
stopQrEventStream()
|
||||
stopQrEventPolling()
|
||||
lastQrId = qrId
|
||||
val client = ApiClient.createOkHttpClient(readTimeoutSeconds = 0)
|
||||
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 {
|
||||
gson.fromJson(data, RazorpayQrEventDto::class.java)
|
||||
}.getOrNull() ?: return
|
||||
if (isClosedStatus(event.status)) {
|
||||
_state.update { it.copy(isClosed = true, imageUrl = null) }
|
||||
val status = event.status?.lowercase()
|
||||
val eventName = event.event?.lowercase()
|
||||
if (eventName == "qr_code.credited" || status == "credited") {
|
||||
_state.update { it.copy(isCredited = true, imageUrl = null) }
|
||||
stopQrEventStream()
|
||||
stopQrEventPolling()
|
||||
return
|
||||
}
|
||||
if (isClosedStatus(status)) {
|
||||
_state.update { it.copy(isClosed = true, imageUrl = null) }
|
||||
stopQrEventStream()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,13 +161,16 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
response: okhttp3.Response?
|
||||
) {
|
||||
stopQrEventStream()
|
||||
startQrEventPolling(propertyId, bookingId, qrId)
|
||||
}
|
||||
|
||||
override fun onClosed(eventSource: EventSource) {
|
||||
stopQrEventStream()
|
||||
startQrEventPolling(propertyId, bookingId, qrId)
|
||||
}
|
||||
}
|
||||
)
|
||||
// Keep polling as a fallback in case SSE is buffered or never delivers events.
|
||||
startQrEventPolling(propertyId, bookingId, qrId)
|
||||
}
|
||||
|
||||
@@ -170,6 +183,7 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
private fun startQrEventPolling(propertyId: String, bookingId: String, qrId: String) {
|
||||
if (qrPollJob?.isActive == true) return
|
||||
qrPollJob = viewModelScope.launch {
|
||||
var delayMs = 4000L
|
||||
while (true) {
|
||||
val currentQrId = state.value.qrId
|
||||
if (currentQrId.isNullOrBlank() || currentQrId != qrId || state.value.isClosed) {
|
||||
@@ -183,16 +197,22 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
)
|
||||
val body = response.body()
|
||||
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) }) {
|
||||
_state.update { it.copy(isClosed = true, imageUrl = null) }
|
||||
stopQrEventStream()
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
// ignore polling errors
|
||||
delayMs = 4000L
|
||||
} catch (e: Exception) {
|
||||
delayMs = (delayMs * 1.5).toLong().coerceAtMost(15000L)
|
||||
}
|
||||
delay(5000)
|
||||
delay(delayMs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,6 +278,7 @@ class RazorpayQrViewModel : ViewModel() {
|
||||
currency = item.currency,
|
||||
imageUrl = item.imageUrl,
|
||||
isClosed = status == "closed" || status == "expired" || status == "credited",
|
||||
isCredited = status == "credited",
|
||||
error = null
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user