Skip to content

Commit

Permalink
Merge branch 'main' into IPC-293-removable-poweredby
Browse files Browse the repository at this point in the history
* main:
  Pp 354 user analytics feature (#449)
  fix(health-sdk): Fix invoices upload in the example app
  fix(health-sdk): Fix copying of extractions in the tests
  feat(health-sdk): Code fix
  feat(health-sdk): Fixed tests for payable check
  feat(health-sdk): Fixed payment state retrieve
  feat(health-sdk): Changed method of checking if document is payable
  feat(bank-sdk): Migrate to registerForActivityResult
  feat(capture-sdk): Migrate to registerForActivityResult
  Revert "Pp 197 migrate from start activity for result to register for result"
  feat(bank-sdk): Migrate to registerForActivityResult
  feat(capture-sdk): Migrate to registerForActivityResult
  refactor(health-sdk): Use `async` in example app to parallelize test invoice uploads and refresh requests
  fix(health-sdk): Fix `paymentComponentView` not collecting again after setting `documentId` and\or `isPayable`
  fix(health-sdk): Fix `paymentComponent` listener not called after config change
  fix(health-sdk): Fix mutability of `PendingIntent`
  fix(health-sdk): Make resetting the `openBankState` flow's PaymentState to NoAction non-cancellable
  fix(health-sdk): Fix `Share With` flow broken when clients pop backstack after getting payment request callback
  • Loading branch information
llevente committed Jul 22, 2024
2 parents d294e30 + 3a2e8a8 commit 065f630
Show file tree
Hide file tree
Showing 86 changed files with 3,640 additions and 919 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.gini.android.bank.api;

import net.gini.android.bank.api.models.AmplitudeRoot
import net.gini.android.bank.api.models.Configuration
import net.gini.android.bank.api.models.ExtractionsContainer
import net.gini.android.bank.api.models.ResolvePaymentInput
import net.gini.android.bank.api.models.ResolvedPayment
Expand Down Expand Up @@ -45,4 +47,11 @@ class BankApiDocumentManager internal constructor(private val documentRepository
errorEvent: ErrorEvent
): Resource<Unit> =
documentRepository.logErrorEvent(errorEvent)


suspend fun getConfigurations(): Resource<Configuration> =
documentRepository.getConfigurations()

suspend fun sendEvents(amplitudeRoot: AmplitudeRoot): Resource<Unit> =
documentRepository.sendEvents(amplitudeRoot)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package net.gini.android.bank.api

import kotlinx.coroutines.withContext
import net.gini.android.bank.api.models.Configuration
import net.gini.android.bank.api.models.ResolvePaymentInput
import net.gini.android.bank.api.models.ResolvedPayment
import net.gini.android.bank.api.models.toResolvedPayment
import net.gini.android.bank.api.requests.ErrorEvent
import net.gini.android.bank.api.requests.toAmplitudeRequestBody
import net.gini.android.bank.api.requests.toResolvePaymentBody
import net.gini.android.bank.api.response.toConfiguration
import net.gini.android.core.api.DocumentRemoteSource
import net.gini.android.core.api.requests.ApiException
import net.gini.android.core.api.requests.SafeApiRequest
Expand Down Expand Up @@ -34,4 +37,11 @@ class BankApiDocumentRemoteSource internal constructor(
documentService.logErrorEvent(bearerHeaderMap(accessToken, contentType = giniApiType.giniJsonMediaType), errorEvent)
}
}

