diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 9a97d60d58..bc868747f0 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -509,6 +509,7 @@ const val showAboveTextField = "show_above_text" const val isDisabledField = "is_disabled" const val preferSmallMediaField = "prefer_small_media" const val preferLargeMediaField = "prefer_large_media" +const val withdrawalStateField = "withdrawal_state" const val requireNameField = "need_name" const val requirePhoneNumberField = "need_phone_number" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt new file mode 100644 index 0000000000..0be81e66bf --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt @@ -0,0 +1,92 @@ +package dev.inmo.tgbotapi.types.payments.stars + +import dev.inmo.tgbotapi.types.TelegramDate +import dev.inmo.tgbotapi.utils.decodeDataAndJson +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonElement + +@Suppress("SERIALIZER_TYPE_INCOMPATIBLE") +@Serializable(RevenueWithdrawalState.Companion::class) +sealed interface RevenueWithdrawalState { + val type: String + + @Serializable(RevenueWithdrawalState.Companion::class) + data object Pending : RevenueWithdrawalState { + override val type: String + get() = "pending" + } + + @Serializable(RevenueWithdrawalState.Companion::class) + data class Succeeded( + val date: TelegramDate, + val url: String + ) : RevenueWithdrawalState { + override val type: String + get() = Companion.type + companion object { + const val type: String = "succeeded" + } + } + + @Serializable(RevenueWithdrawalState.Companion::class) + data object Failed : RevenueWithdrawalState { + override val type: String + get() = "failed" + } + + @Serializable(RevenueWithdrawalState.Companion::class) + data class Unknown( + override val type: String, + val raw: JsonElement? + ) : RevenueWithdrawalState + + companion object : KSerializer { + @Serializable + private data class Surrogate( + val type: String, + val date: TelegramDate? = null, + val url: String? = null + ) + + override val descriptor: SerialDescriptor + get() = Surrogate.serializer().descriptor + + override fun deserialize(decoder: Decoder): RevenueWithdrawalState { + val (data, json) = decoder.decodeDataAndJson(Surrogate.serializer()) + + val unknown by lazy { + Unknown(data.type, json) + } + return when (data.type) { + Pending.type -> Pending + Failed.type -> Failed + Succeeded.type -> Succeeded( + data.date ?: return unknown, + data.url ?: return unknown, + ) + else -> unknown + } + } + + override fun serialize(encoder: Encoder, value: RevenueWithdrawalState) { + val surrogate = when (value) { + Failed -> Surrogate(value.type) + Pending -> Surrogate(value.type) + is Succeeded -> Surrogate( + value.type, + value.date, + value.url + ) + is Unknown -> value.raw ?.let { + return JsonElement.serializer().serialize(encoder, it) + } ?: Surrogate(value.type) + } + + Surrogate.serializer().serialize(encoder, surrogate) + } + } +} \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt new file mode 100644 index 0000000000..990156c928 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt @@ -0,0 +1,109 @@ +package dev.inmo.tgbotapi.types.payments.stars + +import dev.inmo.tgbotapi.types.TelegramDate +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.chat.PreviewUser +import dev.inmo.tgbotapi.types.userField +import dev.inmo.tgbotapi.types.withdrawalStateField +import dev.inmo.tgbotapi.utils.decodeDataAndJson +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonElement + +@Suppress("SERIALIZER_TYPE_INCOMPATIBLE") +@Serializable(StarTransaction.Companion::class) +sealed interface StarTransaction { + val amount: Int + val date: TelegramDate + val partner: TransactionPartner + val source: TransactionPartner? + val receiver: TransactionPartner? + + @Serializable(StarTransaction.Companion::class) + data class Incoming( + + ) : StarTransaction { + override val type: String + get() = Companion.type + + companion object { + const val type: String = "fragment" + } + } + + @Serializable(StarTransaction.Companion::class) + data class User( + @SerialName(userField) + val user: PreviewUser + ) : StarTransaction { + override val type: String + get() = Companion.type + + companion object { + const val type: String = "user" + } + } + + @Serializable(StarTransaction.Companion::class) + data object Other : StarTransaction { + override val type: String = "other" + } + + @Serializable(StarTransaction.Companion::class) + data class Unknown( + override val type: String, + val raw: JsonElement? + ) : StarTransaction + + companion object : KSerializer { + @Serializable + private data class Surrogate( + val type: String, + val amount: Int, + val date: TelegramDate, + val source: TransactionPartner?, + val receiver: TransactionPartner?, + ) + + override val descriptor: SerialDescriptor + get() = Surrogate.serializer().descriptor + + override fun deserialize(decoder: Decoder): StarTransaction { + val (data, json) = decoder.decodeDataAndJson(Surrogate.serializer()) + + val unknown by lazy { + Unknown(data.type, json) + } + return when (data.type) { + Other.type -> Other + User.type -> User( + data.user ?: return unknown, + ) + Fragment.type -> Fragment( + data.withdrawal_state ?: return unknown, + ) + else -> unknown + } + } + + override fun serialize(encoder: Encoder, value: StarTransaction) { + val surrogate = when (value) { + Other -> Surrogate(value.type) + is User -> Surrogate(value.type, user = value.user) + is Fragment -> Surrogate( + value.type, + value.withdrawalState + ) + is Unknown -> value.raw ?.let { + return JsonElement.serializer().serialize(encoder, it) + } ?: Surrogate(value.type) + } + + Surrogate.serializer().serialize(encoder, surrogate) + } + } +} \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt new file mode 100644 index 0000000000..7dcfd98eb2 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt @@ -0,0 +1,102 @@ +package dev.inmo.tgbotapi.types.payments.stars + +import dev.inmo.tgbotapi.types.chat.PreviewUser +import dev.inmo.tgbotapi.types.userField +import dev.inmo.tgbotapi.types.withdrawalStateField +import dev.inmo.tgbotapi.utils.decodeDataAndJson +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonElement + +@Suppress("SERIALIZER_TYPE_INCOMPATIBLE") +@Serializable(TransactionPartner.Companion::class) +sealed interface TransactionPartner { + val type: String + + @Serializable(TransactionPartner.Companion::class) + data class Fragment( + @SerialName(withdrawalStateField) + val withdrawalState: RevenueWithdrawalState + ) : TransactionPartner { + override val type: String + get() = Companion.type + + companion object { + const val type: String = "fragment" + } + } + + @Serializable(TransactionPartner.Companion::class) + data class User( + @SerialName(userField) + val user: PreviewUser + ) : TransactionPartner { + override val type: String + get() = Companion.type + + companion object { + const val type: String = "user" + } + } + + @Serializable(TransactionPartner.Companion::class) + data object Other : TransactionPartner { + override val type: String = "other" + } + + @Serializable(TransactionPartner.Companion::class) + data class Unknown( + override val type: String, + val raw: JsonElement? + ) : TransactionPartner + + companion object : KSerializer { + @Serializable + private data class Surrogate( + val type: String, + val withdrawal_state: RevenueWithdrawalState? = null, + val user: PreviewUser? = null + ) + + override val descriptor: SerialDescriptor + get() = Surrogate.serializer().descriptor + + override fun deserialize(decoder: Decoder): TransactionPartner { + val (data, json) = decoder.decodeDataAndJson(Surrogate.serializer()) + + val unknown by lazy { + Unknown(data.type, json) + } + return when (data.type) { + Other.type -> Other + User.type -> User( + data.user ?: return unknown, + ) + Fragment.type -> Fragment( + data.withdrawal_state ?: return unknown, + ) + else -> unknown + } + } + + override fun serialize(encoder: Encoder, value: TransactionPartner) { + val surrogate = when (value) { + Other -> Surrogate(value.type) + is User -> Surrogate(value.type, user = value.user) + is Fragment -> Surrogate( + value.type, + value.withdrawalState + ) + is Unknown -> value.raw ?.let { + return JsonElement.serializer().serialize(encoder, it) + } ?: Surrogate(value.type) + } + + Surrogate.serializer().serialize(encoder, surrogate) + } + } +} \ No newline at end of file