1
Fork 0
mirror of https://github.com/Steffo99/greed.git synced 2024-11-25 07:14:18 +00:00

Some new stuff, but now the keyboard disappears?

This commit is contained in:
Steffo 2018-02-28 20:07:40 +01:00
parent c3d3cb2c3e
commit 4658cdc31b
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: C27544372FBB445D
4 changed files with 141 additions and 46 deletions

View file

@ -7,6 +7,7 @@ import telegram
import strings import strings
import requests import requests
from html import escape from html import escape
from utils import Price
# Create a (lazy) database engine # Create a (lazy) database engine
engine = create_engine(configloader.config["Database"]["engine"]) engine = create_engine(configloader.config["Database"]["engine"])
@ -83,15 +84,24 @@ class Product(TableDeclarativeBase):
def __str__(self): def __str__(self):
return self.text() return self.text()
def text(self, one_row:bool=False, cart_qty:int=None): def text(self, style:str="full", cart_qty:int=None):
"""Return the product details formatted with Telegram HTML. The image is omitted.""" """Return the product details formatted with Telegram HTML. The image is omitted."""
if one_row: if style == "short":
return f"{escape(self.name)} - {strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price / (10 ** int(configloader.config['Payments']['currency_exp'])))}" return f"{cart_qty}x {escape(self.name)} - {str(Price(self.price) * cart_qty)}"
elif style == "full":
return f"<b>{escape(self.name)}</b>\n" \ return f"<b>{escape(self.name)}</b>\n" \
f"{escape(self.description)}\n" \ f"{escape(self.description)}\n" \
f"<i>{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}</i>\n" \ f"<i>{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}</i>\n" \
f"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price / (10 ** int(configloader.config['Payments']['currency_exp'])))}\n" \ f"{str(Price(self.price))}\n" \
f"<b>{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}</b>" f"<b>{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}</b>"
elif style == "image":
return f"{escape(self.name)}\n" \
f"{escape(self.description)}\n" \
f"{strings.in_stock_format_string.format(quantity=self.stock) if self.stock is not None else ''}\n" \
f"{strings.currency_format_string.format(symbol=strings.currency_symbol, value=self.price / (10 ** int(configloader.config['Payments']['currency_exp'])))}\n" \
f"{strings.in_cart_format_string.format(quantity=cart_qty) if cart_qty is not None else ''}"
else:
raise ValueError("style is not an accepted value")
def __repr__(self): def __repr__(self):
return f"<Product {self.name}>" return f"<Product {self.name}>"
@ -101,13 +111,13 @@ class Product(TableDeclarativeBase):
if self.image is None: if self.image is None:
r = requests.get(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendMessage", r = requests.get(f"https://api.telegram.org/bot{configloader.config['Telegram']['token']}/sendMessage",
params={"chat_id": chat_id, params={"chat_id": chat_id,
"text": str(self), "text": self.text(),
"parse_mode": "HTML"}) "parse_mode": "HTML"})
else: else:
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": str(self), "caption": self.text(style="image"),
"parse_mode": "HTML"}) "parse_mode": "HTML"})
return r.json() return r.json()

View file

@ -42,7 +42,7 @@ conversation_cart_actions = "Quando hai finito di aggiungere prodotti al carrell
# Conversation: confirm the cart contents # Conversation: confirm the cart contents
conversation_confirm_cart = "Il tuo carrello contiene questi prodotti:\n" \ conversation_confirm_cart = "Il tuo carrello contiene questi prodotti:\n" \
"{product_list}\n" \ "{product_list}" \
"\n" \ "\n" \
"Totale: {total_cost}\n" \ "Totale: {total_cost}\n" \
"Procedere?" "Procedere?"

80
utils.py Normal file
View file

