paymentbot.pyΒΆ

  1#!/usr/bin/env python
  2# pylint: disable=unused-argument, wrong-import-position
  3# This program is dedicated to the public domain under the CC0 license.
  4
  5"""Basic example for a bot that can receive payment from user."""
  6
  7import logging
  8
  9from telegram import __version__ as TG_VER
 10
 11try:
 12    from telegram import __version_info__
 13except ImportError:
 14    __version_info__ = (0, 0, 0, 0, 0)  # type: ignore[assignment]
 15
 16if __version_info__ < (20, 0, 0, "alpha", 1):
 17    raise RuntimeError(
 18        f"This example is not compatible with your current PTB version {TG_VER}. To view the "
 19        f"{TG_VER} version of this example, "
 20        f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
 21    )
 22from telegram import LabeledPrice, ShippingOption, Update
 23from telegram.ext import (
 24    Application,
 25    CommandHandler,
 26    ContextTypes,
 27    MessageHandler,
 28    PreCheckoutQueryHandler,
 29    ShippingQueryHandler,
 30    filters,
 31)
 32
 33# Enable logging
 34logging.basicConfig(
 35    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
 36)
 37logger = logging.getLogger(__name__)
 38
 39PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
 40
 41
 42async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
 43    """Displays info on how to use the bot."""
 44    msg = (
 45        "Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
 46        "invoice without shipping."
 47    )
 48
 49    await update.message.reply_text(msg)
 50
 51
 52async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
 53    """Sends an invoice with shipping-payment."""
 54    chat_id = update.message.chat_id
 55    title = "Payment Example"
 56    description = "Payment Example using python-telegram-bot"
 57    # select a payload just for you to recognize its the donation from your bot
 58    payload = "Custom-Payload"
 59    # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
 60    currency = "USD"
 61    # price in dollars
 62    price = 1
 63    # price * 100 so as to include 2 decimal points
 64    # check https://core.telegram.org/bots/payments#supported-currencies for more details
 65    prices = [LabeledPrice("Test", price * 100)]
 66
 67    # optionally pass need_name=True, need_phone_number=True,
 68    # need_email=True, need_shipping_address=True, is_flexible=True
 69    await context.bot.send_invoice(
 70        chat_id,
 71        title,
 72        description,
 73        payload,
 74        PAYMENT_PROVIDER_TOKEN,
 75        currency,
 76        prices,
 77        need_name=True,
 78        need_phone_number=True,
 79        need_email=True,
 80        need_shipping_address=True,
 81        is_flexible=True,
 82    )
 83
 84
 85async def start_without_shipping_callback(
 86    update: Update, context: ContextTypes.DEFAULT_TYPE
 87) -> None:
 88    """Sends an invoice without shipping-payment."""
 89    chat_id = update.message.chat_id
 90    title = "Payment Example"
 91    description = "Payment Example using python-telegram-bot"
 92    # select a payload just for you to recognize its the donation from your bot
 93    payload = "Custom-Payload"
 94    # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
 95    currency = "USD"
 96    # price in dollars
 97    price = 1
 98    # price * 100 so as to include 2 decimal points
 99    prices = [LabeledPrice("Test", price * 100)]
100
101    # optionally pass need_name=True, need_phone_number=True,
102    # need_email=True, need_shipping_address=True, is_flexible=True
103    await context.bot.send_invoice(
104        chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices
105    )
106
107
108async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
109    """Answers the ShippingQuery with ShippingOptions"""
110    query = update.shipping_query
111    # check the payload, is this from your bot?
112    if query.invoice_payload != "Custom-Payload":
113        # answer False pre_checkout_query
114        await query.answer(ok=False, error_message="Something went wrong...")
115        return
116
117    # First option has a single LabeledPrice
118    options = [ShippingOption("1", "Shipping Option A", [LabeledPrice("A", 100)])]
119    # second option has an array of LabeledPrice objects
120    price_list = [LabeledPrice("B1", 150), LabeledPrice("B2", 200)]
121    options.append(ShippingOption("2", "Shipping Option B", price_list))
122    await query.answer(ok=True, shipping_options=options)
123
124
125# after (optional) shipping, it's the pre-checkout
126async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
127    """Answers the PreQecheckoutQuery"""
128    query = update.pre_checkout_query
129    # check the payload, is this from your bot?
130    if query.invoice_payload != "Custom-Payload":
131        # answer False pre_checkout_query
132        await query.answer(ok=False, error_message="Something went wrong...")
133    else:
134        await query.answer(ok=True)
135
136
137# finally, after contacting the payment provider...
138async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
139    """Confirms the successful payment."""
140    # do something after successfully receiving payment?
141    await update.message.reply_text("Thank you for your payment!")
142
143
144def main() -> None:
145    """Run the bot."""
146    # Create the Application and pass it your bot's token.
147    application = Application.builder().token("TOKEN").build()
148
149    # simple start function
150    application.add_handler(CommandHandler("start", start_callback))
151
152    # Add command handler to start the payment invoice
153    application.add_handler(CommandHandler("shipping", start_with_shipping_callback))
154    application.add_handler(CommandHandler("noshipping", start_without_shipping_callback))
155
156    # Optional handler if your product requires shipping
157    application.add_handler(ShippingQueryHandler(shipping_callback))
158
159    # Pre-checkout handler to final check
160    application.add_handler(PreCheckoutQueryHandler(precheckout_callback))
161
162    # Success! Notify your user!
163    application.add_handler(
164        MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)
165    )
166
167    # Run the bot until the user presses Ctrl-C
168    application.run_polling()
169
170
171if __name__ == "__main__":
172    main()