diff --git a/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt index 1f59d332..26a2cf4d 100644 --- a/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt +++ b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt @@ -207,6 +207,13 @@ data class ContractProduct( override val image: String? = null, override val taxes: Set? = null, val quantity: Int = 1, + /** + * Quantity as a decimal string (since merchant protocol v25), preferred over + * [quantity], which is only the legacy integer part. + */ + @SerialName("unit_quantity") + val unitQuantity: String? = null, + val unit: String? = null, ) : OrderProduct() { val totalPrice: Amount? by lazy { price?.let { price * quantity } diff --git a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt index 3663d1d3..6870388f 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt @@ -379,25 +379,38 @@ fun ProductItem( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.End, ) { - // NAME + // NAME, prefixed with the quantity unless it is a single item + val name = product.productName?.takeIf { it.isNotBlank() } + ?: product.localizedDescription + val quantity = (product.unitQuantity ?: product.quantity.toString()).let { q -> + product.unit?.takeIf { it.isNotBlank() }?.let { "$q $it" } ?: q + } Text( - product.localizedDescription, + if (quantity != "1") { + stringResource(R.string.payment_product_price_quantity, quantity, name) + } else { + name + }, modifier = Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge, ) - // PRICE + // DESCRIPTION, if the name did not already show it + if (name != product.localizedDescription) { + Text( + product.localizedDescription, + modifier = Modifier.fillMaxWidth(), + style = MaterialTheme.typography.bodyMedium.copy( + color = ListItemDefaults.colors().supportingTextColor, + ), + ) + } + + // PRICE: the merchant already gives the total for this line + // (price of the quantity), it must not be multiplied again product.price?.let { price -> Text( - if (product.quantity > 1) { - stringResource( - R.string.payment_product_price_quantity, - product.quantity.toString(), - price.toString(), - ) - } else { - price.toString() - }, + price.toString(), style = MaterialTheme.typography.bodyMedium.copy( color = ListItemDefaults.colors().supportingTextColor, ),