@ -0,0 +1,80 @@
from configloader import config
from strings import currency_format_string, currency_symbol
import typing
class Price:
def __init__(self, value:typing.Union[int, float, str, "Price"]=0):
if isinstance(value, int):
# Keep the value as it is
self.value = int(value)
elif isinstance(value, float):
# Convert the value to minimum units
self.value = int(value * (10 ** int(config["Payments"]["currency_exp"])))
elif isinstance(value, str):
# Remove decimal points, then cast to int
self.value = int(value.replace(".", "").replace(",", ""))
elif isinstance(value, Price):
# Copy self
self.value = value.value
def __str__(self):
return currency_format_string.format(symbol=currency_symbol, value="{0:.2f}".format(self.value / (10 ** int(config["Payments"]["currency_exp"]))))
def __int__(self):
return self.value
def __float__(self):
return self.value / (10 ** int(config["Payments"]["currency_exp"]))
def __ge__(self, other):
return self.value >= Price(other).value
def __le__(self, other):
return self.value <= Price(other).value
def __eq__(self, other):
return self.value == Price(other).value
def __gt__(self, other):
return self.value > Price(other).value
def __lt__(self, other):
return self.value < Price(other).value
def __add__(self, other):
return Price(self.value + Price(other).value)
def __sub__(self, other):
return Price(self.value - Price(other).value)
def __mul__(self, other):
return Price(self.value * Price(other).value)
def __floordiv__(self, other):
return Price(self.value // Price(other).value)
def __radd__(self, other):
self.__add__(other)
def __rsub__(self, other):
return Price(Price(other).value - self.value)
def __rmul__(self, other):
self.__mul__(other)
def __iadd__(self, other):
self.value += Price(other).value
return self
def __isub__(self, other):
self.value -= Price(other).value
return self
def __imul__(self, other):
self.value *= Price(other).value
return self
def __ifloordiv__(self, other):
self.value //= Price(other).value
return self

View file

@ -1,7 +1,6 @@
import threading import threading
import typing import typing
import uuid import uuid
import datetime import datetime
import telegram import telegram
import strings import strings
@ -10,6 +9,7 @@ import sys
import queue as queuem import queue as queuem
import database as db import database as db
import re import re
from utils import Price
from html import escape from html import escape
class StopSignal: class StopSignal:
@ -232,7 +232,7 @@ class ChatWorker(threading.Thread):
products = self.session.query(db.Product).all() products = self.session.query(db.Product).all()
# Create a dict to be used as 'cart' # Create a dict to be used as 'cart'
# The key is the message id of the product list # The key is the message id of the product list
cart = {} # type: typing.Dict[typing.List[db.Product, int]] cart: typing.Dict[typing.List[db.Product, int]] = {}
# Initialize the products list # Initialize the products list
for product in products: for product in products:
# If the product is not for sale, don't display it # If the product is not for sale, don't display it
@ -279,13 +279,16 @@ class ChatWorker(threading.Thread):
text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard) text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
else: else:
self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id, self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id,
caption=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard) caption=product.text(style="image", cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
try: # Create the cart summary
product_list = ""
total_cost = 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.message_id, self.bot.edit_message_text(chat_id=self.chat.id, message_id=final.message_id,
text=strings.conversation_cart_actions, reply_markup=final_inline_keyboard) text=strings.conversation_confirm_cart.format(product_list=product_list, total_cost=str(total_cost), reply_markup=final_inline_keyboard))
except telegram.error.BadRequest:
# Telegram returns an error if the message is not edited
pass
# If the Remove from cart button has been pressed... # If the Remove from cart button has been pressed...
elif callback.data == "cart_remove": elif callback.data == "cart_remove":
# Get the selected product # Get the selected product
@ -313,13 +316,18 @@ class ChatWorker(threading.Thread):
text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard) text=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
else: else:
self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id, self.bot.edit_message_caption(chat_id=self.chat.id, message_id=callback.message.message_id,
caption=product.text(cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard) caption=product.text(style="image", cart_qty=cart[callback.message.message_id][1]), parse_mode="HTML", reply_markup=product_inline_keyboard)
try: # Create the cart summary
product_list = ""
total_cost = 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.message_id, self.bot.edit_message_text(chat_id=self.chat.id, message_id=final.message_id,
text=strings.conversation_cart_actions, reply_markup=final_inline_keyboard) text=strings.conversation_confirm_cart.format(product_list=product_list,
except telegram.error.BadRequest: total_cost=str(total_cost),
# Telegram returns an error if the message is not edited reply_markup=final_inline_keyboard))
pass
# If the done button has been pressed... # If the done button has been pressed...
elif callback.data == "cart_done": elif callback.data == "cart_done":
# End the loop # End the loop
@ -364,7 +372,6 @@ class ChatWorker(threading.Thread):
# Notify the user of the order result # Notify the user of the order result
self.bot.send_message(self.chat.id, strings.success_order_created) self.bot.send_message(self.chat.id, strings.success_order_created)
def __order_status(self): def __order_status(self):
raise NotImplementedError() raise NotImplementedError()
@ -406,10 +413,10 @@ class ChatWorker(threading.Thread):
def __add_credit_cc(self): def __add_credit_cc(self):
"""Add money to the wallet through a credit card payment.""" """Add money to the wallet through a credit card payment."""
# Create a keyboard to be sent later # Create a keyboard to be sent later
keyboard = [[telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="10"))], keyboard = [[telegram.KeyboardButton(str(Price("10.00")))],
[telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="25"))], [telegram.KeyboardButton(str(Price("25.00")))],
[telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="50"))], [telegram.KeyboardButton(str(Price("50.00")))],
[telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="100"))], [telegram.KeyboardButton(str(Price("100.00")))],
[telegram.KeyboardButton(strings.menu_cancel)]] [telegram.KeyboardButton(strings.menu_cancel)]]
# Boolean variable to check if the user has cancelled the action # Boolean variable to check if the user has cancelled the action
cancelled = False cancelled = False
@ -427,13 +434,13 @@ class ChatWorker(threading.Thread):
cancelled = True cancelled = True
continue continue
# Convert the amount to an integer # Convert the amount to an integer
value = int(float(selection.replace(",", ".")) * (10 ** int(configloader.config["Payments"]["currency_exp"]))) value = Price(selection)
# Ensure the amount is within the range # Ensure the amount is within the range
if value > int(configloader.config["Payments"]["max_amount"]): if value > int(configloader.config["Payments"]["max_amount"]):
self.bot.send_message(self.chat.id, strings.error_payment_amount_over_max.format(max_amount=strings.currency_format_string.format(symbol=strings.currency_symbol, value=configloader.config["Payments"]["max_amount"]))) self.bot.send_message(self.chat.id, strings.error_payment_amount_over_max.format(max_amount=Price(configloader.config["Payments"]["max_amount"])))
continue continue
elif value < int(configloader.config["Payments"]["min_amount"]): elif value < int(configloader.config["Payments"]["min_amount"]):
self.bot.send_message(self.chat.id, strings.error_payment_amount_under_min.format(min_amount=strings.currency_format_string.format(symbol=strings.currency_symbol, value=configloader.config["Payments"]["min_amount"]))) self.bot.send_message(self.chat.id, strings.error_payment_amount_under_min.format(min_amount=Price(configloader.config["Payments"]["min_amount"])))
continue continue
break break
# If the user cancelled the action... # If the user cancelled the action...
@ -443,11 +450,11 @@ class ChatWorker(threading.Thread):
# Set the invoice active invoice payload # Set the invoice active invoice payload
self.invoice_payload = str(uuid.uuid4()) self.invoice_payload = str(uuid.uuid4())
# Create the price array # Create the price array
prices = [telegram.LabeledPrice(label=strings.payment_invoice_label, amount=value)] prices = [telegram.LabeledPrice(label=strings.payment_invoice_label, amount=int(value))]
# If the user has to pay a fee when using the credit card, add it to the prices list # 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_percentage = Price(configloader.config["Credit Card"]["fee_percentage"]) // 100
fee_fixed = int(configloader.config["Credit Card"]["fee_fixed"]) fee_fixed = Price(configloader.config["Credit Card"]["fee_fixed"])
total_fee = int(value * fee_percentage) + fee_fixed total_fee = value * fee_percentage + fee_fixed
if total_fee > 0: if total_fee > 0:
prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, amount=int(total_fee))) prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label, amount=int(total_fee)))
else: else:
@ -459,7 +466,7 @@ class ChatWorker(threading.Thread):
# The amount is valid, send the invoice # The amount is valid, send the invoice
self.bot.send_invoice(self.chat.id, self.bot.send_invoice(self.chat.id,
title=strings.payment_invoice_title, title=strings.payment_invoice_title,
description=strings.payment_invoice_description.format(amount=strings.currency_format_string.format(symbol=strings.currency_symbol, value=value / (10 ** int(configloader.config["Payments"]["currency_exp"])))), description=strings.payment_invoice_description.format(amount=str(value)),
payload=self.invoice_payload, payload=self.invoice_payload,
provider_token=configloader.config["Credit Card"]["credit_card_token"], provider_token=configloader.config["Credit Card"]["credit_card_token"],
start_parameter="tempdeeplink", # TODO: no idea on how deeplinks should work start_parameter="tempdeeplink", # TODO: no idea on how deeplinks should work
@ -490,7 +497,7 @@ class ChatWorker(threading.Thread):
transaction.payment_email = successfulpayment.order_info.email transaction.payment_email = successfulpayment.order_info.email
transaction.payment_phone = successfulpayment.order_info.phone_number transaction.payment_phone = successfulpayment.order_info.phone_number
# Add the credit to the user account # Add the credit to the user account
self.user.credit += successfulpayment.total_amount - total_fee self.user.credit += successfulpayment.total_amount - int(total_fee)
# Add and commit the transaction # Add and commit the transaction
self.session.add(transaction) self.session.add(transaction)
self.session.commit() self.session.commit()
@ -587,7 +594,7 @@ class ChatWorker(threading.Thread):
self.bot.send_message(self.chat.id, strings.ask_product_price, parse_mode="HTML") self.bot.send_message(self.chat.id, strings.ask_product_price, parse_mode="HTML")
# Display the current name if you're editing an existing product # Display the current name if you're editing an existing product
if product: if product:
self.bot.send_message(self.chat.id, strings.edit_current_value.format(value=(strings.currency_format_string.format(symbol=strings.currency_symbol, value=(product.price / (10 ** int(configloader.config["Payments"]["currency_exp"]))))) if product.price is not None else 'Non in vendita'), parse_mode="HTML", reply_markup=cancel) self.bot.send_message(self.chat.id, strings.edit_current_value.format(value=(str(Price(product.price)) if product.price is not None else 'Non in vendita')), parse_mode="HTML", reply_markup=cancel)
# Wait for an answer # Wait for an answer
price = self.__wait_for_regex(r"([0-9]{1,3}(?:[.,][0-9]{1,2})?|[Xx])", cancellable=True) price = self.__wait_for_regex(r"([0-9]{1,3}(?:[.,][0-9]{1,2})?|[Xx])", cancellable=True)
# If the price is skipped # If the price is skipped
@ -596,19 +603,17 @@ class ChatWorker(threading.Thread):
elif price.lower() == "x": elif price.lower() == "x":
price = None price = None
else: else:
price = int(float(price.replace(",", ".")) * (10 ** int(configloader.config["Payments"]["currency_exp"]))) price = Price(price)
# Ask for the product image # Ask for the product image
self.bot.send_message(self.chat.id, strings.ask_product_image, reply_markup=cancel) self.bot.send_message(self.chat.id, strings.ask_product_image, reply_markup=cancel)
# Wait for an answer # Wait for an answer
photo_list = self.__wait_for_photo(cancellable=True) photo_list = self.__wait_for_photo(cancellable=True)
# TODO: ask for boolean status
# If a new product is being added... # If a new product is being added...
if not product: if not product:
# Create the db record for the product # Create the db record for the product
# TODO: add the boolean status
product = db.Product(name=name, product = db.Product(name=name,
description=description, description=description,
price=price, price=int(price),
boolean_product=False) boolean_product=False)
# Add the record to the database # Add the record to the database
self.session.add(product) self.session.add(product)