taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

ContractTerms.kt (9223B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2020 Taler Systems S.A.
      4  *
      5  * GNU Taler is free software; you can redistribute it and/or modify it under the
      6  * terms of the GNU General Public License as published by the Free Software
      7  * Foundation; either version 3, or (at your option) any later version.
      8  *
      9  * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License along with
     14  * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 package net.taler.common
     18 
     19 import kotlinx.serialization.DeserializationStrategy
     20 import kotlinx.serialization.ExperimentalSerializationApi
     21 import kotlinx.serialization.EncodeDefault
     22 import kotlinx.serialization.SerialName
     23 import kotlinx.serialization.Serializable
     24 import kotlinx.serialization.json.JsonClassDiscriminator
     25 import kotlinx.serialization.json.JsonContentPolymorphicSerializer
     26 import kotlinx.serialization.json.JsonElement
     27 import kotlinx.serialization.json.intOrNull
     28 import kotlinx.serialization.json.jsonObject
     29 import kotlinx.serialization.json.jsonPrimitive
     30 
     31 @Serializable
     32 enum class ContractVersion(val version: Int) {
     33     V0(0),
     34     V1(1),
     35 }
     36 
     37 @OptIn(ExperimentalSerializationApi::class)
     38 @Serializable(with = ContractTermsSerializer::class)
     39 sealed class ContractTerms {
     40     abstract val version: ContractVersion
     41     abstract val summary: String
     42     abstract val summaryI18n: Map<String, String>?
     43     abstract val orderId: String
     44     abstract val fulfillmentUrl: String?
     45     abstract val fulfillmentMessage: String?
     46     abstract val fulfillmentMessageI18n: Map <String, String>?
     47     abstract val products: List<ContractProduct>?
     48     abstract val refundDeadline: Timestamp?
     49     abstract val payDeadline: Timestamp?
     50     abstract val wireTransferDeadline: Timestamp?
     51     abstract val merchantBaseUrl: String
     52     abstract val merchant: Merchant
     53     abstract val exchanges: List<Exchange>
     54     abstract val deliveryLocation: Location?
     55     abstract val deliveryDate: Timestamp?
     56 
     57     @Serializable
     58     @JsonClassDiscriminator("version")
     59     data class V0 (
     60         override val summary: String,
     61 
     62         @SerialName("summary_i18n")
     63         override val summaryI18n: Map<String, String>? = null,
     64 
     65         @SerialName("order_id")
     66         override val orderId: String,
     67 
     68         @SerialName("fulfillment_url")
     69         override val fulfillmentUrl: String? = null,
     70 
     71         @SerialName("fulfillment_message")
     72         override val fulfillmentMessage: String? = null,
     73 
     74         @SerialName("fulfillment_message_i18n")
     75         override val fulfillmentMessageI18n: Map<String, String>? = null,
     76 
     77         override val products: List<ContractProduct>? = null,
     78 
     79         @SerialName("refund_deadline")
     80         override val refundDeadline: Timestamp? = null,
     81 
     82         @SerialName("pay_deadline")
     83         override val payDeadline: Timestamp? = null,
     84 
     85         @SerialName("wire_transfer_deadline")
     86         override val wireTransferDeadline: Timestamp? = null,
     87 
     88         @SerialName("merchant_base_url")
     89         override val merchantBaseUrl: String,
     90 
     91         override val merchant: Merchant,
     92 
     93         override val exchanges: List<Exchange> = listOf(),
     94 
     95         @SerialName("delivery_location")
     96         override val deliveryLocation: Location? = null,
     97 
     98         @SerialName("delivery_date")
     99         override val deliveryDate: Timestamp? = null,
    100 
    101         val amount: Amount,
    102 
    103         @SerialName("max_fee")
    104         val maxFee: Amount,
    105     ) : ContractTerms() {
    106         override val version: ContractVersion = ContractVersion.V0
    107     }
    108 
    109     @Serializable
    110     @JsonClassDiscriminator("version")
    111     data class V1 (
    112         override val summary: String,
    113 
    114         @SerialName("summary_i18n")
    115         override val summaryI18n: Map<String, String>? = null,
    116 
    117         @SerialName("order_id")
    118         override val orderId: String,
    119 
    120         @SerialName("fulfillment_url")
    121         override val fulfillmentUrl: String? = null,
    122 
    123         @SerialName("fulfillment_message")
    124         override val fulfillmentMessage: String? = null,
    125 
    126         @SerialName("fulfillment_message_i18n")
    127         override val fulfillmentMessageI18n: Map<String, String>? = null,
    128 
    129         override val products: List<ContractProduct>? = null,
    130 
    131         @SerialName("refund_deadline")
    132         override val refundDeadline: Timestamp? = null,
    133 
    134         @SerialName("pay_deadline")
    135         override val payDeadline: Timestamp? = null,
    136 
    137         @SerialName("wire_transfer_deadline")
    138         override val wireTransferDeadline: Timestamp? = null,
    139 
    140         @SerialName("merchant_base_url")
    141         override val merchantBaseUrl: String,
    142 
    143         override val merchant: Merchant,
    144 
    145         override val exchanges: List<Exchange> = listOf(),
    146 
    147         @SerialName("delivery_location")
    148         override val deliveryLocation: Location? = null,
    149 
    150         @SerialName("delivery_date")
    151         override val deliveryDate: Timestamp? = null,
    152 
    153         val choices: List<ContractChoice>,
    154 
    155         @SerialName("token_families")
    156         val tokenFamilies: Map<String, ContractTokenFamily>,
    157     ) : ContractTerms() {
    158         override val version: ContractVersion = ContractVersion.V1
    159     }
    160 }
    161 
    162 @Serializable
    163 data class Merchant(
    164     val name: String,
    165     val email: String? = null,
    166     val website: String? = null,
    167     val logo: String? = null,
    168     val address: Location? = null,
    169     val jurisdiction: Location? = null
    170 )
    171 
    172 @Serializable
    173 data class Location(
    174     val country: String? = null,
    175     @SerialName("country_subdivision")
    176     val countrySubdivision: String? = null,
    177     val district: String? = null,
    178     val town: String? = null,
    179     @SerialName("town_location")
    180     val townLocation: String? = null,
    181     @SerialName("post_code")
    182     val postCode: String? = null,
    183     val street: String? = null,
    184     @SerialName("building_name")
    185     val buildingName: String? = null,
    186     @SerialName("building_number")
    187     val buildingNumber: String? = null,
    188     @SerialName("address_lines")
    189     val addressLines: List<String>? = null,
    190 )
    191 
    192 @Serializable
    193 data class ContractProduct(
    194     @SerialName("product_id")
    195     override val productId: String? = null,
    196     @SerialName("product_name")
    197     override val productName: String? = null,
    198     override val description: String,
    199     @SerialName("description_i18n")
    200     override val descriptionI18n: Map<String, String>? = null,
    201     override val price: Amount? = null,
    202     @SerialName("prices_are_net")
    203     @EncodeDefault
    204     val pricesAreNet: Boolean = false,
    205     @SerialName("delivery_location")
    206     override val location: String? = null,
    207     override val image: String? = null,
    208     override val taxes: Set<Tax>? = null,
    209     val quantity: Int = 1,
    210 ) : OrderProduct() {
    211     val totalPrice: Amount? by lazy {
    212         price?.let { price * quantity }
    213     }
    214 }
    215 
    216 @Serializable
    217 data class Exchange(
    218     val url: String,
    219 )
    220 
    221 @Serializable
    222 data class Tax(
    223     val name: String,
    224     val tax: Amount,
    225 )
    226 
    227 @Serializable
    228 data class ContractChoice(
    229     val amount: Amount,
    230     val description: String? = null,
    231     @SerialName("description_i18n")
    232     val descriptionI18n: Map<String, String>? = null,
    233     val inputs: List<ContractInput>,
    234     val outputs: List<ContractOutput>,
    235     @SerialName("max_fee")
    236     val maxFee: Amount,
    237 )
    238 
    239 @Serializable
    240 @OptIn(ExperimentalSerializationApi::class)
    241 @JsonClassDiscriminator("type")
    242 sealed class ContractInput {
    243     @Serializable
    244     @SerialName("token")
    245     data class Token(
    246         @SerialName("token_family_slug")
    247         val tokenFamilySlug: String,
    248         val count: Int = 1,
    249     ): ContractInput()
    250 }
    251 
    252 @Serializable
    253 @OptIn(ExperimentalSerializationApi::class)
    254 @JsonClassDiscriminator("type")
    255 sealed class ContractOutput {
    256     @Serializable
    257     @SerialName("token")
    258     data class Token(
    259         @SerialName("token_family_slug")
    260         val tokenFamilySlug: String,
    261         val count: Int = 1,
    262     ): ContractOutput()
    263 
    264     @Serializable
    265     @SerialName("tax-receipt")
    266     data class TaxReceipt(
    267         val amount: Amount,
    268         @SerialName("donau_urls")
    269         val donauUrls: List<String>,
    270     ): ContractOutput()
    271 }
    272 
    273 @Serializable
    274 data class ContractTokenFamily(
    275     val name: String,
    276     val description: String,
    277     val descriptionI18n: Map<String, String>? = null,
    278     val details: ContractTokenDetails,
    279     val critical: Boolean,
    280 )
    281 
    282 @OptIn(ExperimentalSerializationApi::class)
    283 @Serializable
    284 @JsonClassDiscriminator("class")
    285 sealed class ContractTokenDetails {
    286     @Serializable
    287     @SerialName("subscription")
    288     data object Subscription: ContractTokenDetails()
    289 
    290     @Serializable
    291     @SerialName("discount")
    292     data object Discount: ContractTokenDetails()
    293 }
    294 
    295 object ContractTermsSerializer : JsonContentPolymorphicSerializer<ContractTerms>(ContractTerms::class) {
    296     override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ContractTerms> {
    297         return when(val type = element.jsonObject["version"]?.jsonPrimitive?.intOrNull) {
    298             null, 0 -> ContractTerms.V0.serializer()
    299             1 -> ContractTerms.V1.serializer()
    300             else -> error("unknown contract version $type")
    301         }
    302     }
    303 }