1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-12-22 08:37:12 +00:00

add support for subscriptions

This commit is contained in:
InsanusMokrassar 2024-12-05 11:35:33 +06:00
parent 32010cf1c7
commit 652765bf46
11 changed files with 194 additions and 9 deletions

View File

@ -0,0 +1,65 @@
package dev.inmo.tgbotapi.extensions.api.edit.payments
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.edit.payments.EditUserStarSubscription
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.payments.abstracts.TelegramPaymentChargeId
public suspend fun TelegramBot.editUserStarSubscription(
userId: UserId,
telegramPaymentChargeId: TelegramPaymentChargeId,
isCanceled: Boolean
): Boolean = execute(
EditUserStarSubscription(
userId = userId,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = isCanceled
)
)
public suspend fun TelegramBot.editUserStarSubscription(
user: User,
telegramPaymentChargeId: TelegramPaymentChargeId,
isCanceled: Boolean
): Boolean = editUserStarSubscription(
userId = user.id,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = isCanceled
)
public suspend fun TelegramBot.cancelUserStarSubscription(
userId: UserId,
telegramPaymentChargeId: TelegramPaymentChargeId,
): Boolean = editUserStarSubscription(
userId = userId,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = true
)
public suspend fun TelegramBot.cancelUserStarSubscription(
user: User,
telegramPaymentChargeId: TelegramPaymentChargeId,
): Boolean = editUserStarSubscription(
user = user,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = true
)
public suspend fun TelegramBot.enableUserStarSubscription(
userId: UserId,
telegramPaymentChargeId: TelegramPaymentChargeId,
): Boolean = editUserStarSubscription(
userId = userId,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = false
)
public suspend fun TelegramBot.enableUserStarSubscription(
user: User,
telegramPaymentChargeId: TelegramPaymentChargeId,
): Boolean = editUserStarSubscription(
user = user,
telegramPaymentChargeId = telegramPaymentChargeId,
isCanceled = false
)

View File

@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.abstracts.types
import korlibs.time.TimeSpan
interface SubscriptionInfo : SubscriptionPeriodInfo {
val subscriptionPrice: UInt?
}

View File

@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.abstracts.types
import korlibs.time.TimeSpan
interface SubscriptionPeriodInfo {
val subscriptionPeriod: TimeSpan?
}

View File

@ -1,5 +1,7 @@
package dev.inmo.tgbotapi.requests.chat.invite_links package dev.inmo.tgbotapi.requests.chat.invite_links
import dev.inmo.tgbotapi.abstracts.types.SubscriptionInfo
import dev.inmo.tgbotapi.abstracts.types.SubscriptionPeriodInfo
import korlibs.time.DateTime import korlibs.time.DateTime
import dev.inmo.tgbotapi.requests.chat.abstracts.* import dev.inmo.tgbotapi.requests.chat.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -15,9 +17,9 @@ sealed interface CreateChatInviteLink<R : SecondaryChatInviteLink> : EditChatInv
override fun method(): String = "createChatInviteLink" override fun method(): String = "createChatInviteLink"
sealed interface Subscription : CreateChatInviteLink<ChatInviteLinkUnlimited> { sealed interface Subscription : CreateChatInviteLink<ChatInviteLinkUnlimited>, SubscriptionInfo {
val subscriptionPeriod: TimeSpan override val subscriptionPeriod: TimeSpan
val subscriptionPrice: UInt override val subscriptionPrice: UInt
override fun method(): String = "createChatSubscriptionInviteLink" override fun method(): String = "createChatSubscriptionInviteLink"
} }

View File

@ -0,0 +1,32 @@
package dev.inmo.tgbotapi.requests.edit.payments
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.isCanceledField
import dev.inmo.tgbotapi.types.payments.abstracts.TelegramPaymentChargeId
import dev.inmo.tgbotapi.types.telegramPaymentChargeIdField
import dev.inmo.tgbotapi.types.userIdField
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.builtins.serializer
@Serializable
data class EditUserStarSubscription(
@SerialName(userIdField)
val userId: UserId,
@SerialName(telegramPaymentChargeIdField)
val telegramPaymentChargeId: TelegramPaymentChargeId,
@SerialName(isCanceledField)
val isCanceled: Boolean
) : SimpleRequest<Boolean> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "editUserStarSubscription"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
}

