diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd12b28d2..6f76eee2ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Added * ui: Add UI for deposit return vouchers (APPS-1643) * core: Handle invalid items (APPS-2039) +* ui/core: Integrate new states for deposit return vouchers into the checkout process and handle them ### Changed ### Removed * ui/core: Remove everything related to the old deposit return voucher feature diff --git a/core/src/main/java/io/snabble/sdk/checkout/Checkout.kt b/core/src/main/java/io/snabble/sdk/checkout/Checkout.kt index ce9fdf8e33..58825bf5bb 100644 --- a/core/src/main/java/io/snabble/sdk/checkout/Checkout.kt +++ b/core/src/main/java/io/snabble/sdk/checkout/Checkout.kt @@ -453,6 +453,15 @@ class Checkout @JvmOverloads constructor( notifyStateChanged(CheckoutState.PAYMENT_ABORTED) return } + val hasAnyFailedDrvRedemptions = + checkoutProcess?.depositReturnVouchers + ?.any { it.state == DepositReturnVoucherState.REDEEMING_FAILED } + ?: false + + if (hasAnyFailedDrvRedemptions) { + notifyStateChanged(CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED) + return + } Logger.d("Polling for approval state...") Logger.d("RoutingTarget = $routingTarget") diff --git a/core/src/main/java/io/snabble/sdk/checkout/CheckoutApi.kt b/core/src/main/java/io/snabble/sdk/checkout/CheckoutApi.kt index 2b1bf154f4..d48e57627b 100644 --- a/core/src/main/java/io/snabble/sdk/checkout/CheckoutApi.kt +++ b/core/src/main/java/io/snabble/sdk/checkout/CheckoutApi.kt @@ -335,11 +335,37 @@ data class Fulfillment( get() = links?.get("self")?.href } +data class DepositReturnVoucher( + @SerializedName("refersTo") + val refersTo: String, + @SerializedName("state") + val state: DepositReturnVoucherState +) + +enum class DepositReturnVoucherState { + @SerializedName("pending") + PENDING, + + @SerializedName("redeemed") + REDEEMED, + + @SerializedName("redeemingFailed") + REDEEMING_FAILED, + + @SerializedName("rolledback") + ROLLED_BACK, + + @SerializedName("rollbackFailed") + ROLLBACK_FAILED +} + data class CheckoutProcessResponse( val links: Map? = null, val checks: List = emptyList(), @SerializedName("orderID") val orderId: String? = null, + @SerializedName("depositReturnVouchers") + val depositReturnVouchers: List? = null, val aborted: Boolean = false, val paymentMethod: PaymentMethod? = null, val paymentInformation: PaymentInformation? = null, diff --git a/core/src/main/java/io/snabble/sdk/checkout/CheckoutState.kt b/core/src/main/java/io/snabble/sdk/checkout/CheckoutState.kt index d54eb5ac11..5cc0df7893 100644 --- a/core/src/main/java/io/snabble/sdk/checkout/CheckoutState.kt +++ b/core/src/main/java/io/snabble/sdk/checkout/CheckoutState.kt @@ -134,4 +134,9 @@ enum class CheckoutState { * will not be communicated */ PAYMENT_TRANSFERRED, + + /** + * One of the deposit return vouchers added couldn't be redeemed + */ + DEPOSIT_RETURN_REDEMPTION_FAILED } diff --git a/core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCart.kt b/core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCart.kt index 74b987d97f..20d72c875f 100644 --- a/core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCart.kt +++ b/core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCart.kt @@ -215,6 +215,16 @@ class ShoppingCart( notifyItemRemoved(this, removedItem, index) } + /** + * Removes a cart item from the cart by its id + */ + fun removeItem(itemId: String) { + val index = indexOf(firstOrNull { it?.id == itemId }) + if (index != -1) { + remove(index) + } + } + /** * The number items in the cart. * diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt index f60b3926a5..41c847f5bb 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt @@ -27,6 +27,7 @@ import io.snabble.sdk.Snabble import io.snabble.sdk.Snabble.instance import io.snabble.sdk.checkout.Checkout import io.snabble.sdk.checkout.CheckoutState +import io.snabble.sdk.checkout.DepositReturnVoucherState import io.snabble.sdk.config.ExternalBillingSubjectLength import io.snabble.sdk.config.ProjectId import io.snabble.sdk.extensions.getApplicationInfoCompat @@ -449,6 +450,11 @@ open class CheckoutBar @JvmOverloads constructor( } } + CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED -> { + progressDialog.dismiss() + handleFailedDepositReturns() + } + CheckoutState.PAYMENT_ABORTED -> { progressDialog.dismiss() } @@ -498,6 +504,34 @@ open class CheckoutBar @JvmOverloads constructor( } } + private fun handleFailedDepositReturns() { + val failedDepositReturnVouchers = + project.checkout.checkoutProcess?.depositReturnVouchers + ?.filter { it.state == DepositReturnVoucherState.REDEEMING_FAILED } + ?: return + + val message = failedDepositReturnVouchers + .mapNotNull { cart.getByItemId(it.refersTo)?.displayName } + .joinToString(separator = "/n") { it } + + AlertDialog.Builder(context) + .setCancelable(false) + .setTitle(context.getString(R.string.Snabble_ShoppingCart_DepositVoucher_RedemptionFailed_title)) + .setMessage( + resources.getQuantityString( + R.plurals.Snabble_ShoppingCart_DepositVoucher_RedemptionFailed_message, + failedDepositReturnVouchers.size, + message + ) + ) + .setPositiveButton(R.string.Snabble_ShoppingCart_DepositVoucher_RedemptionFailed_button) { _, _ -> + failedDepositReturnVouchers + .map { it.refersTo } + .forEach(cart::removeItem) + } + .show() + } + private fun getMaxSubjectLength(): Int? = Snabble.checkedInProject.value ?.id ?.let { id -> diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt index 62b9ab107b..c12f44cda7 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt @@ -179,6 +179,7 @@ class CheckoutActivity : FragmentActivity() { } } + CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED, CheckoutState.PAYMENT_ABORTED -> { finish() null diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt index f722605a11..7e812d2661 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt @@ -29,5 +29,6 @@ val CheckoutState.isCheckoutState: Boolean CheckoutState.PAYMENT_ABORT_FAILED, CheckoutState.PAYMENT_PROCESSING_ERROR, CheckoutState.PAYMENT_TRANSFERRED, + CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED, CheckoutState.PAYONE_SEPA_MANDATE_REQUIRED -> true } diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt index a33374a925..580aaf14bb 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt @@ -298,6 +298,11 @@ class PaymentStatusView @JvmOverloads constructor( handlePaymentAborted() } + CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED -> { + Telemetry.event(Telemetry.Event.CheckoutDepositReturnRedemptionFailed) + handlePaymentAborted() + } + CheckoutState.PAYMENT_ABORTED -> { Telemetry.event(Telemetry.Event.CheckoutAbortByUser) handlePaymentAborted() diff --git a/ui/src/main/java/io/snabble/sdk/ui/telemetry/Telemetry.java b/ui/src/main/java/io/snabble/sdk/ui/telemetry/Telemetry.java index 87ca394b9b..fb9c593d12 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/telemetry/Telemetry.java +++ b/ui/src/main/java/io/snabble/sdk/ui/telemetry/Telemetry.java @@ -7,6 +7,7 @@ public enum Event { ClickCheckout, SelectedPaymentMethod, CheckoutSuccessful, + CheckoutDepositReturnRedemptionFailed, CheckoutDeniedByTooYoung, CheckoutDeniedBySupervisor, CheckoutDeniedByPaymentProvider, diff --git a/ui/src/main/res/values-de/strings.xml b/ui/src/main/res/values-de/strings.xml index 2ec93d70b9..54e6c48057 100644 --- a/ui/src/main/res/values-de/strings.xml +++ b/ui/src/main/res/values-de/strings.xml @@ -341,6 +341,7 @@ aufklappen Shop-Details anzeigen Einkaufen + Ungültiger Leergutbon Damit der Leergutbon eingelöst werden kann, fülle deinen Warenkorb mit deinen Wunschprodukten. Leergutbon Entfernen @@ -465,4 +466,10 @@ Speichern Rückgängig Ja + Entfernen + + + Dieser Leergutbon kann derzeit leider nicht in der App eingelöst werden: \n\n%s\n\nBitte versuche es an der Kassen. + Diese Leergutbon\'s können derzeit leider nicht in der App eingelöst werden: \n\n%s\n\nBitte versuche es an der Kassen. + diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 3c9592205e..12cdcbc4c3 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -343,6 +343,7 @@ Shopping To redeem your voucher, fill your shopping basket with the products you wish to purchase. Deposit voucher + Invalid deposit voucher Remove @@ -407,7 +408,7 @@ Quantity Selected Pay now - Buy %1$d product for %2$s + Buy %1$d product for %2$s1 Select payment method Scan now Visit a store that supports Snabble and scan the barcodes of products you wish to purchase. @@ -465,4 +466,10 @@ Save Undo Yes + Remove + + + Unfortunately, this deposit voucher cannot currently be redeemed in the app: \n\n%s\n\nPlease try for it at the cash desk. + Unfortunately, these deposit vouchers cannot currently be redeemed in the app: \n\n%s\n\nPlease try for it at the cash desk. +