1
Fork 0
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:
Steffo 2018-04-12 09:28:52 +02:00
parent e8250cd64d
commit c573c4db62
3 changed files with 114 additions and 30 deletions

View file

@ -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)

View file

@ -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."

View file

@ -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