import conf import sqlalchemy from db import Transaction, Product, User from helpers import less from text_interface.helpermenus import Menu, Selector class TransferMenu(Menu): def __init__(self): Menu.__init__(self, 'Transfer credit between users', uses_db=True) def _execute(self): self.print_header() 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}') user2 = self.input_user('To user> ') self.add_to_context(f' to {user2.name}') comment = self.input_str('Comment> ') self.add_to_context(f' (comment) {user2.name}') t1 = Transaction(user1, amount, f'transfer to {user2.name} "{comment}"') t2 = Transaction(user2, -amount, f'transfer from {user1.name} "{comment}"') t1.perform_transaction() t2.perform_transaction() self.session.add(t1) self.session.add(t2) try: self.session.commit() print(f"Transferred {amount:d} kr from {user1} to {user2}") print(f"User {user1}'s credit is now {user1.credit:d} kr") print(f"User {user2}'s credit is now {user2.credit:d} kr") print(f"Comment: {comment}") except sqlalchemy.exc.SQLAlchemyError as e: print(f'Could not perform transfer: {e}') # self.pause() class ShowUserMenu(Menu): def __init__(self): Menu.__init__(self, 'Show user', uses_db=True) def _execute(self): self.print_header() user = self.input_user('User name, card number or RFID> ') print(f'User name: {user.name}') print(f'Card number: {user.card}') print(f'RFID: {user.rfid}') print(f'Credit: {user.credit} kr') selector = Selector(f'What do you want to know about {user.name}?', items=[('transactions', 'Recent transactions (List of last ' + str( conf.user_recent_transaction_limit) + ')'), ('products', f'Which products {user.name} has bought, and how many'), ('transactions-all', 'Everything (List of all transactions)')]) what = selector.execute() if what == 'transactions': self.print_transactions(user, conf.user_recent_transaction_limit) elif what == 'products': self.print_purchased_products(user) elif what == 'transactions-all': self.print_all_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): num_trans = len(user.transactions) 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)) if t.purchase: 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_purchased_products(user): products = [] for ref in user.products: product = ref.product count = ref.count if count > 0: products.append((product, count)) num_products = len(products) if num_products == 0: print('No products purchased yet') else: text = '' text += 'Products purchased:\n' for product, count in products: text += f'{product.name:<47} {count:>3}\n' less(text) class UserListMenu(Menu): def __init__(self): Menu.__init__(self, 'User list', uses_db=True) def _execute(self): self.print_header() user_list = self.session.query(User).all() total_credit = self.session.query(sqlalchemy.func.sum(User.credit)).first()[0] line_format = '%-12s | %6s\n' hline = '---------------------\n' text = '' text += line_format % ('username', 'credit') text += hline for user in user_list: text += line_format % (user.name, user.credit) text += hline 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) def _execute(self): self.print_header() user = self.input_user('User> ') print(f"User {user.name}'s credit is {user.credit:d} kr") self.set_context(f'Adjusting credit for user {user.name}', display=False) 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> ', (-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)') description = self.input_str('Log message> ', length_range=(0, 50)) if description == '': description = 'manually adjusted credit' transaction = Transaction(user, -amount, description) transaction.perform_transaction() self.session.add(transaction) try: self.session.commit() print(f"User {user.name}'s credit is now {user.credit:d} kr") except sqlalchemy.exc.SQLAlchemyError as e: print(f'Could not store transaction: {e}') # self.pause() class ProductListMenu(Menu): def __init__(self): Menu.__init__(self, 'Product list', uses_db=True) def _execute(self): self.print_header() text = '' product_list = self.session.query(Product).filter(Product.hidden.is_(False)).order_by(Product.stock.desc()) total_value = 0 for p in product_list: total_value += p.price * p.stock line_format = '%-15s | %5s | %-' + str(Product.name_length) + 's | %5s \n' text += line_format % ('bar code', 'price', 'name', 'stock') text += 78 * '-' + '\n' for p in product_list: text += line_format % (p.bar_code, p.price, p.name, p.stock) text += 78 * '-' + '\n' text += line_format % ('Total value', total_value, '', '',) less(text) class ProductSearchMenu(Menu): def __init__(self): Menu.__init__(self, 'Product search', uses_db=True) def _execute(self): self.print_header() self.set_context('Enter (part of) product name or bar code') product = self.input_product() print('Result: %s, price: %d kr, bar code: %s, stock: %d, hidden: %s' % (product.name, product.price, product.bar_code, product.stock, ("Y" if product.hidden else "N"))) # self.pause()