From 6cda8d052c8639160ae481c0c8159e0e943a31d8 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Fri, 19 May 2017 17:19:15 +0300 Subject: [PATCH 1/7] VideoNote support Send and recieve round video messages. Support for send_video_note metod and video_note content type. --- README.md | 7 ++++++- telebot/__init__.py | 21 +++++++++++++++++++++ telebot/apihelper.py | 26 +++++++++++++++++++++++++- telebot/types.py | 25 +++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f446fd..e4f5322 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)). The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings: -`text`, `audio`, `document`, `photo`, `sticker`, `video`, `voice`, `location`, `contact`, `new_chat_member`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`. +`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_member`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`. ### Methods @@ -284,6 +284,11 @@ video = open('/tmp/video.mp4', 'rb') tb.send_video(chat_id, video) tb.send_video(chat_id, "FILEID") +# sendVideoNote +videonote = open('/tmp/videonote.mp4', 'rb') +tb.send_video(chat_id, videonote) +tb.send_video(chat_id, "FILEID") + # sendLocation tb.send_location(chat_id, lat, lon) diff --git a/telebot/__init__.py b/telebot/__init__.py index da2d0fe..bac8206 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -39,6 +39,7 @@ class TeleBot: sendDocument sendSticker sendVideo + sendVideoNote sendLocation sendChatAction getUserProfilePhotos @@ -510,6 +511,22 @@ class TeleBot: apihelper.send_video(self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup, disable_notification, timeout)) + def send_video_note(self, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None, + disable_notification=None, timeout=None): + """ + Use this method to send video files, Telegram clients support mp4 videos. + :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id + :param data: InputFile or String : Video note to send. You can either pass a file_id as String to resend a video that is already on the Telegram server + :param duration: Integer : Duration of sent video in seconds + :param length: Integer : Video width and height, Can't be None and should be in range of (0, 640) + :param reply_to_message_id: + :param reply_markup: + :return: + """ + return types.Message.de_json( + apihelper.send_video_note(self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup, + disable_notification, timeout)) + def send_location(self, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None, disable_notification=None): """ @@ -953,6 +970,10 @@ class AsyncTeleBot(TeleBot): def send_video(self, *args, **kwargs): return TeleBot.send_video(self, *args, **kwargs) + @util.async() + def send_video_note(self, *args, **kwargs): + return TeleBot.send_video_note(self, *args, **kwargs) + @util.async() def send_location(self, *args, **kwargs): return TeleBot.send_location(self, *args, **kwargs) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index c134cbc..72be649 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -328,6 +328,31 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess return _make_request(token, method_url, params=payload, files=files, method='post') +def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None, + disable_notification=None, timeout=None): + method_url = r'sendVideoNote' + payload = {'chat_id': chat_id} + files = None + if not util.is_string(data): + files = {'video_note': data} + files['video_note']['length'] = 639 # seems like it is MAX length size + else: + payload['video_note'] = data + if duration: + payload['duration'] = duration + if length: + payload['length'] = length + if reply_to_message_id: + payload['reply_to_message_id'] = reply_to_message_id + if reply_markup: + payload['reply_markup'] = _convert_markup(reply_markup) + if disable_notification: + payload['disable_notification'] = disable_notification + if timeout: + payload['connect-timeout'] = timeout + return _make_request(token, method_url, params=payload, files=files, method='post') + + def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None, reply_markup=None, disable_notification=None, timeout=None): method_url = r'sendAudio' @@ -525,7 +550,6 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None, """ Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned. Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via BotFather and accept the terms. Otherwise, you may use links like telegram.me/your_bot?start=XXXX that open your bot with a parameter. - :param token: Bot's token (you don't need to fill this) :param callback_query_id: Unique identifier for the query to be answered :param text: (Optional) Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters diff --git a/telebot/types.py b/telebot/types.py index 497996f..2c5fdb9 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -263,6 +263,9 @@ class Message(JsonDeserializable): if 'video' in obj: opts['video'] = Video.de_json(obj['video']) content_type = 'video' + if 'video_note' in obj: + opts['video_note'] = VideoNote.de_json(obj['video_note']) + content_type = 'video_note' if 'voice' in obj: opts['voice'] = Audio.de_json(obj['voice']) content_type = 'voice' @@ -342,6 +345,7 @@ class Message(JsonDeserializable): self.photo = None self.sticker = None self.video = None + self.video_note = None self.voice = None self.caption = None self.contact = None @@ -507,6 +511,27 @@ class Video(JsonDeserializable): self.file_size = file_size +class VideoNote(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + file_id = obj['file_id'] + length = obj['length'] + duration = obj['duration'] + thumb = None + if 'thumb' in obj: + thumb = PhotoSize.de_json(obj['thumb']) + file_size = obj.get('file_size') + return cls(file_id, length, duration, thumb, file_size) + + def __init__(self, file_id, length, duration, thumb=None, file_size=None): + self.file_id = file_id + self.length = length + self.duration = duration + self.thumb = thumb + self.file_size = file_size + + class Contact(JsonDeserializable): @classmethod def de_json(cls, json_string): From 443d81d4db5e72f41d470c6183db342aaae0aba5 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Fri, 19 May 2017 18:08:07 +0300 Subject: [PATCH 2/7] FIX: Can't edit file bytes --- telebot/apihelper.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 72be649..f72ce79 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -335,13 +335,14 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m files = None if not util.is_string(data): files = {'video_note': data} - files['video_note']['length'] = 639 # seems like it is MAX length size else: payload['video_note'] = data if duration: payload['duration'] = duration if length: payload['length'] = length + else: + payload['length'] = 639 # seems like it is MAX length size if reply_to_message_id: payload['reply_to_message_id'] = reply_to_message_id if reply_markup: From 3f5596ddce5a94aaf2cfda11139aab9931c74f01 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sun, 21 May 2017 14:27:31 +0300 Subject: [PATCH 3/7] new_chat_members content type and new send_action actions --- telebot/__init__.py | 2 +- telebot/types.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index bac8206..dad0164 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -576,7 +576,7 @@ class TeleBot: its typing status). :param chat_id: :param action: One of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video', - 'record_audio', 'upload_audio', 'upload_document', 'find_location'. + 'record_audio', 'upload_audio', 'upload_document', 'find_location', 'record_video_note', 'upload_video_note'. :return: API reply. :type: boolean """ return apihelper.send_chat_action(self.token, chat_id, action) diff --git a/telebot/types.py b/telebot/types.py index 2c5fdb9..475824a 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -283,6 +283,9 @@ class Message(JsonDeserializable): if 'new_chat_member' in obj: opts['new_chat_member'] = User.de_json(obj['new_chat_member']) content_type = 'new_chat_member' + if 'new_chat_members' in obj: + opts['new_chat_members'] = obj['new_chat_members'] + content_type = 'new_chat_members' if 'left_chat_member' in obj: opts['left_chat_member'] = User.de_json(obj['left_chat_member']) content_type = 'left_chat_member' From 9134e8dd1a6a1cff30fc68a666659f5069707715 Mon Sep 17 00:00:00 2001 From: eternnoir Date: Sun, 21 May 2017 19:58:00 +0800 Subject: [PATCH 4/7] Add send video note test case. --- tests/test_telebot.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_telebot.py b/tests/test_telebot.py index b9b460c..8c0cf76 100644 --- a/tests/test_telebot.py +++ b/tests/test_telebot.py @@ -403,3 +403,9 @@ class TestTeleBot: def test_not_string(self): i1 = 10 assert not util.is_string(i1) + + def test_send_video_note(self): + file_data = open('./test_data/test_video.mp4', 'rb') + tb = telebot.TeleBot(TOKEN) + ret_msg = tb.send_video_note(CHAT_ID, file_data) + assert ret_msg.message_id From 5ed333492b2ac59c04beb3c9dd1633d881c969a0 Mon Sep 17 00:00:00 2001 From: eternnoir Date: Sun, 21 May 2017 21:45:12 +0800 Subject: [PATCH 5/7] All payment type done. --- telebot/apihelper.py | 13 ++++ telebot/types.py | 170 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 181 insertions(+), 2 deletions(-) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index f72ce79..b77515e 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -544,6 +544,19 @@ def get_game_high_scores(token, user_id, chat_id=None, message_id=None, inline_m payload['inline_message_id'] = inline_message_id return _make_request(token, method_url, params=payload) +# Payments (https://core.telegram.org/bots/api#payments) + +def send_invoice(): + # TODO + pass + +def answer_shippingQuery(): + # TODO + pass + +def answer_pre_checkout_query(): + # TODO + pass # InlineQuery diff --git a/telebot/types.py b/telebot/types.py index 475824a..1fe66de 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -148,9 +148,11 @@ class WebhookInfo(JsonDeserializable): max_connections = obj['max_connections'] if 'allowed_updates' in obj: allowed_updates = obj['allowed_updates'] - return cls(url, has_custom_certificate, pending_update_count, last_error_date, last_error_message, max_connections, allowed_updates) + return cls(url, has_custom_certificate, pending_update_count, last_error_date, last_error_message, + max_connections, allowed_updates) - def __init__(self, url, has_custom_certificate, pending_update_count, last_error_date, last_error_message, max_connections, allowed_updates): + def __init__(self, url, has_custom_certificate, pending_update_count, last_error_date, last_error_message, + max_connections, allowed_updates): self.url = url self.has_custom_certificate = has_custom_certificate self.pending_update_count = pending_update_count @@ -1608,3 +1610,167 @@ class GameHighScore(JsonDeserializable): self.position = position self.user = user self.score = score + + +# Payments + +class LabeledPrice(JsonSerializable): + def __init__(self, label, amount): + self.label = label + self.amount = amount + + def to_json(self): + return json.dumps(self.to_dic()) + + def to_dic(self): + return {'label': self.label, 'amount': self.amount} + + +class Invoice(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + title = obj['title'] + description = obj['description'] + start_parameter = obj['start_parameter'] + currency = obj['currency'] + total_amount = obj['total_amount'] + return cls(title, description, start_parameter, currency, total_amount) + + def __init__(self, title, description, start_parameter, currency, total_amount): + self.title = title + self.description = description + self.start_parameter = start_parameter + self.currency = currency + self.total_amount = total_amount + + +class ShippingAddress(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + country_code = obj['country_code'] + state = obj['state'] + city = obj['city'] + street_line1 = obj['street_line1'] + street_line2 = obj['street_line2'] + post_code = obj['post_code'] + return cls(country_code, state, city, street_line1, street_line2, post_code) + + def __init__(self, country_code, state, city, street_line1, street_line2, post_code): + self.country_code = country_code + self.state = state + self.city = city + self.street_line1 = street_line1 + self.street_line2 = street_line2 + self.post_code = post_code + + +class OrderInfo(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + name = obj.get('name') + phone_number = obj.get('phone_number') + email = obj.get('email') + shipping_address = None + if 'shipping_address' in obj: + shipping_address = ShippingAddress.de_json(obj['shipping_address']) + return cls(name, phone_number, email, shipping_address) + + def __init__(self, name, phone_number, email, shipping_address): + self.name = name + self.phone_number = phone_number + self.email = email + self.shipping_address = shipping_address + + +class ShippingOption(JsonSerializable): + def __init__(self, id, title): + self.id = id + self.title = title + self.prices = [] + + def add_price(self, *args): + """ + Add LabeledPrice to ShippingOption + :param args: LabeledPrices + """ + for price in args: + self.prices.append(price) + + def to_json(self): + price_list = [] + for p in self.prices: + price_list.append(p.to_dic()) + json_dict = {'id': self.id, 'title': self.title, 'prices': price_list} + return json_dict + + +class SuccessfulPayment(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + currency = obj['currency'] + total_amount = obj['total_amount'] + invoice_payload = obj['invoice_payload'] + shipping_option_id = obj.get('shipping_option_id') + order_info = None + if 'order_info' in obj: + order_info = OrderInfo.de_json(obj['order_info']) + telegram_payment_charge_id = obj['telegram_payment_charge_id'] + provider_payment_charge_id = obj['provider_payment_charge_id'] + return cls(currency, total_amount, invoice_payload, shipping_option_id, order_info, + telegram_payment_charge_id, provider_payment_charge_id) + + def __init__(self, currency, total_amount, invoice_payload, shipping_option_id, order_info, + telegram_payment_charge_id, provider_payment_charge_id): + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.shipping_option_id = shipping_option_id + self.order_info = order_info + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + + +class ShippingQuery(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + id = obj['id'] + from_user = User.de_json(obj['from']) + invoice_payload = obj['invoice_payload'] + shipping_address = ShippingAddress.de_json(obj['shipping_address']) + return cls(id, from_user, invoice_payload, shipping_address) + + def __init__(self, id, from_user, invoice_payload, shipping_address): + self.id = id + self.from_user = from_user + self.invoice_payload = invoice_payload + self.shipping_address = shipping_address + + +class PreCheckoutQuery(JsonDeserializable): + @classmethod + def de_json(cls, json_string): + obj = cls.check_json(json_string) + id = obj['id'] + from_user = User.de_json(obj['from']) + currency = obj['currency'] + total_amount = obj['total_amount'] + invoice_payload = obj['invoice_payload'] + shipping_option_id = obj.get('shipping_option_id') + order_info = None + if 'order_info' in obj: + order_info = OrderInfo.de_json(obj['order_info']) + return cls(id, from_user, currency, total_amount, invoice_payload, shipping_option_id, order_info) + + def __init__(self, id, from_user, currency, total_amount, invoice_payload, shipping_option_id, order_info): + self.id = id + self.from_user = from_user + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.shipping_option_id = shipping_option_id + self.order_info = order_info From 12791e1366a25380e4028db5d3dca3581593cd96 Mon Sep 17 00:00:00 2001 From: eternnoir Date: Sun, 21 May 2017 21:52:56 +0800 Subject: [PATCH 6/7] Add payments type to update and message. --- telebot/types.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 1fe66de..68c1aa4 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -101,6 +101,8 @@ class Update(JsonDeserializable): inline_query = None chosen_inline_result = None callback_query = None + shipping_query = None + pre_checkout_query = None if 'message' in obj: message = Message.de_json(obj['message']) if 'edited_message' in obj: @@ -115,11 +117,15 @@ class Update(JsonDeserializable): chosen_inline_result = ChosenInlineResult.de_json(obj['chosen_inline_result']) if 'callback_query' in obj: callback_query = CallbackQuery.de_json(obj['callback_query']) + if 'shipping_query' in obj: + shipping_query = ShippingQuery.de_json(obj['shipping_query']) + if 'pre_checkout_query' in obj: + pre_checkout_query = PreCheckoutQuery.de_json(obj['pre_checkout_query']) return cls(update_id, message, edited_message, channel_post, edited_channel_post, inline_query, - chosen_inline_result, callback_query) + chosen_inline_result, callback_query, shipping_query, pre_checkout_query) def __init__(self, update_id, message, edited_message, channel_post, edited_channel_post, inline_query, - chosen_inline_result, callback_query): + chosen_inline_result, callback_query, shipping_query, pre_checkout_query): self.update_id = update_id self.edited_message = edited_message self.message = message @@ -129,6 +135,8 @@ class Update(JsonDeserializable): self.inline_query = inline_query self.chosen_inline_result = chosen_inline_result self.callback_query = callback_query + self.shipping_query = shipping_query + self.pre_checkout_query = pre_checkout_query class WebhookInfo(JsonDeserializable): @@ -309,6 +317,12 @@ class Message(JsonDeserializable): opts['migrate_from_chat_id'] = obj['migrate_from_chat_id'] if 'pinned_message' in obj: opts['pinned_message'] = Message.de_json(obj['pinned_message']) + if 'invoice' in obj: + opts['invoice'] = Invoice.de_json(obj['invoice']) + content_type = 'invoice' + if 'successful_payment' in obj: + opts['successful_payment'] = SuccessfulPayment.de_json(obj['successful_payment']) + content_type = 'successful_payment' return cls(message_id, from_user, date, chat, content_type, opts) @classmethod @@ -367,6 +381,8 @@ class Message(JsonDeserializable): self.migrate_to_chat_id = None self.migrate_from_chat_id = None self.pinned_message = None + self.invoice = None + self.successful_payment = None for key in options: setattr(self, key, options[key]) From 3a10c907998b523630f6046341560f5dd2c2b4a3 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Wed, 24 May 2017 01:23:52 +0300 Subject: [PATCH 7/7] Payments methods --- telebot/apihelper.py | 103 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index b77515e..afc2724 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -472,7 +472,7 @@ def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_messa return _make_request(token, method_url, params=payload) -def delete_message(token, chat_id=None, message_id=None): +def delete_message(token, chat_id, message_id): method_url = r'deleteMessage' payload = {'chat_id': chat_id, 'message_id': message_id} return _make_request(token, method_url, params=payload) @@ -546,17 +546,100 @@ def get_game_high_scores(token, user_id, chat_id=None, message_id=None, inline_m # Payments (https://core.telegram.org/bots/api#payments) -def send_invoice(): - # TODO - pass +def send_invoice(token, chat_id, title, description, invoice_payload, provider_token, currency, prices, start_parameter=None, + photo_url=None, photo_size=None, photo_width=None, photo_height=None, need_name=None, + need_phone_number=None, need_email=None, need_shipping_address=None, is_flexible=None, + disable_notification=None, reply_to_message_id=None, reply_markup=None): + """ + Use this method to send invoices. On success, the sent Message is returned. + :param token: Bot's token (you don't need to fill this) + :param chat_id: Unique identifier for the target private chat + :param title: Product name + :param description: Product description + :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + :param provider_token: Payments provider token, obtained via @Botfather + :param currency: Three-letter ISO 4217 currency code, see https://core.telegram.org/bots/payments#supported-currencies + :param prices: Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) + :param start_parameter: Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter + :param photo_url: 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. + :param photo_size: Photo size + :param photo_width: Photo width + :param photo_height: Photo height + :param need_name: Pass True, if you require the user's full name to complete the order + :param need_phone_number: Pass True, if you require the user's phone number to complete the order + :param need_email: Pass True, if you require the user's email to complete the order + :param need_shipping_address: Pass True, if you require the user's shipping address to complete the order + :param is_flexible: Pass True, if the final price depends on the shipping method + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :param reply_to_message_id: If the message is a reply, ID of the original message + :param reply_markup: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button + :return: + """ + method_url = r'sendInvoice' + payload = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': invoice_payload, 'provider_token': provider_token, 'currency': currency, 'prices': prices} + if start_parameter: + payload['start_parameter'] = start_parameter + if photo_url: + payload['photo_url'] = photo_url + if photo_size: + payload['photo_size'] = photo_size + if photo_width: + payload['photo_width'] = photo_width + if photo_height: + payload['photo_height'] = photo_height + if need_name: + payload['need_name'] = need_name + if need_phone_number: + payload['need_phone_number'] = need_phone_number + if need_email: + payload['need_email'] = need_email + if need_shipping_address: + payload['need_shipping_address'] = need_shipping_address + if is_flexible: + payload['is_flexible'] = is_flexible + if disable_notification: + payload['disable_notification'] = disable_notification + if reply_to_message_id: + payload['reply_to_message_id'] = reply_to_message_id + if reply_markup: + payload['reply_markup'] = reply_markup + return _make_request(token, method_url, params=payload) -def answer_shippingQuery(): - # TODO - pass -def answer_pre_checkout_query(): - # TODO - pass +def answer_shippingQuery(token, shipping_query_id, ok, shipping_options=None, error_message=None): + """ + If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is returned. + :param token: Bot's token (you don't need to fill this) + :param shipping_query_id: Unique identifier for the query to be answered + :param ok: Specify True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible) + :param shipping_options: Required if ok is True. A JSON-serialized array of available shipping options. + :param error_message: Required if ok is False. Error message in human readable form that explains why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user. + :return: + """ + method_url = 'answerShippingQuery' + payload = {'shipping_query_id': shipping_query_id, 'ok': ok} + if shipping_options: + payload['reply_markup'] = shipping_options + if error_message: + payload['reply_markup'] = error_message + return _make_request(token, method_url, params=payload) + + +def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_message=None): + """ + Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned. Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent. + :param token: Bot's token (you don't need to fill this) + :param pre_checkout_query_id: Unique identifier for the query to be answered + :param ok: 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. + :param error_message: 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. + :return: + """ + method_url = 'answerPreCheckoutQuery' + payload = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok} + if error_message: + payload['error_message'] = error_message + return _make_request(token, method_url, params=payload) + # InlineQuery