Skip to content

Bot API 8.0: Add New Attributes to SuccessfulPayment #4570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions telegram/_payment/successfulpayment.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram SuccessfulPayment."""

import datetime as dtm
from typing import TYPE_CHECKING, Optional

from telegram._payment.orderinfo import OrderInfo
from telegram._telegramobject import TelegramObject
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict

if TYPE_CHECKING:
Expand All @@ -45,6 +47,17 @@ class SuccessfulPayment(TelegramObject):
it shows the number of digits past the decimal point for each currency
(2 for the majority of currencies).
invoice_payload (:obj:`str`): Bot-specified invoice payload.
subscription_expiration_date (:class:`datetime.datetime`, optional): Expiration date of the
subscription; for recurring payments only.

.. versionadded:: NEXT.VERSION
is_recurring (:obj:`bool`, optional): True, if the payment is for a subscription.

.. versionadded:: NEXT.VERSION
is_first_recurring (:obj:`bool`, optional): True, if the payment is the first payment of a
subscription.

.. versionadded:: NEXT.VERSION
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
user.
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
Expand All @@ -61,6 +74,17 @@ class SuccessfulPayment(TelegramObject):
it shows the number of digits past the decimal point for each currency
(2 for the majority of currencies).
invoice_payload (:obj:`str`): Bot-specified invoice payload.
subscription_expiration_date (:class:`datetime.datetime`): Optional. Expiration
date of the subscription; for recurring payments only.

.. versionadded:: NEXT.VERSION
is_recurring (:obj:`bool`): Optional. True, if the payment is for a subscription.

.. versionadded:: NEXT.VERSION
is_first_recurring (:obj:`bool`): Optional. True, if the payment is the first payment of a
subscription.

.. versionadded:: NEXT.VERSION
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
user.
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
Expand All @@ -72,9 +96,12 @@ class SuccessfulPayment(TelegramObject):
__slots__ = (
"currency",
"invoice_payload",
"is_first_recurring",
"is_recurring",
"order_info",
"provider_payment_charge_id",
"shipping_option_id",
"subscription_expiration_date",
"telegram_payment_charge_id",
"total_amount",
)
Expand All @@ -88,6 +115,9 @@ def __init__(
provider_payment_charge_id: str,
shipping_option_id: Optional[str] = None,
order_info: Optional[OrderInfo] = None,
subscription_expiration_date: Optional[dtm.datetime] = None,
is_recurring: Optional[bool] = None,
is_first_recurring: Optional[bool] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
Expand All @@ -99,6 +129,9 @@ def __init__(
self.order_info: Optional[OrderInfo] = order_info
self.telegram_payment_charge_id: str = telegram_payment_charge_id
self.provider_payment_charge_id: str = provider_payment_charge_id
self.subscription_expiration_date: Optional[dtm.datetime] = subscription_expiration_date
self.is_recurring: Optional[bool] = is_recurring
self.is_first_recurring: Optional[bool] = is_first_recurring

self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)

Expand All @@ -116,4 +149,11 @@ def de_json(

data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot)

# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)

data["subscription_expiration_date"] = from_timestamp(
data.get("subscription_expiration_date"), tzinfo=loc_tzinfo
)

return super().de_json(data=data, bot=bot)
45 changes: 45 additions & 0 deletions tests/_payment/test_successfulpayment.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import datetime as dtm

import pytest

from telegram import OrderInfo, SuccessfulPayment
from telegram._utils.datetime import UTC, to_timestamp
from tests.auxil.slots import mro_slots


Expand All @@ -32,6 +35,9 @@ def successful_payment():
SuccessfulPaymentTestBase.provider_payment_charge_id,
shipping_option_id=SuccessfulPaymentTestBase.shipping_option_id,
order_info=SuccessfulPaymentTestBase.order_info,
subscription_expiration_date=SuccessfulPaymentTestBase.subscription_expiration_date,
is_recurring=SuccessfulPaymentTestBase.is_recurring,
is_first_recurring=SuccessfulPaymentTestBase.is_first_recurring,
)


Expand All @@ -43,6 +49,9 @@ class SuccessfulPaymentTestBase:
order_info = OrderInfo()
telegram_payment_charge_id = "telegram_payment_charge_id"
provider_payment_charge_id = "provider_payment_charge_id"
subscription_expiration_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
is_recurring = True
is_first_recurring = True


class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
Expand All @@ -61,6 +70,9 @@ def test_de_json(self, offline_bot):
"order_info": self.order_info.to_dict(),
"telegram_payment_charge_id": self.telegram_payment_charge_id,
"provider_payment_charge_id": self.provider_payment_charge_id,
"subscription_expiration_date": to_timestamp(self.subscription_expiration_date),
"is_recurring": self.is_recurring,
"is_first_recurring": self.is_first_recurring,
}
successful_payment = SuccessfulPayment.de_json(json_dict, offline_bot)
assert successful_payment.api_kwargs == {}
Expand All @@ -72,6 +84,32 @@ def test_de_json(self, offline_bot):
assert successful_payment.order_info == self.order_info
assert successful_payment.telegram_payment_charge_id == self.telegram_payment_charge_id
assert successful_payment.provider_payment_charge_id == self.provider_payment_charge_id
assert successful_payment.subscription_expiration_date == self.subscription_expiration_date
assert successful_payment.is_recurring == self.is_recurring
assert successful_payment.is_first_recurring == self.is_first_recurring

def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
json_dict = {
"invoice_payload": self.invoice_payload,
"currency": self.currency,
"total_amount": self.total_amount,
"telegram_payment_charge_id": self.telegram_payment_charge_id,
"provider_payment_charge_id": self.provider_payment_charge_id,
"subscription_expiration_date": to_timestamp(self.subscription_expiration_date),
}
successful_payment = SuccessfulPayment.de_json(json_dict, offline_bot)
successful_payment_raw = SuccessfulPayment.de_json(json_dict, raw_bot)
successful_payment_tz = SuccessfulPayment.de_json(json_dict, tz_bot)

# comparing utcoffsets because comparing timezones is unpredicatable
date_offset = successful_payment_tz.subscription_expiration_date.utcoffset()
tz_bot_offset = tz_bot.defaults.tzinfo.utcoffset(
successful_payment_tz.subscription_expiration_date.replace(tzinfo=None)
)

assert successful_payment_raw.subscription_expiration_date.tzinfo == UTC
assert successful_payment.subscription_expiration_date.tzinfo == UTC
assert date_offset == tz_bot_offset

def test_to_dict(self, successful_payment):
successful_payment_dict = successful_payment.to_dict()
Expand All @@ -92,6 +130,13 @@ def test_to_dict(self, successful_payment):
successful_payment_dict["provider_payment_charge_id"]
== successful_payment.provider_payment_charge_id
)
assert successful_payment_dict["subscription_expiration_date"] == to_timestamp(
successful_payment.subscription_expiration_date
)
assert successful_payment_dict["is_recurring"] == successful_payment.is_recurring
assert (
successful_payment_dict["is_first_recurring"] == successful_payment.is_first_recurring
)

def test_equality(self):
a = SuccessfulPayment(
Expand Down
Loading