Fix errors, make menu formatting more readable

This commit is contained in:
Robert Maikher 2019-09-21 16:48:49 +02:00
parent c188d692dd
commit 92f3990cc0
5 changed files with 66 additions and 81 deletions

View File

@ -42,8 +42,7 @@ much money you're due in credits for the purchase when prompted.\n'''
if isinstance(thing, Product): if isinstance(thing, Product):
self.printc(f"{amount:d} of {thing.name} registered") self.printc(f"{amount:d} of {thing.name} registered")
thing_price = self.input_int('What did you pay a piece? ', (1, 100000), thing_price = self.input_int('What did you pay a piece?', 1, 100000, default=thing.price) * amount
default=thing.price) * amount
self.price += thing_price self.price += thing_price
# once we get something in the # once we get something in the
@ -65,21 +64,25 @@ much money you're due in credits for the purchase when prompted.\n'''
def complete_input(self): def complete_input(self):
return bool(self.users) and len(self.products) and self.price return bool(self.users) and len(self.products) and self.price
# TODO: Rewrite this madness
def print_info(self): def print_info(self):
print((6 + Product.name_length) * '-') width = 6 + Product.name_length
print()
print(width * '-')
if self.price: if self.price:
print("Amount to be credited: {{0:>{0}d}}".format(Product.name_length-17).format(self.price)) print(f"Amount to be credited:{self.price:>{width - 22}}")
if self.users: if self.users:
print("Users to credit:") print("Users to credit:")
for user in self.users: for user in self.users:
print(f" {str(user.name)}") print(f"\t{user.name}")
print("\n{{0:s}}{{1:>{0}s}}".format(Product.name_length-1).format("Product", "Amount")) print()
print((6 + Product.name_length) * '-') print("Products", end="")
print("Amount".rjust(width - 8))
print(width * '-')
if len(self.products): if len(self.products):
for product in list(self.products.keys()): for product in list(self.products.keys()):
print('{{0:<{0}}}{{1:>6d}}'.format(Product.name_length).format(product.name, self.products[product][0])) print(f"{product.name}", end="")
print((6 + Product.name_length) * '-') print(f"{self.products[product][0]}".rjust(width - len(product.name)))
print(width * '-')
def add_thing_to_pending(self, thing, amount, price): def add_thing_to_pending(self, thing, amount, price):
if isinstance(thing, User): if isinstance(thing, User):
@ -94,12 +97,7 @@ much money you're due in credits for the purchase when prompted.\n'''
def perform_transaction(self): def perform_transaction(self):
print('Did you pay a different price?') print('Did you pay a different price?')
if self.confirm('>', default=False): if self.confirm('>', default=False):
price = self.input_int('How much did you pay?', default=self.price) self.price = self.input_int('How much did you pay?', 0, self.price, default=self.price)
# TODO: Loop until we get a valid answer instead of assuming default
if price > self.price:
print('Illegal action, total can not be higher than your total.')
else:
self.price = price
description = self.input_str('Log message', length_range=(0, 50)) description = self.input_str('Log message', length_range=(0, 50))
if description == '': if description == '':

View File