View File

@ -3,8 +3,8 @@ package dev.inmo.tgbotapi.requests.send.payments
import dev.inmo.tgbotapi.abstracts.CommonSendInvoiceData import dev.inmo.tgbotapi.abstracts.CommonSendInvoiceData
import dev.inmo.tgbotapi.abstracts.types.* import dev.inmo.tgbotapi.abstracts.types.*
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.InvoiceContent import dev.inmo.tgbotapi.types.message.content.InvoiceContent
@ -12,6 +12,8 @@ import dev.inmo.tgbotapi.types.payments.LabeledPrice
import dev.inmo.tgbotapi.types.payments.LabeledPricesSerializer import dev.inmo.tgbotapi.types.payments.LabeledPricesSerializer
import dev.inmo.tgbotapi.types.payments.abstracts.Currency import dev.inmo.tgbotapi.types.payments.abstracts.Currency
import dev.inmo.tgbotapi.types.payments.abstracts.XTR import dev.inmo.tgbotapi.types.payments.abstracts.XTR
import dev.inmo.tgbotapi.utils.TimeSpanAsSecondsSerializer
import korlibs.time.TimeSpan
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
@ -30,9 +32,14 @@ data class CreateInvoiceLink(
override val providerToken: String?, override val providerToken: String?,
@SerialName(currencyField) @SerialName(currencyField)
override val currency: Currency, override val currency: Currency,
@SerialName(businessConnectionIdField)
override val businessConnectionId: BusinessConnectionId? = null,
@Serializable(LabeledPricesSerializer::class) @Serializable(LabeledPricesSerializer::class)
@SerialName(pricesField) @SerialName(pricesField)
override val prices: List<LabeledPrice>, override val prices: List<LabeledPrice>,
@SerialName(subscriptionPeriodField)
@Serializable(TimeSpanAsSecondsSerializer::class)
override val subscriptionPeriod: TimeSpan? = null,
@SerialName(maxTipAmountField) @SerialName(maxTipAmountField)
override val maxTipAmount: Int? = null, override val maxTipAmount: Int? = null,
@SerialName(suggestedTipAmountsField) @SerialName(suggestedTipAmountsField)
@ -53,7 +60,7 @@ data class CreateInvoiceLink(
override val shouldSendEmailToProvider: Boolean = false, override val shouldSendEmailToProvider: Boolean = false,
@SerialName(priceDependOnShipAddressField) @SerialName(priceDependOnShipAddressField)
override val priceDependOnShipAddress: Boolean = false override val priceDependOnShipAddress: Boolean = false
) : CommonSendInvoiceData, SimpleRequest<String> { ) : CommonSendInvoiceData, SimpleRequest<String>, WithOptionalBusinessConnectionId, SubscriptionPeriodInfo {
override fun method(): String = "createInvoiceLink" override fun method(): String = "createInvoiceLink"
override val resultDeserializer: DeserializationStrategy<String> override val resultDeserializer: DeserializationStrategy<String>
get() = String.serializer() get() = String.serializer()
@ -137,4 +144,8 @@ data class CreateInvoiceLink(
photoWidth = null photoWidth = null
photoHeight = null photoHeight = null
} }
companion object {
const val DEFAULT: Seconds = 2592000 // 30 days
}
} }

View File

