Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ All notable changes to this project will be documented in this file.
### Removed
### Fixed

## [0.83.3]
### Changed
* ui: show coupons as part of the shopping cart and change discount design

## [0.83.2]
### Changed
* ui: update unknown barcode message
Expand Down
14 changes: 11 additions & 3 deletions core/src/main/java/io/snabble/sdk/coupons/Coupon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ data class Coupon(
@SerializedName("disclaimer") val disclaimer: String?,
@SerializedName("colors") val colors: Map<String, String>?,
) : Parcelable {

val isValid: Boolean
get() = when (type) {
CouponType.DIGITAL -> image != null
Expand All @@ -40,6 +41,9 @@ data class Coupon(
val validUntil: ZonedDateTime?
get() = _validUntil?.let { ZonedDateTime.parse(_validUntil) }

@IgnoredOnParcel
var isRedeemed: Boolean = false

@IgnoredOnParcel
val backgroundColor
get() = parseColor(colors?.get("background"), Color.WHITE)
Expand All @@ -60,6 +64,7 @@ data class CouponImage(
@SerializedName("name") val name: String?,
@SerializedName("formats") val formats: List<CouponImageFormats>,
) : Parcelable {

val bestResolutionUrl: String
get() {
val res = Snabble.application.resources
Expand Down Expand Up @@ -98,7 +103,10 @@ data class CouponImageFormats(
) : Parcelable

enum class CouponType {
@SerializedName("manual") MANUAL,
@SerializedName("printed") PRINTED,
@SerializedName("digital") DIGITAL,
@SerializedName("manual")
MANUAL,
@SerializedName("printed")
PRINTED,
@SerializedName("digital")
DIGITAL,
}
37 changes: 35 additions & 2 deletions core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCart.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.snabble.sdk.shoppingcart

import androidx.annotation.Keep
import androidx.annotation.RestrictTo
import com.google.gson.annotations.SerializedName
import io.snabble.sdk.PriceFormatter
import io.snabble.sdk.Product
import io.snabble.sdk.Product.Type
Expand All @@ -18,6 +19,7 @@ import io.snabble.sdk.codes.ScannedCode
import io.snabble.sdk.codes.templates.CodeTemplate
import io.snabble.sdk.coupons.Coupon
import io.snabble.sdk.coupons.CouponType
import io.snabble.sdk.extensions.xx
import io.snabble.sdk.shoppingcart.data.Taxation
import io.snabble.sdk.shoppingcart.data.cart.BackendCart
import io.snabble.sdk.shoppingcart.data.cart.BackendCartCustomer
Expand Down Expand Up @@ -217,6 +219,19 @@ class ShoppingCart(
notifyItemRemoved(this, removedItem, index)
}

/**
* Removed a cart item from the cart by its index
*/
fun removeDiscount(index: Int, discountId: String) {
data = data.copy(modCount = modCount.inc())
generateNewUUID()
val removedItem = data.items.removeAt(index)
checkLimits()
updatePrices(debounce = size() != 0)
invalidateOnlinePrices()
notifyItemRemoved(this, removedItem, index)
}

/**
* Removes a cart item from the cart by its id
*/
Expand Down Expand Up @@ -453,6 +468,11 @@ class ShoppingCart(
if (index != -1) remove(index)
}

fun removeCoupon(id: String) {
val index = indexOfFirst { it?.coupon?.id == id }
if (index != -1) remove(index)
}

/**
* Gets a list of invalid products that were rejected by the backend.
*/
Expand Down Expand Up @@ -954,28 +974,34 @@ class ShoppingCart(
/**
* Returns the product associated with the shopping cart item.
*/
@SerializedName("product")
var product: Product? = null

/**
* Returns the scanned code which was used when scanning the product and adding it to the shopping cart
*/
@SerializedName("scannedCode")
var scannedCode: ScannedCode? = null
private set

@SerializedName("quantity")
var quantity = 0

@SerializedName("lineItem")
var lineItem: LineItem? = null
set(value) {
field = value
value?.let { lastPrice= it.totalPrice }
value?.let { lastPrice = it.totalPrice }
}

/**
* Returns the id of the shopping cart item
*/
@SerializedName("id")
var id: String? = null
private set

@SerializedName("isUsingSpecifiedQuantity")
private var isUsingSpecifiedQuantity = false

@Transient
Expand All @@ -985,24 +1011,29 @@ class ShoppingCart(
* Sets or Returns true if a manual coupon (coupon applied by the user after scanning) is applied
*/
@JvmField
@SerializedName("isManualCouponApplied")
var isManualCouponApplied = false

/**
* Gets the user associated coupon of this item
*/
@SerializedName("coupon")
var coupon: Coupon? = null

/**
* Returns the depositReturnVoucher associated with the shopping cart item.
*/
@SerializedName("depositReturnVoucher")
var depositReturnVoucher: DepositReturnVoucher? = null

/**
* Returns the deposit associated with the shopping cart item.
*/
var deposit : Deposit? = null
@SerializedName("deposit")
var deposit: Deposit? = null

// The local generated UUID of a coupon which which will be used by the backend
@SerializedName("backendCouponId")
var backendCouponId: String? = null

constructor(cart: ShoppingCart, coupon: Coupon, scannedCode: ScannedCode?) {
Expand Down Expand Up @@ -1195,7 +1226,9 @@ class ShoppingCart(
val totalPrice: Int
get() = lineItem?.totalPrice ?: localTotalPrice

@SerializedName("lastPrice")
private var lastPrice: Int = 0

/**
* Gets the total price of the items, ignoring the backend response
*/
Expand Down
30 changes: 16 additions & 14 deletions core/src/main/java/io/snabble/sdk/shoppingcart/ShoppingCartData.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.snabble.sdk.shoppingcart

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
import io.snabble.sdk.Product
import io.snabble.sdk.ViolationNotification
import io.snabble.sdk.shoppingcart.data.Taxation
Expand All @@ -9,20 +10,21 @@ import java.util.UUID

@Keep
data class ShoppingCartData @JvmOverloads constructor(
val id: String = UUID.randomUUID().toString(),
val uuid: String = UUID.randomUUID().toString(),
val lastModificationTime: Long = 0,
val items: MutableList<ShoppingCart.Item> = mutableListOf(),
@SerializedName("id") val id: String = UUID.randomUUID().toString(),
@SerializedName("uuid") val uuid: String = UUID.randomUUID().toString(),
@SerializedName("lastModificationTime") val lastModificationTime: Long = 0,
@SerializedName("items") val items: MutableList<ShoppingCart.Item> = mutableListOf(),
@SerializedName("violationNotifications")
val violationNotifications: MutableList<ViolationNotification> = mutableListOf(),
val modCount: Int = 0,
val addCount: Int = 0,
val onlineTotalPrice: Int? = null,
val invalidProducts: List<Product>? = null,
val invalidItemIds: List<String>? = null,
val taxation: Taxation = Taxation.UNDECIDED,
val hasReachedMaxCheckoutLimit: Boolean = false,
val hasReachedMaxOnlinePaymentLimit: Boolean = false,
val backupTimestamp: Long = 0,
@SerializedName("modCount") val modCount: Int = 0,
@SerializedName("addCount") val addCount: Int = 0,
@SerializedName("onlineTotalPrice") val onlineTotalPrice: Int? = null,
@SerializedName("invalidProducts") val invalidProducts: List<Product>? = null,
@SerializedName("invalidItemIds") val invalidItemIds: List<String>? = null,
@SerializedName("taxation") val taxation: Taxation = Taxation.UNDECIDED,
@SerializedName("hasReachedMaxCheckoutLimit") val hasReachedMaxCheckoutLimit: Boolean = false,
@SerializedName("hasReachedMaxOnlinePaymentLimit") val hasReachedMaxOnlinePaymentLimit: Boolean = false,
@SerializedName("backupTimestamp") val backupTimestamp: Long = 0,
) {

fun applyShoppingCart(shoppingCart: ShoppingCart) {
Expand All @@ -31,7 +33,7 @@ data class ShoppingCartData @JvmOverloads constructor(
}
}

fun deepCopy() : ShoppingCartData {
fun deepCopy(): ShoppingCartData {
val json = GsonHolder.get().toJson(this)
return GsonHolder.get().fromJson(json, ShoppingCartData::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ internal class ShoppingCartUpdater(
addCartDiscounts(filter { it.type == LineItemType.DISCOUNT && it.discountType == "cart" })
addLineItemsAsCartItems(filter { it.type == LineItemType.DISCOUNT && it.discountType != "cart" })

addLineItemsAsCartItems(filter { it.type == LineItemType.COUPON })
addCouponLineItems(filter { it.type == LineItemType.COUPON })
addDepositToItem(filter { it.type == LineItemType.DEPOSIT })
addDepositReturnsToVoucher(filter { it.type == LineItemType.DEPOSIT_RETURN })
}
Expand Down Expand Up @@ -199,9 +199,17 @@ internal class ShoppingCartUpdater(
}

private fun addCartDiscounts(cartDiscountItems: List<LineItem>) {
val totalCartDiscount = cartDiscountItems.sumOf { it.totalPrice }
val cartDiscounts = cartDiscountItems.mapNotNull { it.name }
addCartDiscountLineItem(totalCartDiscount, cartDiscounts)
val cartLevelDiscounts = cartDiscountItems.filter { it.refersTo == cart.id }
val itemLevelDiscounts = cartDiscountItems.filter { it.refersTo != cart.id }

if (cartLevelDiscounts.isNotEmpty()) {
val totalCartDiscount = cartLevelDiscounts.sumOf { it.totalPrice }
val cartDiscounts = cartLevelDiscounts.mapNotNull { it.name }
val discount = cartLevelDiscounts.firstOrNull { it.discountRuleID != null }
addCartDiscountLineItem(totalCartDiscount, cartDiscounts, discount?.discountRuleID)
}

addLineItemsAsCartItems(itemLevelDiscounts)
}

private fun deserializedCheckoutInfo(
Expand Down Expand Up @@ -238,13 +246,30 @@ internal class ShoppingCartUpdater(
}
}

private fun addCartDiscountLineItem(discounts: Int, cartDiscounts: List<String>) {
private fun addCouponLineItems(couponLineItems: List<LineItem>) {
couponLineItems.forEach { lineItem ->
val existing = cart.firstOrNull { it?.coupon?.id == lineItem.couponId }
if (existing != null) {
existing.lineItem = lineItem
existing.coupon?.isRedeemed = lineItem.redeemed
} else {
val newItem = cart.newItem(lineItem)
val coupon = project.coupons.get()?.find { it.id == lineItem.couponId }
coupon?.isRedeemed = lineItem.redeemed
newItem.coupon = coupon
cart.insert(newItem, cart.size(), false)
}
}
}

private fun addCartDiscountLineItem(discounts: Int, cartDiscounts: List<String>, discountRuleId: String?) {
if (discounts != 0) {
val lineItem = LineItem(
id = UUID.randomUUID().toString(),
amount = 1,
discountType = "cart",
name = cartDiscounts.first(),
name = cartDiscounts.firstOrNull(),
discountRuleID = discountRuleId,
price = discounts,
totalPrice = discounts,
type = LineItemType.DISCOUNT
Expand Down
Loading
Loading