paymentbot.pyΒΆ

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