mirror of
https://github.com/Steffo99/greed.git
synced 2024-11-24 23:04:18 +00:00
Add "Create Transaction" menu option and fix image formatting
This commit is contained in:
parent
e8250cd64d
commit
c573c4db62
3 changed files with 114 additions and 30 deletions
38
database.py
38
database.py
|
@ -57,6 +57,10 @@ class User(TableDeclarativeBase):
|
||||||
else:
|
else:
|
||||||
return self.first_name
|
return self.first_name
|
||||||
|
|
||||||
|
def identifiable_str(self):
|
||||||
|
"""Describe the user in the best way possible, ensuring a way back to the database record exists."""
|
||||||
|
return f"user_{self.user_id} ({str(self)})"
|
||||||
|
|
||||||
def mention(self):
|
def mention(self):
|
||||||
"""Mention the user in the best way possible given the available data."""
|
"""Mention the user in the best way possible given the available data."""
|
||||||
if self.username is not None:
|
if self.username is not None:
|
||||||
|
@ -107,18 +111,11 @@ class Product(TableDeclarativeBase):
|
||||||
cart = strings.in_cart_format_string.format(quantity=cart_qty)
|
cart = strings.in_cart_format_string.format(quantity=cart_qty)
|
||||||
else:
|
else:
|
||||||
cart = ''
|
cart = ''
|
||||||
return strings.order_format_string.format(name=escape(self.name),
|
return strings.product_format_string.format(name=escape(self.name),
|
||||||
description=escape(self.description),
|
description=escape(self.description),
|
||||||
stock=stock,
|
stock=stock,
|
||||||
price=str(Price(self.price)),
|
price=str(Price(self.price)),
|
||||||
cart=cart)
|
cart=cart)
|
||||||
elif style == "image":
|
|
||||||
print("WARNING: image text is obsolete and shouldn't be used anymore")
|
|
||||||
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"{str(Price(self.price))}\n" \
|
|
||||||
f"{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}"
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("style is not an accepted value")
|
raise ValueError("style is not an accepted value")
|
||||||
|
|
||||||
|
@ -136,7 +133,7 @@ class Product(TableDeclarativeBase):
|
||||||
r = requests.post(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendPhoto",
|
r = requests.post(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendPhoto",
|
||||||
files={"photo": self.image},
|
files={"photo": self.image},
|
||||||
params={"chat_id": chat_id,
|
params={"chat_id": chat_id,
|
||||||
"caption": self.text(style="image"),
|
"caption": self.text(),
|
||||||
"parse_mode": "HTML"})
|
"parse_mode": "HTML"})
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -186,12 +183,13 @@ class Transaction(TableDeclarativeBase):
|
||||||
__table_args__ = (UniqueConstraint("provider", "provider_charge_id"),)
|
__table_args__ = (UniqueConstraint("provider", "provider_charge_id"),)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return the correctly formatted transaction value"""
|
string = f"<b>T{self.transaction_id}</b> | {str(self.user)} | {Price(self.value)}"
|
||||||
# Add a plus symbol if the value is positive
|
if self.refunded:
|
||||||
string = "+" if self.value > 0 else ""
|
string += f" | {strings.emoji_refunded}"
|
||||||
# Add the correctly formatted value
|
if self.provider:
|
||||||
string += strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.value)
|
string += f" | {self.provider}"
|
||||||
# Return the created string
|
if self.notes:
|
||||||
|
string += f" | {self.notes}"
|
||||||
return string
|
return string
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -207,7 +205,7 @@ class Admin(TableDeclarativeBase):
|
||||||
# Permissions
|
# Permissions
|
||||||
edit_products = Column(Boolean, default=True)
|
edit_products = Column(Boolean, default=True)
|
||||||
receive_orders = Column(Boolean, default=True)
|
receive_orders = Column(Boolean, default=True)
|
||||||
view_transactions = Column(Boolean, default=True)
|
create_transactions = Column(Boolean, default=True)
|
||||||
# Live mode enabled
|
# Live mode enabled
|
||||||
live_mode = Column(Boolean, default=False)
|
live_mode = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
|
26
strings.py
26
strings.py
|
@ -57,6 +57,9 @@ conversation_admin_select_product = "✏️ Che prodotto vuoi modificare?"
|
||||||
# Conversation: select a product to delete
|
# Conversation: select a product to delete
|
||||||
conversation_admin_select_product_to_delete = "❌ Che prodotto vuoi eliminare?"
|
conversation_admin_select_product_to_delete = "❌ Che prodotto vuoi eliminare?"
|
||||||
|
|
||||||
|
# Conversation: select a user to edit
|
||||||
|
conversation_admin_select_user = "✏️ Che utente 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?"
|
||||||
|
|
||||||
|
@ -105,6 +108,9 @@ menu_orders = "📦 Ordini"
|
||||||
# Menu: transactions
|
# Menu: transactions
|
||||||
menu_transactions = "💳 Transazioni"
|
menu_transactions = "💳 Transazioni"
|
||||||
|
|
||||||
|
# Menu: edit credit
|
||||||
|
menu_edit_credit = "💰 Crea transazione"
|
||||||
|
|
||||||
# Admin menu: go to user mode
|
# Admin menu: go to user mode
|
||||||
menu_user_mode = "👤 Passa alla modalità utente"
|
menu_user_mode = "👤 Passa alla modalità utente"
|
||||||
|
|
||||||
|
@ -142,7 +148,7 @@ menu_add_to_cart = "➕ Aggiungi"
|
||||||
menu_remove_from_cart = "➖ Rimuovi"
|
menu_remove_from_cart = "➖ Rimuovi"
|
||||||
|
|
||||||
# Emoji: unprocessed order
|
# Emoji: unprocessed order
|
||||||
emoji_not_processed = "*️⃣ "
|
emoji_not_processed = "*️⃣"
|
||||||
|
|
||||||
# Emoji: completed order
|
# Emoji: completed order
|
||||||
emoji_completed = "✅"
|
emoji_completed = "✅"
|
||||||
|
@ -171,6 +177,14 @@ ask_order_notes = "Vuoi lasciare un messaggio insieme all'ordine?\n" \
|
||||||
ask_refund_reason = "Allega una motivazione a questo rimborso.\n" \
|
ask_refund_reason = "Allega una motivazione a questo rimborso.\n" \
|
||||||
"Sarà visibile al cliente."
|
"Sarà visibile al cliente."
|
||||||
|
|
||||||
|
# Edit credit: notes?
|
||||||
|
ask_transaction_notes = "Allega una nota a questa transazione.\n" \
|
||||||
|
"Sarà visibile al cliente in seguito all'accredito / addebito e nel registro delle transazioni."
|
||||||
|
|
||||||
|
# Edit credit: amount?
|
||||||
|
ask_credit = "Di quanto vuoi modificare il credito dell'utente?\n" \
|
||||||
|
"(Se vuoi addebitargli soldi, aggiungi un - davanti al numero.)"
|
||||||
|
|
||||||
# Thread has started downloading an image and might be unresponsive
|
# Thread has started downloading an image and might be unresponsive
|
||||||
downloading_image = "Sto scaricando la tua foto!\n" \
|
downloading_image = "Sto scaricando la tua foto!\n" \
|
||||||
"Potrei metterci un po'... Abbi pazienza!\n" \
|
"Potrei metterci un po'... Abbi pazienza!\n" \
|
||||||
|
@ -211,6 +225,10 @@ notification_order_completed = "Un tuo ordine è stato completato!\n" \
|
||||||
notification_order_refunded = "Un tuo ordine è stato rimborsato!\n" \
|
notification_order_refunded = "Un tuo ordine è stato rimborsato!\n" \
|
||||||
"{order}"
|
"{order}"
|
||||||
|
|
||||||
|
# Notification: a manual transaction was applied
|
||||||
|
notification_transaction_created = "E' stata applicata una nuova transazione al tuo portafoglio:\n" \
|
||||||
|
"{transaction}"
|
||||||
|
|
||||||
# Refund reason
|
# Refund reason
|
||||||
refund_reason = "Motivazione del rimborso:\n" \
|
refund_reason = "Motivazione del rimborso:\n" \
|
||||||
"{reason}"
|
"{reason}"
|
||||||
|
@ -236,6 +254,9 @@ success_order_completed = "✅ Hai segnato l'ordine #{order_id} come completato.
|
||||||
# Success: order was refunded successfully
|
# Success: order was refunded successfully
|
||||||
success_order_refunded = "✴️ L'ordine #{order_id} è stato rimborsato con successo."
|
success_order_refunded = "✴️ L'ordine #{order_id} è stato rimborsato con successo."
|
||||||
|
|
||||||
|
# Success: transaction was created successfully
|
||||||
|
success_transaction_created = "✅ La transazione è stata creata con successo!"
|
||||||
|
|
||||||
# Error: message received not in a private chat
|
# Error: message received not in a private chat
|
||||||
error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private."
|
error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private."
|
||||||
|
|
||||||
|
@ -267,3 +288,6 @@ error_order_already_cleared = "⚠️ Questo ordine è già stato processato."
|
||||||
|
|
||||||
# Error: no orders have been placed, so none can be shown
|
# Error: no orders have been placed, so none can be shown
|
||||||
error_no_orders = "⚠️ Non hai ancora piazzato ordini, quindi non c'è niente da visualizzare!"
|
error_no_orders = "⚠️ Non hai ancora piazzato ordini, quindi non c'è niente da visualizzare!"
|
||||||
|
|
||||||
|
# Error: selected user does not exist
|
||||||
|
error_user_does_not_exist = "⚠️ L'utente selezionato non esiste."
|
80
worker.py
80
worker.py
|
@ -273,7 +273,7 @@ class ChatWorker(threading.Thread):
|
||||||
else:
|
else:
|
||||||
self.bot.edit_message_caption(chat_id=self.chat.id,
|
self.bot.edit_message_caption(chat_id=self.chat.id,
|
||||||
message_id=message['result']['message_id'],
|
message_id=message['result']['message_id'],
|
||||||
caption=product.text(style="image"),
|
caption=product.text(),
|
||||||
parse_mode="HTML",
|
parse_mode="HTML",
|
||||||
reply_markup=inline_keyboard)
|
reply_markup=inline_keyboard)
|
||||||
# Create the keyboard with the cancel button
|
# Create the keyboard with the cancel button
|
||||||
|
@ -317,8 +317,7 @@ class ChatWorker(threading.Thread):
|
||||||
else:
|
else:
|
||||||
self.bot.edit_message_caption(chat_id=self.chat.id,
|
self.bot.edit_message_caption(chat_id=self.chat.id,
|
||||||
message_id=callback.message.message_id,
|
message_id=callback.message.message_id,
|
||||||
caption=product.text(style="image",
|
caption=product.text(cart_qty=cart[callback.message.message_id][1]),
|
||||||
cart_qty=cart[callback.message.message_id][1]),
|
|
||||||
parse_mode="HTML",
|
parse_mode="HTML",
|
||||||
reply_markup=product_inline_keyboard)
|
reply_markup=product_inline_keyboard)
|
||||||
# Create the cart summary
|
# Create the cart summary
|
||||||
|
@ -364,8 +363,7 @@ class ChatWorker(threading.Thread):
|
||||||
else:
|
else:
|
||||||
self.bot.edit_message_caption(chat_id=self.chat.id,
|
self.bot.edit_message_caption(chat_id=self.chat.id,
|
||||||
message_id=callback.message.message_id,
|
message_id=callback.message.message_id,
|
||||||
caption=product.text(style="image",
|
caption=product.text(cart_qty=cart[callback.message.message_id][1]),
|
||||||
cart_qty=cart[callback.message.message_id][1]),
|
|
||||||
parse_mode="HTML",
|
parse_mode="HTML",
|
||||||
reply_markup=product_inline_keyboard)
|
reply_markup=product_inline_keyboard)
|
||||||
# Create the cart summary
|
# Create the cart summary
|
||||||
|
@ -444,7 +442,7 @@ class ChatWorker(threading.Thread):
|
||||||
orders = self.session.query(db.Order)\
|
orders = self.session.query(db.Order)\
|
||||||
.filter(db.Order.user == self.user)\
|
.filter(db.Order.user == self.user)\
|
||||||
.order_by(db.Order.creation_date.desc())\
|
.order_by(db.Order.creation_date.desc())\
|
||||||
.limit(5)\
|
.limit(20)\
|
||||||
.all()
|
.all()
|
||||||
# Ensure there is at least one order to display
|
# Ensure there is at least one order to display
|
||||||
if len(orders) == 0:
|
if len(orders) == 0:
|
||||||
|
@ -601,14 +599,14 @@ class ChatWorker(threading.Thread):
|
||||||
keyboard.append([strings.menu_products])
|
keyboard.append([strings.menu_products])
|
||||||
if self.admin.receive_orders:
|
if self.admin.receive_orders:
|
||||||
keyboard.append([strings.menu_orders])
|
keyboard.append([strings.menu_orders])
|
||||||
if self.admin.view_transactions:
|
if self.admin.create_transactions:
|
||||||
keyboard.append([strings.menu_transactions])
|
keyboard.append([strings.menu_edit_credit])
|
||||||
# Send the previously created keyboard to the user (ensuring it can be clicked only 1 time)
|
# Send the previously created keyboard to the user (ensuring it can be clicked only 1 time)
|
||||||
self.bot.send_message(self.chat.id, strings.conversation_open_admin_menu,
|
self.bot.send_message(self.chat.id, strings.conversation_open_admin_menu,
|
||||||
reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
|
reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
|
||||||
# Wait for a reply from the user
|
# Wait for a reply from the user
|
||||||
selection = self.__wait_for_specific_message([strings.menu_products, strings.menu_orders,
|
selection = self.__wait_for_specific_message([strings.menu_products, strings.menu_orders,
|
||||||
strings.menu_user_mode])
|
strings.menu_user_mode, strings.menu_edit_credit])
|
||||||
# If the user has selected the Products option...
|
# If the user has selected the Products option...
|
||||||
if selection == strings.menu_products:
|
if selection == strings.menu_products:
|
||||||
# Open the products menu
|
# Open the products menu
|
||||||
|
@ -617,6 +615,10 @@ class ChatWorker(threading.Thread):
|
||||||
elif selection == strings.menu_orders:
|
elif selection == strings.menu_orders:
|
||||||
# Open the orders menu
|
# Open the orders menu
|
||||||
self.__orders_menu()
|
self.__orders_menu()
|
||||||
|
# If the user has selected the Transactions option...
|
||||||
|
elif selection == strings.menu_edit_credit:
|
||||||
|
# Open the edit credit menu
|
||||||
|
self.__create_transaction()
|
||||||
# If the user has selected the User mode option...
|
# If the user has selected the User mode option...
|
||||||
elif selection == strings.menu_user_mode:
|
elif selection == strings.menu_user_mode:
|
||||||
# Start the bot in user mode
|
# Start the bot in user mode
|
||||||
|
@ -862,6 +864,66 @@ class ChatWorker(threading.Thread):
|
||||||
self.bot.send_message(order.user_id,
|
self.bot.send_message(order.user_id,
|
||||||
strings.notification_order_refunded.format(order=order.get_text(self.session)))
|
strings.notification_order_refunded.format(order=order.get_text(self.session)))
|
||||||
|
|
||||||
|
def __create_transaction(self):
|
||||||
|
"""Edit manually the credit of an user."""
|
||||||
|
# Find all the users in the database
|
||||||
|
users = self.session.query(db.User).all()
|
||||||
|
# Create a list containing all the keyboard button strings
|
||||||
|
keyboard_buttons = [[strings.menu_cancel]]
|
||||||
|
# Add to the list all the users
|
||||||
|
for user in users:
|
||||||
|
keyboard_buttons.append([user.identifiable_str()])
|
||||||
|
# TODO: handle more than 99 users
|
||||||
|
# Create the keyboard
|
||||||
|
keyboard = telegram.ReplyKeyboardMarkup(keyboard_buttons, one_time_keyboard=True)
|
||||||
|
# Send the keyboard
|
||||||
|
self.bot.send_message(self.chat.id, strings.conversation_admin_select_user, reply_markup=keyboard)
|
||||||
|
# Wait for a reply
|
||||||
|
reply = self.__wait_for_regex("user_([0-9]+)", cancellable=True)
|
||||||
|
# Allow the cancellation of the operation
|
||||||
|
if reply == strings.menu_cancel:
|
||||||
|
return
|
||||||
|
# Find the user in the database
|
||||||
|
user = self.session.query(db.User).filter_by(user_id=int(reply)).one_or_none()
|
||||||
|
# Ensure the user exists
|
||||||
|
if not user:
|
||||||
|
self.bot.send_message(self.chat.id, strings.error_user_does_not_exist)
|
||||||
|
# Create an inline keyboard with a single cancel button
|
||||||
|
cancel = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_cancel,
|
||||||
|
callback_data="cmd_cancel")]])
|
||||||
|
# Request from the user the amount of money to be credited manually
|
||||||
|
self.bot.send_message(self.chat.id, strings.ask_credit, reply_markup=cancel)
|
||||||
|
# Wait for an answer
|
||||||
|
reply = self.__wait_for_regex(r"(-? ?[0-9]{1,3}(?:[.,][0-9]{1,2})?)", cancellable=True)
|
||||||
|
# Allow the cancellation of the operation
|
||||||
|
if isinstance(reply, CancelSignal):
|
||||||
|
return
|
||||||
|
# Convert the reply to a price object
|
||||||
|
price = utils.Price(reply)
|
||||||
|
# Ask the user for notes
|
||||||
|
self.bot.send_message(self.chat.id, strings.ask_transaction_notes, reply_markup=cancel)
|
||||||
|
# Wait for an answer
|
||||||
|
reply = self.__wait_for_regex(r"(.*)", cancellable=True)
|
||||||
|
# Allow the cancellation of the operation
|
||||||
|
if isinstance(reply, CancelSignal):
|
||||||
|
return
|
||||||
|
# Create a new transaction
|
||||||
|
transaction = db.Transaction(user=user,
|
||||||
|
value=int(price),
|
||||||
|
provider="Manual",
|
||||||
|
notes=reply)
|
||||||
|
self.session.add(transaction)
|
||||||
|
# Change the user credit
|
||||||
|
user.credit += int(price)
|
||||||
|
# Commit the changes
|
||||||
|
self.session.commit()
|
||||||
|
# Notify the user of the credit/debit
|
||||||
|
self.bot.send_message(user.user_id,
|
||||||
|
strings.notification_transaction_created.format(transaction=str(transaction)),
|
||||||
|
parse_mode="HTML")
|
||||||
|
# Notify the admin of the success
|
||||||
|
self.bot.send_message(self.chat.id, strings.success_transaction_created)
|
||||||
|
|
||||||
def __graceful_stop(self):
|
def __graceful_stop(self):
|
||||||
"""Handle the graceful stop of the thread."""
|
"""Handle the graceful stop of the thread."""
|
||||||
# Notify the user that the session has expired and remove the keyboard
|
# Notify the user that the session has expired and remove the keyboard
|
||||||
|
|
Loading…
Reference in a new issue