From d0faae11fba9aa7f92607b9c7418c948511a0c11 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 31 Mar 2020 01:52:44 +0200 Subject: [PATCH 01/24] Accept any commands starting with /start to start the bot --- core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.py b/core.py index 32fbf3f..bf9e6f5 100644 --- a/core.py +++ b/core.py @@ -53,7 +53,7 @@ def main(): # Skip the update continue # If the message is a start command... - if isinstance(update.message.text, str) and update.message.text == "/start": + if isinstance(update.message.text, str) and update.message.text.startswith("/start"): # Check if a worker already exists for that chat old_worker = chat_workers.get(update.message.chat.id) # If it exists, gracefully stop the worker From 23febf1b4a7a81edfe44ff0b5d5971332600ec98 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 02:05:59 +0300 Subject: [PATCH 02/24] fix Cancellable calls --- worker.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/worker.py b/worker.py index 4de75af..3560cbc 100644 --- a/worker.py +++ b/worker.py @@ -560,7 +560,7 @@ class ChatWorker(threading.Thread): self.bot.send_message(self.chat.id, strings.conversation_payment_method, reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait for a reply from the user - selection = self.__wait_for_specific_message([strings.menu_cash, strings.menu_credit_card, strings.menu_cancel]) + selection = self.__wait_for_specific_message([strings.menu_cash, strings.menu_credit_card, strings.menu_cancel], cancellable=True) # If the user has selected the Cash option... if selection == strings.menu_cash: # Go to the pay with cash function @@ -571,7 +571,7 @@ class ChatWorker(threading.Thread): # Go to the pay with credit card function self.__add_credit_cc() # If the user has selected the Cancel option... - elif selection == strings.menu_cancel: + elif isinstance(selection, CancelSignal): # Send him back to the previous menu return @@ -591,9 +591,9 @@ class ChatWorker(threading.Thread): self.bot.send_message(self.chat.id, strings.payment_cc_amount, reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait until a valid amount is sent - selection = self.__wait_for_regex(r"([0-9]+(?:[.,][0-9]+)?|" + strings.menu_cancel + r")") + selection = self.__wait_for_regex(r"([0-9]+(?:[.,][0-9]+)?|" + strings.menu_cancel + r")", cancellable=True) # If the user cancelled the action - if selection == strings.menu_cancel: + if isinstance(selection, CancelSignal): # Exit the loop cancelled = True continue @@ -747,9 +747,9 @@ class ChatWorker(threading.Thread): self.bot.send_message(self.chat.id, strings.conversation_admin_select_product, reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait for a reply from the user - selection = self.__wait_for_specific_message(product_names) + selection = self.__wait_for_specific_message(product_names, cancellable = True) # If the user has selected the Cancel option... - if selection == strings.menu_cancel: + if isinstance(selection, CancelSignal): # Exit the menu return # If the user has selected the Add Product option... @@ -869,8 +869,8 @@ class ChatWorker(threading.Thread): self.bot.send_message(self.chat.id, strings.conversation_admin_select_product_to_delete, reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait for a reply from the user - selection = self.__wait_for_specific_message(product_names) - if selection == strings.menu_cancel: + selection = self.__wait_for_specific_message(product_names, cancellable = True) + if isinstance(selection, CancelSignal): # Exit the menu return else: From 96c295b327ef76375c0eb5c8473490996269b565 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Fri, 3 Apr 2020 20:19:46 +0300 Subject: [PATCH 03/24] adding Ukrainian translations --- strings/uk_UA.py | 415 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 strings/uk_UA.py diff --git a/strings/uk_UA.py b/strings/uk_UA.py new file mode 100644 index 0000000..a9b13a1 --- /dev/null +++ b/strings/uk_UA.py @@ -0,0 +1,415 @@ +# Strings / localization file for greed +# Can be edited, but DON'T REMOVE THE REPLACEMENT FIELDS (words surrounded by {curly braces}) + +# Part of the translation by https://github.com/DarrenWestwood + +# Currency symbol +currency_symbol = "₴" + +# Positioning of the currency symbol +currency_format_string = "{value} {symbol}" + +# Quantity of a product in stock +in_stock_format_string = "{quantity} наявні" + +# Copies of a product in cart +in_cart_format_string = "{quantity} в кошику" + +# Product information +product_format_string = "{name}\n" \ + "{description}\n" \ + "{price}\n" \ + "{cart}" + +# Order number, displayed in the order info +order_number = "Замовлення #{id}" + +# Order info string, shown to the admins +order_format_string = "Користувач {user}\n" \ + "Створено {date}\n" \ + "\n" \ + "{items}\n" \ + "ЗАГАЛОМ: {value}\n" \ + "\n" \ + "Нотатка: {notes}\n" + +# Order info string, shown to the user +user_order_format_string = "{status_emoji} Замовлення {status_text}\n" \ + "{items}\n" \ + "Загалом: {value}\n" \ + "\n" \ + "Нотатка: {notes}\n" + +# Transaction page is loading +loading_transactions = "Завантажую транзакції...\n" \ + "Зачекайте кілька секунд." + +# Transactions page +transactions_page = "Сторінка {page}:\n" \ + "\n" \ + "{transactions}" + +# transactions.csv caption +csv_caption = "Файл 📄 .csv, який має всі транзакції з бази даних бота було сгенеровано.\n" \ + "Можете відкрити файл за допомогою Microsoft Excel, щоб переглянути деталі" + +# Conversation: the start command was sent and the bot should welcome the user +conversation_after_start = "Привіт!\n" \ + "Вітаю в greed!\n" \ + "Це 🅱️ Бета версія програми.\n" \ + "Програма повністю придатна до використання, але ще можуть бути баги.\n" \ + "Якщо знайшли баг - повідомте на https://github.com/Steffo99/greed/issues." + +# Conversation: to send an inline keyboard you need to send a message with it +conversation_open_user_menu = "Щоб ви хотіли зробити?\n" \ + "💰 У вас {credit} в гаманці.\n" \ + "\n" \ + "Виберіть опцію з варіантів на клавіатурі.\n" \ + "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." + +# Conversation: like above, but for administrators +conversation_open_admin_menu = "Ви є 💼 Менеджером цього магазину!\n" \ + "Що б ви хотіли зробити?\n" \ + "\n" \ + "Виберіть опцію з варіантів на клавіатурі.\n" \ + "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." + +# Conversation: select a payment method +conversation_payment_method = "Як би Ви хотіли поповнити гаманець?" + +# Conversation: select a product to edit +conversation_admin_select_product = "✏️ Який продукт потрібно редагувати?" + +# Conversation: select a product to delete +conversation_admin_select_product_to_delete = "❌ Який продукт потрібно видалит?" + +# Conversation: select a user to edit +conversation_admin_select_user = "Виберіть користувача для редагування." + +# Conversation: click below to pay for the purchase +conversation_cart_actions = "Додайте продукти в кошик натисканням кнопки Додати." \ + " Коли зробите Ваш вибір, повертайтесь до цього повідомлення" \ + " і натисніть кнопку Готово." + +# Conversation: confirm the cart contents +conversation_confirm_cart = "🛒 У вас в кошику наступні продукти:\n" \ + "{product_list}" \ + "Всього: {total_cost}\n" \ + "\n" \ + "Щоб продовжити натисніть Готово.\n" \ + "Якщо змінили свою думку - вибері Відміна." + +# Conversation: the user activated the live orders mode +conversation_live_orders_start = "Ви в режимі Свіжі Замовлення\n" \ + "Всі нові замовення від покупців зʼявляться в цьому чаті в режимі живого часу," \ + " і ви зможете помічати їх ✅ Виконано" \ + " або ✴️ Повернути кошти покупцю.\n" \ + "\n" \ + "Натисніть кнопку Стоп в цьому чаті, щоб зупинити цей режим" + +# Conversation: help menu has been opened +conversation_open_help_menu = "Як можемо Вам допомогти?" + +# Conversation: confirm promotion to admin +conversation_confirm_admin_promotion = "Ви впевнені, що хочете підвищити цього користувача до 💼 Менеджера?\n" \ + "Цю дію неможливо відмінити!" + +# Conversation: switching to user mode +conversation_switch_to_user_mode = " Ви перейшли в режим 👤 Замовника.\n" \ + "Якщо хочете повернутись в меню 💼 Менеджера, рестартуйте розмову з /start." + +# Notification: the conversation has expired +conversation_expired = "🕐 За довгий час я не отримав жодного повідомлення, тому я завершив розмову" \ + " щоб зберегти ресурси.\n" \ + "Щоб почату знову, надішліть команду /start ." + +# User menu: order +menu_order = "🛒 Замовлення" + +# User menu: order status +menu_order_status = "🛍 Мої замовлення" + +# User menu: add credit +menu_add_credit = "💵 Поповнити гаманець" + +# User menu: bot info +menu_bot_info = "ℹ️ Інформація про бот" + +# User menu: cash +menu_cash = "💵 Готівкою" + +# User menu: credit card +menu_credit_card = "💳 Кредитною картою" + +# Admin menu: products +menu_products = "📝️ Продукти" + +# Admin menu: orders +menu_orders = "📦 Замовлення" + +# Menu: transactions +menu_transactions = "💳 Список транзакцій" + +# Menu: edit credit +menu_edit_credit = "💰 Створити транзакцію" + +# Admin menu: go to user mode +menu_user_mode = "👤 Режим замовника" + +# Admin menu: add product +menu_add_product = "✨ Новий продукт" + +# Admin menu: delete product +menu_delete_product = "❌ Видалити продукт" + +# Menu: cancel +menu_cancel = "🔙 Відміна" + +# Menu: skip +menu_skip = "⏭ Пропустити" + +# Menu: done +menu_done = "✅️ Готово" + +# Menu: pay invoice +menu_pay = "💳 Заплатити" + +# Menu: complete +menu_complete = "✅ Готово" + +# Menu: refund +menu_refund = "✴️ Повернення коштів" + +# Menu: stop +menu_stop = "🛑 Стоп" + +# Menu: add to cart +menu_add_to_cart = "➕ Додати" + +# Menu: remove from cart +menu_remove_from_cart = "➖ Прибрати" + +# Menu: help menu +menu_help = "❓ Допомога" + +# Menu: guide +menu_guide = "📖 Інструкція" + +# Menu: next page +menu_next = "▶️ Наступна" + +# Menu: previous page +menu_previous = "◀️ Попередня" + +# Menu: contact the shopkeeper +menu_contact_shopkeeper = "👨‍💼 Контакти магазину" + +# Menu: generate transactions .csv file +menu_csv = "📄 .csv" + +# Menu: edit admins list +menu_edit_admins = "🏵 Редагувати менеджерів" + +# Emoji: unprocessed order +emoji_not_processed = "*️⃣" + +# Emoji: completed order +emoji_completed = "✅" + +# Emoji: refunded order +emoji_refunded = "✴️" + +# Emoji: yes +emoji_yes = "✅" + +# Emoji: no +emoji_no = "🚫" + +# Text: unprocessed order +text_not_processed = "очікує" + +# Text: completed order +text_completed = "завершено" + +# Text: refunded order +text_refunded = "повернуто" + +# Add product: name? +ask_product_name = "Як назвати продукт?" + +# Add product: description? +ask_product_description = "Який буде опис продукту?" + +# Add product: price? +ask_product_price = "Яка буде ціна?\n" \ + "Введіть X Якщо продукт зараз не продається." + +# Add product: image? +ask_product_image = "🖼 Яку картинку додати до продукта?\n" \ + "\n" \ + "Надішліть фото, або Пропустіть цей крок." + +# Order product: notes? +ask_order_notes = "Залишити повідомлення разом з цією покупкою?\n" \ + "💼 Повідомлення буде доступне Менеджеру магазину.\n" \ + "\n" \ + "Надішліть Ваше повідомлення, або натисність Пропустити" \ + " щоб не залишати повідомлення." + +# Refund product: reason? +ask_refund_reason = " Напишіть причину повернення коштів.\n" \ + "👤 Причина буде доступна замовнику." + +# Edit credit: notes? +ask_transaction_notes = " Додайте повідомлення до транзакції.\n" \ + "👤 Повідомлення буде доступне замовнику після поповнення/списання" \ + " і 💼 Адміністратору в логах транзакцій." + +# Edit credit: amount? +ask_credit = "Як ви хочете змінити баланс замовника?\n" \ + "\n" \ + "Надішліть повідомлення з сумою.\n" \ + "Використовуйте + щоб поповнити рахунок," \ + " і знак - щоб списати кошти." + +# Header for the edit admin message +admin_properties = "Доступи користувача {name}:" + +# Edit admin: can edit products? +prop_edit_products = "Редагувати продукти" + +# Edit admin: can receive orders? +prop_receive_orders = "Отримувати замовлення" + +# Edit admin: can create transactions? +prop_create_transactions = "Керувати транзакціями" + +# Edit admin: show on help message? +prop_display_on_help = "Показувати замовнику" + +# Thread has started downloading an image and might be unresponsive +downloading_image = "Я завантажую фото!\n" \ + "Може зайняти деякий час... Майте терпіння!\n" \ + "Я не зможу відповідати, поки йде завантаження." + +# Edit product: current value +edit_current_value = "Поточне значення:\n" \ + "
{value}
\n" \ + "\n" \ + "Натисність Пропустити під цим повідомленням, щоб залишити значення таким." + +# Payment: cash payment info +payment_cash = "Ви можете поповнити готівкою прямо в магазині.\n" \ + "Розрахуйтесь і дайте цей id менеджеру:\n" \ + "{user_cash_id}" + +# Payment: invoice amount +payment_cc_amount = "На яку сумму ви хочете поповнити гаманець?\n" \ + "\n" \ + "Виберіть сумму зі значень зараз, або введіть вручну в повідомленні" + +# Payment: add funds invoice title +payment_invoice_title = "Поповнення" + +# Payment: add funds invoice description +payment_invoice_description = "Оплата цього рахунку додасть {amount} в ваш гаманець." + +# Payment: label of the labeled price on the invoice +payment_invoice_label = "Платіж" + +# Payment: label of the labeled price on the invoice +payment_invoice_fee_label = "Оплата за поповнення" + +# Notification: order has been placed +notification_order_placed = "Отримано нове замовлення:\n" \ + "{order}" + +# Notification: order has been completed +notification_order_completed = "Ваше замовнення успішно завершено!\n" \ + "{order}" + +# Notification: order has been refunded +notification_order_refunded = "Ваше замовлення відмінено. Кошти повернуто!\n" \ + "{order}" + +# Notification: a manual transaction was applied +notification_transaction_created = "ℹ️ Нова транзакція в вашому гаманці:\n" \ + "{transaction}" + +# Refund reason +refund_reason = "Причина повернення:\n" \ + "{reason}" + +# Info: informazioni sul bot +bot_info = 'Цей бот використовує greed,' \ + ' фреймворк розроблений @Steffo для платежів Телеграм випущений під ліцензією' \ + ' ' \ + 'Affero General Public License 3.0.\n' + +# Help: guide +help_msg = "Інструкція по greed доступна за цією адресою:\n" \ + "https://docs.google.com/document/d/1f4MKVr0B7RSQfWTSa_6ZO0LM4nPpky_GX_qdls3EHtQ/" + +# Help: contact shopkeeper +contact_shopkeeper = "Наразі наступні працівники доступні і зможуть допомогти:\n" \ + "{shopkeepers}\n" \ + "Виберіть когось одного і напишіть в Телеграм чат." + +# Success: product has been added/edited to the database +success_product_edited = "✅ Продукт успішно створено/оновлено!" + +# Success: product has been added/edited to the database +success_product_deleted = "✅ Продукт успішно видалено!" + +# Success: order has been created +success_order_created = "✅ Замовлення успішно надіслано!\n" \ + "\n" \ + "{order}" + +# Success: order was marked as completed +success_order_completed = "✅ Ваше замовлення #{order_id} було успішно проведено." + +# Success: order was refunded successfully +success_order_refunded = "✴️ Кошти по замовленню #{order_id} було відшкодовано." + +# Success: transaction was created successfully +success_transaction_created = "✅ Транзакцію успішно створено!\n" \ + "{transaction}" + +# Error: message received not in a private chat +error_nonprivate_chat = "⚠️ Цей бот працює тільки в приватних чатах." + +# Error: a message was sent in a chat, but no worker exists for that chat. +# Suggest the creation of a new worker with /start +error_no_worker_for_chat = "⚠️ Спілкування з ботом було перервано.\n" \ + "Щоб почати знову, надішліть боту команду /start " + +# Error: add funds amount over max +error_payment_amount_over_max = "⚠️ Максимальна сума однієї транзакції {max_amount}." + +# Error: add funds amount under min +error_payment_amount_under_min = "⚠️ Мінімальна сума однієї транзакції {min_amount}." + +# Error: the invoice has expired and can't be paid +error_invoice_expired = "⚠️ Час дії інвойсу було вичерпано. Якщо все хочете додати кошти - виберіть Додати" \ + " кошти в меню." + +# Error: a product with that name already exists +error_duplicate_name = "️⚠️ Продукт з таким імʼям вже існує." + +# Error: not enough credit to order +error_not_enough_credit = "⚠️ У вас недостатньо коштів, щоб виконати замовлення." + +# Error: order has already been cleared +error_order_already_cleared = "⚠️ Це замовлення вже було опрацьовано раніше." + +# Error: no orders have been placed, so none can be shown +error_no_orders = "⚠️ Ви ще не зробили жодного замовлення, тому тут пусто." + +# Error: selected user does not exist +error_user_does_not_exist = "⚠️ Такого користувача не існує." + +# Fatal: conversation raised an exception +fatal_conversation_exception = "☢️ Ой лишенько! Помилка перервала нашу розмову\n" \ + "Про помилку було повідомлено власника бота..\n" \ + "Щоб почати розмову знову, надішліть команду /start." From c54e56b59ca3153c40f4a0966d9b9a6b165bdacc Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Fri, 3 Apr 2020 23:56:11 +0300 Subject: [PATCH 04/24] minor fix --- strings/uk_UA.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/strings/uk_UA.py b/strings/uk_UA.py index a9b13a1..99cb45e 100644 --- a/strings/uk_UA.py +++ b/strings/uk_UA.py @@ -51,7 +51,7 @@ transactions_page = "Сторінка {page}:\n" \ # transactions.csv caption csv_caption = "Файл 📄 .csv, який має всі транзакції з бази даних бота було сгенеровано.\n" \ - "Можете відкрити файл за допомогою Microsoft Excel, щоб переглянути деталі" + "Можете відкрити файл за допомогою Microsoft Excel, щоб переглянути деталі" # Conversation: the start command was sent and the bot should welcome the user conversation_after_start = "Привіт!\n" \ @@ -65,14 +65,14 @@ conversation_open_user_menu = "Щоб ви хотіли зробити?\n" \ "💰 У вас {credit} в гаманці.\n" \ "\n" \ "Виберіть опцію з варіантів на клавіатурі.\n" \ - "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." + "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." # Conversation: like above, but for administrators conversation_open_admin_menu = "Ви є 💼 Менеджером цього магазину!\n" \ "Що б ви хотіли зробити?\n" \ "\n" \ "Виберіть опцію з варіантів на клавіатурі.\n" \ - "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." + "Якщо клавіатури не видно - її можна активувати кнопкою з чотирма квадратами внизу." # Conversation: select a payment method conversation_payment_method = "Як би Ви хотіли поповнити гаманець?" @@ -97,7 +97,7 @@ conversation_confirm_cart = "🛒 У вас в кошику наступні п "Всього: {total_cost}\n" \ "\n" \ "Щоб продовжити натисніть Готово.\n" \ - "Якщо змінили свою думку - вибері Відміна." + "Якщо змінили свою думку - обирайте Відміна." # Conversation: the user activated the live orders mode conversation_live_orders_start = "Ви в режимі Свіжі Замовлення\n" \ From d70a8f2134c37dada160da49a5ee622329dfcb01 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 00:30:27 +0300 Subject: [PATCH 05/24] full stops --- strings/uk_UA.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/strings/uk_UA.py b/strings/uk_UA.py index 99cb45e..a9afe08 100644 --- a/strings/uk_UA.py +++ b/strings/uk_UA.py @@ -1,7 +1,7 @@ # Strings / localization file for greed # Can be edited, but DON'T REMOVE THE REPLACEMENT FIELDS (words surrounded by {curly braces}) -# Part of the translation by https://github.com/DarrenWestwood +# Part of the translation by https://github.com/pzhuk # Currency symbol currency_symbol = "₴" @@ -51,7 +51,7 @@ transactions_page = "Сторінка {page}:\n" \ # transactions.csv caption csv_caption = "Файл 📄 .csv, який має всі транзакції з бази даних бота було сгенеровано.\n" \ - "Можете відкрити файл за допомогою Microsoft Excel, щоб переглянути деталі" + "Можете відкрити файл за допомогою LibreOffice Calc, щоб переглянути деталі." # Conversation: the start command was sent and the bot should welcome the user conversation_after_start = "Привіт!\n" \ @@ -105,7 +105,7 @@ conversation_live_orders_start = "Ви в режимі Свіжі Замов " і ви зможете помічати їх ✅ Виконано" \ " або ✴️ Повернути кошти покупцю.\n" \ "\n" \ - "Натисніть кнопку Стоп в цьому чаті, щоб зупинити цей режим" + "Натисніть кнопку Стоп в цьому чаті, щоб зупинити цей режим." # Conversation: help menu has been opened conversation_open_help_menu = "Як можемо Вам допомогти?" @@ -249,6 +249,8 @@ ask_product_image = "🖼 Яку картинку додати до продук "\n" \ "Надішліть фото, або Пропустіть цей крок." +ask_product_category = "Оберіть категорію товару" + # Order product: notes? ask_order_notes = "Залишити повідомлення разом з цією покупкою?\n" \ "💼 Повідомлення буде доступне Менеджеру магазину.\n" \ @@ -306,7 +308,7 @@ payment_cash = "Ви можете поповнити готівкою прямо # Payment: invoice amount payment_cc_amount = "На яку сумму ви хочете поповнити гаманець?\n" \ "\n" \ - "Виберіть сумму зі значень зараз, або введіть вручну в повідомленні" + "Виберіть сумму із запропонованих значень, або введіть вручну в повідомленні." # Payment: add funds invoice title payment_invoice_title = "Поповнення" @@ -411,5 +413,5 @@ error_user_does_not_exist = "⚠️ Такого користувача не і # Fatal: conversation raised an exception fatal_conversation_exception = "☢️ Ой лишенько! Помилка перервала нашу розмову\n" \ - "Про помилку було повідомлено власника бота..\n" \ + "Про помилку було повідомлено власника бота.\n" \ "Щоб почати розмову знову, надішліть команду /start." From 9688575fd7311aecf767d7a56463ed32652462fa Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 12:23:45 +0300 Subject: [PATCH 06/24] refactor + add __get_cart_value() and __get_cart_summary() --- worker.py | 57 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/worker.py b/worker.py index 3560cbc..bec5c84 100644 --- a/worker.py +++ b/worker.py @@ -407,16 +407,10 @@ class ChatWorker(threading.Thread): message_id=callback.message.message_id, caption=product.text(cart_qty=cart[callback.message.message_id][1]), reply_markup=product_inline_keyboard) - # Create the cart summary - product_list = "" - total_cost = utils.Price(0) - for product_id in cart: - if cart[product_id][1] > 0: - product_list += cart[product_id][0].text(style="short", cart_qty=cart[product_id][1]) + "\n" - total_cost += cart[product_id][0].price * cart[product_id][1] + self.bot.edit_message_text(chat_id=self.chat.id, message_id=final_msg.message_id, - text=strings.conversation_confirm_cart.format(product_list=product_list, - total_cost=str(total_cost)), + text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), + total_cost=str(self.__get_cart_value(cart))), reply_markup=final_inline_keyboard) # If the Remove from cart button has been pressed... elif callback.data == "cart_remove": @@ -455,16 +449,10 @@ class ChatWorker(threading.Thread): message_id=callback.message.message_id, caption=product.text(cart_qty=cart[callback.message.message_id][1]), reply_markup=product_inline_keyboard) - # Create the cart summary - product_list = "" - total_cost = utils.Price(0) - for product_id in cart: - if cart[product_id][1] > 0: - product_list += cart[product_id][0].text(style="short", cart_qty=cart[product_id][1]) + "\n" - total_cost += cart[product_id][0].price * cart[product_id][1] + self.bot.edit_message_text(chat_id=self.chat.id, message_id=final_msg.message_id, - text=strings.conversation_confirm_cart.format(product_list=product_list, - total_cost=str(total_cost)), + text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), + total_cost=str(self.__get_cart_value(cart))), reply_markup=final_inline_keyboard) # If the done button has been pressed... elif callback.data == "cart_done": @@ -484,23 +472,40 @@ class ChatWorker(threading.Thread): # 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 each product added to the cart, create a new OrderItem 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]): order_item = db.OrderItem(product=cart[product][0], order_id=order.order_id) self.session.add(order_item) # Ensure the user has enough credit to make the purchase - if self.user.credit + value < 0: + if self.user.credit - self.__get_cart_value(cart) < 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 + + # User has credit and valid order, perform transaction now + self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart))) + + def __get_cart_value(self, cart): + # Calculate total items value in cart + value = utils.Price(0) + for product in cart: + value += cart[product][0].price * cart[product][1] + return value + + def __get_cart_summary(self, cart): + # Create the cart summary + product_list = "" + for product_id in cart: + if cart[product_id][1] > 0: + product_list += cart[product_id][0].text(style="short", cart_qty=cart[product_id][1]) + "\n" + return product_list + + def __order_transaction(self, order, value): + # Create a new transaction and add it to the session transaction = db.Transaction(user=self.user, value=value, order_id=order.order_id) @@ -511,6 +516,10 @@ class ChatWorker(threading.Thread): self.user.recalculate_credit() # Commit all the changes self.session.commit() + # Notify admins about new transation + self.__order_notify_admins(order=order) + + def __order_notify_admins(self, order): # Notify the user of the order result self.bot.send_message(self.chat.id, strings.success_order_created.format(order=order.get_text(self.session, user=True))) From 5828ba8f3106953e2bafbc9e4252dc564083df7a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 4 Apr 2020 13:06:57 +0200 Subject: [PATCH 07/24] PEP8 --- worker.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/worker.py b/worker.py index bec5c84..f998d72 100644 --- a/worker.py +++ b/worker.py @@ -408,10 +408,12 @@ class ChatWorker(threading.Thread): caption=product.text(cart_qty=cart[callback.message.message_id][1]), reply_markup=product_inline_keyboard) - self.bot.edit_message_text(chat_id=self.chat.id, message_id=final_msg.message_id, - text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), - total_cost=str(self.__get_cart_value(cart))), - reply_markup=final_inline_keyboard) + self.bot.edit_message_text( + chat_id=self.chat.id, + message_id=final_msg.message_id, + text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), + total_cost=str(self.__get_cart_value(cart))), + reply_markup=final_inline_keyboard) # If the Remove from cart button has been pressed... elif callback.data == "cart_remove": # Get the selected product, ensuring it exists @@ -450,10 +452,12 @@ class ChatWorker(threading.Thread): caption=product.text(cart_qty=cart[callback.message.message_id][1]), reply_markup=product_inline_keyboard) - self.bot.edit_message_text(chat_id=self.chat.id, message_id=final_msg.message_id, - text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), - total_cost=str(self.__get_cart_value(cart))), - reply_markup=final_inline_keyboard) + self.bot.edit_message_text( + chat_id=self.chat.id, + message_id=final_msg.message_id, + text=strings.conversation_confirm_cart.format(product_list=self.__get_cart_summary(cart), + total_cost=str(self.__get_cart_value(cart))), + reply_markup=final_inline_keyboard) # If the done button has been pressed... elif callback.data == "cart_done": # End the loop @@ -489,14 +493,16 @@ class ChatWorker(threading.Thread): # User has credit and valid order, perform transaction now self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart))) - def __get_cart_value(self, cart): + @staticmethod + def __get_cart_value(cart): # Calculate total items value in cart value = utils.Price(0) for product in cart: value += cart[product][0].price * cart[product][1] return value - def __get_cart_summary(self, cart): + @staticmethod + def __get_cart_summary(cart): # Create the cart summary product_list = "" for product_id in cart: @@ -505,7 +511,7 @@ class ChatWorker(threading.Thread): return product_list def __order_transaction(self, order, value): - # Create a new transaction and add it to the session + # Create a new transaction and add it to the session transaction = db.Transaction(user=self.user, value=value, order_id=order.order_id) From 37ce8ca57d891fae3b58da2d8f53e275991abc87 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sun, 5 Apr 2020 00:18:45 +0300 Subject: [PATCH 08/24] add russian language support --- config/template_config.ini | 2 + strings/ru_RU.py | 417 +++++++++++++++++++++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100644 strings/ru_RU.py diff --git a/config/template_config.ini b/config/template_config.ini index cb1650c..3d42652 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -12,6 +12,8 @@ is_template = yes ; Available languages: ; it_IT - Italian, by Steffo ; en_US - English, by https://github.com/DarrenWestwood (incomplete, please improve it!) +; ua_UK - Ukrainian, by https://github.com/pzhuk +; ru_RU - Russian, by https://github.com/pzhuk language = it_IT # Telegram bot parameters diff --git a/strings/ru_RU.py b/strings/ru_RU.py new file mode 100644 index 0000000..e093572 --- /dev/null +++ b/strings/ru_RU.py @@ -0,0 +1,417 @@ +# Strings / localization file for greed +# Can be edited, but DON'T REMOVE THE REPLACEMENT FIELDS (words surrounded by {curly braces}) + +# Part of the translation by https://github.com/pzhuk + +# Currency symbol +currency_symbol = "₽" + +# Positioning of the currency symbol +currency_format_string = "{value} {symbol}" + +# Quantity of a product in stock +in_stock_format_string = "{quantity} доступно" + +# Copies of a product in cart +in_cart_format_string = "{quantity} в корзине" + +# Product information +product_format_string = "{name}\n" \ + "{description}\n" \ + "{price}\n" \ + "{cart}" + +# Order number, displayed in the order info +order_number = "Заказ #{id}" + +# Order info string, shown to the admins +order_format_string = "Покупатель {user}\n" \ + "Создано {date}\n" \ + "\n" \ + "{items}\n" \ + "ИТОГО: {value}\n" \ + "\n" \ + "Сообщение: {notes}\n" + +# Order info string, shown to the user +user_order_format_string = "{status_emoji} Заказ {status_text}\n" \ + "{items}\n" \ + "Итого: {value}\n" \ + "\n" \ + "Сообщение: {notes}\n" + +# Transaction page is loading +loading_transactions = "Загружаю транзакции...\n" \ + "Это займет несколько секунд." + +# Transactions page +transactions_page = "Страница {page}:\n" \ + "\n" \ + "{transactions}" + +# transactions.csv caption +csv_caption = "Файл 📄 .csv сгенерирован, и содержит все транзакции из базы данных бота.\n" \ + "Вы можете открыть этот файт с помощью LibreOffice Calc, чтобы просмотреть детали." + +# Conversation: the start command was sent and the bot should welcome the user +conversation_after_start = "Привет!\n" \ + "Добро пожаловать в greed!\n" \ + "Это 🅱️ Бета версия программы.\n" \ + "Программа полностью готова к использованию, но могут быть баги.\n" \ + "Если нашли баг - сообщите тут: https://github.com/Steffo99/greed/issues." + +# Conversation: to send an inline keyboard you need to send a message with it +conversation_open_user_menu = "Что бы Вы хотели сделать?\n" \ + "💰 У вас в кошельке {credit}.\n" \ + "\n" \ + "Выберите опцию из вариантов на клавиатуре.\n" \ + "Если клавиатуры не видно - её можно активировать кнопкой с квардатами внизу." + +# Conversation: like above, but for administrators +conversation_open_admin_menu = "Вы 💼 Менеджер этого магазина!\n" \ + "Что бы Вы хотели сделать?\n" \ + "\n" \ + "Выберите опцию из вариантов на клавиатуре.\n" \ + "Если клавиатуры не видно - её можно активировать кнопкой с квардатами внизу." + +# Conversation: select a payment method +conversation_payment_method = "Как бы Вы хотели пополнить ваш кошелек?" + +# Conversation: select a product to edit +conversation_admin_select_product = "✏️ Какой продукт необходимо отредактировать?" + +# Conversation: select a product to delete +conversation_admin_select_product_to_delete = "❌ Какой продукт необходимо удалить?" + +# Conversation: select a user to edit +conversation_admin_select_user = "Выберите пользователя для редактирования." + +# Conversation: click below to pay for the purchase +conversation_cart_actions = "Добавьте продукты в корзину с помощью кнопки Добавить." \ + " Когда сделаете Ваш выбор, возвращайтесь к этому сообщению" \ + " и нажмите кнопку Готово." + +# Conversation: confirm the cart contents +conversation_confirm_cart = "🛒 Продукты у Вас в корзине:\n" \ + "{product_list}" \ + "Итого: {total_cost}\n" \ + "\n" \ + "Нажмите Готово, чтобы продолжить.\n" \ + "Если передумали - выберите Отмена." + +# Conversation: the user activated the live orders mode +conversation_live_orders_start = "Вы в режиме Новые заказы\n" \ + "Все новые заказы появятся в этом чате в режиме реального времени," \ + " и их можно отметить ✅ Выполнено" \ + " или ✴️ Возвращено в случае возврата денег.\n" \ + "\n" \ + "Нажмите Стоп в этом чате, чтобы остановить этот режим." + +# Conversation: help menu has been opened +conversation_open_help_menu = "Чем могу Вам помочь?" + +# Conversation: confirm promotion to admin +conversation_confirm_admin_promotion = "Вы уверены, что хотите повысить этого пользователя до 💼 Менеджера?\n" \ + "Это действие невозможно отменить!" + +# Conversation: switching to user mode +conversation_switch_to_user_mode = " Вы перешли в режим 👤 Покупателя.\n" \ + "Если хотите вернутся в режим 💼 Менеджера, рестартуйте с помощью команды /start." + +# Notification: the conversation has expired +conversation_expired = "🕐 За долгое время я не получил ни одного сообщения, поэтому я прекратил общение" \ + " чтобы сохранить ресурсы.\n" \ + "Чтобы начать снова, пришлите команду /start ." + +# User menu: order +menu_order = "🛒 Заказать" + +# User menu: order status +menu_order_status = "🛍 Мои заказы" + +# User menu: add credit +menu_add_credit = "💵 Пополнить кошелек" + +# User menu: bot info +menu_bot_info = "ℹ️ Информация о боте" + +# User menu: cash +menu_cash = "💵 Наличными" + +# User menu: credit card +menu_credit_card = "💳 Кредитной картой" + +# Admin menu: products +menu_products = "📝️ Продукты" + +# Admin menu: orders +menu_orders = "📦 Заказы" + +# Menu: transactions +menu_transactions = "💳 Список транзакций" + +# Menu: edit credit +menu_edit_credit = "💰 Создать транзакцию" + +# Admin menu: go to user mode +menu_user_mode = "👤 Режим покупателя" + +# Admin menu: add product +menu_add_product = "✨ Новый продукт" + +# Admin menu: delete product +menu_delete_product = "❌ Удалить продукт" + +# Menu: cancel +menu_cancel = "🔙 Отмена" + +# Menu: skip +menu_skip = "⏭ Пропустить" + +# Menu: done +menu_done = "✅️ Готово" + +# Menu: pay invoice +menu_pay = "💳 Заплатить" + +# Menu: complete +menu_complete = "✅ Готово" + +# Menu: refund +menu_refund = "✴️ Возврат средств" + +# Menu: stop +menu_stop = "🛑 Стоп" + +# Menu: add to cart +menu_add_to_cart = "➕ Добавить" + +# Menu: remove from cart +menu_remove_from_cart = "➖ Удалить" + +# Menu: help menu +menu_help = "❓ Помощь" + +# Menu: guide +menu_guide = "📖 Инструкция" + +# Menu: next page +menu_next = "▶️ Следующая" + +# Menu: previous page +menu_previous = "◀️ Предыдущая" + +# Menu: contact the shopkeeper +menu_contact_shopkeeper = "👨‍💼 Контакты" + +# Menu: generate transactions .csv file +menu_csv = "📄 .csv" + +# Menu: edit admins list +menu_edit_admins = "🏵 Изменить менеджеров" + +# Emoji: unprocessed order +emoji_not_processed = "*️⃣" + +# Emoji: completed order +emoji_completed = "✅" + +# Emoji: refunded order +emoji_refunded = "✴️" + +# Emoji: yes +emoji_yes = "✅" + +# Emoji: no +emoji_no = "🚫" + +# Text: unprocessed order +text_not_processed = "ожидает" + +# Text: completed order +text_completed = "выполнен" + +# Text: refunded order +text_refunded = "возмещен" + +# Add product: name? +ask_product_name = "Как назовем продукт?" + +# Add product: description? +ask_product_description = "Каким будет описание продукта?" + +# Add product: price? +ask_product_price = "Какова будет цена?\n" \ + "Введите X если продукт сейчас недоступен." + +# Add product: image? +ask_product_image = "🖼 Добавим фото продукта?\n" \ + "\n" \ + "Пришлите фото, или Пропустите этот шаг." + +ask_product_category = "Выберите категорию товара" + +# Order product: notes? +ask_order_notes = "Оставить заметку к этом заказу?\n" \ + "💼 Заметка будет доступна Менеджеру магазина.\n" \ + "\n" \ + "Напишите Ваше сообщение, или выберите Пропустить," \ + " чтобы не оставлять заметку." + +# Refund product: reason? +ask_refund_reason = " Сообщите причину возврата средств.\n" \ + " Причина будет видна 👤 Покупателю." + +# Edit credit: notes? +ask_transaction_notes = " Добавьте сообщение к транзакции.\n" \ + " Сообщение будет доступно 👤 Покупателю после пополнения/списания средств" \ + " и 💼 Администратору в логах транзакций." + +# Edit credit: amount? +ask_credit = "Вы хотите изменить баланс Покупателя?\n" \ + "\n" \ + "Напишите сообщение и укажите сумму.\n" \ + "Используйте + чтобы пополнить счет," \ + " и знак - чтобы списать средства." + +# Header for the edit admin message +admin_properties = "Доступы пользователя {name}:" + +# Edit admin: can edit products? +prop_edit_products = "Редактировать продукты" + +# Edit admin: can receive orders? +prop_receive_orders = "Получать заказы" + +# Edit admin: can create transactions? +prop_create_transactions = "Управлять транзакциями" + +# Edit admin: show on help message? +prop_display_on_help = "Показывать покупателям" + +# Thread has started downloading an image and might be unresponsive +downloading_image = "Я загружаю фото!\n" \ + "Это может занять некоторое время...!\n" \ + "Я не смогу отвечать, пока идет загрузка." + +# Edit product: current value +edit_current_value = "Текущее значение:\n" \ + "
{value}
\n" \ + "\n" \ + "Нажмите Пропустить, чтобы оставить значение без изменений." + +# Payment: cash payment info +payment_cash = "Вы можете пополнить счет наличными в торговых точках.\n" \ + "Рассчитайтесь и сообщение Менеджеру следующее значение:\n" \ + "{user_cash_id}" + +# Payment: invoice amount +payment_cc_amount = "На какую сумму пополнить Ваш кошелек?\n" \ + "\n" \ + "Выберите сумму из предложеных значений, или введите вручную в сообщении." + +# Payment: add funds invoice title +payment_invoice_title = "Пополнение" + +# Payment: add funds invoice description +payment_invoice_description = "Оплата этого счета добавит {amount} в Ваш кошелек." + +# Payment: label of the labeled price on the invoice +payment_invoice_label = "Платеж" + +# Payment: label of the labeled price on the invoice +payment_invoice_fee_label = "Сбор за пополнение" + +# Notification: order has been placed +notification_order_placed = "Получен новый заказ:\n" \ + "{order}" + +# Notification: order has been completed +notification_order_completed = "Выш заказ успешно выполнен!\n" \ + "{order}" + +# Notification: order has been refunded +notification_order_refunded = "Ваш заказ отменен. Средства возвращены в Ваш кошелек!\n" \ + "{order}" + +# Notification: a manual transaction was applied +notification_transaction_created = "ℹ️ Новая транзакция в Вашем кошельке:\n" \ + "{transaction}" + +# Refund reason +refund_reason = "Причина возврата:\n" \ + "{reason}" + +# Info: informazioni sul bot +bot_info = 'Этот бот использует greed,' \ + ' фреймворк разработан @Steffo для платежей Телеграм и выпущен под лицензией' \ + ' ' \ + 'Affero General Public License 3.0.\n' + +# Help: guide +help_msg = "Инструкция к greed доступна по этому адресу:\n" \ + "https://docs.google.com/document/d/1f4MKVr0B7RSQfWTSa_6ZO0LM4nPpky_GX_qdls3EHtQ/" + +# Help: contact shopkeeper +contact_shopkeeper = "Следующие сотрудники доступны сейчас и могут помочь:\n" \ + "{shopkeepers}\n" \ + "Выберите одного из них и напишите в Телеграм чат." + +# Success: product has been added/edited to the database +success_product_edited = "✅ Продукт успешно создан/обновлен!" + +# Success: product has been added/edited to the database +success_product_deleted = "✅ Продукт успешно удален!" + +# Success: order has been created +success_order_created = "✅ Заказ успешно создан!\n" \ + "\n" \ + "{order}" + +# Success: order was marked as completed +success_order_completed = "✅ Ваш заказ #{order_id} был успешно выполнен." + +# Success: order was refunded successfully +success_order_refunded = "✴️ Средства по заказу #{order_id} были возвращены." + +# Success: transaction was created successfully +success_transaction_created = "✅ Транзакция успешно создана!\n" \ + "{transaction}" + +# Error: message received not in a private chat +error_nonprivate_chat = "⚠️ Этот бот работает только в частных чатах." + +# Error: a message was sent in a chat, but no worker exists for that chat. +# Suggest the creation of a new worker with /start +error_no_worker_for_chat = "⚠️ Общение с ботом было прервано.\n" \ + "Чтобы начать снова, воспользуйтесь командой /start " + +# Error: add funds amount over max +error_payment_amount_over_max = "⚠️ Максимальная сумма одной транзакции {max_amount}." + +# Error: add funds amount under min +error_payment_amount_under_min = "⚠️ Минимальная сумма одной транзакции {min_amount}." + +# Error: the invoice has expired and can't be paid +error_invoice_expired = "⚠️ Время действия инвойса завершено. Если все еще хотите пополнить счет - выберите" \ + " Пополнить счет в меню." + +# Error: a product with that name already exists +error_duplicate_name = "️⚠️ Продукт с таким именем уже существует." + +# Error: not enough credit to order +error_not_enough_credit = "⚠️ У Вас недостаточно средств, чтобы выполнить заказ." + +# Error: order has already been cleared +error_order_already_cleared = "⚠️ Этот заказ уже был выполнен ранее." + +# Error: no orders have been placed, so none can be shown +error_no_orders = "⚠️ Вы еще не сделали ни одного заказа, поэтому здесь пусто." + +# Error: selected user does not exist +error_user_does_not_exist = "⚠️ Нет такого пользователя." + +# Fatal: conversation raised an exception +fatal_conversation_exception = "☢️ Вот беда! Ошибка прервала наше общение\n" \ + "Владельцу бота будет сообщено об этой ошибке.\n" \ + "Чтобы начать общение заново, воспользуйтесь командой /start." From be31210afac5824a0413f1d809bcf19107d794d3 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sun, 5 Apr 2020 00:43:41 +0300 Subject: [PATCH 09/24] Allow configuration of currency symbol instead of using language-based one --- config/template_config.ini | 3 +++ utils.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/template_config.ini b/config/template_config.ini index cb1650c..26cfeee 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -41,6 +41,9 @@ currency = EUR ; Currency exp parameter. You can find that on https://core.telegram.org/bots/payments/currencies.json. ; It has a value of 2 in most currencies (EUR, USD, GBP...) currency_exp = 2 +; Currency symbol which is show to the client users when displaying prices and transaction values +; If not defined here, default language specific currency symbol from strings would be used +currency_symbol = "€" # Credit card payment settings [Credit Card] diff --git a/utils.py b/utils.py index 855540f..36866f6 100644 --- a/utils.py +++ b/utils.py @@ -47,7 +47,7 @@ class Price: return f"" def __str__(self): - return strings.currency_format_string.format(symbol=strings.currency_symbol, + return strings.currency_format_string.format(symbol=(config["Payments"]["currency_symbol"] or strings.currency_symbol), value="{0:.2f}".format( self.value / (10 ** int(config["Payments"]["currency_exp"])))) From b1c313bf1de1fb275569d7875308db927fc419fd Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sun, 5 Apr 2020 19:04:32 +0200 Subject: [PATCH 10/24] Bump config version --- config/template_config.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/template_config.ini b/config/template_config.ini index 26cfeee..cbe2381 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -5,7 +5,7 @@ # Config file parameters [Config] ; Config file version. DO NOT EDIT THIS! -version = 14 +version = 15 ; Set this to no when you are done editing the file is_template = yes ; Language code for string file From 4c0c38902e88cfe0a7a012840654caf67734d7e0 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 20:18:35 +0300 Subject: [PATCH 11/24] create __issue_invoice() --- worker.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/worker.py b/worker.py index f998d72..bc2fc85 100644 --- a/worker.py +++ b/worker.py @@ -630,19 +630,17 @@ class ChatWorker(threading.Thread): else: # Exit the function return + # Issue the invoice + self.__make_payment(amount=value) + + def __make_payment(self, amount): # Set the invoice active invoice payload self.invoice_payload = str(uuid.uuid4()) # Create the price array - prices = [telegram.LabeledPrice(label=strings.payment_invoice_label, amount=int(value))] + prices = [telegram.LabeledPrice(label=strings.payment_invoice_label, amount=int(amount))] # If the user has to pay a fee when using the credit card, add it to the prices list - fee_percentage = float(configloader.config["Credit Card"]["fee_percentage"]) / 100 - fee_fixed = int(configloader.config["Credit Card"]["fee_fixed"]) - total_fee = value * fee_percentage + fee_fixed - if total_fee > 0: - prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, amount=int(total_fee))) - else: - # Otherwise, set the fee to 0 to ensure no accidental discounts are applied - total_fee = 0 + prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, amount=int(self.__get_total_fee(amount)))) + # Create the invoice keyboard inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_pay, pay=True)], [telegram.InlineKeyboardButton(strings.menu_cancel, @@ -650,7 +648,7 @@ class ChatWorker(threading.Thread): # The amount is valid, send the invoice self.bot.send_invoice(self.chat.id, title=strings.payment_invoice_title, - description=strings.payment_invoice_description.format(amount=str(value)), + description=strings.payment_invoice_description.format(amount=str(amount)), payload=self.invoice_payload, provider_token=configloader.config["Credit Card"]["credit_card_token"], start_parameter="tempdeeplink", @@ -660,7 +658,7 @@ class ChatWorker(threading.Thread): need_email=configloader.config["Credit Card"]["email_required"] == "yes", need_phone_number=configloader.config["Credit Card"]["phone_required"] == "yes", reply_markup=inline_keyboard) - # Wait for the invoice + precheckoutquery = self.__wait_for_precheckoutquery(cancellable=True) # Check if the user has cancelled the invoice if isinstance(precheckoutquery, CancelSignal): @@ -672,10 +670,11 @@ class ChatWorker(threading.Thread): successfulpayment = self.__wait_for_successfulpayment() # Create a new database transaction transaction = db.Transaction(user=self.user, - value=successfulpayment.total_amount - int(total_fee), + value=int(successfulpayment.total_amount - self.__get_total_fee(amount=amount)), provider="Credit Card", telegram_charge_id=successfulpayment.telegram_payment_charge_id, provider_charge_id=successfulpayment.provider_payment_charge_id) + if successfulpayment.order_info is not None: transaction.payment_name = successfulpayment.order_info.name transaction.payment_email = successfulpayment.order_info.email @@ -685,6 +684,17 @@ class ChatWorker(threading.Thread): # Commit all the changes self.session.commit() + @staticmethod + def __get_total_fee(amount): + #Calculate a fee for the required amount + fee_percentage = float(configloader.config["Credit Card"]["fee_percentage"]) / 100 + fee_fixed = int(configloader.config["Credit Card"]["fee_fixed"]) + total_fee = amount * fee_percentage + fee_fixed + if total_fee > 0: + return total_fee + # Set the fee to 0 to ensure no accidental discounts are applied + return 0 + def __bot_info(self): """Send information about the bot.""" self.bot.send_message(self.chat.id, strings.bot_info) From 5be2f9e76282c133c02ee0d1d7085e1fa3f3bbcf Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 20:53:10 +0300 Subject: [PATCH 12/24] add configurable payment presets --- config/template_config.ini | 3 +++ worker.py | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/config/template_config.ini b/config/template_config.ini index cbe2381..149eca7 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -72,6 +72,9 @@ phone_required = yes ; Display the full order information to the customers instead of the shortened version ; The full order information includes the order number and the timestamp of the order placement full_order_info = no +; Payment presets would be suggested to the user as buttons, when making credit card transaction +payment_presets = 10.00,25.00,50.00,100.00 + # Exception reporting settings [Error Reporting] diff --git a/worker.py b/worker.py index bc2fc85..c2716ea 100644 --- a/worker.py +++ b/worker.py @@ -593,11 +593,9 @@ class ChatWorker(threading.Thread): def __add_credit_cc(self): """Add money to the wallet through a credit card payment.""" # Create a keyboard to be sent later - keyboard = [[telegram.KeyboardButton(str(utils.Price("10.00")))], - [telegram.KeyboardButton(str(utils.Price("25.00")))], - [telegram.KeyboardButton(str(utils.Price("50.00")))], - [telegram.KeyboardButton(str(utils.Price("100.00")))], - [telegram.KeyboardButton(strings.menu_cancel)]] + presets = configloader.config["Appearance"]["payment_presets"].split(',') + keyboard = [[telegram.KeyboardButton(str(utils.Price(preset)))] for preset in presets] + keyboard.append([telegram.KeyboardButton(strings.menu_cancel)]); # Boolean variable to check if the user has cancelled the action cancelled = False # Loop used to continue asking if there's an error during the input @@ -630,7 +628,7 @@ class ChatWorker(threading.Thread): else: # Exit the function return - # Issue the invoice + # Issue the payment invoice self.__make_payment(amount=value) def __make_payment(self, amount): From 23f395ee8a2e7d97dd862297427f721167c0e8b3 Mon Sep 17 00:00:00 2001 From: Pavlo Zhuk Date: Sat, 4 Apr 2020 23:37:03 +0300 Subject: [PATCH 13/24] allow refill on insufficient funds during checkout --- config/template_config.ini | 3 ++- worker.py | 16 +++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/config/template_config.ini b/config/template_config.ini index 149eca7..c9e107e 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -74,7 +74,8 @@ phone_required = yes full_order_info = no ; Payment presets would be suggested to the user as buttons, when making credit card transaction payment_presets = 10.00,25.00,50.00,100.00 - +; Allow balance refill during the order checkout in case of unsufficient balance +refill_on_checkout = yes # Exception reporting settings [Error Reporting] diff --git a/worker.py b/worker.py index c2716ea..5d81b93 100644 --- a/worker.py +++ b/worker.py @@ -484,14 +484,20 @@ class ChatWorker(threading.Thread): order_id=order.order_id) self.session.add(order_item) # Ensure the user has enough credit to make the purchase - if self.user.credit - self.__get_cart_value(cart) < 0: + credit_required = self.__get_cart_value(cart) - self.user.credit + # Notify user In case of insufficient credit + if credit_required > 0: self.bot.send_message(self.chat.id, strings.error_not_enough_credit) + # Suggest payment for missing credit value if configuration allows refill + if configloader.config["Appearance"]["refill_on_checkout"] == 'yes': + self.__make_payment(utils.Price(credit_required)) + # If afer requested payment credit is still insufficient (either payment failure or cancel) + if self.user.credit < self.__get_cart_value(cart): # Rollback all the changes self.session.rollback() - return - - # User has credit and valid order, perform transaction now - self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart))) + else: + # User has credit and valid order, perform transaction now + self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart))) @staticmethod def __get_cart_value(cart): From c9561f0da5c15b7f98b2c3f8a0d0e476031a02fa Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 01:30:13 +0200 Subject: [PATCH 14/24] Bump up config file version --- config/template_config.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/template_config.ini b/config/template_config.ini index c9e107e..edc234d 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -5,7 +5,7 @@ # Config file parameters [Config] ; Config file version. DO NOT EDIT THIS! -version = 15 +version = 16 ; Set this to no when you are done editing the file is_template = yes ; Language code for string file From 9df1203b3e6a1c2d5a93c39ceb67cdfc3c5a6f36 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 01:44:23 +0200 Subject: [PATCH 15/24] Made a few changes --- worker.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/worker.py b/worker.py index 5d81b93..bee1423 100644 --- a/worker.py +++ b/worker.py @@ -581,7 +581,8 @@ class ChatWorker(threading.Thread): self.bot.send_message(self.chat.id, strings.conversation_payment_method, reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)) # Wait for a reply from the user - selection = self.__wait_for_specific_message([strings.menu_cash, strings.menu_credit_card, strings.menu_cancel], cancellable=True) + selection = self.__wait_for_specific_message([strings.menu_cash, strings.menu_credit_card, strings.menu_cancel], + cancellable=True) # If the user has selected the Cash option... if selection == strings.menu_cash: # Go to the pay with cash function @@ -601,7 +602,7 @@ class ChatWorker(threading.Thread): # Create a keyboard to be sent later presets = configloader.config["Appearance"]["payment_presets"].split(',') keyboard = [[telegram.KeyboardButton(str(utils.Price(preset)))] for preset in presets] - keyboard.append([telegram.KeyboardButton(strings.menu_cancel)]); + keyboard.append([telegram.KeyboardButton(strings.menu_cancel)]) # Boolean variable to check if the user has cancelled the action cancelled = False # Loop used to continue asking if there's an error during the input @@ -643,8 +644,10 @@ class ChatWorker(threading.Thread): # Create the price array prices = [telegram.LabeledPrice(label=strings.payment_invoice_label, amount=int(amount))] # If the user has to pay a fee when using the credit card, add it to the prices list - prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, amount=int(self.__get_total_fee(amount)))) - + fee = int(self.__get_total_fee(amount)) + if fee > 0: + prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, + amount=fee)) # Create the invoice keyboard inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_pay, pay=True)], [telegram.InlineKeyboardButton(strings.menu_cancel, @@ -662,7 +665,7 @@ class ChatWorker(threading.Thread): need_email=configloader.config["Credit Card"]["email_required"] == "yes", need_phone_number=configloader.config["Credit Card"]["phone_required"] == "yes", reply_markup=inline_keyboard) - + # Wait for the precheckout query precheckoutquery = self.__wait_for_precheckoutquery(cancellable=True) # Check if the user has cancelled the invoice if isinstance(precheckoutquery, CancelSignal): @@ -674,7 +677,7 @@ class ChatWorker(threading.Thread): successfulpayment = self.__wait_for_successfulpayment() # Create a new database transaction transaction = db.Transaction(user=self.user, - value=int(successfulpayment.total_amount - self.__get_total_fee(amount=amount)), + value=int(successfulpayment.total_amount) - fee, provider="Credit Card", telegram_charge_id=successfulpayment.telegram_payment_charge_id, provider_charge_id=successfulpayment.provider_payment_charge_id) @@ -690,7 +693,7 @@ class ChatWorker(threading.Thread): @staticmethod def __get_total_fee(amount): - #Calculate a fee for the required amount + # Calculate a fee for the required amount fee_percentage = float(configloader.config["Credit Card"]["fee_percentage"]) / 100 fee_fixed = int(configloader.config["Credit Card"]["fee_fixed"]) total_fee = amount * fee_percentage + fee_fixed From 9d6e21fb4ee22c9f45654d5d393a6a3265a0971e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 02:02:07 +0200 Subject: [PATCH 16/24] Move the presets to the [Credit Card] section --- config/template_config.ini | 5 +++-- worker.py | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/config/template_config.ini b/config/template_config.ini index edc234d..2b95dd1 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -53,6 +53,9 @@ credit_card_token = 123456789:YOUR_TOKEN_HERE_ min_amount = 1000 ; Maximum wallet payment accepted (in miniumum currency units, $1.00 = 100 units) max_amount = 10000 +; The preset selections that can be made when adding credit to the wallet with a credit card +; Presets are pipe-separated |, and should never be outside the bounds provided by the min_amount and max_amount options +payment_presets = 10.00 | 25.00 | 50.00 | 100.00 ; Make the user pay a extra fee when adding credit to the wallet with a credit card ; The formula for determining the total cost is: ; cost = added_funds + added_funds * fee_percentage / 100 + fee_fixed @@ -72,8 +75,6 @@ phone_required = yes ; Display the full order information to the customers instead of the shortened version ; The full order information includes the order number and the timestamp of the order placement full_order_info = no -; Payment presets would be suggested to the user as buttons, when making credit card transaction -payment_presets = 10.00,25.00,50.00,100.00 ; Allow balance refill during the order checkout in case of unsufficient balance refill_on_checkout = yes diff --git a/worker.py b/worker.py index bee1423..c4c6496 100644 --- a/worker.py +++ b/worker.py @@ -600,7 +600,7 @@ class ChatWorker(threading.Thread): def __add_credit_cc(self): """Add money to the wallet through a credit card payment.""" # Create a keyboard to be sent later - presets = configloader.config["Appearance"]["payment_presets"].split(',') + presets = list(map(lambda s: s.strip(" "), configloader.config["Credit Card"]["payment_presets"].split('|'))) keyboard = [[telegram.KeyboardButton(str(utils.Price(preset)))] for preset in presets] keyboard.append([telegram.KeyboardButton(strings.menu_cancel)]) # Boolean variable to check if the user has cancelled the action @@ -623,12 +623,14 @@ class ChatWorker(threading.Thread): if value > utils.Price(int(configloader.config["Credit Card"]["max_amount"])): self.bot.send_message(self.chat.id, strings.error_payment_amount_over_max.format( - max_amount=utils.Price(configloader.config["Payments"]["max_amount"]))) + max_amount=utils.Price(configloader.config["Credit Card"]["max_amount"])) + ) continue elif value < utils.Price(int(configloader.config["Credit Card"]["min_amount"])): self.bot.send_message(self.chat.id, strings.error_payment_amount_under_min.format( - min_amount=utils.Price(configloader.config["Payments"]["min_amount"]))) + min_amount=utils.Price(configloader.config["Credit Card"]["min_amount"])) + ) continue break # If the user cancelled the action... From 5da299f044e43621f78203eb473a0a47ad184ca4 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 02:22:47 +0200 Subject: [PATCH 17/24] #45: Load config files with UTF8 encoding --- configloader.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configloader.py b/configloader.py index ad96b43..87d21e6 100644 --- a/configloader.py +++ b/configloader.py @@ -5,18 +5,19 @@ import configparser # Check if the config file exists, and create one if it doesn't if not os.path.isfile("config/config.ini"): # Open the template file and create the config file - with open("config/template_config.ini") as template_file, open("config/config.ini", "w") as config_file: + with open("config/template_config.ini", encoding="utf8") as template_file, \ + open("config/config.ini", "w", encoding="utf8") as config_file: # Copy the template file to the config file config_file.write(template_file.read()) -with open("config/template_config.ini") as template_file: +with open("config/template_config.ini", encoding="utf8") as template_file: # Find the template version number config = configparser.ConfigParser() config.read_file(template_file) template_version = int(config["Config"]["version"]) # Overwrite the template config with the values in the config -with open("config/config.ini") as config_file: +with open("config/config.ini", encoding="utf8") as config_file: config.read_file(config_file) # Check if the file has been edited @@ -32,7 +33,7 @@ if template_version > int(config["Config"]["version"]): # Update the config version config["Config"]["version"] = str(template_version) # Save the file - with open("config/config.ini", "w") as config_file: + with open("config/config.ini", "w", encoding="utf8") as config_file: config.write(config_file) # Notify the user and quit print("The config file in config/config.ini has been updated.\n" From 3f6b208ba1a3120ea463b072b5670b47d84a974c Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 23:42:35 +0200 Subject: [PATCH 18/24] #47: Add a link to the greed Telegram group in the README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6fd5992..f54bb91 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ Users will be able to add credit to their wallet, place orders and contact you i `greed` currently does not have a documentation page, but you can try to read the [paper](https://docs.google.com/document/d/1f4MKVr0B7RSQfWTSa_6ZO0LM4nPpky_GX_qdls3EHtQ/edit?usp=sharing) (in Italian) I wrote for my final Scuola Superiore exam about it. +## Help! + +If you find a bug, have an idea for a new feature or just require help with `greed`, please [post an issue](https://github.com/Steffo99/greed/issues/new) on GitHub, or, if GitHub is blocked in your country, join [our Telegram group](https://t.me/greed_project) and send a message there. + ## Forks > Please note that @Steffo99, the developer of `greed`, does not endorse any of these forks. From 13243521a557841cf8e76b569f9de754c2a7c0ee Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 23:51:59 +0200 Subject: [PATCH 19/24] Don't refill on checkout if credit card payments are disabled --- worker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worker.py b/worker.py index c4c6496..45e13f3 100644 --- a/worker.py +++ b/worker.py @@ -489,7 +489,8 @@ class ChatWorker(threading.Thread): if credit_required > 0: self.bot.send_message(self.chat.id, strings.error_not_enough_credit) # Suggest payment for missing credit value if configuration allows refill - if configloader.config["Appearance"]["refill_on_checkout"] == 'yes': + if configloader.config["Credit Card"]["credit_card_token"] != "" \ + and configloader.config["Appearance"]["refill_on_checkout"] == 'yes': self.__make_payment(utils.Price(credit_required)) # If afer requested payment credit is still insufficient (either payment failure or cancel) if self.user.credit < self.__get_cart_value(cart): From 45eadb74b249f26ae3f2cd5d2d0b78cb547c768b Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 23:52:17 +0200 Subject: [PATCH 20/24] Clarify how to disable credit card payments in the template config --- config/template_config.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/template_config.ini b/config/template_config.ini index 070fc72..60b41f8 100644 --- a/config/template_config.ini +++ b/config/template_config.ini @@ -18,7 +18,7 @@ language = it_IT # Telegram bot parameters [Telegram] -; Your bot token goes here. Get one from @BotFather! +; Your bot token goes here. Get one from https://t.me/BotFather! token = 123456789:YOUR_TOKEN_GOES_HERE_______________ ; Time in seconds before a conversation (thread) with no new messages expires ; A lower value reduces memory usage, but can be inconvenient for the users @@ -49,7 +49,9 @@ currency_symbol = "€" # Credit card payment settings [Credit Card] -; Provider token: get the token by linking the payment provider with @BotFather +; Telegram Payments provider token obtainable at https://t.me/BotFather in the bot's Payments menu +; If empty, credit card payments are disabled. +# credit_card_token = credit_card_token = 123456789:YOUR_TOKEN_HERE_ ; Minimum wallet payment accepted (in miniumum currency units, $1.00 = 100 units) min_amount = 1000 From 1523863fed69242ce9e9122617009ed765f6a621 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 7 Apr 2020 23:54:24 +0200 Subject: [PATCH 21/24] #46: Don't crash if Sentry is enabled and greed isn't being run in a git repository --- utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils.py b/utils.py index 36866f6..296cbeb 100644 --- a/utils.py +++ b/utils.py @@ -17,9 +17,13 @@ except ModuleNotFoundError: if config["Error Reporting"]["sentry_token"] != \ "https://00000000000000000000000000000000:00000000000000000000000000000000@sentry.io/0000000": import raven - + import raven.exceptions + try: + release = raven.fetch_git_sha(os.path.dirname(__file__)) + except raven.exceptions.InvalidGitRepository: + release = "Unknown" sentry_client = raven.Client(config["Error Reporting"]["sentry_token"], - release=raven.fetch_git_sha(os.path.dirname(__file__)), + release=release, environment="Dev" if __debug__ else "Prod") else: sentry_client = None From 357b0e568071950918af8d68740722a1f425a712 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Wed, 8 Apr 2020 00:03:33 +0200 Subject: [PATCH 22/24] #43: Improve README.md --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f54bb91..6f0f7fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # greed -A customizable Telegram shop bot, developed as a project for the final exam. +A [customizable](/config/template_config.ini), [multilanguage](/strings) Telegram shop bot with [Telegram Payments support](https://core.telegram.org/bots/payments)! ![](https://img.shields.io/badge/version-beta-blue.svg) ![](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen) @@ -15,7 +15,7 @@ A customizable Telegram shop bot, developed as a project for the final exam. ## Installation -1. Download the project files through `git clone https://github.com/Steffo99/greed.git` or [this link](https://github.com/Steffo99/greed/archive/master.zip). +1. Download the project files through `git clone https://github.com/Steffo99/greed.git` (recommended) or [this link](https://github.com/Steffo99/greed/archive/master.zip). 2. Install the project requirements with `pip install -r requirements.txt` 3. Run `python -OO core.py` to generate the configuration file. 4. Open the config folder and edit the `config.ini` file following the contained instructions. @@ -31,6 +31,22 @@ All the bot features are available through Telegram. As the administrator, you can add new products, check the placed orders, create new transactions and generate .csv log files. Users will be able to add credit to their wallet, place orders and contact you in case they require assistance. +## Updating + +### Through `git` + +If you downloaded `greed` through `git`, you can update it by running: + +``` +git stash +git pull +git stash pop +``` + +### By redownloading the zip file + +If you downloaded `greed` through the zip archive, you can update it by redownloading [the latest version](https://github.com/Steffo99/greed/archive/master.zip) and by moving your `config.ini` and `database.sqlite` (if applicable) files to the new folder. + ## Documentation `greed` currently does not have a documentation page, but you can try to read the [paper](https://docs.google.com/document/d/1f4MKVr0B7RSQfWTSa_6ZO0LM4nPpky_GX_qdls3EHtQ/edit?usp=sharing) (in Italian) I wrote for my final Scuola Superiore exam about it. From 279b8f1539559a036fb2d22e0684d312be52132f Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Wed, 8 Apr 2020 14:51:44 +0200 Subject: [PATCH 23/24] #44: Change CancelSignal handling --- worker.py | 59 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/worker.py b/worker.py index 45e13f3..052e7e4 100644 --- a/worker.py +++ b/worker.py @@ -153,8 +153,9 @@ class ChatWorker(threading.Thread): while True: # Get the next update update = self.__receive_next_update() - # Ensure the update isn't a CancelSignal + # If a CancelSignal is received... if isinstance(update, CancelSignal): + # And the wait is cancellable... if cancellable: # Return the CancelSignal return update @@ -178,10 +179,15 @@ class ChatWorker(threading.Thread): while True: # Get the next update update = self.__receive_next_update() - # Ensure the update isn't a CancelSignal - if cancellable and isinstance(update, CancelSignal): - # Return the CancelSignal - return update + # If a CancelSignal is received... + if isinstance(update, CancelSignal): + # And the wait is cancellable... + if cancellable: + # Return the CancelSignal + return update + else: + # Ignore the signal + continue # Ensure the update contains a message if update.message is None: continue @@ -203,10 +209,15 @@ class ChatWorker(threading.Thread): while True: # Get the next update update = self.__receive_next_update() - # Ensure the update isn't a CancelSignal - if cancellable and isinstance(update, CancelSignal): - # Return the CancelSignal - return update + # If a CancelSignal is received... + if isinstance(update, CancelSignal): + # And the wait is cancellable... + if cancellable: + # Return the CancelSignal + return update + else: + # Ignore the signal + continue # Ensure the update contains a precheckoutquery if update.pre_checkout_query is None: continue @@ -232,10 +243,15 @@ class ChatWorker(threading.Thread): while True: # Get the next update update = self.__receive_next_update() - # Ensure the update isn't a CancelSignal - if cancellable and isinstance(update, CancelSignal): - # Return the CancelSignal - return update + # If a CancelSignal is received... + if isinstance(update, CancelSignal): + # And the wait is cancellable... + if cancellable: + # Return the CancelSignal + return update + else: + # Ignore the signal + continue # Ensure the update contains a message if update.message is None: continue @@ -245,16 +261,21 @@ class ChatWorker(threading.Thread): # Return the photo array return update.message.photo - def __wait_for_inlinekeyboard_callback(self, cancellable: bool = True) \ + def __wait_for_inlinekeyboard_callback(self, cancellable: bool = False) \ -> Union[telegram.CallbackQuery, CancelSignal]: """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 isn't a CancelSignal - if cancellable and isinstance(update, CancelSignal): - # Return the CancelSignal - return update + # If a CancelSignal is received... + if isinstance(update, CancelSignal): + # And the wait is cancellable... + if cancellable: + # Return the CancelSignal + return update + else: + # Ignore the signal + continue # Ensure the update is a CallbackQuery if update.callback_query is None: continue @@ -1229,7 +1250,7 @@ class ChatWorker(threading.Thread): callback = self.__wait_for_inlinekeyboard_callback() # Toggle the correct property if callback.data == "toggle_edit_products": - admin.edit_products = not admin.edit_products + admin.edit_products = not admin.edit_products1 elif callback.data == "toggle_receive_orders": admin.receive_orders = not admin.receive_orders elif callback.data == "toggle_create_transactions": From 788163458e98e330c5e8c776c66c8413d2ece83a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Wed, 8 Apr 2020 15:02:19 +0200 Subject: [PATCH 24/24] Offer refill only if the credit_required is between the min_amount and max_amount range --- worker.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/worker.py b/worker.py index 052e7e4..e9126c4 100644 --- a/worker.py +++ b/worker.py @@ -506,12 +506,14 @@ class ChatWorker(threading.Thread): self.session.add(order_item) # Ensure the user has enough credit to make the purchase credit_required = self.__get_cart_value(cart) - self.user.credit - # Notify user In case of insufficient credit + # Notify user in case of insufficient credit if credit_required > 0: self.bot.send_message(self.chat.id, strings.error_not_enough_credit) # Suggest payment for missing credit value if configuration allows refill if configloader.config["Credit Card"]["credit_card_token"] != "" \ - and configloader.config["Appearance"]["refill_on_checkout"] == 'yes': + and configloader.config["Appearance"]["refill_on_checkout"] == 'yes' \ + and credit_required <= utils.Price(int(configloader.config["Credit Card"]["max_amount"])) \ + and credit_required >= utils.Price(int(configloader.config["Credit Card"]["min_amount"])): self.__make_payment(utils.Price(credit_required)) # If afer requested payment credit is still insufficient (either payment failure or cancel) if self.user.credit < self.__get_cart_value(cart):