mirror of
https://github.com/Steffo99/greed.git
synced 2024-11-21 13:34:18 +00:00
First part of the order products
This commit is contained in:
parent
b0186edd42
commit
6686543cc7
3 changed files with 138 additions and 81 deletions
33
database.py
33
database.py
|
@ -80,25 +80,36 @@ class Product(TableDeclarativeBase):
|
|||
|
||||
# No __init__ is needed, the default one is sufficient
|
||||
|
||||
def __str__(self, one_row=False):
|
||||
def __str__(self):
|
||||
return self.text()
|
||||
|
||||
def text(self, one_row:bool=False, cart_qty:int=None):
|
||||
"""Return the product details formatted with Telegram HTML. The image is omitted."""
|
||||
if one_row:
|
||||
return f"{escape(self.name)} - {strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price)}"
|
||||
return f"{escape(self.name)}\n" \
|
||||
f"{escape(self.description)}\n\n" \
|
||||
f"{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}\n" \
|
||||
f"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price)}"
|
||||
return f"<b>{escape(self.name)}</b>\n" \
|
||||
f"{escape(self.description)}\n" \
|
||||
f"<i>{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}</i>\n" \
|
||||
f"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price)}\n" \
|
||||
f"<b>{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}</b>"
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Product {self.name}>"
|
||||
|
||||
def send_as_message(self, chat_id: int) -> requests.Response:
|
||||
def send_as_message(self, chat_id: int) -> dict:
|
||||
"""Send a message containing the product data."""
|
||||
r = requests.post(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendPhoto",
|
||||
files={"photo": self.image},
|
||||
params={"chat_id": chat_id,
|
||||
"caption": str(self)})
|
||||
return r
|
||||
if self.image is None:
|
||||
r = requests.get(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendMessage",
|
||||
params={"chat_id": chat_id,
|
||||
"text": str(self),
|
||||
"parse_mode": "HTML"})
|
||||
else:
|
||||
r = requests.post(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendPhoto",
|
||||
files={"photo": self.image},
|
||||
params={"chat_id": chat_id,
|
||||
"caption": str(self),
|
||||
"parse_mode": "HTML"})
|
||||
return r.json()
|
||||
|
||||
def set_image(self, file: telegram.File):
|
||||
"""Download an image from Telegram and store it in the image column.
|
||||
|
|
12
strings.py
12
strings.py
|
@ -11,6 +11,9 @@ currency_format_string = "{symbol} {value}"
|
|||
# Quantity of a product in stock
|
||||
in_stock_format_string = "{quantity} disponibili"
|
||||
|
||||
# Copies of a product in cart
|
||||
in_cart_format_string = "{quantity} nel carrello"
|
||||
|
||||
# Conversation: the start command was sent and the bot should welcome the user
|
||||
conversation_after_start = "Ciao!\n" \
|
||||
"Benvenuto su greed!"
|
||||
|
@ -34,6 +37,9 @@ conversation_admin_select_product = "Che prodotto vuoi modificare?"
|
|||
# Conversation: add extra notes to the order
|
||||
conversation_extra_notes = "Che messaggio vuoi lasciare insieme al tuo ordine?"
|
||||
|
||||
# Conversation: click below to pay for the purchase
|
||||
conversation_cart_actions = "Quando hai finito di aggiungere prodotti al carrello, clicca uno dei pulsanti qui sotto!"
|
||||
|
||||
# Conversation: confirm the cart contents
|
||||
conversation_confirm_cart = "Il tuo carrello contiene questi prodotti:\n" \
|
||||
"{product_list}\n" \
|
||||
|
@ -87,6 +93,12 @@ menu_done = "✅️ Fatto"
|
|||
# Menu: pay invoice
|
||||
menu_pay = "💳 Paga"
|
||||
|
||||
# Menu: add to cart
|
||||
menu_add_to_cart = "➕ Aggiungi"
|
||||
|
||||
# Menu: remove from cart
|
||||
menu_remove_from_cart = "➖ Rimuovi"
|
||||
|
||||
# Add product: name?
|
||||
ask_product_name = "Come si deve chiamare il prodotto?"
|
||||
|
||||
|
|
174
worker.py
174
worker.py
|
@ -163,7 +163,7 @@ class ChatWorker(threading.Thread):
|
|||
return update.message.successful_payment
|
||||
|
||||
def __wait_for_photo(self, cancellable:bool=False) -> typing.Union[typing.List[telegram.PhotoSize], CancelSignal]:
|
||||
"""Continue getting updates until a photo is received, then download and return it."""
|
||||
"""Continue getting updates until a photo is received, then return it."""
|
||||
while True:
|
||||
# Get the next update
|
||||
update = self.__receive_next_update()
|
||||
|
@ -180,6 +180,17 @@ class ChatWorker(threading.Thread):
|
|||
# Return the photo array
|
||||
return update.message.photo
|
||||
|
||||
def __wait_for_inlinekeyboard_callback(self) -> telegram.CallbackQuery:
|
||||
"""Continue getting updates until an inline keyboard callback is received, then return it."""
|
||||
while True:
|
||||
# Get the next update
|
||||
update = self.__receive_next_update()
|
||||
# Ensure the update is a CallbackQuery
|
||||
if update.callback_query is None:
|
||||
continue
|
||||
# Return the callbackquery
|
||||
return update.callback_query
|
||||
|
||||
def __user_menu(self):
|
||||
"""Function called from the run method when the user is not an administrator.
|
||||
Normal bot actions should be placed here."""
|
||||
|
@ -215,75 +226,98 @@ class ChatWorker(threading.Thread):
|
|||
|
||||
def __order_menu(self):
|
||||
"""User menu to order products from the shop."""
|
||||
raise NotImplementedError()
|
||||
# # Create a list with the requested items
|
||||
# order_items = []
|
||||
# # Get the products list from the db
|
||||
# products = self.session.query(db.Product).all()
|
||||
# # TODO: this should be changed
|
||||
# # Loop exit reason
|
||||
# exit_reason = None
|
||||
# # Ask for a list of products to order
|
||||
# while True:
|
||||
# # Create a list of product names
|
||||
# product_names = [product.name for product in products]
|
||||
# # Add a Cancel button at the end of the keyboard
|
||||
# product_names.append(strings.menu_cancel)
|
||||
# # If at least 1 product has been ordered, add a Done button at the start of the keyboard
|
||||
# if len(order_items) > 0:
|
||||
# product_names.insert(0, strings.menu_done)
|
||||
# # Create a keyboard using the product names
|
||||
# keyboard = [[telegram.KeyboardButton(product_name)] for product_name in product_names]
|
||||
# # Wait for an answer
|
||||
# selection = self.__wait_for_specific_message(product_names)
|
||||
# # If the user selected the Cancel option...
|
||||
# if selection == strings.menu_cancel:
|
||||
# exit_reason = "Cancel"
|
||||
# break
|
||||
# # If the user selected the Done option...
|
||||
# elif selection == strings.menu_done:
|
||||
# exit_reason = "Done"
|
||||
# break
|
||||
# # If the user selected a product...
|
||||
# else:
|
||||
# # Find the selected product
|
||||
# product = self.session.query(db.Product).filter_by(name=selection).one()
|
||||
# # Add the product to the order_items list
|
||||
# order_items.append(product)
|
||||
# # Ask for extra notes
|
||||
# self.bot.send_message(self.chat.id, strings.conversation_extra_notes)
|
||||
# # Wait for an answer
|
||||
# notes = self.__wait_for_regex("(.+)")
|
||||
# # Create the confirmation message and find the total cost
|
||||
# total_cost = 0
|
||||
# product_list_string = ""
|
||||
# for item in order_items:
|
||||
# # Add to the string and the cost
|
||||
# product_list_string += f"{str(item)}\n"
|
||||
# total_cost += item.price
|
||||
# # Send the confirmation message
|
||||
# self.bot.send_message(self.chat.id, strings.conversation_confirm_cart.format(product_list=product_list_string, total_cost=strings.currency_format_string.format(symbol=strings.currency_symbol, value=(total_cost / (10 ** int(configloader.config["Payments"]["currency_exp"]))))))
|
||||
# # TODO: wait for an answer
|
||||
# # TODO: create a new transaction
|
||||
# # TODO: test the code
|
||||
# # TODO: everything
|
||||
# # Create the order record and add it to the session
|
||||
# order = db.Order(user=self.user,
|
||||
# creation_date=datetime.datetime.now(),
|
||||
# notes=notes)
|
||||
# self.session.add(order)
|
||||
# # Commit the session so the order record gets an id
|
||||
# self.session.commit()
|
||||
# # Create the orderitems for the selected products
|
||||
# for item in order_items:
|
||||
# item_record = db.OrderItem(product=item,
|
||||
# order_id=order.order_id)
|
||||
# # Add the created item to the session
|
||||
# self.session.add(item_record)
|
||||
# # Commit the session
|
||||
# self.session.commit()
|
||||
# # Send a confirmation to the user
|
||||
# self.bot.send_message(self.chat.id, strings.success_order_created)
|
||||
# Get the products list from the db
|
||||
products = self.session.query(db.Product).all()
|
||||
# Create a dict to be used as 'cart'
|
||||
# The key is the message id of the product list
|
||||
cart = {} # type: typing.Dict[typing.List[db.Product, int]]
|
||||
# Initialize the products list
|
||||
for product in products:
|
||||
# If the product is not for sale, don't display it
|
||||
if product.price is None:
|
||||
continue
|
||||
# Send the message without the keyboard to get the message id
|
||||
message = product.send_as_message(self.chat.id)
|
||||
# Add the product to the cart
|
||||
cart[message['result']['message_id']] = [product, 0]
|
||||
# Create the inline keyboard to add the product to the cart
|
||||
inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_add_to_cart, callback_data="cart_add")]])
|
||||
# Edit the sent message and add the inline keyboard
|
||||
if product.image is None:
|
||||
self.bot.edit_message_text(chat_id=self.chat.id, message_id=message['result']['message_id'], text=str(product), parse_mode="HTML", reply_markup=inline_keyboard)
|
||||
else:
|
||||
self.bot.edit_message_caption(chat_id=self.chat.id, message_id=message['result']['message_id'], caption=str(product), parse_mode="HTML", reply_markup=inline_keyboard)
|
||||
# Create the keyboard with the cancel button
|
||||
inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_cancel, callback_data="cart_cancel")]])
|
||||
# Send a message containing the button to cancel or pay
|
||||
final = self.bot.send_message(self.chat.id, strings.conversation_cart_actions, reply_markup=inline_keyboard)
|
||||
# Wait for user input
|
||||
while True:
|
||||
callback = self.__wait_for_inlinekeyboard_callback()
|
||||
# React to the user input
|
||||
# If the cancel button has been pressed...
|
||||
if callback.data == "cart_cancel":
|
||||
# Stop waiting for user input and go back to the previous menu
|
||||
return
|
||||
# If a Add to Cart button has been pressed...
|
||||
elif callback.data == "cart_add":
|
||||
# Get the selected product
|
||||
product = cart[callback.message.message_id][0]
|
||||
# Add 1 copy to the cart
|
||||
cart[callback.message.message_id][1] += 1
|
||||
# Create the product inline keyboard
|
||||
product_inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_add_to_cart, callback_data="cart_add")],
|
||||
[telegram.InlineKeyboardButton(strings.menu_remove_from_cart, callback_data="cart_remove")]])
|
||||
# Create the final inline keyboard
|
||||
final_inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_cancel, callback_data="cart_cancel")],
|
||||
[telegram.InlineKeyboardButton(strings.menu_done, callback_data="cart_done")]])
|
||||
# Edit both the product and the final message
|
||||
if product.image is None:
|
||||
self.bot.edit_message_text(chat_id=self.chat.id, message_id=callback.message.message_id,
|
||||
text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
|
||||
else:
|
||||
self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id,
|
||||
caption=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
|
||||
try:
|
||||
self.bot.edit_message_text(chat_id=self.chat.id, message_id=final.message_id,
|
||||
text=strings.conversation_cart_actions, reply_markup=final_inline_keyboard)
|
||||
except telegram.error.BadRequest:
|
||||
# Telegram returns an error if the message is not edited
|
||||
pass
|
||||
# If the Remove from cart button has been pressed...
|
||||
elif callback.data == "cart_remove":
|
||||
# Get the selected product
|
||||
product = cart[callback.message.message_id][0]
|
||||
# Remove 1 copy from the cart
|
||||
if cart[callback.message.message_id][1] > 0:
|
||||
cart[callback.message.message_id][1] -= 1
|
||||
else:
|
||||
continue
|
||||
# Create the product inline keyboard
|
||||
product_inline_list = [[telegram.InlineKeyboardButton(strings.menu_add_to_cart, callback_data="cart_add")]]
|
||||
if cart[callback.message.message_id][1] > 0:
|
||||
product_inline_list.append([telegram.InlineKeyboardButton(strings.menu_remove_from_cart, callback_data="cart_remove")])
|
||||
product_inline_keyboard = telegram.InlineKeyboardMarkup(product_inline_list)
|
||||
# Create the final inline keyboard
|
||||
final_inline_list = [[telegram.InlineKeyboardButton(strings.menu_cancel, callback_data="cart_cancel")]]
|
||||
for product_id in cart:
|
||||
if cart[product_id][1] > 0:
|
||||
final_inline_list.append([telegram.InlineKeyboardButton(strings.menu_done, callback_data="cart_done")])
|
||||
break
|
||||
final_inline_keyboard = telegram.InlineKeyboardMarkup(final_inline_list)
|
||||
# Edit both the product and the final message
|
||||
if product.image is None:
|
||||
self.bot.edit_message_text(chat_id=self.chat.id, message_id=callback.message.message_id,
|
||||
text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
|
||||
else:
|
||||
self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id,
|
||||
caption=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
|
||||
try:
|
||||
self.bot.edit_message_text(chat_id=self.chat.id, message_id=final.message_id,
|
||||
text=strings.conversation_cart_actions, reply_markup=final_inline_keyboard)
|
||||
except telegram.error.BadRequest:
|
||||
# Telegram returns an error if the message is not edited
|
||||
pass
|
||||
|
||||
def __order_status(self):
|
||||
raise NotImplementedError()
|
||||
|
|
Loading…
Reference in a new issue