@ -2,8 +2,12 @@ package dev.inmo.tgbotapi.types
import korlibs.time.DateTime import korlibs.time.DateTime
import dev.inmo.tgbotapi.abstracts.WithUser import dev.inmo.tgbotapi.abstracts.WithUser
import dev.inmo.tgbotapi.abstracts.types.SubscriptionInfo
import dev.inmo.tgbotapi.abstracts.types.SubscriptionPeriodInfo
import dev.inmo.tgbotapi.types.chat.User import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.TimeSpanAsSecondsSerializer
import korlibs.time.TimeSpan
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
@ -64,7 +68,7 @@ sealed interface ChatInviteLink : WithUser {
* Base interface for all [ChatInviteLink]s which are NOT [PrimaryInviteLink] * Base interface for all [ChatInviteLink]s which are NOT [PrimaryInviteLink]
*/ */
@Serializable(ChatInviteLinkSerializer::class) @Serializable(ChatInviteLinkSerializer::class)
sealed interface SecondaryChatInviteLink : ChatInviteLink { sealed interface SecondaryChatInviteLink : ChatInviteLink, SubscriptionInfo {
override val isPrimary: Boolean override val isPrimary: Boolean
get() = false get() = false
} }
@ -108,7 +112,12 @@ data class ChatInviteLinkWithJoinRequest(
@SerialName(isRevokedField) @SerialName(isRevokedField)
override val isRevoked: Boolean = false, override val isRevoked: Boolean = false,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expireDate: TelegramDate? = null private val expireDate: TelegramDate? = null,
@SerialName(subscriptionPeriodField)
@Serializable(TimeSpanAsSecondsSerializer::class)
override val subscriptionPeriod: TimeSpan? = null,
@SerialName(subscriptionPriceField)
override val subscriptionPrice: UInt? = null
) : SecondaryChatInviteLink { ) : SecondaryChatInviteLink {
override val expirationDateTime: DateTime? override val expirationDateTime: DateTime?
get() = expireDate ?.asDate get() = expireDate ?.asDate
@ -131,6 +140,11 @@ data class ChatInviteLinkWithLimitedMembers(
override val isRevoked: Boolean = false, override val isRevoked: Boolean = false,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expireDate: TelegramDate? = null, private val expireDate: TelegramDate? = null,
@SerialName(subscriptionPeriodField)
@Serializable(TimeSpanAsSecondsSerializer::class)
override val subscriptionPeriod: TimeSpan? = null,
@SerialName(subscriptionPriceField)
override val subscriptionPrice: UInt? = null
) : SecondaryChatInviteLink { ) : SecondaryChatInviteLink {
override val expirationDateTime: DateTime? override val expirationDateTime: DateTime?
get() = expireDate ?.asDate get() = expireDate ?.asDate
@ -152,6 +166,11 @@ data class ChatInviteLinkUnlimited(
override val isRevoked: Boolean = false, override val isRevoked: Boolean = false,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expireDate: TelegramDate? = null, private val expireDate: TelegramDate? = null,
@SerialName(subscriptionPeriodField)
@Serializable(TimeSpanAsSecondsSerializer::class)
override val subscriptionPeriod: TimeSpan? = null,
@SerialName(subscriptionPriceField)
override val subscriptionPrice: UInt? = null
) : SecondaryChatInviteLink { ) : SecondaryChatInviteLink {
override val expirationDateTime: DateTime? override val expirationDateTime: DateTime?
get() = expireDate ?.asDate get() = expireDate ?.asDate

View File

@ -535,7 +535,11 @@ const val secondStreetLineField = "street_line2"
const val postCodeField = "post_code" const val postCodeField = "post_code"
const val shippingAddressField = "shipping_address" const val shippingAddressField = "shipping_address"
const val orderInfoField = "order_info" const val orderInfoField = "order_info"
const val subscriptionExpirationDateField = "subscription_expiration_date"
const val isRecurringField = "is_recurring"
const val isFirstRecurringField = "is_first_recurring"
const val telegramPaymentChargeIdField = "telegram_payment_charge_id" const val telegramPaymentChargeIdField = "telegram_payment_charge_id"
const val isCanceledField = "is_canceled"
const val providerPaymentChargeIdField = "provider_payment_charge_id" const val providerPaymentChargeIdField = "provider_payment_charge_id"
const val providerTokenField = "provider_token" const val providerTokenField = "provider_token"
const val providerDataField = "provider_data" const val providerDataField = "provider_data"

View File

@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.types.payments
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.isFirstRecurringField
import dev.inmo.tgbotapi.types.subscriptionExpirationDateField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class RecurringInfo(
@SerialName(subscriptionExpirationDateField)
val subscriptionExpirationDate: TelegramDate,
@SerialName(isFirstRecurringField)
val firstSubscriptionPeriod: Boolean
)

View File

@ -13,6 +13,12 @@ data class SuccessfulPayment(
override val amount: Long, override val amount: Long,
@SerialName(invoicePayloadField) @SerialName(invoicePayloadField)
val invoicePayload: String, val invoicePayload: String,
@SerialName(subscriptionExpirationDateField)
val subscriptionExpirationDate: TelegramDate? = null,
@SerialName(isRecurringField)
val subscriptionPayment: Boolean? = null,
@SerialName(isFirstRecurringField)
val isFirstPeriodPayment: Boolean? = null,
@SerialName(telegramPaymentChargeIdField) @SerialName(telegramPaymentChargeIdField)
val telegramPaymentChargeId: TelegramPaymentChargeId, val telegramPaymentChargeId: TelegramPaymentChargeId,
@SerialName(providerPaymentChargeIdField) @SerialName(providerPaymentChargeIdField)
@ -21,4 +27,15 @@ data class SuccessfulPayment(
val shippingOptionId: String? = null, val shippingOptionId: String? = null,
@SerialName(orderInfoField) @SerialName(orderInfoField)
val orderInfo: OrderInfo? = null val orderInfo: OrderInfo? = null
) : Amounted, Currencied ) : Amounted, Currencied {
val recurringInfo: RecurringInfo? by lazy {
if (subscriptionPayment == true && subscriptionExpirationDate != null) {
RecurringInfo(
subscriptionExpirationDate,
isFirstPeriodPayment == true,
)
} else {
null
}
}
}

View File

@ -2,12 +2,15 @@
package dev.inmo.tgbotapi.types.payments.stars package dev.inmo.tgbotapi.types.payments.stars
import dev.inmo.tgbotapi.abstracts.types.SubscriptionPeriodInfo
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.PreviewUser import dev.inmo.tgbotapi.types.chat.PreviewUser
import dev.inmo.tgbotapi.types.gifts.Gift import dev.inmo.tgbotapi.types.gifts.Gift
import dev.inmo.tgbotapi.types.message.payments.PaidMedia import dev.inmo.tgbotapi.types.message.payments.PaidMedia
import dev.inmo.tgbotapi.utils.TimeSpanAsSecondsSerializer
import dev.inmo.tgbotapi.utils.decodeDataAndJson import dev.inmo.tgbotapi.utils.decodeDataAndJson
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import korlibs.time.TimeSpan
import kotlinx.serialization.EncodeDefault import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -43,13 +46,16 @@ sealed interface TransactionPartner {
val user: PreviewUser, val user: PreviewUser,
@SerialName(invoicePayloadField) @SerialName(invoicePayloadField)
val invoicePayload: InvoicePayload? = null, val invoicePayload: InvoicePayload? = null,
@SerialName(subscriptionPeriodField)
@Serializable(TimeSpanAsSecondsSerializer::class)
override val subscriptionPeriod: TimeSpan? = null,
@SerialName(paidMediaField) @SerialName(paidMediaField)
val paidMedia: List<PaidMedia>? = null, val paidMedia: List<PaidMedia>? = null,
@SerialName(paidMediaPayloadField) @SerialName(paidMediaPayloadField)
val paidMediaPayload: PaidMediaPayload? = null, val paidMediaPayload: PaidMediaPayload? = null,
@SerialName(giftField) @SerialName(giftField)
val gift: Gift? = null val gift: Gift? = null
) : TransactionPartner { ) : TransactionPartner, SubscriptionPeriodInfo {
@EncodeDefault @EncodeDefault
override val type: String = Companion.type override val type: String = Companion.type