From c3d3cb2c3e6710a3154549f884e1eb3fa235f9aa Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 19 Feb 2018 13:47:43 +0100 Subject: [PATCH] Add order product menu --- database.py | 4 ++-- strings.py | 10 ++++++++++ worker.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/database.py b/database.py index 3bebc4d..3472c87 100644 --- a/database.py +++ b/database.py @@ -86,11 +86,11 @@ class Product(TableDeclarativeBase): 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)} - {strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price / (10 ** int(configloader.config['Payments']['currency_exp'])))}" return f"{escape(self.name)}\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"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price)}\n" \ + f"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price / (10 ** int(configloader.config['Payments']['currency_exp'])))}\n" \ f"{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}" def __repr__(self): diff --git a/strings.py b/strings.py index 19b7bbc..7963d0a 100644 --- a/strings.py +++ b/strings.py @@ -112,6 +112,10 @@ ask_product_price = "Quanto deve costare il prodotto?\n" \ # Add product: image? ask_product_image = "Che immagine vuoi che abbia il prodotto?" +# Order product: notes? +ask_order_notes = "Vuoi lasciare un messaggio insieme all'ordine?\n" \ + "Sarà visibile al negoziante." + # Thread has started downloading an image and might be unresponsive downloading_image = "Sto scaricando la tua foto!\n" \ "Potrei metterci un po'... Abbi pazienza!\n" \ @@ -149,6 +153,9 @@ bot_info = 'Questo bot utilizza gree # Success: product has been added/edited to the database success_product_edited = "✅ Il prodotto è stato aggiunto/modificato con successo!" +# Success: order has been created +success_order_created = "✅ L'ordine è stato inviato con successo!" + # Error: message received not in a private chat error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private." @@ -167,3 +174,6 @@ error_invoice_expired = "⚠️ Questo pagamento è scaduto ed è stato annullat # Error: a product with that name already exists error_duplicate_name = "️⚠ Esiste già un prodotto con questo nome." + +# Error: not enough credit to order +error_not_enough_credit = "⚠ Non hai credito sufficiente per effettuare l'ordine." diff --git a/worker.py b/worker.py index 61b53e2..a563470 100644 --- a/worker.py +++ b/worker.py @@ -1,6 +1,8 @@ import threading import typing import uuid + +import datetime import telegram import strings import configloader @@ -305,7 +307,7 @@ class ChatWorker(threading.Thread): 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 + # Edit the product 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) @@ -318,6 +320,50 @@ class ChatWorker(threading.Thread): except telegram.error.BadRequest: # Telegram returns an error if the message is not edited pass + # If the done button has been pressed... + elif callback.data == "cart_done": + # End the loop + break + # Create an inline keyboard with a single skip button + cancel = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_skip, callback_data="cmd_cancel")]]) + # Ask if the user wants to add notes to the order + self.bot.send_message(self.chat.id, strings.ask_order_notes, reply_markup=cancel) + # Wait for user input + notes = self.__wait_for_regex(r"(.*)", cancellable=True) + # Create a new Order + order = db.Order(user=self.user, + creation_date=datetime.datetime.now(), + notes=notes if not isinstance(notes, CancelSignal) else "") + # Add the record to the session and get an ID + self.session.add(order) + self.session.flush() + # For each product added to the cart, create a new OrderItem and get the total value + value = 0 + for product in cart: + # Add the price multiplied by the quantity to the total price + value -= cart[product][0].price * cart[product][1] + # Create {quantity} new OrderItems + for i in range(0, cart[product][1]): + orderitem = db.OrderItem(product=cart[product][0], + order_id=order.order_id) + self.session.add(orderitem) + # Ensure the user has enough credit to make the purchase + if self.user.credit + value < 0: + self.bot.send_message(self.chat.id, strings.error_not_enough_credit) + # Rollback all the changes + self.session.rollback() + return + # Create a new transaction and add it to the session + transaction = db.Transaction(user=self.user, + value=value) + self.session.add(transaction) + # Subtract credit from the user + self.user.credit += value + # Commit all the changes + self.session.commit() + # Notify the user of the order result + self.bot.send_message(self.chat.id, strings.success_order_created) + def __order_status(self): raise NotImplementedError() @@ -374,14 +420,14 @@ class ChatWorker(threading.Thread): reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait until a valid amount is sent # TODO: check and debug the regex - selection = self.__wait_for_regex(r"([0-9]{1,3}(?:[.,][0-9]{1,2})?|" + strings.menu_cancel + r")") + selection = self.__wait_for_regex(r"([0-9]{1,3}(?:[.,][0-9]+)?|" + strings.menu_cancel + r")") # If the user cancelled the action if selection == strings.menu_cancel: # Exit the loop cancelled = True continue # Convert the amount to an integer - value = int(selection.replace(".", "").replace(",", "")) * (10 ** int(configloader.config["Payments"]["currency_exp"])) + value = int(float(selection.replace(",", ".")) * (10 ** int(configloader.config["Payments"]["currency_exp"]))) # Ensure the amount is within the range if value > int(configloader.config["Payments"]["max_amount"]): self.bot.send_message(self.chat.id, strings.error_payment_amount_over_max.format(max_amount=strings.currency_format_string.format(symbol=strings.currency_symbol, value=configloader.config["Payments"]["max_amount"]))) @@ -550,7 +596,7 @@ class ChatWorker(threading.Thread): elif price.lower() == "x": price = None else: - price = int(price.replace(".", "").replace(",", "")) * (10 ** int(configloader.config["Payments"]["currency_exp"])) + price = int(float(price.replace(",", ".")) * (10 ** int(configloader.config["Payments"]["currency_exp"]))) # Ask for the product image self.bot.send_message(self.chat.id, strings.ask_product_image, reply_markup=cancel) # Wait for an answer