1
Fork 0
mirror of https://github.com/Steffo99/greed.git synced 2024-11-21 21:44:19 +00:00

First part of the order products

This commit is contained in:
Steffo 2018-02-15 10:37:51 +01:00
parent b0186edd42
commit 6686543cc7
3 changed files with 138 additions and 81 deletions

View file

@ -80,25 +80,36 @@ class Product(TableDeclarativeBase):
# No __init__ is needed, the default one is sufficient # 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.""" """Return the product details formatted with Telegram HTML. The image is omitted."""
if one_row: 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)} - {strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price)}"
return f"{escape(self.name)}\n" \ return f"<b>{escape(self.name)}</b>\n" \
f"{escape(self.description)}\n\n" \ f"{escape(self.description)}\n" \
f"{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}\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)}" 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): def __repr__(self):
return f"<Product {self.name}>" 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.""" """Send a message containing the product data."""
r = requests.post(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendPhoto", if self.image is None:
files={"photo": self.image}, r = requests.get(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendMessage",
params={"chat_id": chat_id, params={"chat_id": chat_id,
"caption": str(self)}) "text": str(self),
return r "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): def set_image(self, file: telegram.File):
"""Download an image from Telegram and store it in the image column. """Download an image from Telegram and store it in the image column.

View file

@ -11,6 +11,9 @@ currency_format_string = "{symbol} {value}"
# Quantity of a product in stock # Quantity of a product in stock
in_stock_format_string = "{quantity} disponibili" 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: the start command was sent and the bot should welcome the user
conversation_after_start = "Ciao!\n" \ conversation_after_start = "Ciao!\n" \
"Benvenuto su greed!" "Benvenuto su greed!"
@ -34,6 +37,9 @@ conversation_admin_select_product = "Che prodotto vuoi modificare?"
# Conversation: add extra notes to the order # Conversation: add extra notes to the order
conversation_extra_notes = "Che messaggio vuoi lasciare insieme al tuo ordine?" 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 the cart contents
conversation_confirm_cart = "Il tuo carrello contiene questi prodotti:\n" \ conversation_confirm_cart = "Il tuo carrello contiene questi prodotti:\n" \
"{product_list}\n" \ "{product_list}\n" \
@ -87,6 +93,12 @@ menu_done = "✅️ Fatto"
# Menu: pay invoice # Menu: pay invoice
menu_pay = "💳 Paga" menu_pay = "💳 Paga"
# Menu: add to cart
menu_add_to_cart = " Aggiungi"
# Menu: remove from cart
menu_remove_from_cart = " Rimuovi"
# Add product: name? # Add product: name?
ask_product_name = "Come si deve chiamare il prodotto?" ask_product_name = "Come si deve chiamare il prodotto?"

174
worker.py
View file

@ -163,7 +163,7 @@ class ChatWorker(threading.Thread):
return update.message.successful_payment return update.message.successful_payment
def __wait_for_photo(self, cancellable:bool=False) -> typing.Union[typing.List[telegram.PhotoSize], CancelSignal]: 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: while True:
# Get the next update # Get the next update
update = self.__receive_next_update() update = self.__receive_next_update()
@ -180,6 +180,17 @@ class ChatWorker(threading.Thread):
# Return the photo array # Return the photo array
return update.message.photo 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): def __user_menu(self):
"""Function called from the run method when the user is not an administrator. """Function called from the run method when the user is not an administrator.
Normal bot actions should be placed here.""" Normal bot actions should be placed here."""
@ -215,75 +226,98 @@ class ChatWorker(threading.Thread):
def __order_menu(self): def __order_menu(self):
"""User menu to order products from the shop.""" """User menu to order products from the shop."""
raise NotImplementedError() # Get the products list from the db
# # Create a list with the requested items products = self.session.query(db.Product).all()
# order_items = [] # Create a dict to be used as 'cart'
# # Get the products list from the db # The key is the message id of the product list
# products = self.session.query(db.Product).all() cart = {} # type: typing.Dict[typing.List[db.Product, int]]
# # TODO: this should be changed # Initialize the products list
# # Loop exit reason for product in products:
# exit_reason = None # If the product is not for sale, don't display it
# # Ask for a list of products to order if product.price is None:
# while True: continue
# # Create a list of product names # Send the message without the keyboard to get the message id
# product_names = [product.name for product in products] message = product.send_as_message(self.chat.id)
# # Add a Cancel button at the end of the keyboard # Add the product to the cart
# product_names.append(strings.menu_cancel) cart[message['result']['message_id']] = [product, 0]
# # If at least 1 product has been ordered, add a Done button at the start of the keyboard # Create the inline keyboard to add the product to the cart
# if len(order_items) > 0: inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_add_to_cart, callback_data="cart_add")]])
# product_names.insert(0, strings.menu_done) # Edit the sent message and add the inline keyboard
# # Create a keyboard using the product names if product.image is None:
# keyboard = [[telegram.KeyboardButton(product_name)] for product_name in product_names] 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)
# # Wait for an answer else:
# selection = self.__wait_for_specific_message(product_names) 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)
# # If the user selected the Cancel option... # Create the keyboard with the cancel button
# if selection == strings.menu_cancel: inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_cancel, callback_data="cart_cancel")]])
# exit_reason = "Cancel" # Send a message containing the button to cancel or pay
# break final = self.bot.send_message(self.chat.id, strings.conversation_cart_actions, reply_markup=inline_keyboard)
# # If the user selected the Done option... # Wait for user input
# elif selection == strings.menu_done: while True:
# exit_reason = "Done" callback = self.__wait_for_inlinekeyboard_callback()
# break # React to the user input
# # If the user selected a product... # If the cancel button has been pressed...
# else: if callback.data == "cart_cancel":
# # Find the selected product # Stop waiting for user input and go back to the previous menu
# product = self.session.query(db.Product).filter_by(name=selection).one() return
# # Add the product to the order_items list # If a Add to Cart button has been pressed...
# order_items.append(product) elif callback.data == "cart_add":
# # Ask for extra notes # Get the selected product
# self.bot.send_message(self.chat.id, strings.conversation_extra_notes) product = cart[callback.message.message_id][0]
# # Wait for an answer # Add 1 copy to the cart
# notes = self.__wait_for_regex("(.+)") cart[callback.message.message_id][1] += 1
# # Create the confirmation message and find the total cost # Create the product inline keyboard
# total_cost = 0 product_inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_add_to_cart, callback_data="cart_add")],
# product_list_string = "" [telegram.InlineKeyboardButton(strings.menu_remove_from_cart, callback_data="cart_remove")]])
# for item in order_items: # Create the final inline keyboard
# # Add to the string and the cost final_inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_cancel, callback_data="cart_cancel")],
# product_list_string += f"{str(item)}\n" [telegram.InlineKeyboardButton(strings.menu_done, callback_data="cart_done")]])
# total_cost += item.price # Edit both the product and the final message
# # Send the confirmation message if product.image is None:
# 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"])))))) self.bot.edit_message_text(chat_id=self.chat.id, message_id=callback.message.message_id,
# # TODO: wait for an answer text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
# # TODO: create a new transaction else:
# # TODO: test the code self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id,
# # TODO: everything caption=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
# # Create the order record and add it to the session try:
# order = db.Order(user=self.user, self.bot.edit_message_text(chat_id=self.chat.id, message_id=final.message_id,
# creation_date=datetime.datetime.now(), text=strings.conversation_cart_actions, reply_markup=final_inline_keyboard)
# notes=notes) except telegram.error.BadRequest:
# self.session.add(order) # Telegram returns an error if the message is not edited
# # Commit the session so the order record gets an id pass
# self.session.commit() # If the Remove from cart button has been pressed...
# # Create the orderitems for the selected products elif callback.data == "cart_remove":
# for item in order_items: # Get the selected product
# item_record = db.OrderItem(product=item, product = cart[callback.message.message_id][0]
# order_id=order.order_id) # Remove 1 copy from the cart
# # Add the created item to the session if cart[callback.message.message_id][1] > 0:
# self.session.add(item_record) cart[callback.message.message_id][1] -= 1
# # Commit the session else:
# self.session.commit() continue
# # Send a confirmation to the user # Create the product inline keyboard
# self.bot.send_message(self.chat.id, strings.success_order_created) 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): def __order_status(self):
raise NotImplementedError() raise NotImplementedError()