diff --git a/text_interface/addstock.py b/text_interface/addstock.py index b878b49..4ef2466 100644 --- a/text_interface/addstock.py +++ b/text_interface/addstock.py @@ -42,8 +42,7 @@ much money you're due in credits for the purchase when prompted.\n''' if isinstance(thing, Product): self.printc(f"{amount:d} of {thing.name} registered") - thing_price = self.input_int('What did you pay a piece? ', (1, 100000), - default=thing.price) * amount + thing_price = self.input_int('What did you pay a piece?', 1, 100000, default=thing.price) * amount self.price += thing_price # 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): return bool(self.users) and len(self.products) and self.price - # TODO: Rewrite this madness def print_info(self): - print((6 + Product.name_length) * '-') + width = 6 + Product.name_length + print() + print(width * '-') 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: print("Users to credit:") for user in self.users: - print(f" {str(user.name)}") - print("\n{{0:s}}{{1:>{0}s}}".format(Product.name_length-1).format("Product", "Amount")) - print((6 + Product.name_length) * '-') + print(f"\t{user.name}") + print() + print("Products", end="") + print("Amount".rjust(width - 8)) + print(width * '-') if len(self.products): for product in list(self.products.keys()): - print('{{0:<{0}}}{{1:>6d}}'.format(Product.name_length).format(product.name, self.products[product][0])) - print((6 + Product.name_length) * '-') + print(f"{product.name}", end="") + print(f"{self.products[product][0]}".rjust(width - len(product.name))) + print(width * '-') def add_thing_to_pending(self, thing, amount, price): 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): print('Did you pay a different price?') if self.confirm('>', default=False): - price = self.input_int('How much did you pay?', 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 + self.price = self.input_int('How much did you pay?', 0, self.price, default=self.price) description = self.input_str('Log message', length_range=(0, 50)) if description == '': diff --git a/text_interface/buymenu.py b/text_interface/buymenu.py index 31ec3aa..db63673 100644 --- a/text_interface/buymenu.py +++ b/text_interface/buymenu.py @@ -77,10 +77,12 @@ When finished, write an empty line to confirm the purchase.\n''' else: Transaction(thing, purchase=self.purchase) elif isinstance(thing, Product): - if len(self.purchase.entries) and self.purchase.entries[-1].product == thing: - self.purchase.entries[-1].amount += amount - else: - PurchaseEntry(self.purchase, thing, amount) + if self.purchase.entries: + for entry in self.purchase.entries: + if entry.product == thing: + entry.amount += amount + return True + PurchaseEntry(self.purchase, thing, amount) return True 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},', 'AND SHOULD CONSIDER PUTTING SOME MONEY IN THE BOX.') - # Superfast mode skips a linebreak for some reason. This looks ugly. - # TODO: Figure out why this happens, and fix it in a less hacky way. + # Superfast mode skips a linebreak for some reason. if self.superfast_mode: - print("") + print("") return True 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' if any(t.penalty > 1 for t in transactions): - # TODO: Rewrite? - string += '\n *total with penalty: %d kr' % sum( - self.purchase.price_per_transaction() * t.penalty for t in transactions) + total = sum(self.purchase.price_per_transaction() * t.penalty for t in transactions) + string += f'\n *total with penalty: {total} kr' return string diff --git a/text_interface/editing.py b/text_interface/editing.py index 3d99891..f680851 100644 --- a/text_interface/editing.py +++ b/text_interface/editing.py @@ -66,7 +66,7 @@ class AddProductMenu(Menu): self.print_header() 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)) - price = self.input_int('Price', allowed_range=(1, 100000)) + price = self.input_int('Price', 1, 100000) product = Product(bar_code, name, price) self.session.add(product) try: @@ -97,7 +97,7 @@ class EditProductMenu(Menu): product.name = self.input_str('Name', default=product.name, regex=Product.name_re, length_range=(1, product.name_length)) 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': product.bar_code = self.input_str('Bar code', default=product.bar_code, regex=Product.bar_code_re, length_range=(8, 13)) @@ -129,7 +129,7 @@ class AdjustStockMenu(Menu): print(f'The stock of this product is: {product.stock:d}') print('Write the number of products you have added to the stock') 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: print(f'You added {add_stock:d} to the stock of {product}') else: @@ -168,7 +168,7 @@ class CleanupStockMenu(Menu): for product in products: 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) if oldstock != product.stock: changed_products.append((product, oldstock)) diff --git a/text_interface/helpermenus.py b/text_interface/helpermenus.py index 6866aa6..85124f6 100644 --- a/text_interface/helpermenus.py +++ b/text_interface/helpermenus.py @@ -185,26 +185,32 @@ class Menu(object): def invalid_menu_choice(self, in_str): 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, - default=None): + def input_int(self, prompt=None, minimum=None, maximum=None, null_allowed=False, zero_allowed=True, 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: - result = self.input_str(prompt, end_prompt, default=default) + result = self.input_str(prompt + end_prompt, default=default) if result == '' and null_allowed: return False try: value = int(result) - # TODO: Should this be turned into greater-than-equals and less-than-equals? - if ((allowed_range[0] and value < allowed_range[0]) or (allowed_range[1] and value > allowed_range[1])): - if allowed_range[0] and allowed_range[1]: - print(f'Value must be in range [{allowed_range[0]:d}, {allowed_range[1]:d}]') - elif allowed_range[0]: - print(f'Value must be at least {allowed_range[0]:d}') - else: - print(f'Value must be at most {allowed_range[1]:d}') - elif not zero_allowed and value == 0: + if minimum is not None and value < minimum: + print(f'Value must be at least {minimum:d}') + continue + if maximum is not None and value > maximum: + print(f'Value must be at most {maximum:d}') + continue + if not zero_allowed and value == 0: print("Value cannot be zero") - else: - return value + continue + return value except ValueError: print("Please enter an integer") @@ -412,8 +418,6 @@ class Menu(object): self.session = None 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: self.print_header() self.set_context(None) @@ -422,7 +426,8 @@ class Menu(object): self.pause() return None 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 if self.item_is_submenu(item_i): self.items[item_i].execute() diff --git a/text_interface/miscmenus.py b/text_interface/miscmenus.py index 8513119..b0f291f 100644 --- a/text_interface/miscmenus.py +++ b/text_interface/miscmenus.py @@ -12,7 +12,7 @@ class TransferMenu(Menu): def _execute(self): 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) user1 = self.input_user('From user') self.add_to_context(f' from {user1.name}') @@ -62,48 +62,32 @@ class ShowUserMenu(Menu): elif what == 'products': self.print_purchased_products(user) elif what == 'transactions-all': - self.print_all_transactions(user) + self.print_transactions(user) else: print('What what?') - # TODO: This is almost identical to the print_transactions function. Reimplement using that one? @staticmethod - def print_all_transactions(user): - 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): + def print_transactions(user, limit=None): num_trans = len(user.transactions) + if limit is None: + limit = num_trans if num_trans <= limit: string = f"{user.name}'s transactions ({num_trans:d}):\n" else: string = f"{user.name}'s transactions ({num_trans:d}, showing only last {limit:d}):\n" for t in user.transactions[-1:-limit - 1:-1]: - string += ' * %s: %s %d kr, ' % \ - (t.time.strftime('%Y-%m-%d %H:%M'), - 'in' if t.amount < 0 else 'out', - abs(t.amount)) + string += f" * {t.time.isoformat(' ')}: {'in' if t.amount < 0 else 'out'} {abs(t.amount)} kr, " 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 += ', '.join([e.product.name for e in t.purchase.entries]) + string += ', '.join(products) string += ')' if t.penalty > 1: string += f' * {t.penalty:d}x penalty applied' @@ -151,8 +135,6 @@ class UserListMenu(Menu): text += line_format % ('total credit', total_credit) less(text) -# reimplements ChargeMenu -# TODO: these should be combined to one class AdjustCreditMenu(Menu): def __init__(self): 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('added money to the PVVVV money box, a negative amount if you have') 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('"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)')