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)
 37# set higher logging level for httpx to avoid all GET and POST requests being logged
 38logging.getLogger("httpx").setLevel(logging.WARNING)
 39
 40logger = logging.getLogger(__name__)
 41
 42PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
 43
 44
 45async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
 46    """Displays info on how to use the bot."""
 47    msg = (
 48        "Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
 49        "invoice without shipping."
 50    )
 51
 52    await update.message.reply_text(msg)
 53
 54
 55async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
 56    """Sends an invoice with shipping-payment."""
 57    chat_id = update.message.chat_id
 58    title = "Payment Example"
 59    description = "Payment Example using python-telegram-bot"
 60    # select a payload just for you to recognize its the donation from your bot
 61    payload = "Custom-Payload"
 62    # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
 63    currency = "USD"
 64    # price in dollars
 65    price = 1
 66    # price * 100 so as to include 2 decimal points
 67    # check https://core.telegram.org/bots/payments#supported-currencies for more details
 68    prices = [LabeledPrice("Test", price * 100)]
 69
 70    # optionally pass need_name=True, need_phone_number=True,
 71    # need_email=True, need_shipping_address=True, is_flexible=True
 72    await context.bot.send_invoice(
 73        chat_id,
 74        title,
 75        description,
 76        payload,
 77        PAYMENT_PROVIDER_TOKEN,
 78        currency,
 79        prices,
 80        need_name=True,
 81        need_phone_number=True,
 82        need_email=True,
 83        need_shipping_address=True,
 84        is_flexible=True,
 85    )
 86
 87
 88async def start_without_shipping_callback(
 89    update: Update, context: ContextTypes.DEFAULT_TYPE
 90) -> None:
 91    """Sends an invoice without shipping-payment."""
 92    chat_id = update.message.chat_id
 93    title = "Payment Example"
 94    description = "Payment Example using python-telegram-bot"
 95    # select a payload just for you to recognize its the donation from your bot
 96    payload = "Custom-Payload"
 97    # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
 98    currency = "USD"
 99    # price in dollars
100    price = 1
101    # price * 100 so as to include 2 decimal points
102    prices = [LabeledPrice("Test", price * 100)]
103
104    # optionally pass need_name=True, need_phone_number=True,
105    # need_email=True, need_shipping_address=True, is_flexible=True
106    await context.bot.send_invoice(
107        chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices
108    )
109
110
111async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
112    """Answers the ShippingQuery with ShippingOptions"""
113    query = update.shipping_query
114    # check the payload, is this from your bot?
115    if query.invoice_payload != "Custom-Payload":
116        # answer False pre_checkout_query
117        await query.answer(ok=False, error_message="Something went wrong...")
118        return
119
120    # First option has a single LabeledPrice
121    options = [ShippingOption("1", "Shipping Option A", [LabeledPrice("A", 100)])]
122    # second option has an array of LabeledPrice objects
123    price_list = [LabeledPrice("B1", 150), LabeledPrice("B2", 200)]
124    options.append(ShippingOption("2", "Shipping Option B", price_list))
125    await query.answer(ok=True, shipping_options=options)
126
127
128# after (optional) shipping, it's the pre-checkout
129async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
130    """Answers the PreQecheckoutQuery"""
131    query = update.pre_checkout_query
132    # check the payload, is this from your bot?
133    if query.invoice_payload != "Custom-Payload":
134        # answer False pre_checkout_query
135        await query.answer(ok=False, error_message="Something went wrong...")
136    else:
137        await query.answer(ok=True)
138
139
140# finally, after contacting the payment provider...
141async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
142    """Confirms the successful payment."""
143    # do something after successfully receiving payment?
144    await update.message.reply_text("Thank you for your payment!")
145
146
147def main() -> None:
148    """Run the bot."""
149    # Create the Application and pass it your bot's token.
150    application = Application.builder().token("TOKEN").build()
151
152    # simple start function
153    application.add_handler(CommandHandler("start", start_callback))
154
155    # Add command handler to start the payment invoice
156    application.add_handler(CommandHandler("shipping", start_with_shipping_callback))
157    application.add_handler(CommandHandler("noshipping", start_without_shipping_callback))
158
159    # Optional handler if your product requires shipping
160    application.add_handler(ShippingQueryHandler(shipping_callback))
161
162    # Pre-checkout handler to final check
163    application.add_handler(PreCheckoutQueryHandler(precheckout_callback))
164
165    # Success! Notify your user!
166    application.add_handler(
167        MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)
168    )
169
170    # Run the bot until the user presses Ctrl-C
171    application.run_polling(allowed_updates=Update.ALL_TYPES)
172
173
174if __name__ == "__main__":
175    main()