Noenlunde fungerende opplegg for kjøp, ymse små forbedringer.
* Ny tabell Transaction som brukes for alle transaksjoner; hver transaksjon kan være knyttet til en Purchase eller ha en tekstlig beskrivelse. (BuyMenu og TransferMenu viser de to måtene å bruke Transaction på) * Hvert kjøp kan ha flere brukere. Prisen fordeles likt blant kjøperne (for øyeblikket antar jeg at alle pengebeløp i databasen er lagret i kroner, og når totalprisen for et kjøp ikke går opp i antall kjøpere rundes det ned til et helt antall kroner) * Forbedret input i BuyMenu -- den gjetter på om man skriver inn et produkt eller en bruker basert på hvor den finner treff. (Hvis treffene er like gode begge steder velges det vilkårlig -- dette kan endres om det viser seg å være et problem i praksis) * BuyMenu lagrer faktisk kjøpene i databasen. * ShowUserMenu viser alle transaksjonene til brukeren. Dette kan bli mye etter hvert, så det bør sikkert begrenses på et eller annet vis (for eksempel at den bare viser de siste N, for et egnet naturlig tall N).
This commit is contained in:
parent
b9f5c39a76
commit
b648c27473
59
db.py
59
db.py
|
@ -54,41 +54,74 @@ class PurchaseEntry(Base):
|
|||
def __init__(self, purchase, product, amount):
|
||||
self.product = product
|
||||
self.product_bar_code = product.bar_code
|
||||
self.purchase_id = purchase.id
|
||||
self.purchase = purchase
|
||||
self.amount = amount
|
||||
|
||||
def __repr__(self):
|
||||
return "<PurchaseEntry('%s', '%s', '%s')>" % (self.purchase.user.user, self.product.name, self.amount )
|
||||
|
||||
|
||||
class Transaction(Base):
|
||||
__tablename__ = 'transactions'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
time = Column(DateTime)
|
||||
user_name = Column(String(10), ForeignKey('users.name'))
|
||||
amount = Column(Integer)
|
||||
description = Column(String(50))
|
||||
purchase_id = Column(Integer, ForeignKey('purchases.id'))
|
||||
|
||||
user = relationship(User, backref=backref('transactions', order_by=time))
|
||||
|
||||
def __init__(self, user, amount=0, description=None, purchase=None):
|
||||
self.user = user
|
||||
self.amount = amount
|
||||
self.description = description
|
||||
self.purchase = purchase
|
||||
|
||||
def perform_transaction(self):
|
||||
self.time = datetime.datetime.now()
|
||||
self.user.credit -= self.amount
|
||||
|
||||
|
||||
class Purchase(Base):
|
||||
__tablename__ = 'purchases'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
time = Column(DateTime)
|
||||
user_name = Column(Integer, ForeignKey('users.name'))
|
||||
# user_name = Column(Integer, ForeignKey('users.name'))
|
||||
price = Column(Integer)
|
||||
performed = Column(Boolean)
|
||||
# performed = Column(Boolean)
|
||||
|
||||
user = relationship(User, backref=backref('purchases', order_by=id))
|
||||
products = relationship(PurchaseEntry, backref=backref("purchase"))
|
||||
# user = relationship(User, backref=backref('purchases', order_by=id))
|
||||
# users = relationship(User, secondary=purchase_user, backref='purhcases'
|
||||
transactions = relationship(Transaction, order_by=Transaction.user_name, backref='purchase')
|
||||
entries = relationship(PurchaseEntry, backref=backref("purchase"))
|
||||
|
||||
def __init__(self ,performed=False):
|
||||
self.performed = performed
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return "<Purchase('%s', '%s', '%s')>" % (self.user.name, self.price, self.time.strftime('%c'))
|
||||
|
||||
def is_complete(self):
|
||||
return len(self.transactions) > 0 and len(self.entries) > 0
|
||||
|
||||
def price_per_transaction(self):
|
||||
return self.price/len(self.transactions)
|
||||
|
||||
def set_price(self):
|
||||
self.price = 0
|
||||
for entry in self.products:
|
||||
for entry in self.entries:
|
||||
self.price += entry.amount*entry.product.price
|
||||
if len(self.transactions) > 0:
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction()
|
||||
|
||||
def perform_purchase(self):
|
||||
if self.performed:
|
||||
print "This transaction has already been performed"
|
||||
else:
|
||||
self.time = datetime.datetime.now()
|
||||
self.set_price()
|
||||
self.user.credit -= self.price
|
||||
self.performed = True
|
||||
for t in self.transactions:
|
||||
t.perform_transaction()
|
||||
# self.user.credit -= self.price
|
||||
# self.performed = True
|
||||
|
|
15
helpers.py
15
helpers.py
|
@ -69,3 +69,18 @@ def select_from_list(list):
|
|||
return list[int(choice)-1]
|
||||
else:
|
||||
return None
|
||||
|
||||
def argmax(d, all=False, value=None):
|
||||
maxarg = None
|
||||
maxargs = []
|
||||
if value != None:
|
||||
dd = d
|
||||
d = {}
|
||||
for key in dd.keys():
|
||||
d[key] = value(dd[key])
|
||||
for key in d.keys():
|
||||
if maxarg == None or d[key] > d[maxarg]:
|
||||
maxarg = key
|
||||
if all:
|
||||
return filter(lambda k: d[k] == d[maxarg], d.keys())
|
||||
return maxarg
|
||||
|
|
190
text_based.py
190
text_based.py
|
@ -57,6 +57,53 @@ class Menu():
|
|||
except ValueError:
|
||||
print 'Please enter an integer'
|
||||
|
||||
def input_user(self, prompt=None):
|
||||
user = None
|
||||
while user == None:
|
||||
user = retrieve_user(self.input_str(prompt),
|
||||
self.session)
|
||||
return user
|
||||
|
||||
def input_product(self, prompt=None):
|
||||
product = None
|
||||
while product == None:
|
||||
product = retrieve_product(self.input_str(prompt),
|
||||
self.session)
|
||||
return product
|
||||
|
||||
def input_thing(self, prompt=None, permitted_things=('user','product'),
|
||||
empty_input_permitted=False):
|
||||
result = None
|
||||
while result == None:
|
||||
search_str = self.input_str(prompt)
|
||||
if search_str == '' and empty_input_permitted:
|
||||
return None
|
||||
result = self.search_for_thing(search_str, permitted_things)
|
||||
return result
|
||||
|
||||
def search_for_thing(self, search_str, permitted_things=('user','product')):
|
||||
search_fun = {'user': search_user,
|
||||
'product': search_product}
|
||||
results = {}
|
||||
result_values = {}
|
||||
for thing in permitted_things:
|
||||
results[thing] = search_fun[thing](search_str, self.session)
|
||||
result_values[thing] = self.search_result_value(results[thing])
|
||||
selected_thing = argmax(result_values)
|
||||
return search_ui2(search_str, results[selected_thing],
|
||||
selected_thing, self.session)
|
||||
|
||||
def search_result_value(self, result):
|
||||
if result == None:
|
||||
return 0
|
||||
if not isinstance(result, list):
|
||||
return 3
|
||||
if len(result) == 0:
|
||||
return 0
|
||||
if len(result) == 1:
|
||||
return 2
|
||||
return 1
|
||||
|
||||
def print_header(self):
|
||||
print
|
||||
print '[%s]' % self.name
|
||||
|
@ -136,21 +183,63 @@ class ChargeMenu(Menu):
|
|||
self.session.close()
|
||||
break
|
||||
|
||||
class TransferMenu(Menu):
|
||||
def __init__(self):
|
||||
Menu.__init__(self, 'Transfer credit between users')
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
self.session = Session()
|
||||
amount = self.input_int('Transfer amount> ')
|
||||
user1 = self.input_user('From user> ')
|
||||
user2 = self.input_user('To user> ')
|
||||
t1 = Transaction(user1, amount,
|
||||
'Transfer to '+user2.name)
|
||||
t2 = Transaction(user2, -amount,
|
||||
'Transfer from '+user1.name)
|
||||
t1.perform_transaction()
|
||||
t2.perform_transaction()
|
||||
self.session.add(t1)
|
||||
self.session.add(t2)
|
||||
self.session.commit()
|
||||
print 'Transfered %d kr from %s to %s' % (amount, user1, user2)
|
||||
print 'User %s\'s credit is now %d kr' % (user1, user1.credit)
|
||||
print 'User %s\'s credit is now %d kr' % (user2, user2.credit)
|
||||
self.session.close()
|
||||
self.pause()
|
||||
|
||||
|
||||
class ShowUserMenu(Menu):
|
||||
def __init__(self):
|
||||
Menu.__init__(self, 'Show user')
|
||||
|
||||
def _execute(self):
|
||||
self.session = Session()
|
||||
self.print_header()
|
||||
user = None
|
||||
while user == None:
|
||||
search_str = self.input_str('User name or card number> ')
|
||||
user = search_ui(search_user, search_str, 'user', Session())
|
||||
user = self.input_user('User name or card number> ')
|
||||
print 'User name: %s' % user.name
|
||||
print 'Card number: %s' % user.card
|
||||
print 'Credit: %s' % user.credit
|
||||
self.print_transactions(user)
|
||||
self.pause()
|
||||
|
||||
def print_transactions(self, user):
|
||||
if len(user.transactions) == 0:
|
||||
print 'No transactions'
|
||||
return
|
||||
print 'Transactions:'
|
||||
for t in user.transactions:
|
||||
string = ' * %s: %d kr, ' % \
|
||||
(t.time.strftime('%Y-%m-%d %H:%M'), t.amount)
|
||||
if t.purchase:
|
||||
string += 'purchase ('
|
||||
string += ', '.join(map(lambda e: e.product.name,
|
||||
t.purchase.entries))
|
||||
string += ')'
|
||||
else:
|
||||
string += t.description
|
||||
print string
|
||||
|
||||
|
||||
class BuyMenu(Menu):
|
||||
def __init__(self):
|
||||
|
@ -158,49 +247,75 @@ class BuyMenu(Menu):
|
|||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
session = Session()
|
||||
user = None
|
||||
products = []
|
||||
self.session = Session()
|
||||
self.purchase = Purchase()
|
||||
while True:
|
||||
self.print_partial_purchase(user, products)
|
||||
self.print_purchase()
|
||||
print {(False,False): 'Enter user or product identification',
|
||||
(False,True): 'Enter user identification or more products',
|
||||
(True,False): 'Enter product identification',
|
||||
(True,True): 'Enter more products, or an empty line to confirm'
|
||||
}[(user != None, len(products) > 0)]
|
||||
string = self.input_str()
|
||||
if string == '':
|
||||
if user == None or len(products) == 0:
|
||||
(True,False): 'Enter product identification or more users',
|
||||
(True,True): 'Enter more products or users, or an empty line to confirm'
|
||||
}[(len(self.purchase.transactions) > 0,
|
||||
len(self.purchase.entries) > 0)]
|
||||
thing = self.input_thing(empty_input_permitted=True)
|
||||
if thing == None:
|
||||
if not self.complete_input():
|
||||
if confirm('Not enough information entered. Abort purchase? (y/n) '):
|
||||
return False
|
||||
continue
|
||||
break
|
||||
(value_type,value) = dwim_search(string, session)
|
||||
if value != None:
|
||||
if value_type == 'user':
|
||||
user = value
|
||||
elif value_type == 'product':
|
||||
products.append(value)
|
||||
print 'OK purchase'
|
||||
print self.format_partial_purchase(user, products)
|
||||
# TODO build Purchase object and commit
|
||||
if isinstance(thing, User):
|
||||
Transaction(thing, purchase=self.purchase)
|
||||
elif isinstance(thing, Product):
|
||||
PurchaseEntry(self.purchase, thing, 1)
|
||||
|
||||
# for user in self.users:
|
||||
# Transaction(user, purchase=self.purchase)
|
||||
# for product in self.products:
|
||||
# PurchaseEntry(self.purchase, product, 1)
|
||||
self.purchase.perform_purchase()
|
||||
|
||||
self.session.add(self.purchase)
|
||||
self.session.commit()
|
||||
|
||||
print 'Purchase stored.' # TODO print info about purchase
|
||||
self.print_purchase()
|
||||
for t in self.purchase.transactions:
|
||||
print 'User %s\'s credit is now %d kr' % (t.user.name, t.user.credit)
|
||||
self.session.close()
|
||||
self.pause()
|
||||
return True
|
||||
|
||||
def complete_input(self):
|
||||
return self.purchase.is_complete()
|
||||
|
||||
def format_partial_purchase(self, user, products):
|
||||
if user == None and len(products) == 0:
|
||||
return
|
||||
strings = []
|
||||
if user != None:
|
||||
strings.append(' user: ' + user.name)
|
||||
if len(products) > 0:
|
||||
strings.append(' products: ' + ', '.join(map(lambda p: p.name, products)))
|
||||
return '\n'.join(strings)
|
||||
def format_purchase(self):
|
||||
self.purchase.set_price()
|
||||
transactions = self.purchase.transactions
|
||||
entries = self.purchase.entries
|
||||
if len(transactions) == 0 and len(entries) == 0:
|
||||
return None
|
||||
string = 'Purchase:'
|
||||
string += '\n buyers: '
|
||||
if len(transactions) == 0:
|
||||
string += '(empty)'
|
||||
else:
|
||||
string += ', '.join(map(lambda t: t.user.name, transactions))
|
||||
string += '\n products: '
|
||||
if len(entries) == 0:
|
||||
string += '(empty)'
|
||||
else:
|
||||
string += ', '.join(map(lambda e: '%s (%d kr)'%(e.product.name, e.product.price),
|
||||
entries))
|
||||
if len(transactions) > 1:
|
||||
string += '\n price per person: %d kr' % self.purchase.price_per_transaction()
|
||||
string += '\n total price: %d kr' % self.purchase.price
|
||||
return string
|
||||
|
||||
def print_partial_purchase(self, user, products):
|
||||
info = self.format_partial_purchase(user, products)
|
||||
def print_purchase(self):
|
||||
info = self.format_purchase()
|
||||
if info != None:
|
||||
print 'Your purchase:\n' + info
|
||||
print info
|
||||
|
||||
|
||||
class ProductListMenu(Menu):
|
||||
|
@ -258,6 +373,9 @@ def dwim_search(string, session):
|
|||
|
||||
def search_ui(search_fun, search_str, thing, session):
|
||||
result = search_fun(search_str, session)
|
||||
return search_ui2(search_str, result, thing, session)
|
||||
|
||||
def search_ui2(search_str, result, thing, session):
|
||||
if not isinstance(result, list):
|
||||
return result
|
||||
if len(result) == 0:
|
||||
|
@ -282,7 +400,7 @@ def retrieve_product(search_str, session):
|
|||
|
||||
#main = MainMenu()
|
||||
main = Menu('Dibbler main menu',
|
||||
items=[BuyMenu(), ChargeMenu(), Menu('Add user'), Menu('Add product'),
|
||||
items=[BuyMenu(), ChargeMenu(), TransferMenu(), Menu('Add user'), Menu('Add product'),
|
||||
ShowUserMenu(), ProductListMenu()],
|
||||
exit_msg='happy happy joy joy')
|
||||
main.execute()
|
||||
|
|
Loading…
Reference in New Issue