OrderHistory.kt
/*
* This file is part of GNU Taler
* (C) 2020 Taler Systems S.A.
*
* GNU Taler is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3, or (at your option) any later version.
*
* GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
package net.taler.merchantlib
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonNames
import net.taler.common.Amount
import net.taler.common.ExternalPayment
import net.taler.common.Timestamp
@Serializable
data class OrderHistory(
val orders: List<OrderHistoryEntry>
)
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class OrderHistoryEntry(
// order ID of the transaction related to this entry.
@SerialName("order_id")
val orderId: String,
// row ID of the order in the database
@SerialName("row_id")
val rowId: Long? = null,
// when the order was created
val timestamp: Timestamp,
// Taler portion only; keep this unchanged for payment and refund operations.
val amount: Amount,
// the summary of the order
val summary: String,
// if the order has been paid
val paid: Boolean,
// whether some part of the order is refundable
val refundable: Boolean,
// whether the order has already been refunded
val refunded: Boolean = false,
// total refunded amount approved for this order
@JsonNames("refund_amount", "refunded_amount")
val refundAmount: Amount? = null,
// portion of refund amount not yet obtained by the wallet
@JsonNames("pending_refund_amount", "refund_pending_amount")
val pendingRefundAmount: Amount? = null,
// whether the backend still reports wallet pickup as pending
val refundPending: Boolean = false,
// Null until details are loaded (older backends may omit them).
@SerialName("amount_external")
val amountExternal: List<ExternalPayment>? = null,
@SerialName("refunds_external")
val refundsExternal: List<ExternalRefundInfo> = emptyList(),
@Transient val claimed: Boolean = false,
) {
val externalAmount: Amount
get() = amountExternal.orEmpty().fold(Amount.zero(amount.currency)) { sum, payment -> sum + payment.amount }
val totalAmount: Amount get() = amount + externalAmount
val totalRefundAmount: Amount
get() = refundsExternal.fold(refundAmount ?: Amount.zero(amount.currency)) { sum, refund -> sum + refund.amount }
val hasExternalPayments: Boolean get() = !externalAmount.isZero()
val hasAnyRefund: Boolean get() = hasRefund || refundsExternal.isNotEmpty()
/** Merge order status without substituting the full sale total for the Taler amount. */
fun withPaymentDetails(response: CheckPaymentResponse): OrderHistoryEntry {
val updated = copy(
paid = response.paid,
claimed = response is CheckPaymentResponse.Claimed,
amountExternal = response.paymentDetails?.amountExternal ?: amountExternal,
)
return if (response is CheckPaymentResponse.Paid) updated.copy(
refunded = response.refunded,
refundAmount = response.refundAmount ?: refundAmount,
refundPending = response.refundPending,
refundsExternal = response.refundsExternal,
) else updated
}
val hasRefund: Boolean
get() = refunded || refundAmount?.isZero() == false
val hasPendingRefund: Boolean
get() = refundPending || pendingRefundAmount?.isZero() == false
}