@ -77,10 +77,12 @@ When finished, write an empty line to confirm the purchase.\n'''
else: else:
Transaction(thing, purchase=self.purchase) Transaction(thing, purchase=self.purchase)
elif isinstance(thing, Product): elif isinstance(thing, Product):
if len(self.purchase.entries) and self.purchase.entries[-1].product == thing: if self.purchase.entries:
self.purchase.entries[-1].amount += amount for entry in self.purchase.entries:
else: if entry.product == thing:
PurchaseEntry(self.purchase, thing, amount) entry.amount += amount
return True
PurchaseEntry(self.purchase, thing, amount)
return True return True
def _execute(self, initial_contents=None): def _execute(self, initial_contents=None):
@ -160,10 +162,9 @@ When finished, write an empty line to confirm the purchase.\n'''
print(f'USER {t.user.name} HAS LOWER CREDIT THAN {conf.low_credit_warning_limit:d},', print(f'USER {t.user.name} HAS LOWER CREDIT THAN {conf.low_credit_warning_limit:d},',
'AND SHOULD CONSIDER PUTTING SOME MONEY IN THE BOX.') 'AND SHOULD CONSIDER PUTTING SOME MONEY IN THE BOX.')
# Superfast mode skips a linebreak for some reason. This looks ugly. # Superfast mode skips a linebreak for some reason.
# TODO: Figure out why this happens, and fix it in a less hacky way.
if self.superfast_mode: if self.superfast_mode:
print("") print("")
return True return True
def complete_input(self): def complete_input(self):
@ -197,9 +198,8 @@ When finished, write an empty line to confirm the purchase.\n'''
string += f'\n total price: {self.purchase.price:d} kr' string += f'\n total price: {self.purchase.price:d} kr'
if any(t.penalty > 1 for t in transactions): if any(t.penalty > 1 for t in transactions):
# TODO: Rewrite? total = sum(self.purchase.price_per_transaction() * t.penalty for t in transactions)
string += '\n *total with penalty: %d kr' % sum( string += f'\n *total with penalty: {total} kr'
self.purchase.price_per_transaction() * t.penalty for t in transactions)
return string return string

View File

@ -66,7 +66,7 @@ class AddProductMenu(Menu):
self.print_header() self.print_header()
bar_code = self.input_str('Bar code', regex=Product.bar_code_re, length_range=(8, 13)) bar_code = self.input_str('Bar code', regex=Product.bar_code_re, length_range=(8, 13))
name = self.input_str('Name', regex=Product.name_re, length_range=(1, Product.name_length)) name = self.input_str('Name', regex=Product.name_re, length_range=(1, Product.name_length))
price = self.input_int('Price', allowed_range=(1, 100000)) price = self.input_int('Price', 1, 100000)
product = Product(bar_code, name, price) product = Product(bar_code, name, price)
self.session.add(product) self.session.add(product)
try: try:
@ -97,7 +97,7 @@ class EditProductMenu(Menu):
product.name = self.input_str('Name', default=product.name, regex=Product.name_re, product.name = self.input_str('Name', default=product.name, regex=Product.name_re,
length_range=(1, product.name_length)) length_range=(1, product.name_length))
elif what == 'price': elif what == 'price':
product.price = self.input_int('Price', default=product.price, allowed_range=(1, 100000)) product.price = self.input_int('Price', 1, 100000, default=product.price)
elif what == 'barcode': elif what == 'barcode':
product.bar_code = self.input_str('Bar code', default=product.bar_code, regex=Product.bar_code_re, product.bar_code = self.input_str('Bar code', default=product.bar_code, regex=Product.bar_code_re,
length_range=(8, 13)) length_range=(8, 13))
@ -129,7 +129,7 @@ class AdjustStockMenu(Menu):
print(f'The stock of this product is: {product.stock:d}') print(f'The stock of this product is: {product.stock:d}')
print('Write the number of products you have added to the stock') print('Write the number of products you have added to the stock')
print('Alternatively, correct the stock for any mistakes') print('Alternatively, correct the stock for any mistakes')
add_stock = self.input_int('Added stock', allowed_range=(-1000, 1000), zero_allowed=False) add_stock = self.input_int('Added stock', -1000, 1000, zero_allowed=False)
if add_stock > 0: if add_stock > 0:
print(f'You added {add_stock:d} to the stock of {product}') print(f'You added {add_stock:d} to the stock of {product}')
else: else:
@ -168,7 +168,7 @@ class CleanupStockMenu(Menu):
for product in products: for product in products:
oldstock = product.stock oldstock = product.stock
product.stock = self.input_int(product.name, allowed_range=(0, 10000), default=max(0, oldstock)) product.stock = self.input_int(product.name, 0, 10000, default=max(0, oldstock))
self.session.add(product) self.session.add(product)
if oldstock != product.stock: if oldstock != product.stock:
changed_products.append((product, oldstock)) changed_products.append((product, oldstock))

View File

@ -185,26 +185,32 @@ class Menu(object):
def invalid_menu_choice(self, in_str): def invalid_menu_choice(self, in_str):
print('Please enter a valid choice.') print('Please enter a valid choice.')
def input_int(self, prompt=None, end_prompt=None, allowed_range=(None, None), null_allowed=False, zero_allowed=True, def input_int(self, prompt=None, minimum=None, maximum=None, null_allowed=False, zero_allowed=True, default=None):
default=None): if minimum is not None and maximum is not None:
end_prompt = f"({minimum}-{maximum})>"
elif minimum is not None:
end_prompt = f"(>{minimum})>"
elif maximum is not None:
end_prompt = f"(<{maximum})>"
else:
end_prompt = ""
while True: while True:
result = self.input_str(prompt, end_prompt, default=default) result = self.input_str(prompt + end_prompt, default=default)
if result == '' and null_allowed: if result == '' and null_allowed:
return False return False
try: try:
value = int(result) value = int(result)
# TODO: Should this be turned into greater-than-equals and less-than-equals? if minimum is not None and value < minimum:
if ((allowed_range[0] and value < allowed_range[0]) or (allowed_range[1] and value > allowed_range[1])): print(f'Value must be at least {minimum:d}')
if allowed_range[0] and allowed_range[1]: continue
print(f'Value must be in range [{allowed_range[0]:d}, {allowed_range[1]:d}]') if maximum is not None and value > maximum:
elif allowed_range[0]: print(f'Value must be at most {maximum:d}')
print(f'Value must be at least {allowed_range[0]:d}') continue
else: if not zero_allowed and value == 0:
print(f'Value must be at most {allowed_range[1]:d}')
elif not zero_allowed and value == 0:
print("Value cannot be zero") print("Value cannot be zero")
else: continue
return value return value
except ValueError: except ValueError:
print("Please enter an integer") print("Please enter an integer")
@ -412,8 +418,6 @@ class Menu(object):
self.session = None self.session = None
def _execute(self, **kwargs): def _execute(self, **kwargs):
# TODO: This is a very awkward line. Is there a better way of doing this?
line_format = '%' + str(len(str(len(self.items)))) + 'd ) %s'
while True: while True:
self.print_header() self.print_header()
self.set_context(None) self.set_context(None)
@ -422,7 +426,8 @@ class Menu(object):
self.pause() self.pause()
return None return None
for i in range(len(self.items)): for i in range(len(self.items)):
self.printc(line_format % (i + 1, self.item_name(i))) length = len(str(len(self.items)))
self.printc(f"{i + 1:>{length}} ) {self.item_name(i)}")
item_i = self.input_choice(len(self.items)) - 1 item_i = self.input_choice(len(self.items)) - 1
if self.item_is_submenu(item_i): if self.item_is_submenu(item_i):
self.items[item_i].execute() self.items[item_i].execute()

View File

@ -12,7 +12,7 @@ class TransferMenu(Menu):
def _execute(self): def _execute(self):
self.print_header() self.print_header()
amount = self.input_int('Transfer amount', (1, 100000)) amount = self.input_int('Transfer amount', 1, 100000)
self.set_context(f'Transferring {amount:d} kr', display=False) self.set_context(f'Transferring {amount:d} kr', display=False)
user1 = self.input_user('From user') user1 = self.input_user('From user')
self.add_to_context(f' from {user1.name}') self.add_to_context(f' from {user1.name}')
@ -62,48 +62,32 @@ class ShowUserMenu(Menu):
elif what == 'products': elif what == 'products':
self.print_purchased_products(user) self.print_purchased_products(user)
elif what == 'transactions-all': elif what == 'transactions-all':
self.print_all_transactions(user) self.print_transactions(user)
else: else:
print('What what?') print('What what?')
# TODO: This is almost identical to the print_transactions function. Reimplement using that one?
@staticmethod @staticmethod
def print_all_transactions(user): def print_transactions(user, limit=None):
num_trans = len(user.transactions)
string = f"{user.name}'s transactions ({num_trans:d}):\n"
for t in user.transactions[::-1]:
string += ' * %s: %s %d kr, ' % \
(t.time.strftime('%Y-%m-%d %H:%M'),
'in' if t.amount < 0 else 'out',
abs(t.amount))
if t.purchase:
# TODO: Print purchased amount, not just product names
# TODO: Print something other than "purchase" when user put products into dibbler?
string += 'purchase ('
string += ', '.join([e.product.name for e in t.purchase.entries])
string += ')'
if t.penalty > 1:
string += f' * {t.penalty:d}x penalty applied'
else:
string += t.description
string += '\n'
less(string)
@staticmethod
def print_transactions(user, limit=10):
num_trans = len(user.transactions) num_trans = len(user.transactions)
if limit is None:
limit = num_trans
if num_trans <= limit: if num_trans <= limit:
string = f"{user.name}'s transactions ({num_trans:d}):\n" string = f"{user.name}'s transactions ({num_trans:d}):\n"
else: else:
string = f"{user.name}'s transactions ({num_trans:d}, showing only last {limit:d}):\n" string = f"{user.name}'s transactions ({num_trans:d}, showing only last {limit:d}):\n"
for t in user.transactions[-1:-limit - 1:-1]: for t in user.transactions[-1:-limit - 1:-1]:
string += ' * %s: %s %d kr, ' % \ string += f" * {t.time.isoformat(' ')}: {'in' if t.amount < 0 else 'out'} {abs(t.amount)} kr, "
(t.time.strftime('%Y-%m-%d %H:%M'),
'in' if t.amount < 0 else 'out',
abs(t.amount))
if t.purchase: if t.purchase:
products = []
for entry in t.purchase.entries:
if abs(entry.amount) != 1:
amount = f"{abs(entry.amount)}x "
else:
amount = ""
product = f"{amount}{entry.product.name}"
products.append(product)
string += 'purchase (' string += 'purchase ('
string += ', '.join([e.product.name for e in t.purchase.entries]) string += ', '.join(products)
string += ')' string += ')'
if t.penalty > 1: if t.penalty > 1:
string += f' * {t.penalty:d}x penalty applied' string += f' * {t.penalty:d}x penalty applied'
@ -151,8 +135,6 @@ class UserListMenu(Menu):
text += line_format % ('total credit', total_credit) text += line_format % ('total credit', total_credit)
less(text) less(text)
# reimplements ChargeMenu
# TODO: these should be combined to one
class AdjustCreditMenu(Menu): class AdjustCreditMenu(Menu):
def __init__(self): def __init__(self):
Menu.__init__(self, 'Adjust credit', uses_db=True) Menu.__init__(self, 'Adjust credit', uses_db=True)
@ -165,7 +147,7 @@ class AdjustCreditMenu(Menu):
print('(Note on sign convention: Enter a positive amount here if you have') print('(Note on sign convention: Enter a positive amount here if you have')
print('added money to the PVVVV money box, a negative amount if you have') print('added money to the PVVVV money box, a negative amount if you have')
print('taken money from it)') print('taken money from it)')
amount = self.input_int('Add amount', allowed_range=(-100000, 100000)) amount = self.input_int('Add amount', -100000, 100000)
print('(The "log message" will show up in the transaction history in the') print('(The "log message" will show up in the transaction history in the')
print('"Show user" menu. It is not necessary to enter a message, but it') print('"Show user" menu. It is not necessary to enter a message, but it')
print('might be useful to help you remember why you adjusted the credit)') print('might be useful to help you remember why you adjusted the credit)')