|
|
|
#! /usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
# Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
|
|
|
|
# Licensed under GPL v3 or later
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
import freitagslib.network as net
|
|
|
|
from freitagslib.commands import BuyCommand, DepositCommand
|
|
|
|
|
|
|
|
import sys
|
|
|
|
from decimal import Decimal
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import urllib2
|
|
|
|
|
|
|
|
|
|
|
|
def clear():
|
|
|
|
os.system('clear')
|
|
|
|
|
|
|
|
|
|
|
|
CODES = {
|
|
|
|
'UNDO':('undo',),
|
|
|
|
'COMMIT':('commit',),
|
|
|
|
|
|
|
|
'DEPOSIT 0.01':('deposit', Decimal('0.01')),
|
|
|
|
'DEPOSIT 0.05':('deposit', Decimal('0.05')),
|
|
|
|
'DEPOSIT 0.10':('deposit', Decimal('0.10')),
|
|
|
|
'DEPOSIT 0.50':('deposit', Decimal('0.50')),
|
|
|
|
'DEPOSIT 1.00':('deposit', Decimal('1.00')),
|
|
|
|
'DEPOSIT 5.00':('deposit', Decimal('5.00')),
|
|
|
|
'DEPOSIT 10.00':('deposit', Decimal('10.00')),
|
|
|
|
'DEPOSIT 50.00':('deposit', Decimal('50.00')),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def delay(what, seconds):
|
|
|
|
for i in xrange(seconds, 0, -1):
|
|
|
|
if i < seconds:
|
|
|
|
sys.stdout.write('\r')
|
|
|
|
sys.stdout.write('%s in %d Sekunden... ' % (what, i))
|
|
|
|
sys.stdout.flush()
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
|
|
def warn_balance():
|
|
|
|
print('Kontostrand im Minus, NICHT cool!')
|
|
|
|
|
|
|
|
|
|
|
|
def error_page(message):
|
|
|
|
clear()
|
|
|
|
print(message)
|
|
|
|
print()
|
|
|
|
delay('Weiter', 3)
|
|
|
|
|
|
|
|
|
|
|
|
class Status:
|
|
|
|
def __init__(self):
|
|
|
|
self._reset()
|
|
|
|
self.item_cache = dict()
|
|
|
|
|
|
|
|
def _reset(self):
|
|
|
|
self.auth_blob = None
|
|
|
|
self.login_name = None
|
|
|
|
self.balance = None
|
|
|
|
self.transfers = None
|
|
|
|
|
|
|
|
def dump(self):
|
|
|
|
if self.logged_in():
|
|
|
|
print('Eingeloggt als: %s' % (self.login_name))
|
|
|
|
print()
|
|
|
|
if self.transfers:
|
|
|
|
print('Geplante Änderungen:')
|
|
|
|
initial_command, initial_balance = self.transfers[0]
|
|
|
|
print(('%3s %-40s %c %6.2f Euro') % ('', '', ' ' if initial_balance > 0 else '-', abs(initial_balance)))
|
|
|
|
for i, (command, balance_backup) in enumerate(self.transfers):
|
|
|
|
difference = command.difference()
|
|
|
|
label = command.label()
|
|
|
|
print(('%2d) %-40s %c %6.2f Euro') % (i + 1, label, '+' if difference > 0 else '-', abs(difference)))
|
|
|
|
print(('%3s %-40s %8s') % ('', '', '============='))
|
|
|
|
print(('%3s %-40s %c %6.2f Euro') % ('', '', ' ' if self.balance > 0 else '-', abs(self.balance)))
|
|
|
|
|
|
|
|
if self.balance < 0:
|
|
|
|
warn_balance()
|
|
|
|
print()
|
|
|
|
|
|
|
|
print('Committen nicht vergessen!')
|
|
|
|
else:
|
|
|
|
print('Kontostand beträgt: %.2f Euro' % (self.balance))
|
|
|
|
if self.balance < 0:
|
|
|
|
print()
|
|
|
|
warn_balance()
|
|
|
|
else:
|
|
|
|
print('Bitte einloggen.')
|
|
|
|
print()
|
|
|
|
print('Scanne dazu deine ID-Karte mit dem Barcode-Leser.')
|
|
|
|
print()
|
|
|
|
|
|
|
|
def logged_in(self):
|
|
|
|
return self.auth_blob is not None
|
|
|
|
|
|
|
|
def login(self, auth_blob):
|
|
|
|
assert(not self.logged_in())
|
|
|
|
|
|
|
|
user_name = net.get_user_name_from_auth_blob(auth_blob)
|
|
|
|
balance = net.get_balance(user_name)
|
|
|
|
|
|
|
|
self.auth_blob = auth_blob
|
|
|
|
self.login_name = user_name
|
|
|
|
self.balance = balance
|
|
|
|
self.transfers = list()
|
|
|
|
|
|
|
|
def commit(self):
|
|
|
|
assert(self.logged_in())
|
|
|
|
|
|
|
|
# Process command queue
|
|
|
|
for (command, balance_backup) in list(self.transfers):
|
|
|
|
try:
|
|
|
|
command.run(self.login_name)
|
|
|
|
except urllib2.HTTPError as e:
|
|
|
|
error_page('FEHLER bei Kommunikation mit Server "%s"' % str(e))
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
self.transfers.pop(0)
|
|
|
|
|
|
|
|
if not self.transfers:
|
|
|
|
# Show final balance for some time
|
|
|
|
clear()
|
|
|
|
self.dump()
|
|
|
|
delay('Logout', 3)
|
|
|
|
|
|
|
|
# Logout
|
|
|
|
self._reset()
|
|
|
|
|
|
|
|
def find(self, item_id):
|
|
|
|
try:
|
|
|
|
return self.item_cache[item_id]
|
|
|
|
except KeyError:
|
|
|
|
item = net.get_item(item_id)
|
|
|
|
self.item_cache[item_id] = item
|
|
|
|
return item
|
|
|
|
|
|
|
|
def buy(self, item):
|
|
|
|
assert(self.logged_in())
|
|
|
|
log_entry = (BuyCommand(item), self.balance)
|
|
|
|
self.transfers.append(log_entry)
|
|
|
|
self.balance = self.balance - item.price
|
|
|
|
|
|
|
|
def deposit(self, amount):
|
|
|
|
assert(self.logged_in())
|
|
|
|
log_entry = (DepositCommand(amount), self.balance)
|
|
|
|
self.transfers.append(log_entry)
|
|
|
|
self.balance = self.balance + amount
|
|
|
|
|
|
|
|
def undo(self):
|
|
|
|
assert(self.logged_in())
|
|
|
|
if self.transfers:
|
|
|
|
(command, balance_backup) = self.transfers[-1]
|
|
|
|
self.transfers.pop()
|
|
|
|
self.balance = balance_backup
|
|
|
|
else:
|
|
|
|
error_page('FEHLER: Nichts da, was ich rückgängig machen könnte.')
|
|
|
|
|
|
|
|
|
|
|
|
def print_prompt():
|
|
|
|
sys.stdout.write(">>> ")
|
|
|
|
|
|
|
|
|
|
|
|
def handle(line, status):
|
|
|
|
if line == 'exit':
|
|
|
|
clear()
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if status.logged_in():
|
|
|
|
if line in CODES:
|
|
|
|
call = CODES[line]
|
|
|
|
method = call[0]
|
|
|
|
params = call[1:]
|
|
|
|
getattr(status, method)(*params)
|
|
|
|
else:
|
|
|
|
item_id = int(line) # TODO
|
|
|
|
try:
|
|
|
|
item = status.find(item_id)
|
|
|
|
except urllib2.HTTPError as e:
|
|
|
|
if e.code == 404: # URL not found == item not found with REST
|
|
|
|
error_page('FEHLER: Aktion oder Ware "%s" nicht bekannt' % line)
|
|
|
|
else:
|
|
|
|
error_page('FEHLER bei Kommunikation mit Server "%s"' % str(e))
|
|
|
|
else:
|
|
|
|
status.buy(item)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
status.login(line)
|
|
|
|
except urllib2.URLError as e:
|
|
|
|
error_page('FEHLER bei Kommunikation mit Server "%s"' % e.reason)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
status = Status()
|
|
|
|
|
|
|
|
while True:
|
|
|
|
clear()
|
|
|
|
status.dump()
|
|
|
|
print_prompt()
|
|
|
|
l = sys.stdin.readline()
|
|
|
|
if not l:
|
|
|
|
break
|
|
|
|
line = l.rstrip()
|
|
|
|
handle(line, status)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|