diff --git a/library/src/main/java/io/constructor/core/ConstructorIo.kt b/library/src/main/java/io/constructor/core/ConstructorIo.kt index c2fa51ed..349b45cc 100755 --- a/library/src/main/java/io/constructor/core/ConstructorIo.kt +++ b/library/src/main/java/io/constructor/core/ConstructorIo.kt @@ -79,6 +79,15 @@ object ConstructorIo { configMemoryHolder.segments = value } + /** + * Sets the default analytics tags param + */ + var defaultAnalyticsTags: Map? + get() = configMemoryHolder.defaultAnalyticsTags + set(value) { + configMemoryHolder.defaultAnalyticsTags = defaultAnalyticsTags + } + internal val component: AppComponent by lazy { DaggerAppComponent.builder() .appModule(AppModule(context)) @@ -105,6 +114,7 @@ object ConstructorIo { configMemoryHolder.autocompleteResultCount = constructorIoConfig.autocompleteResultCount configMemoryHolder.testCellParams = constructorIoConfig.testCells configMemoryHolder.segments = constructorIoConfig.segments + configMemoryHolder.defaultAnalyticsTags = constructorIoConfig.defaultAnalyticsTags preferenceHelper = component.preferenceHelper() preferenceHelper.apiKey = constructorIoConfig.apiKey @@ -262,6 +272,16 @@ object ConstructorIo { return encodedParams } + private fun mergeAnalyticsTags(defaultAnalyticsTags: Map?, analyticsTags: Map?): Map? { + if (analyticsTags.isNullOrEmpty()) { + return defaultAnalyticsTags + } else if (!defaultAnalyticsTags.isNullOrEmpty()) { + return defaultAnalyticsTags + analyticsTags + } + + return analyticsTags + } + /** * Returns a list of autocomplete suggestions. * @@ -1146,14 +1166,15 @@ object ConstructorIo { * @param numResultsPerPage The count of quiz results on each page * @param resultPage The current page that quiz result is on * @param resultCount The total number of quiz results + * @param analyticsTags Additional analytics tags to pass */ - fun trackQuizResultClick(quizId: String, quizVersionId: String, quizSessionId: String, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, resultId: String? = null,resultPositionOnPage: Int? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null) { - var completable = trackQuizResultClickInternal(quizId, quizVersionId, quizSessionId, customerId, variationId, itemName, sectionName, resultId, resultPositionOnPage, numResultsPerPage, resultPage, resultCount) + fun trackQuizResultClick(quizId: String, quizVersionId: String, quizSessionId: String, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, resultId: String? = null,resultPositionOnPage: Int? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, analyticsTags: Map? = null) { + var completable = trackQuizResultClickInternal(quizId, quizVersionId, quizSessionId, customerId, variationId, itemName, sectionName, resultId, resultPositionOnPage, numResultsPerPage, resultPage, resultCount, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Quiz Result Click error: ${t.message}") })) } - internal fun trackQuizResultClickInternal(quizId: String, quizVersionId: String, quizSessionId: String, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, resultId: String? = null, resultPositionOnPage: Int? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null): Completable { + internal fun trackQuizResultClickInternal(quizId: String, quizVersionId: String, quizSessionId: String, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, resultId: String? = null, resultPositionOnPage: Int? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val quizResultClickRequestBody = QuizResultClickRequestBody( @@ -1174,7 +1195,8 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, - true, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), + true, section, System.currentTimeMillis() ) @@ -1198,14 +1220,15 @@ object ConstructorIo { * @param resultId The result ID of the quiz response that the selection came from * @param resultPage The current page that quiz result is on * @param resultCount The total number of quiz results + * @param analyticsTags Additional analytics tags to pass */ - fun trackQuizResultLoad(quizId: String, quizVersionId: String, quizSessionId: String, sectionName: String? = null, resultId: String? = null, resultPage: Int? = null, resultCount: Int? = null, url: String = "Not Available") { - var completable = trackQuizResultLoadInternal(quizId, quizVersionId, quizSessionId, sectionName, resultId, resultPage, resultCount, url) + fun trackQuizResultLoad(quizId: String, quizVersionId: String, quizSessionId: String, sectionName: String? = null, resultId: String? = null, resultPage: Int? = null, resultCount: Int? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackQuizResultLoadInternal(quizId, quizVersionId, quizSessionId, sectionName, resultId, resultPage, resultCount, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Quiz Result Load error: ${t.message}") })) } - internal fun trackQuizResultLoadInternal(quizId: String, quizVersionId: String, quizSessionId: String, sectionName: String? = null, resultId: String? = null, resultPage: Int? = null, resultCount: Int? = null, url: String = "Not Available"): Completable { + internal fun trackQuizResultLoadInternal(quizId: String, quizVersionId: String, quizSessionId: String, sectionName: String? = null, resultId: String? = null, resultPage: Int? = null, resultCount: Int? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val quizResultLoadRequestBody = QuizResultLoadRequestBody( @@ -1222,7 +1245,8 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, - true, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), + true, section, System.currentTimeMillis() ) @@ -1250,14 +1274,15 @@ object ConstructorIo { * @param itemName The item name of the clicked item i.e "Jacket Denim" * @param sectionName The section that the results came from, i.e. "Products" * @param revenue The revenue of the item converted + * @param analyticsTags Additional analytics tags to pass */ - fun trackQuizConversion(quizId: String, quizVersionId: String, quizSessionId: String, displayName: String? = null, type: String? = null, isCustomType: Boolean? = null, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, revenue: String? = null) { - var completable = trackQuizConversionInternal(quizId, quizVersionId, quizSessionId, displayName, type, isCustomType, customerId, variationId, itemName, sectionName, revenue) + fun trackQuizConversion(quizId: String, quizVersionId: String, quizSessionId: String, displayName: String? = null, type: String? = null, isCustomType: Boolean? = null, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, revenue: String? = null, analyticsTags: Map? = null) { + var completable = trackQuizConversionInternal(quizId, quizVersionId, quizSessionId, displayName, type, isCustomType, customerId, variationId, itemName, sectionName, revenue, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Quiz Conversion error: ${t.message}") })) } - internal fun trackQuizConversionInternal(quizId: String, quizVersionId: String, quizSessionId: String, displayName: String? = null, type: String? = null, isCustomType: Boolean? = null, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, revenue: String? = null): Completable { + internal fun trackQuizConversionInternal(quizId: String, quizVersionId: String, quizSessionId: String, displayName: String? = null, type: String? = null, isCustomType: Boolean? = null, customerId: String, variationId: String? = null, itemName: String? = null, sectionName: String? = null, revenue: String? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val quizConversionRequestBody = QuizConversionRequestBody( @@ -1277,7 +1302,8 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, - true, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), + true, section, System.currentTimeMillis() ) @@ -1478,9 +1504,10 @@ object ConstructorIo { * @param searchTerm the search term that lead to the event (if adding to cart in a search flow) * @param sectionName the section that the results came from, i.e. "Products" * @param conversionType the type of conversion, i.e. "add_to_cart" + * @param analyticsTags Additional analytics tags to pass */ - fun trackConversion(itemName: String, customerId: String, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null) { - var completable = trackConversionInternal(itemName, customerId, null, revenue, searchTerm, sectionName, conversionType) + fun trackConversion(itemName: String, customerId: String, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null, analyticsTags: Map? = null) { + var completable = trackConversionInternal(itemName, customerId, null, revenue, searchTerm, sectionName, conversionType, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Conversion error: ${t.message}") })) @@ -1499,15 +1526,16 @@ object ConstructorIo { * @param searchTerm the search term that lead to the event (if adding to cart in a search flow) * @param sectionName the section that the results came from, i.e. "Products" * @param conversionType the type of conversion, i.e. "add_to_cart" + * @param analyticsTags Additional analytics tags to pass */ - fun trackConversion(itemName: String, customerId: String, variationId: String?, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null) { - var completable = trackConversionInternal(itemName, customerId, variationId, revenue, searchTerm, sectionName, conversionType) + fun trackConversion(itemName: String, customerId: String, variationId: String?, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null, analyticsTags: Map? = null) { + var completable = trackConversionInternal(itemName, customerId, variationId, revenue, searchTerm, sectionName, conversionType, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Conversion error: ${t.message}") })) } - internal fun trackConversionInternal(itemName: String, customerId: String, variationId: String?, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null): Completable { + internal fun trackConversionInternal(itemName: String, customerId: String, variationId: String?, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, conversionType: String? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val conversionRequestBody = ConversionRequestBody( @@ -1523,6 +1551,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis() @@ -1541,10 +1570,11 @@ object ConstructorIo { * @param customerIds the identifiers of the purchased items * @param revenue the revenue of the purchase event * @param orderID the identifier of the order + * @param analyticsTags Additional analytics tags to pass */ - fun trackPurchase(customerIds: Array, revenue: Double?, orderID: String, sectionName: String? = null) { + fun trackPurchase(customerIds: Array, revenue: Double?, orderID: String, sectionName: String? = null, analyticsTags: Map? = null) { val items = customerIds.map { item -> PurchaseItem(item) } - var completable = trackPurchaseInternal(items.toTypedArray(), revenue, orderID, sectionName) + var completable = trackPurchaseInternal(items.toTypedArray(), revenue, orderID, sectionName, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Purchase error: ${t.message}") })) @@ -1560,15 +1590,16 @@ object ConstructorIo { * @param items the purchased items * @param revenue the revenue of the purchase event * @param orderID the identifier of the order + * @param analyticsTags Additional analytics tags to pass */ - fun trackPurchase(items: Array, revenue: Double?, orderID: String, sectionName: String? = null) { - var completable = trackPurchaseInternal(items, revenue, orderID, sectionName) + fun trackPurchase(items: Array, revenue: Double?, orderID: String, sectionName: String? = null, analyticsTags: Map? = null) { + var completable = trackPurchaseInternal(items, revenue, orderID, sectionName, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Purchase error: ${t.message}") })) } - internal fun trackPurchaseInternal(items: Array, revenue: Double?, orderID: String, sectionName: String? = null): Completable { + internal fun trackPurchaseInternal(items: Array, revenue: Double?, orderID: String, sectionName: String? = null, analyticsTags: Map? = null): Completable { var itemsCopy: MutableList = ArrayList() for (item in items) { repeat(item.quantity) { itemsCopy.add(item) } @@ -1585,6 +1616,7 @@ object ConstructorIo { preferenceHelper.getSessionId(), configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), preferenceHelper.apiKey, true, System.currentTimeMillis() @@ -1604,9 +1636,10 @@ object ConstructorIo { * @param filterValue the value of the primary filter, i.e. "Produce" * @param itemIds the item ids of the displayed items * @param resultCount the number of results for that filter name/value pair + * @param analyticsTags Additional analytics tags to pass */ - fun trackBrowseResultsLoaded(filterName: String, filterValue: String, itemIds: Array, resultCount: Int, sectionName: String? = null, url: String = "Not Available") { - var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, itemIds, resultCount, sectionName, url) + fun trackBrowseResultsLoaded(filterName: String, filterValue: String, itemIds: Array, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, itemIds, resultCount, sectionName, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Results Loaded error: ${t.message}") })) @@ -1622,15 +1655,16 @@ object ConstructorIo { * @param filterName the name of the primary filter, i.e. "Aisle" * @param filterValue the value of the primary filter, i.e. "Produce" * @param resultCount the number of results for that filter name/value pair + * @param analyticsTags Additional analytics tags to pass */ - fun trackBrowseResultsLoaded(filterName: String, filterValue: String, resultCount: Int, sectionName: String? = null, url: String = "Not Available") { - var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, null, resultCount, sectionName, url) + fun trackBrowseResultsLoaded(filterName: String, filterValue: String, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, null, resultCount, sectionName, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Results Loaded error: ${t.message}") })) } - internal fun trackBrowseResultsLoadedInternal(filterName: String, filterValue: String, itemIds: Array? = null, resultCount: Int, sectionName: String? = null, url: String = "Not Available"): Completable { + internal fun trackBrowseResultsLoadedInternal(filterName: String, filterValue: String, itemIds: Array? = null, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val items = itemIds?.map{ item -> TrackingItem(item, null)} @@ -1646,6 +1680,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis() @@ -1670,9 +1705,10 @@ object ConstructorIo { * @param resultPositionOnPage the position of the clicked item on the page i.e. 4 * @param sectionName the section that the results came from, i.e. "Products" * @param resultID the result ID of the browse response that the selection came from + * @param analyticsTags Additional analytics tags to pass */ - fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null) { - var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, null, resultPositionOnPage, sectionName, resultID) + fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null) { + var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, null, resultPositionOnPage, sectionName, resultID, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Result Click error: ${t.message}") })) @@ -1692,15 +1728,16 @@ object ConstructorIo { * @param resultPositionOnPage the position of the clicked item on the page i.e. 4 * @param sectionName the section that the results came from, i.e. "Products" * @param resultID the result ID of the browse response that the selection came from + * @param analyticsTags Additional analytics tags to pass */ - fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, variationId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null) { - var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, variationId, resultPositionOnPage, sectionName, resultID) + fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, variationId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null) { + var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, variationId, resultPositionOnPage, sectionName, resultID, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Result Click error: ${t.message}") })) } - internal fun trackBrowseResultClickInternal(filterName: String, filterValue: String, customerId: String, variationId: String? = null, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null): Completable { + internal fun trackBrowseResultClickInternal(filterName: String, filterValue: String, customerId: String, variationId: String? = null, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val browseResultClickRequestBody = BrowseResultClickRequestBody( @@ -1715,6 +1752,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis(), @@ -1740,15 +1778,16 @@ object ConstructorIo { * @param variationId the variationId of the item loaded * @param sectionName section of the item loaded * @param url the url of the item + * @param analyticsTags Additional analytics tags to pass */ - fun trackItemDetailLoaded(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, url: String = "Not Available") { - var completable = trackItemDetailLoadedInternal(itemName, customerId, variationId, sectionName, url) + fun trackItemDetailLoaded(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackItemDetailLoadedInternal(itemName, customerId, variationId, sectionName, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Item Detail Loaded error: ${t.message}") })) } - internal fun trackItemDetailLoadedInternal(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, url: String = "Not Available"): Completable { + internal fun trackItemDetailLoadedInternal(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val itemDetailLoadRequestBody = ItemDetailLoadRequestBody( @@ -1762,6 +1801,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis() @@ -1784,15 +1824,16 @@ object ConstructorIo { * @param customerId the id of the item clicked * @param variationId the variationId of the item clicked * @param sectionName section of the item clicked + * @param analyticsTags Additional analytics tags to pass */ - fun trackGenericResultClick(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null) { - var completable = trackGenericResultClickInternal(itemName, customerId, variationId, sectionName) + fun trackGenericResultClick(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, analyticsTags: Map? = null) { + var completable = trackGenericResultClickInternal(itemName, customerId, variationId, sectionName, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Generic Result Click error: ${t.message}") })) } - internal fun trackGenericResultClickInternal(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null): Completable { + internal fun trackGenericResultClickInternal(itemName: String, customerId: String, variationId: String? = null, sectionName: String? = null, analyticsTags: Map? = null) : Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val genericResultClickRequestBody = GenericResultClickRequestBody( @@ -1805,7 +1846,8 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, - true, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), + true, section, System.currentTimeMillis() ) @@ -1926,14 +1968,15 @@ object ConstructorIo { * @param resultPage The current page that recommendation result is on * @param resultCount The total number of recommendation results * @param resultPositionOnPage The position of the recommendation result that was clicked on + * @param analyticsTags Additional analytics tags to pass */ - fun trackRecommendationResultClick(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null) { - var completable = trackRecommendationResultClickInternal(podId, strategyId, customerId, variationId, sectionName, resultId, numResultsPerPage, resultPage, resultCount, resultPositionOnPage) + fun trackRecommendationResultClick(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map? = null) { + var completable = trackRecommendationResultClickInternal(podId, strategyId, customerId, variationId, sectionName, resultId, numResultsPerPage, resultPage, resultCount, resultPositionOnPage, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Recommendation Result Click error: ${t.message}") })) } - internal fun trackRecommendationResultClickInternal(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null): Completable { + internal fun trackRecommendationResultClickInternal(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val recommendationsResultClickRequestBody = RecommendationResultClickRequestBody( @@ -1952,6 +1995,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis() @@ -1976,14 +2020,15 @@ object ConstructorIo { * @param resultCount The total number of recommendation results * @param resultId The result ID of the recommendation response that the selection came from * @param sectionName The section that the results came from, i.e. "Products" + * @param analyticsTags Additional analytics tags to pass */ - fun trackRecommendationResultsView(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available") { - var completable = trackRecommendationResultsViewInternal(podId, numResultsViewed, resultPage, resultCount, resultId, sectionName, url) + fun trackRecommendationResultsView(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackRecommendationResultsViewInternal(podId, numResultsViewed, resultPage, resultCount, resultId, sectionName, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Recommendation Results View error: ${t.message}") })) } - internal fun trackRecommendationResultsViewInternal(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available"): Completable { + internal fun trackRecommendationResultsViewInternal(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val recommendationResultViewRequestBody = RecommendationResultViewRequestBody( @@ -1999,6 +2044,7 @@ object ConstructorIo { preferenceHelper.apiKey, configMemoryHolder.userId, configMemoryHolder.segments, + mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), true, section, System.currentTimeMillis() diff --git a/library/src/main/java/io/constructor/core/ConstructorIoConfig.kt b/library/src/main/java/io/constructor/core/ConstructorIoConfig.kt index c5504cae..f9467541 100644 --- a/library/src/main/java/io/constructor/core/ConstructorIoConfig.kt +++ b/library/src/main/java/io/constructor/core/ConstructorIoConfig.kt @@ -12,6 +12,7 @@ import io.constructor.BuildConfig * @property testCells Test cell name/value pairs if A/B testing * @property servicePort The port to use (for testing purposes only, defaults to 443) * @property serviceScheme The scheme to use (for testing purposes only, defaults to HTTPS) + * @property defaultAnalyticsTags Additional analytics tags to pass. Will be merged with analytics tags passed on the request level */ data class ConstructorIoConfig( val apiKey: String, @@ -22,5 +23,6 @@ data class ConstructorIoConfig( val autocompleteResultCount: Map = mapOf(Constants.QueryValues.SEARCH_SUGGESTIONS to 10, Constants.QueryValues.PRODUCTS to 0), val defaultItemSection: String = BuildConfig.DEFAULT_ITEM_SECTION, val servicePort: Int = BuildConfig.SERVICE_PORT, - val serviceScheme: String = BuildConfig.SERVICE_SCHEME + val serviceScheme: String = BuildConfig.SERVICE_SCHEME, + val defaultAnalyticsTags: Map = emptyMap() ) \ No newline at end of file diff --git a/library/src/main/java/io/constructor/data/memory/ConfigMemoryHolder.kt b/library/src/main/java/io/constructor/data/memory/ConfigMemoryHolder.kt index 86e1d825..59752e4e 100644 --- a/library/src/main/java/io/constructor/data/memory/ConfigMemoryHolder.kt +++ b/library/src/main/java/io/constructor/data/memory/ConfigMemoryHolder.kt @@ -40,4 +40,6 @@ class ConfigMemoryHolder @Inject constructor() { var autocompleteResultCount: Map? = null var userId: String? = null + + var defaultAnalyticsTags: Map? = null } \ No newline at end of file diff --git a/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt b/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt index b25bda00..86c0de62 100644 --- a/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt @@ -21,6 +21,7 @@ data class BrowseResultClickRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long?, diff --git a/library/src/main/java/io/constructor/data/model/browse/BrowseResultLoadRequestBody.kt b/library/src/main/java/io/constructor/data/model/browse/BrowseResultLoadRequestBody.kt index cca5c25e..f84f4450 100644 --- a/library/src/main/java/io/constructor/data/model/browse/BrowseResultLoadRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/browse/BrowseResultLoadRequestBody.kt @@ -21,6 +21,7 @@ data class BrowseResultLoadRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/conversion/ConversionRequestBody.kt b/library/src/main/java/io/constructor/data/model/conversion/ConversionRequestBody.kt index a775a102..7d36ea58 100644 --- a/library/src/main/java/io/constructor/data/model/conversion/ConversionRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/conversion/ConversionRequestBody.kt @@ -22,6 +22,7 @@ data class ConversionRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/purchase/PurchaseRequestBody.kt b/library/src/main/java/io/constructor/data/model/purchase/PurchaseRequestBody.kt index aaec06b0..ff439c6d 100644 --- a/library/src/main/java/io/constructor/data/model/purchase/PurchaseRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/purchase/PurchaseRequestBody.kt @@ -18,6 +18,7 @@ data class PurchaseRequestBody( @Json(name = "s") val s: Int?, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name = "key") val key: String?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/quiz/QuizConversionRequestBody.kt b/library/src/main/java/io/constructor/data/model/quiz/QuizConversionRequestBody.kt index e3684bd2..7f6030ea 100644 --- a/library/src/main/java/io/constructor/data/model/quiz/QuizConversionRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/quiz/QuizConversionRequestBody.kt @@ -23,6 +23,7 @@ data class QuizConversionRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/quiz/QuizResultClickRequestBody.kt b/library/src/main/java/io/constructor/data/model/quiz/QuizResultClickRequestBody.kt index 4056458d..309160ea 100644 --- a/library/src/main/java/io/constructor/data/model/quiz/QuizResultClickRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/quiz/QuizResultClickRequestBody.kt @@ -24,6 +24,7 @@ data class QuizResultClickRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/quiz/QuizResultLoadRequestBody.kt b/library/src/main/java/io/constructor/data/model/quiz/QuizResultLoadRequestBody.kt index a80be4fc..d70db879 100644 --- a/library/src/main/java/io/constructor/data/model/quiz/QuizResultLoadRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/quiz/QuizResultLoadRequestBody.kt @@ -20,6 +20,7 @@ data class QuizResultLoadRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultClickRequestBody.kt b/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultClickRequestBody.kt index 4960b22e..f6881704 100644 --- a/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultClickRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultClickRequestBody.kt @@ -22,6 +22,7 @@ data class RecommendationResultClickRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultViewRequestBody.kt b/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultViewRequestBody.kt index 8c059427..f6e36a13 100644 --- a/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultViewRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/recommendations/RecommendationResultViewRequestBody.kt @@ -19,6 +19,7 @@ data class RecommendationResultViewRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/tracking/GenericResultClickRequestBody.kt b/library/src/main/java/io/constructor/data/model/tracking/GenericResultClickRequestBody.kt index 3ce8f927..ed5b629a 100644 --- a/library/src/main/java/io/constructor/data/model/tracking/GenericResultClickRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/tracking/GenericResultClickRequestBody.kt @@ -19,6 +19,7 @@ data class GenericResultClickRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/main/java/io/constructor/data/model/tracking/ItemDetailLoadRequestBody.kt b/library/src/main/java/io/constructor/data/model/tracking/ItemDetailLoadRequestBody.kt index f02fa8bc..1122ae2b 100644 --- a/library/src/main/java/io/constructor/data/model/tracking/ItemDetailLoadRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/tracking/ItemDetailLoadRequestBody.kt @@ -20,6 +20,7 @@ data class ItemDetailLoadRequestBody( @Json(name = "key") val key: String, @Json(name = "ui") val ui: String?, @Json(name = "us") val us: List, + @Json(name = "analytics_tags") val analyticsTags: Map?, @Json(name= "beacon") val beacon: Boolean?, @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long? diff --git a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationQuizTest.kt b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationQuizTest.kt index 794f2eb3..e9762893 100644 --- a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationQuizTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationQuizTest.kt @@ -43,6 +43,7 @@ class ConstructorIoIntegrationQuizTest { every { configMemoryHolder.autocompleteResultCount } returns null every { configMemoryHolder.userId } returns "player-three" + every { configMemoryHolder.defaultAnalyticsTags } returns mapOf("appVersion" to "123", "appPlatform" to "Android") every { configMemoryHolder.testCellParams } returns emptyList() every { configMemoryHolder.segments } returns emptyList() diff --git a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt index 308d40f2..d7a97849 100644 --- a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt @@ -43,6 +43,7 @@ class ConstructorIoIntegrationTest { every { preferencesHelper.getSessionId(any(), any()) } returns 67 every { configMemoryHolder.autocompleteResultCount } returns null + every { configMemoryHolder.defaultAnalyticsTags } returns mapOf("appVersion" to "123", "appPlatform" to "Android") every { configMemoryHolder.userId } returns "player-three" every { configMemoryHolder.testCellParams } returns emptyList() every { configMemoryHolder.segments } returns emptyList() diff --git a/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt b/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt index fee639de..35add66c 100755 --- a/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt @@ -196,6 +196,7 @@ class ConstructorIoTrackingTest { every { preferencesHelper.getSessionId(any(), any()) } returns 67 every { configMemoryHolder.autocompleteResultCount } returns null + every { configMemoryHolder.defaultAnalyticsTags } returns mapOf("appVersion" to "123", "appPlatform" to "Android") every { configMemoryHolder.userId } returns "player-three" every { configMemoryHolder.testCellParams } returns emptyList() every { configMemoryHolder.segments } returns emptyList() @@ -508,6 +509,26 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackConversionWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackConversionInternal("titanic replica", "TIT-REP-1997","RED",89.00, "test", null, null, mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val path = "/v2/behavioral_action/conversion?key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + val requestBody = getRequestBody(request) + + assertEquals("TIT-REP-1997", requestBody["item_id"]) + assertEquals("titanic replica", requestBody["item_name"]) + assertEquals("RED", requestBody["variation_id"]) + assertEquals("89.00", requestBody["revenue"]) + assertEquals("Products", requestBody["section"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackConversion500() { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") @@ -584,6 +605,23 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackPurchaseWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackPurchaseInternal(arrayOf(PurchaseItem("TIT-REP-1997", "RED"), PurchaseItem("QE2-REP-1969")), 12.99, "ORD-1312343", null, mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/purchase?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("[{item_id:TIT-REP-1997,variation_id:RED},{item_id:QE2-REP-1969}]", requestBody["items"]) + assertEquals("ORD-1312343", requestBody["order_id"]) + assertEquals("12.99", requestBody["revenue"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackPurchase500() { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") @@ -644,6 +682,24 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackBrowseResultLoadedWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, 10, null, analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/browse_result_load?key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("group_id", requestBody["filter_name"]) + assertEquals("Movies", requestBody["filter_value"]) + assertEquals("10", requestBody["result_count"]) + assertEquals(null, requestBody["items"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackBrowseResultLoadedWithItems() { val mockResponse = MockResponse().setResponseCode(204) @@ -708,6 +764,26 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackBrowseResultClickWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackBrowseResultClickInternal("group_id", "Movies","TIT-REP-1997", null,4, "Products", "123456", analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/browse_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("group_id", requestBody["filter_name"]) + assertEquals("Movies", requestBody["filter_value"]) + assertEquals("TIT-REP-1997", requestBody["item_id"]) + assertEquals("4", requestBody["result_position_on_page"]) + assertEquals(null, requestBody["variation_id"]) + assertEquals("123456", requestBody["result_id"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackBrowseResultClickWithVariationId() { val mockResponse = MockResponse().setResponseCode(204) @@ -789,6 +865,25 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackItemDetailLoadedWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackItemDetailLoadedInternal("pencil", "123", "456", "Products", analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/item_detail_load?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("pencil", requestBody["item_name"]) + assertEquals("123", requestBody["item_id"]) + assertEquals("456", requestBody["variation_id"]) + assertEquals("Products", requestBody["section"]) + assertEquals("Not Available", requestBody["url"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackItemDetailLoaded500() { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") @@ -835,6 +930,24 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackGenericResultClickWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackGenericResultClickInternal("pencil", "123", "456", "Products", analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("pencil", requestBody["item_name"]) + assertEquals("123", requestBody["item_id"]) + assertEquals("456", requestBody["variation_id"]) + assertEquals("Products", requestBody["section"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackGenericResultClick500() { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") @@ -879,6 +992,23 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackRecommendationResultClickWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackRecommendationResultClickInternal("pdp5", "User Featured","TIT-REP-1997", analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/recommendation_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("pdp5", requestBody["pod_id"]) + assertEquals("User Featured", requestBody["strategy_id"]) + assertEquals("TIT-REP-1997", requestBody["item_id"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackRecommendationResultClickWithSectionAndResultID() { val mockResponse = MockResponse().setResponseCode(204) @@ -937,6 +1067,22 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackRecommendationResultsViewWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackRecommendationResultsViewInternal("pdp5", 4, analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/recommendation_result_view?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("pdp5", requestBody["pod_id"]) + assertEquals("4", requestBody["num_results_viewed"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackRecommendationResultsViewWithSectionAndResultID() { val mockResponse = MockResponse().setResponseCode(204) @@ -1004,6 +1150,30 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackQuizResultClickWithAnalyticsTags() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackQuizResultClickInternal("coffee-quiz", "23AECMA-1EFKCI", "34NCUIEI-214CDN", "shirt-a", "shirt-a--reg", "White shirt", null, null, 10, 10, 1, 10, mapOf("test" to "test1", "appVersion" to "150")).test(); + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + val path = "/v2/behavioral_action/quiz_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.28.0&_dt=" + assertEquals("coffee-quiz", requestBody["quiz_id"]) + assertEquals("23AECMA-1EFKCI", requestBody["quiz_version_id"]) + assertEquals("34NCUIEI-214CDN", requestBody["quiz_session_id"]) + assertEquals("1", requestBody["result_page"]) + assertEquals("10", requestBody["result_count"]) + assertEquals("10", requestBody["num_results_per_page"]) + assertEquals("10", requestBody["result_position_on_page"]) + assertEquals("shirt-a", requestBody["item_id"]) + assertEquals("White shirt", requestBody["item_name"]) + assertEquals("shirt-a--reg", requestBody["variation_id"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) + assertEquals("POST", request.method) + assert(request.path!!.startsWith(path)) + } + @Test fun trackQuizResultClickWithSectionAndResultID() { val mockResponse = MockResponse().setResponseCode(204) @@ -1084,7 +1254,7 @@ class ConstructorIoTrackingTest { fun trackQuizConversionWithAllOptionalParameters() { val mockResponse = MockResponse().setResponseCode(204) mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackQuizConversionInternal("coffee-quiz", "23AECMA-1EFKCI", "34NCUIEI-214CDN", "quizConversion", "quizConversion", true, "shirt-a", "shirt-a--reg", "White shirt", "Search Suggestions", "129.99").test(); + val observer = ConstructorIo.trackQuizConversionInternal("coffee-quiz", "23AECMA-1EFKCI", "34NCUIEI-214CDN", "quizConversion", "quizConversion", true, "shirt-a", "shirt-a--reg", "White shirt", "Search Suggestions", "129.99", analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test(); observer.assertComplete() val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -1099,6 +1269,7 @@ class ConstructorIoTrackingTest { assertEquals("quizConversion", requestBody["display_name"]) assertEquals("quizConversion", requestBody["type"]) assertEquals("true", requestBody["is_custom_type"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) assertEquals("POST", request.method) assert(request.path!!.startsWith(path)) } @@ -1158,7 +1329,7 @@ class ConstructorIoTrackingTest { fun trackQuizResultLoadWithAllOptionalParameters() { val mockResponse = MockResponse().setResponseCode(204) mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackQuizResultLoadInternal("coffee-quiz", "23AECMA-1EFKCI", "34NCUIEI-214CDN", "Search Suggestions", "123", 1, 10).test(); + val observer = ConstructorIo.trackQuizResultLoadInternal("coffee-quiz", "23AECMA-1EFKCI", "34NCUIEI-214CDN", "Search Suggestions", "123", 1, 10, analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test(); observer.assertComplete() val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -1169,6 +1340,7 @@ class ConstructorIoTrackingTest { assertEquals("10", requestBody["result_count"]) assertEquals("1", requestBody["result_page"]) assertEquals("Not Available", requestBody["url"]) + assertEquals("{appVersion:150,appPlatform:Android,test:test1}", requestBody["analytics_tags"]) assertEquals("123", requestBody["result_id"]) assertEquals("POST", request.method) assert(request.path!!.startsWith(path)) diff --git a/library/src/test/java/io/constructor/core/ConstructorioSegmentsTest.kt b/library/src/test/java/io/constructor/core/ConstructorioSegmentsTest.kt index 46794ade..43484dfe 100644 --- a/library/src/test/java/io/constructor/core/ConstructorioSegmentsTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorioSegmentsTest.kt @@ -44,6 +44,7 @@ class ConstructorioSegmentsTest { every { preferencesHelper.getSessionId(any(), any()) } returns 14 every { configMemoryHolder.autocompleteResultCount } returns null + every { configMemoryHolder.defaultAnalyticsTags } returns mapOf("appVersion" to "123", "appPlatform" to "Android") every { configMemoryHolder.userId } returns "player-two" every { configMemoryHolder.testCellParams } returns emptyList() every { configMemoryHolder.segments } returns listOf("mobile", "COUNTRY_US") diff --git a/library/src/test/java/io/constructor/core/ConstructorioTestCellTest.kt b/library/src/test/java/io/constructor/core/ConstructorioTestCellTest.kt index a60baf87..e3f3babf 100644 --- a/library/src/test/java/io/constructor/core/ConstructorioTestCellTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorioTestCellTest.kt @@ -45,6 +45,7 @@ class ConstructorioTestCellTest { every { configMemoryHolder.autocompleteResultCount } returns null every { configMemoryHolder.userId } returns "player-two" + every { configMemoryHolder.defaultAnalyticsTags } returns mapOf("appVersion" to "123", "appPlatform" to "Android") every { configMemoryHolder.testCellParams } returns listOf("cellone" to "vanilla", "celltwo" to "whipped-cream") every { configMemoryHolder.segments } returns emptyList()