diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index e1917a6b..8f5f0091 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -536,7 +536,7 @@ def pyrogram_api(): RequestChatInfo RequestUserInfo RequestPollInfo - PaymentInfo + OrderInfo PreCheckoutQuery ShippingAddress """, diff --git a/pyrogram/methods/bots/__init__.py b/pyrogram/methods/bots/__init__.py index cc4dc3f1..ea009c5b 100644 --- a/pyrogram/methods/bots/__init__.py +++ b/pyrogram/methods/bots/__init__.py @@ -26,9 +26,11 @@ from .get_bot_default_privileges import GetBotDefaultPrivileges from .get_chat_menu_button import GetChatMenuButton from .get_game_high_scores import GetGameHighScores from .get_inline_bot_results import GetInlineBotResults +from .refund_star_payment import RefundStarPayment from .request_callback_answer import RequestCallbackAnswer from .send_game import SendGame from .send_inline_bot_result import SendInlineBotResult +from .send_invoice import SendInvoice from .set_bot_commands import SetBotCommands from .set_bot_default_privileges import SetBotDefaultPrivileges from .set_chat_menu_button import SetChatMenuButton @@ -39,8 +41,10 @@ class Bots( AnswerCallbackQuery, AnswerInlineQuery, GetInlineBotResults, + RefundStarPayment, RequestCallbackAnswer, SendInlineBotResult, + SendInvoice, SendGame, SetGameScore, GetGameHighScores, diff --git a/pyrogram/methods/bots/answer_pre_checkout_query.py b/pyrogram/methods/bots/answer_pre_checkout_query.py index e9cc452c..6d1d0cbe 100644 --- a/pyrogram/methods/bots/answer_pre_checkout_query.py +++ b/pyrogram/methods/bots/answer_pre_checkout_query.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import Optional + import pyrogram from pyrogram import raw @@ -24,8 +26,8 @@ class AnswerPreCheckoutQuery: async def answer_pre_checkout_query( self: "pyrogram.Client", pre_checkout_query_id: str, - success: bool = None, - error: str = None + ok: Optional[bool] = None, + error_message: Optional[str] = None ): """Send answers to pre-checkout queries. @@ -35,11 +37,11 @@ class AnswerPreCheckoutQuery: pre_checkout_query_id (``str``): Unique identifier for the query to be answered. - success (``bool``, *optional*): + ok (``bool``, *optional*): Set this flag if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Otherwise do not set it, and set the error field, instead. - error (``str``, *optional*): + error_message (``str``, *optional*): Error message in human readable form that explains the reason for failure to proceed with the checkout. Required if ``success`` isn't set. @@ -50,15 +52,15 @@ class AnswerPreCheckoutQuery: .. code-block:: python # Proceed with the order - await app.answer_pre_checkout_query(query_id, success=True) + await app.answer_pre_checkout_query(query_id, ok=True) # Answer with error message - await app.answer_pre_checkout_query(query_id, error=error) + await app.answer_pre_checkout_query(query_id, ok=False, error_message="Out of stock") """ return await self.invoke( raw.functions.messages.SetBotPrecheckoutResults( query_id=int(pre_checkout_query_id), - success=success or None, - error=error or None + success=ok, + error=error_message ) ) diff --git a/pyrogram/methods/bots/refund_star_payment.py b/pyrogram/methods/bots/refund_star_payment.py new file mode 100644 index 00000000..7fc28017 --- /dev/null +++ b/pyrogram/methods/bots/refund_star_payment.py @@ -0,0 +1,54 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union + +import pyrogram +from pyrogram import raw + + +class RefundStarPayment: + async def refund_star_payment( + self: "pyrogram.Client", + user_id: Union[int, str], + telegram_payment_charge_id: str + ) -> bool: + """Refunds a successful payment in `Telegram Stars `_. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user, whose payment will be refunded. + + telegram_payment_charge_id (``str``): + Telegram payment identifier. + + Returns: + ``bool``: True on success + + """ + + r = await self.invoke( + raw.functions.payments.RefundStarsCharge( + user_id=await self.resolve_peer(user_id), + charge_id=telegram_payment_charge_id + ) + ) + + return bool(r) diff --git a/pyrogram/methods/bots/send_invoice.py b/pyrogram/methods/bots/send_invoice.py new file mode 100644 index 00000000..f0964650 --- /dev/null +++ b/pyrogram/methods/bots/send_invoice.py @@ -0,0 +1,237 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging +from typing import List, Optional, Union + +import pyrogram +from pyrogram import enums, raw, utils, types + +log = logging.getLogger(__name__) + + +class SendInvoice: + async def send_invoice( + self: "pyrogram.Client", + chat_id: Union[int, str], + title: str, + description: str, + payload: Union[str, bytes], + currency: str, + prices: List["types.LabeledPrice"], + message_thread_id: Optional[int] = None, + provider_token: Optional[str] = None, + max_tip_amount: Optional[int] = None, + suggested_tip_amounts: Optional[List[int]] = None, + start_parameter: Optional[str] = None, + provider_data: Optional[str] = None, + photo_url: Optional[str] = None, + photo_size: Optional[int] = None, + photo_width: Optional[int] = None, + photo_height: Optional[int] = None, + need_name: Optional[bool] = None, + need_phone_number: Optional[bool] = None, + need_email: Optional[bool] = None, + need_shipping_address: Optional[bool] = None, + send_phone_number_to_provider: Optional[bool] = None, + send_email_to_provider: Optional[bool] = None, + is_flexible: Optional[bool] = None, + disable_notification: Optional[bool] = None, + protect_content: Optional[bool] = None, + message_effect_id: Optional[int] = None, + reply_to_message_id: Optional[int] = None, + reply_markup: Optional[Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ]] = None, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: Optional[List["types.MessageEntity"]] = None + ) -> "types.Message": + """Use this method to send invoices. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + title (``str``): + Product name, 1-32 characters. + + description (``str``): + Product description, 1-255 characters + + payload (``str`` | ``bytes``): + Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + + currency (``str``): + Three-letter ISO 4217 currency code, see `more on currencies `_. Pass ``XTR`` for payments in `Telegram Stars `_. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_. + + message_thread_id (``int``, *optional*): + If the message is in a thread, ID of the original message. + + reply_to_message_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + provider_token (``str``, *optional*): + Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_. + + max_tip_amount (``int``, *optional*): + The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_. + + suggested_tip_amounts (List of ``int``, *optional*): + An array of suggested amounts of tips in the smallest units of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed ``max_tip_amount``. + + start_parameter (``str``, *optional*): + Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a Pay button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button), with the value used as the start parameter. + + provider_data (``str``, *optional*): + JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + + photo_url (``str``, *optional*): + URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. + + photo_size (``int``, *optional*): + Photo size in bytes + + photo_width (``int``, *optional*): + Photo width + + photo_height (``int``, *optional*): + Photo height + + need_name (``bool``, *optional*): + Pass True if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_. + + need_phone_number (``bool``, *optional*): + Pass True if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_. + + need_email (``bool``, *optional*): + Pass True if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_. + + need_shipping_address (``bool``, *optional*): + Pass True if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_. + + send_phone_number_to_provider (``bool``, *optional*): + Pass True if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + send_email_to_provider (``bool``, *optional*): + Pass True if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + is_flexible (``bool``, *optional*): + Pass True if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): + Additional interface options. An object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + + caption (``str``, *optional*): + Document caption, 0-1024 characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent invoice message is returned. + + """ + media = raw.types.InputMediaInvoice( + title=title, + description=description, + photo=raw.types.InputWebDocument( + url=photo_url, + mime_type="image/jpg", + size=photo_size, + attributes=[ + raw.types.DocumentAttributeImageSize( + w=photo_width, + h=photo_height + ) + ] + ) if photo_url else None, + invoice=raw.types.Invoice( + currency=currency, + prices=[i.write() for i in prices], + test=self.test_mode, + name_requested=need_name, + phone_requested=need_phone_number, + email_requested=need_email, + shipping_address_requested=need_shipping_address, + flexible=is_flexible, + phone_to_provider=send_phone_number_to_provider, + email_to_provider=send_email_to_provider, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts + ), + payload=payload.encode() if isinstance(payload, str) else payload, + provider=provider_token, + provider_data=raw.types.DataJSON( + data=provider_data if provider_data else "{}" + ), + start_param=start_parameter + ) + + rpc = raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + media=media, + silent=disable_notification or None, + reply_to=utils.get_reply_to( + reply_to_message_id=reply_to_message_id, + message_thread_id=message_thread_id + ), + random_id=self.rnd_id(), + noforwards=protect_content, + reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, + **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) + ) + + r = await self.invoke(rpc) + + for i in r.updates: + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage, + raw.types.UpdateBotNewBusinessMessage)): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + business_connection_id=getattr(i, "connection_id", None) + ) diff --git a/pyrogram/types/bots_and_keyboards/__init__.py b/pyrogram/types/bots_and_keyboards/__init__.py index ebec18ea..21af449c 100644 --- a/pyrogram/types/bots_and_keyboards/__init__.py +++ b/pyrogram/types/bots_and_keyboards/__init__.py @@ -32,23 +32,23 @@ from .game_high_score import GameHighScore from .inline_keyboard_button import InlineKeyboardButton from .inline_keyboard_markup import InlineKeyboardMarkup from .keyboard_button import KeyboardButton +from .labeled_price import LabeledPrice from .login_url import LoginUrl from .menu_button import MenuButton from .menu_button_commands import MenuButtonCommands from .menu_button_default import MenuButtonDefault from .menu_button_web_app import MenuButtonWebApp -from .payment_info import PaymentInfo +from .order_info import OrderInfo from .pre_checkout_query import PreCheckoutQuery from .reply_keyboard_markup import ReplyKeyboardMarkup from .reply_keyboard_remove import ReplyKeyboardRemove from .request_channel_info import RequestChannelInfo from .request_chat_info import RequestChatInfo -from .request_user_info import RequestUserInfo from .request_poll_info import RequestPollInfo +from .request_user_info import RequestUserInfo from .requested_chats import RequestedChats from .sent_web_app_message import SentWebAppMessage from .shipping_address import ShippingAddress -from .successful_payment import SuccessfulPayment from .web_app_info import WebAppInfo __all__ = [ @@ -66,6 +66,7 @@ __all__ = [ "RequestUserInfo", "RequestPollInfo", "RequestedChats", + "LabeledPrice", "LoginUrl", "BotCommand", "BotCommandScope", @@ -80,10 +81,9 @@ __all__ = [ "MenuButton", "MenuButtonCommands", "MenuButtonWebApp", + "OrderInfo", + "PreCheckoutQuery", "MenuButtonDefault", "SentWebAppMessage", - "ShippingAddress", - "PaymentInfo", - "PreCheckoutQuery", - "SuccessfulPayment" + "ShippingAddress" ] diff --git a/pyrogram/types/bots_and_keyboards/labeled_price.py b/pyrogram/types/bots_and_keyboards/labeled_price.py new file mode 100644 index 00000000..ca497b42 --- /dev/null +++ b/pyrogram/types/bots_and_keyboards/labeled_price.py @@ -0,0 +1,58 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram import raw + +from ..object import Object + + +class LabeledPrice(Object): + """This object represents a portion of the price for goods or services. + + Parameters: + label (``str``): + Portion label. + + amount (``int``): + Price of the product in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + """ + + def __init__( + self, + label: str, + amount: int + ): + super().__init__() + + self.label = label + self.amount = amount + + @staticmethod + def _parse(labeled_price: "raw.types.LabeledPrice") -> "LabeledPrice": + if isinstance(labeled_price, raw.types.LabeledPrice): + return LabeledPrice( + label=labeled_price.label, + amount=labeled_price.amount + ) + + def write(self): + return raw.types.LabeledPrice( + label=self.label, + amount=self.amount + ) diff --git a/pyrogram/types/bots_and_keyboards/payment_info.py b/pyrogram/types/bots_and_keyboards/order_info.py similarity index 75% rename from pyrogram/types/bots_and_keyboards/payment_info.py rename to pyrogram/types/bots_and_keyboards/order_info.py index 690fe9e4..59668602 100644 --- a/pyrogram/types/bots_and_keyboards/payment_info.py +++ b/pyrogram/types/bots_and_keyboards/order_info.py @@ -16,32 +16,38 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import Optional + +from pyrogram import types + from ..object import Object -class PaymentInfo(Object): - """Contains information about a payment. +class OrderInfo(Object): + """This object represents information about an order. Parameters: name (``str``, *optional*): - User's name. + User name. phone_number (``str``, *optional*): User's phone number. email (``str``, *optional*): - User's email. + User email. shipping_address (:obj:`~pyrogram.types.ShippingAddress`, *optional*): - User's shipping address. + User shipping address. + """ def __init__( - self, *, - name: str = None, - phone_number: str = None, - email: str = None, - shipping_address: "types.ShippingAddress" = None + self, + *, + name: Optional[str] = None, + phone_number: Optional[str] = None, + email: Optional[str] = None, + shipping_address: Optional["types.ShippingAddress"] = None ): super().__init__() diff --git a/pyrogram/types/bots_and_keyboards/pre_checkout_query.py b/pyrogram/types/bots_and_keyboards/pre_checkout_query.py index f8fde554..e90ba50a 100644 --- a/pyrogram/types/bots_and_keyboards/pre_checkout_query.py +++ b/pyrogram/types/bots_and_keyboards/pre_checkout_query.py @@ -16,18 +16,16 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union, List, Match, Optional +from typing import Union, Optional import pyrogram -from pyrogram import raw, enums -from pyrogram import types +from pyrogram import types, raw from ..object import Object from ..update import Update -from ... import utils class PreCheckoutQuery(Object, Update): - """An incoming pre-checkout query from a buy button in an inline keyboard. + """This object contains information about an incoming pre-checkout query. Parameters: id (``str``): @@ -37,18 +35,18 @@ class PreCheckoutQuery(Object, Update): User who sent the query. currency (``str``): - Three-letter ISO 4217 currency code. + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. total_amount (``int``): - Total price in the smallest units of the currency. + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). - payload (``str``): + invoice_payload (``str``): Bot specified invoice payload. shipping_option_id (``str``, *optional*): Identifier of the shipping option chosen by the user. - payment_info (:obj:`~pyrogram.types.PaymentInfo`, *optional*): + order_info (:obj:`~pyrogram.types.OrderInfo`, *optional*): Payment information provided by the user. """ @@ -60,9 +58,9 @@ class PreCheckoutQuery(Object, Update): from_user: "types.User", currency: str, total_amount: int, - payload: str, - shipping_option_id: str = None, - payment_info: "types.PaymentInfo" = None + invoice_payload: str, + shipping_option_id: Optional[str] = None, + order_info: Optional["types.OrderInfo"] = None ): super().__init__(client) @@ -70,27 +68,31 @@ class PreCheckoutQuery(Object, Update): self.from_user = from_user self.currency = currency self.total_amount = total_amount - self.payload = payload + self.invoice_payload = invoice_payload self.shipping_option_id = shipping_option_id - self.payment_info = payment_info + self.order_info = order_info @staticmethod - async def _parse(client: "pyrogram.Client", pre_checkout_query, users) -> "PreCheckoutQuery": + async def _parse( + client: "pyrogram.Client", + pre_checkout_query: "raw.types.UpdateBotPrecheckoutQuery", + users: dict + ) -> "PreCheckoutQuery": # Try to decode pre-checkout query payload into string. If that fails, fallback to bytes instead of decoding by # ignoring/replacing errors, this way, button clicks will still work. try: - payload = pre_checkout_query.payload.decode() + invoice_payload = pre_checkout_query.payload.decode() except (UnicodeDecodeError, AttributeError): - payload = pre_checkout_query.payload + invoice_payload = pre_checkout_query.payload return PreCheckoutQuery( id=str(pre_checkout_query.query_id), from_user=types.User._parse(client, users[pre_checkout_query.user_id]), currency=pre_checkout_query.currency, total_amount=pre_checkout_query.total_amount, - payload=payload, + invoice_payload=invoice_payload, shipping_option_id=pre_checkout_query.shipping_option_id, - payment_info=types.PaymentInfo( + order_info=types.OrderInfo( name=pre_checkout_query.info.name, phone_number=pre_checkout_query.info.phone, email=pre_checkout_query.info.email, @@ -106,7 +108,7 @@ class PreCheckoutQuery(Object, Update): client=client ) - async def answer(self, success: bool = None, error: str = None): + async def answer(self, ok: bool = None, error_message: str = None): """Bound method *answer* of :obj:`~pyrogram.types.PreCheckoutQuery`. Use this method as a shortcut for: @@ -115,25 +117,26 @@ class PreCheckoutQuery(Object, Update): await client.answer_pre_checkout_query( pre_checkout_query.id, - success=True + ok=True ) Example: .. code-block:: python - await pre_checkout_query.answer(success=True) + await pre_checkout_query.answer(ok=True) Parameters: - success (``bool`` *optional*): - If true, an alert will be shown by the client instead of a notification at the top of the chat screen. - Defaults to False. + ok (``bool`` *optional*): + Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems. - error (``bool`` *optional*): - If true, an alert will be shown by the client instead of a notification at the top of the chat screen. - Defaults to False. + error_message (``str`` *optional*): + Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user. + + Returns: + ``bool``: True, on success. """ return await self._client.answer_pre_checkout_query( pre_checkout_query_id=self.id, - success=success, - error=error + ok=ok, + error_message=error_message ) diff --git a/pyrogram/types/bots_and_keyboards/shipping_address.py b/pyrogram/types/bots_and_keyboards/shipping_address.py index 8e373f31..c7a468e2 100644 --- a/pyrogram/types/bots_and_keyboards/shipping_address.py +++ b/pyrogram/types/bots_and_keyboards/shipping_address.py @@ -23,39 +23,41 @@ class ShippingAddress(Object): """Contains information about a shipping address. Parameters: + country_code (``str``): + Two-letter `ISO 3166-1 alpha-2 `_ country code. + + state (``str``): + State, if applicable. + + city (``str``): + City. + street_line1 (``str``): First line for the address. - street_line1 (``str``): + street_line2 (``str``): Second line for the address. - city (``str``): - City for the address. - - state (``str``): - State for the address, if applicable. - post_code (``str``): - Post code for the address. + Address post code. - country_code (``str``): - Two-letter ISO 3166-1 alpha-2 country code. """ def __init__( - self, *, + self, + *, + country_code: str, + state: str, + city: str, street_line1: str, street_line2: str, - city: str, - state: str, - post_code: str, - country_code: str + post_code: str ): super().__init__() + self.country_code = country_code + self.state = state + self.city = city self.street_line1 = street_line1 self.street_line2 = street_line2 - self.city = city - self.state = state self.post_code = post_code - self.country_code = country_code diff --git a/pyrogram/types/bots_and_keyboards/successful_payment.py b/pyrogram/types/bots_and_keyboards/successful_payment.py deleted file mode 100644 index d362f2f7..00000000 --- a/pyrogram/types/bots_and_keyboards/successful_payment.py +++ /dev/null @@ -1,111 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-present Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram 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 Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from pyrogram import raw -from pyrogram import types -from ..object import Object - - -class SuccessfulPayment(Object): - """Contains information about a successful payment. - - Parameters: - currency (``str``): - Three-letter ISO 4217 currency code. - - total_amount (``int``): - Total price in the smallest units of the currency. - - payload (``str``, *optional*): - Bot specified invoice payload. Only available to the bot that received the payment. - - telegram_payment_charge_id (``str``, *optional*): - Telegram payment identifier. Only available to the bot that received the payment. - - provider_payment_charge_id (``str``, *optional*): - Provider payment identifier. Only available to the bot that received the payment. - - shipping_option_id (``str``, *optional*): - Identifier of the shipping option chosen by the user. Only available to the bot that received the payment. - - payment_info (:obj:`~pyrogram.types.PaymentInfo`, *optional*): - Payment information provided by the user. Only available to the bot that received the payment. - """ - - def __init__( - self, *, - currency: str, - total_amount: str, - payload: str, - telegram_payment_charge_id: str, - provider_payment_charge_id: str, - shipping_option_id: str = None, - payment_info: "types.PaymentInfo" = None - ): - super().__init__() - - self.currency = currency - self.total_amount = total_amount - self.payload = payload - self.telegram_payment_charge_id = telegram_payment_charge_id - self.provider_payment_charge_id = provider_payment_charge_id - self.shipping_option_id = shipping_option_id - self.payment_info = payment_info - - @staticmethod - def _parse(client: "pyrogram.Client", successful_payment) -> "SuccessfulPayment": - payload = None - telegram_payment_charge_id = None - provider_payment_charge_id = None - shipping_option_id = None - payment_info = None - - if isinstance(successful_payment, raw.types.MessageActionPaymentSentMe): - # Try to decode invoice payload into string. If that fails, fallback to bytes instead of decoding by - # ignoring/replacing errors, this way, button clicks will still work. - try: - payload = successful_payment.payload.decode() - except (UnicodeDecodeError, AttributeError): - payload = successful_payment.payload - - telegram_payment_charge_id = successful_payment.charge.id - provider_payment_charge_id = successful_payment.charge.provider_charge_id - shipping_option_id = successful_payment.shipping_option_id - payment_info = types.PaymentInfo( - name=successful_payment.info.name, - phone_number=successful_payment.info.phone, - email=successful_payment.info.email, - shipping_address=types.ShippingAddress( - street_line1=successful_payment.info.shipping_address.street_line1, - street_line2=successful_payment.info.shipping_address.street_line2, - city=successful_payment.info.shipping_address.city, - state=successful_payment.info.shipping_address.state, - post_code=successful_payment.info.shipping_address.post_code, - country_code=successful_payment.info.shipping_address.country_iso2 - ) - ) if successful_payment.info else None - - return SuccessfulPayment( - currency=successful_payment.currency, - total_amount=successful_payment.total_amount, - payload=payload, - telegram_payment_charge_id=telegram_payment_charge_id, - provider_payment_charge_id=shipping_option_id, - shipping_option_id=shipping_option_id, - payment_info=payment_info - ) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index b4ca8a49..00b46d9d 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -49,6 +49,7 @@ from .reaction import Reaction from .sticker import Sticker from .story import Story from .stripped_thumbnail import StrippedThumbnail +from .successful_payment import SuccessfulPayment from .thumbnail import Thumbnail from .venue import Venue from .video import Video @@ -91,6 +92,7 @@ __all__ = [ "Sticker", "Story", "StrippedThumbnail", + "SuccessfulPayment", "Thumbnail", "Venue", "Video", diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index b86a96ba..a8402626 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -405,7 +405,7 @@ class Message(Object, Update): Generate a link to this message, only for groups and channels. """ - # TODO: Add game missing field. Also successful_payment, connected_website + # TODO: Add game missing field, connected_website def __init__( self, diff --git a/pyrogram/types/messages_and_media/successful_payment.py b/pyrogram/types/messages_and_media/successful_payment.py new file mode 100644 index 00000000..53ff98ce --- /dev/null +++ b/pyrogram/types/messages_and_media/successful_payment.py @@ -0,0 +1,140 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union, Optional + +from pyrogram import raw +from pyrogram import types +from ..object import Object + + +class SuccessfulPayment(Object): + """A service message about a new successful payment. + + Parameters: + currency (``str``): + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + invoice_payload (``str``, *optional*): + Bot specified invoice payload. Only available to the bot that received the payment. + + telegram_payment_charge_id (``str``, *optional*): + Telegram payment identifier. Only available to the bot that received the payment. + + provider_payment_charge_id (``str``, *optional*): + Provider payment identifier. Only available to the bot that received the payment. + + shipping_option_id (``str``, *optional*): + Identifier of the shipping option chosen by the user. Only available to the bot that received the payment. + + payment_info (:obj:`~pyrogram.types.PaymentInfo`, *optional*): + Payment information provided by the user. Only available to the bot that received the payment. + + is_recurring (``bool``, *optional*): + True, if this is a recurring payment. + + is_first_recurring (``bool``, *optional*): + True, if this is the first recurring payment. + + invoice_slug (``str``, *optional*): + Name of the invoice. + """ + + def __init__( + self, *, + currency: str, + total_amount: str, + invoice_payload: str, + telegram_payment_charge_id: str, + provider_payment_charge_id: str, + shipping_option_id: Optional[str] = None, + order_info: Optional["types.OrderInfo"] = None, + is_recurring: Optional[bool] = None, + is_first_recurring: Optional[bool] = None, + invoice_slug: Optional[str] = None + ): + super().__init__() + + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + self.shipping_option_id = shipping_option_id + self.order_info = order_info + self.is_recurring = is_recurring + self.is_first_recurring = is_first_recurring + self.invoice_slug = invoice_slug + + @staticmethod + def _parse( + client: "pyrogram.Client", + successful_payment: Union[ + "raw.types.MessageActionPaymentSent", + "raw.types.MessageActionPaymentSentMe" + ]) -> "SuccessfulPayment": + invoice_payload = None + telegram_payment_charge_id = None + provider_payment_charge_id = None + shipping_option_id = None + order_info = None + + if isinstance(successful_payment, raw.types.MessageActionPaymentSentMe): + # Try to decode invoice payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + invoice_payload = successful_payment.payload.decode() + except (UnicodeDecodeError, AttributeError): + invoice_payload = successful_payment.payload + + telegram_payment_charge_id = successful_payment.charge.id + provider_payment_charge_id = successful_payment.charge.provider_charge_id + shipping_option_id = getattr(successful_payment, "shipping_option_id") + + if successful_payment.info: + payment_info = successful_payment.info + + order_info = types.OrderInfo( + name=getattr(payment_info, "name", None), + phone_number=getattr(payment_info, "phone", None), + email=getattr(payment_info, "email", None), + shipping_address=types.ShippingAddress( + country_code=successful_payment.info.shipping_address.country_iso2, + state=successful_payment.info.shipping_address.state, + city=successful_payment.info.shipping_address.city, + street_line1=successful_payment.info.shipping_address.street_line1, + street_line2=successful_payment.info.shipping_address.street_line2, + post_code=successful_payment.info.shipping_address.post_code + ) + ) + + return SuccessfulPayment( + currency=successful_payment.currency, + total_amount=successful_payment.total_amount, + invoice_payload=invoice_payload, + telegram_payment_charge_id=telegram_payment_charge_id, + provider_payment_charge_id=provider_payment_charge_id, + shipping_option_id=shipping_option_id, + order_info=order_info, + is_recurring=getattr(successful_payment, "recurring_used", None), + is_first_recurring=getattr(successful_payment, "recurring_init", None), + invoice_slug=getattr(successful_payment, "invoice_slug", None), + )