suspend fun getConfigurations(accessToken: String): Configuration = withContext(coroutineContext) {
val response = SafeApiRequest.apiRequest {
documentService.getConfigurations(bearerHeaderMap(accessToken, giniApiType.giniJsonMediaType))
}
response.body()?.toConfiguration() ?: throw ApiException.forResponse("Empty response body", response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,32 @@ import org.json.JSONObject
class BankApiDocumentRepository(
private val documentRemoteSource: BankApiDocumentRemoteSource,
sessionManager: SessionManager,
giniApiType: GiniBankApiType
giniApiType: GiniBankApiType,
private val trackingAnalysisRemoteSource: TrackingAnalysisRemoteSource
) : DocumentRepository<ExtractionsContainer>(documentRemoteSource, sessionManager, giniApiType) {

override fun createExtractionsContainer(
specificExtractions: Map<String, SpecificExtraction>,
compoundExtractions: Map<String, CompoundExtraction>,
responseJSON: JSONObject
): ExtractionsContainer {
val returnReasons: List<ReturnReason> = parseReturnReason(responseJSON.optJSONArray("returnReasons"))
val returnReasons: List<ReturnReason> =
parseReturnReason(responseJSON.optJSONArray("returnReasons"))

return ExtractionsContainer(specificExtractions, compoundExtractions, returnReasons)
}

suspend fun resolvePaymentRequest(requestId: String, resolvePaymentInput: ResolvePaymentInput): Resource<ResolvedPayment> =
suspend fun resolvePaymentRequest(
requestId: String,
resolvePaymentInput: ResolvePaymentInput
): Resource<ResolvedPayment> =
withAccessToken { accessToken ->
wrapInResource {
documentRemoteSource.resolvePaymentRequests(accessToken, requestId, resolvePaymentInput)
documentRemoteSource.resolvePaymentRequests(
accessToken,
requestId,
resolvePaymentInput
)
}
}

Expand All @@ -45,6 +54,19 @@ class BankApiDocumentRepository(
}
}

suspend fun getConfigurations(): Resource<Configuration> =
withAccessToken { accessToken ->
wrapInResource {
documentRemoteSource.getConfigurations(accessToken)
}
}

suspend fun sendEvents(amplitudeRoot: AmplitudeRoot): Resource<Unit> =
wrapInResource {
trackingAnalysisRemoteSource.sendEvents(amplitudeRoot)
}


@Throws(JSONException::class)
private fun parseReturnReason(returnReasonsJson: JSONArray?): List<ReturnReason> {
if (returnReasonsJson == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package net.gini.android.bank.api

import net.gini.android.bank.api.requests.ErrorEvent
import net.gini.android.bank.api.requests.ResolvePaymentBody
import net.gini.android.bank.api.response.ConfigurationResponse
import net.gini.android.bank.api.response.ResolvePaymentResponse
import net.gini.android.core.api.DocumentService
import okhttp3.RequestBody
Expand All @@ -19,4 +20,7 @@ internal interface BankApiDocumentService: DocumentService {

@POST("events/error")
suspend fun logErrorEvent(@HeaderMap bearer: Map<String, String>, @Body errorEvent: ErrorEvent): Response<ResponseBody>

@GET("configurations")
suspend fun getConfigurations(@HeaderMap bearer: Map<String, String>): Response<ConfigurationResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class GiniBankAPIBuilder @JvmOverloads constructor(
return BankApiDocumentRemoteSource(Dispatchers.IO, getApiRetrofit().create(BankApiDocumentService::class.java), bankApiType, getApiBaseUrl() ?: "")
}

private fun createTrackingAnalysisRemoteSource(): TrackingAnalysisRemoteSource {
return TrackingAnalysisRemoteSource(Dispatchers.IO,getTrackingAnalyticsApiRetrofit().create(TrackingAnalysisService::class.java))
}

override fun createDocumentRepository(): BankApiDocumentRepository {
return BankApiDocumentRepository(createDocumentRemoteSource(), getSessionManager(), bankApiType)
return BankApiDocumentRepository(createDocumentRemoteSource(), getSessionManager(), bankApiType, createTrackingAnalysisRemoteSource())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package net.gini.android.bank.api

import kotlinx.coroutines.withContext
import net.gini.android.bank.api.models.AmplitudeRoot
import net.gini.android.bank.api.requests.toAmplitudeRequestBody
import net.gini.android.core.api.requests.SafeApiRequest
import kotlin.coroutines.CoroutineContext

/**
* Internal use only.
*/
class TrackingAnalysisRemoteSource internal constructor(
private val coroutineContext: CoroutineContext,
private val trackingAnalysisService: TrackingAnalysisService
) {

suspend fun sendEvents(amplitudeRoot: AmplitudeRoot): Unit =
withContext(coroutineContext) {
SafeApiRequest.apiRequest {
trackingAnalysisService.sendEvents(amplitudeRoot.toAmplitudeRequestBody())
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.gini.android.bank.api

import net.gini.android.bank.api.requests.AmplitudeRequestBody
import net.gini.android.core.api.DocumentService
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST

internal interface TrackingAnalysisService: DocumentService {

@POST("/batch")
suspend fun sendEvents(@Body amplitudeBody: AmplitudeRequestBody): Response<ResponseBody>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.gini.android.bank.api.models

data class AmplitudeRoot(
val apiKey: String,
val events: List<AmplitudeEvent>,
)

data class AmplitudeEvent(
val userId: String,
val deviceId: String,
val eventType: String,
val sessionId: String,
val eventId: String,
val time: Long,
val platform: String,
val osVersion: String,
val deviceManufacturer: String,
val deviceBrand: String,
val deviceModel: String,
val versionName: String,
val osName: String,
val carrier: String,
val language: String,
val eventProperties: Map<String, Any>? = null,
val userProperties: Map<String, Any>? = null,
)


Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.gini.android.bank.api.models

data class Configuration(
val clientID: String,
val isUserJourneyAnalyticsEnabled: Boolean,
val isSkontoEnabled: Boolean,
val isReturnAssistantEnabled: Boolean,
val mixpanelToken: String?,
val amplitudeApiKey: String?,

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package net.gini.android.bank.api.requests

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import net.gini.android.bank.api.models.AmplitudeEvent
import net.gini.android.bank.api.models.AmplitudeRoot

@JsonClass(generateAdapter = true)
data class AmplitudeRequestBody(
@Json(name = "api_key") val apiKey: String,
@Json(name = "events") val events: List<AmplitudeEventBody>,
)

@JsonClass(generateAdapter = true)
data class AmplitudeEventBody(
@Json(name = "user_id") val userId: String,
@Json(name = "device_id") val deviceId: String,
@Json(name = "event_type") val eventType: String,
@Json(name = "session_id") val sessionId: String,
@Json(name = "event_id") val eventId: String,
@Json(name = "time") val time: Long = 0,
@Json(name = "platform") val platform: String,
@Json(name = "os_version") val osVersion: String,
@Json(name = "device_manufacturer") val deviceManufacturer: String,
@Json(name = "device_brand") val deviceBrand: String,
@Json(name = "device_model") val deviceModel: String,
@Json(name = "version_name") val versionName: String,
@Json(name = "os_name") val osName: String,
@Json(name = "carrier") val carrier: String,
@Json(name = "language") val language: String,
@Json(name = "ip") val ip: String = "\$remote",
@Json(name = "event_properties") val eventProperties: Map<String, Any>? = null,
@Json(name = "user_properties") val userProperties: Map<String, Any>? = null,
)


internal fun AmplitudeRoot.toAmplitudeRequestBody() = AmplitudeRequestBody(
apiKey = apiKey,
events = events.map { it.toAmplitudeEventBody() }
)

internal fun AmplitudeEvent.toAmplitudeEventBody() = AmplitudeEventBody(
userId = userId,
deviceId = deviceId,
eventType = eventType,
sessionId = sessionId,
eventId = eventId,
time = time,
platform = platform,
osVersion = osVersion,
deviceManufacturer = deviceManufacturer,
deviceBrand = deviceBrand,
deviceModel = deviceModel,
versionName = versionName,
osName = osName,
carrier = carrier,
language = language,
eventProperties = eventProperties,
userProperties = userProperties,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.gini.android.bank.api.response

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import net.gini.android.bank.api.models.Configuration

@JsonClass(generateAdapter = true)
data class ConfigurationResponse(
@Json(name = "clientID") val clientID: String?,
@Json(name = "userJourneyAnalyticsEnabled") val userJourneyAnalyticsEnabled: Boolean?,
@Json(name = "skontoEnabled") val skontoEnabled: Boolean?,
@Json(name = "returnAssistantEnabled") val returnAssistantEnabled: Boolean?,
@Json(name = "mixpanelToken") val mixpanelToken: String?,
@Json(name = "amplitudeApiKey") val amplitudeApiKey: String?,
)

internal fun ConfigurationResponse.toConfiguration() = Configuration(
clientID = clientID ?: "",
isUserJourneyAnalyticsEnabled = userJourneyAnalyticsEnabled ?: false,
isSkontoEnabled = skontoEnabled ?: false,
isReturnAssistantEnabled = returnAssistantEnabled ?: false,
mixpanelToken = mixpanelToken,
amplitudeApiKey = amplitudeApiKey
)

Loading

0 comments on commit 065f630

Please sign in to comment.