1
Fork 0
mirror of https://github.com/Steffo99/greed.git synced 2024-11-21 21:44:19 +00:00

Merge pull request #40 from pzhuk/order-invoice

Order invoice
This commit is contained in:
Steffo 2020-04-07 02:04:55 +02:00 committed by GitHub
commit 102d58b387
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 26 deletions

View file

@ -5,7 +5,7 @@
# Config file parameters # Config file parameters
[Config] [Config]
; Config file version. DO NOT EDIT THIS! ; Config file version. DO NOT EDIT THIS!
version = 15 version = 16
; Set this to no when you are done editing the file ; Set this to no when you are done editing the file
is_template = yes is_template = yes
; Language code for string file ; Language code for string file
@ -53,6 +53,9 @@ credit_card_token = 123456789:YOUR_TOKEN_HERE_
min_amount = 1000 min_amount = 1000
; Maximum wallet payment accepted (in miniumum currency units, $1.00 = 100 units) ; Maximum wallet payment accepted (in miniumum currency units, $1.00 = 100 units)
max_amount = 10000 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 ; 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: ; The formula for determining the total cost is:
; cost = added_funds + added_funds * fee_percentage / 100 + fee_fixed ; cost = added_funds + added_funds * fee_percentage / 100 + fee_fixed
@ -72,6 +75,8 @@ phone_required = yes
; Display the full order information to the customers instead of the shortened version ; 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 ; The full order information includes the order number and the timestamp of the order placement
full_order_info = no full_order_info = no
; Allow balance refill during the order checkout in case of unsufficient balance
refill_on_checkout = yes
# Exception reporting settings # Exception reporting settings
[Error Reporting] [Error Reporting]

View file

@ -484,14 +484,20 @@ class ChatWorker(threading.Thread):
order_id=order.order_id) order_id=order.order_id)
self.session.add(order_item) self.session.add(order_item)
# Ensure the user has enough credit to make the purchase # 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) 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 # Rollback all the changes
self.session.rollback() self.session.rollback()
return else:
# User has credit and valid order, perform transaction now
# User has credit and valid order, perform transaction now self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart)))
self.__order_transaction(order=order, value=-int(self.__get_cart_value(cart)))
@staticmethod @staticmethod
def __get_cart_value(cart): def __get_cart_value(cart):
@ -575,7 +581,8 @@ class ChatWorker(threading.Thread):
self.bot.send_message(self.chat.id, strings.conversation_payment_method, self.bot.send_message(self.chat.id, strings.conversation_payment_method,
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_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 the user has selected the Cash option...
if selection == strings.menu_cash: if selection == strings.menu_cash:
# Go to the pay with cash function # Go to the pay with cash function
@ -593,11 +600,9 @@ 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(str(utils.Price("10.00")))], presets = list(map(lambda s: s.strip(" "), configloader.config["Credit Card"]["payment_presets"].split('|')))
[telegram.KeyboardButton(str(utils.Price("25.00")))], keyboard = [[telegram.KeyboardButton(str(utils.Price(preset)))] for preset in presets]
[telegram.KeyboardButton(str(utils.Price("50.00")))], keyboard.append([telegram.KeyboardButton(strings.menu_cancel)])
[telegram.KeyboardButton(str(utils.Price("100.00")))],
[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
# Loop used to continue asking if there's an error during the input # Loop used to continue asking if there's an error during the input
@ -618,31 +623,33 @@ class ChatWorker(threading.Thread):
if value > utils.Price(int(configloader.config["Credit Card"]["max_amount"])): if value > utils.Price(int(configloader.config["Credit Card"]["max_amount"])):
self.bot.send_message(self.chat.id, self.bot.send_message(self.chat.id,
strings.error_payment_amount_over_max.format( 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 continue
elif value < utils.Price(int(configloader.config["Credit Card"]["min_amount"])): elif value < utils.Price(int(configloader.config["Credit Card"]["min_amount"])):
self.bot.send_message(self.chat.id, self.bot.send_message(self.chat.id,
strings.error_payment_amount_under_min.format( 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 continue
break break
# If the user cancelled the action... # If the user cancelled the action...
else: else:
# Exit the function # Exit the function
return return
# Issue the payment invoice
self.__make_payment(amount=value)
def __make_payment(self, amount):
# 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=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 # 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 = int(self.__get_total_fee(amount))
fee_fixed = int(configloader.config["Credit Card"]["fee_fixed"]) if fee > 0:
total_fee = value * fee_percentage + fee_fixed prices.append(telegram.LabeledPrice(label=strings.payment_invoice_fee_label,
if total_fee > 0: amount=fee))
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
# Create the invoice keyboard # Create the invoice keyboard
inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_pay, pay=True)], inline_keyboard = telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton(strings.menu_pay, pay=True)],
[telegram.InlineKeyboardButton(strings.menu_cancel, [telegram.InlineKeyboardButton(strings.menu_cancel,
@ -650,7 +657,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=str(value)), description=strings.payment_invoice_description.format(amount=str(amount)),
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", start_parameter="tempdeeplink",
@ -660,7 +667,7 @@ class ChatWorker(threading.Thread):
need_email=configloader.config["Credit Card"]["email_required"] == "yes", need_email=configloader.config["Credit Card"]["email_required"] == "yes",
need_phone_number=configloader.config["Credit Card"]["phone_required"] == "yes", need_phone_number=configloader.config["Credit Card"]["phone_required"] == "yes",
reply_markup=inline_keyboard) reply_markup=inline_keyboard)
# Wait for the invoice # Wait for the precheckout query
precheckoutquery = self.__wait_for_precheckoutquery(cancellable=True) precheckoutquery = self.__wait_for_precheckoutquery(cancellable=True)
# Check if the user has cancelled the invoice # Check if the user has cancelled the invoice
if isinstance(precheckoutquery, CancelSignal): if isinstance(precheckoutquery, CancelSignal):
@ -672,10 +679,11 @@ class ChatWorker(threading.Thread):
successfulpayment = self.__wait_for_successfulpayment() successfulpayment = self.__wait_for_successfulpayment()
# Create a new database transaction # Create a new database transaction
transaction = db.Transaction(user=self.user, transaction = db.Transaction(user=self.user,
value=successfulpayment.total_amount - int(total_fee), value=int(successfulpayment.total_amount) - fee,
provider="Credit Card", provider="Credit Card",
telegram_charge_id=successfulpayment.telegram_payment_charge_id, telegram_charge_id=successfulpayment.telegram_payment_charge_id,
provider_charge_id=successfulpayment.provider_payment_charge_id) provider_charge_id=successfulpayment.provider_payment_charge_id)
if successfulpayment.order_info is not None: if successfulpayment.order_info is not None:
transaction.payment_name = successfulpayment.order_info.name transaction.payment_name = successfulpayment.order_info.name
transaction.payment_email = successfulpayment.order_info.email transaction.payment_email = successfulpayment.order_info.email
@ -685,6 +693,17 @@ class ChatWorker(threading.Thread):
# Commit all the changes # Commit all the changes
self.session.commit() 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): def __bot_info(self):
"""Send information about the bot.""" """Send information about the bot."""
self.bot.send_message(self.chat.id, strings.bot_info) self.bot.send_message(self.chat.id, strings.bot_info)