dibbler/statistikkHelpers.py

418 lines
15 KiB
Python

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
import datetime
from collections import defaultdict
import operator
from helpers import *
import sys
import db
def getUser():
while 1:
string = raw_input('user? ')
session = Session()
user = search_user(string, session)
session.close()
if not isinstance(user, list):
return user.name
i=0
if len(user)==0:
print 'no matching string'
if len(user)==1:
print 'antar: ', user[0].name, '\n'
return user[0].name
if len(user)>10:
continue
for u in user:
print i, u.name
i += 1
try:
n = int(raw_input ('enter number:'))
except:
print 'invalid input, restarting'
continue
if (n>-1) and (n<i):
return user[n].name
def getProduct():
while 1:
string = raw_input('product? ')
session = Session()
product = search_product(string, session)
session.close()
if not isinstance(product, list):
return product.name
i=0
if len(product)==0:
print 'no matching string'
if len(product)==1:
print 'antar: ', product[0].name, '\n'
return product[0].name
if len(product)>10:
continue
for u in product:
print i, u.name
i += 1
try:
n = int(raw_input ('enter number:'))
except:
print 'invalid input, restarting'
continue
if (n>-1) and (n<i):
return product[n].name
class Database:
#for varer
varePersonAntall = defaultdict(dict) #varePersonAntall[Oreo][trygvrad] == 3
vareDatoAntall = defaultdict(list) #dict->array
vareUkedagAntall = defaultdict(list)
#for personer
personVareAntall = defaultdict(dict) #personVareAntall[trygvrad][Oreo] == 3
personVareVerdi = defaultdict(dict) #personVareVerdi[trygvrad][Oreo] == 30 #[kr]
personDatoVerdi = defaultdict(list) #dict->array
personUkedagVerdi = defaultdict(list)
#for global
personPosTransactions = {} # personPosTransactions[trygvrad] == 100 #trygvrad har lagt 100kr i boksen
personNegTransactions = {} # personNegTransactions[trygvrad» == 70 #trygvrad har tatt 70kr fra boksen
globalVareAntall = {}#globalVareAntall[Oreo] == 3
globalVareVerdi = {}#globalVareVerdi[Oreo] == 30 #[kr]
globalPersonAntall = {}#globalPersonAntall[trygvrad] == 3
globalPersonForbruk = {}#globalPersonVerdi == 30 #[kr]
globalUkedagForbruk = []
globalDatoVarer = []
globalDatoForbruk = []
pengebeholdning = []
class InputLine:
def __init__(self, u, p, t):
self.inputUser = u
self.inputProduct = p
self.inputType = t
def getDateDb(date, inp):
try:
year = inp.partition('-')
month = year[2].partition('-')
return datetime.datetime(int(year[0]), int(month[0]), int(month[2]))
except:
print 'invalid date, setting date to date found in db'
print date
return date
def dateToDateNumDb(date, startDate):
deltaDays = date-startDate
return int(deltaDays.days), date.weekday()
def getInputType():
inp = 0
while not (inp == '1' or inp == '2' or inp == '3' or inp == '4'):
print 'type 1 for user-statistics'
print 'type 2 for product-statistics'
print 'type 3 for global-statistics'
print 'type 4 to enter loop-mode'
inp = raw_input('')
return int(inp)
def getProducts(products):
product = []
products = products.partition('¤')
product.append(products[0])
while (products[1]=='¤'):
products = products[2].partition('¤')
product.append(products[0])
return product
def getDateFile(date, inp):
try:
year = inp.partition('-')
month = year[2].partition('-')
return datetime.date(int(year[0]), int(month[0]), int(month[2]))
except:
print 'invalid date, setting date to date found on file file'
print date
return datetime.date(int(date.partition('-')[0]), int(date.partition('-')[2].partition('-')[0]), int(date.partition('-')[2].partition('-')[2]))
def dateToDateNumFile(date, startDate):
year = date.partition('-')
month = year[2].partition('-')
day = datetime.date(int(year[0]), int(month[0]), int(month[2]))
deltaDays = day-startDate
return int(deltaDays.days), day.weekday()
def clearDatabase(database):
database.varePersonAntall.clear()
database.vareDatoAntall.clear()
database.vareUkedagAntall.clear()
database.personVareAntall.clear()
database.personVareVerdi.clear()
database.personDatoVerdi.clear()
database.personUkedagVerdi.clear()
database.personPosTransactions.clear()
database.personNegTransactions.clear()
database.globalVareAntall.clear()
database.globalVareVerdi.clear()
database.globalPersonAntall.clear()
database.globalPersonForbruk.clear()
return(database)
def addLineToDatabase(database, inputLine):
if abs(inputLine.price)>90000:
return database
#fyller inn for varer
if (not inputLine.product=='') and ((inputLine.inputProduct=='') or (inputLine.inputProduct==inputLine.product)):
database.varePersonAntall[inputLine.product][inputLine.user] = database.varePersonAntall[inputLine.product].setdefault(inputLine.user,0) + 1
if inputLine.product not in database.vareDatoAntall:
database.vareDatoAntall[inputLine.product] = [0]*(inputLine.numberOfDays+1)
database.vareDatoAntall[inputLine.product][inputLine.dateNum] += 1
if inputLine.product not in database.vareUkedagAntall:
database.vareUkedagAntall[inputLine.product] = [0]*7
database.vareUkedagAntall[inputLine.product][inputLine.weekday] += 1
#fyller inn for personer
if (inputLine.inputUser=='') or (inputLine.inputUser==inputLine.user):
if not inputLine.product == '':
database.personVareAntall[inputLine.user][inputLine.product] = database.personVareAntall[inputLine.user].setdefault(inputLine.product,0) + 1
database.personVareVerdi[inputLine.user][inputLine.product] = database.personVareVerdi[inputLine.user].setdefault(inputLine.product,0) + inputLine.price
if inputLine.user not in database.personDatoVerdi:
database.personDatoVerdi[inputLine.user] = [0]*(inputLine.numberOfDays+1)
database.personDatoVerdi[inputLine.user][inputLine.dateNum] += inputLine.price
if inputLine.user not in database.personUkedagVerdi:
database.personUkedagVerdi[inputLine.user] = [0]*7
database.personUkedagVerdi[inputLine.user][inputLine.weekday] += inputLine.price
#fyller inn delt statistikk (genereres uansett)
if (inputLine.product==''):
if (inputLine.price>0):
database.personPosTransactions[inputLine.user] = database.personPosTransactions.setdefault(inputLine.user,0) + inputLine.price
else:
database.personNegTransactions[inputLine.user] = database.personNegTransactions.setdefault(inputLine.user,0) + inputLine.price
elif not (inputLine.inputType==1):
database.globalVareAntall[inputLine.product] = database.globalVareAntall.setdefault(inputLine.product,0) + 1
database.globalVareVerdi[inputLine.product] = database.globalVareVerdi.setdefault(inputLine.product,0) + inputLine.price
#fyller inn for global statistikk
if (inputLine.inputType==3) or (inputLine.inputType==4):
database.pengebeholdning[inputLine.dateNum] += inputLine.price
if not (inputLine.product==''):
database.globalPersonAntall[inputLine.user] = database.globalPersonAntall.setdefault(inputLine.user,0) + 1
database.globalPersonForbruk[inputLine.user] = database.globalPersonForbruk.setdefault(inputLine.user,0) + inputLine.price
database.globalDatoVarer[inputLine.dateNum] += 1
database.globalDatoForbruk[inputLine.dateNum] += inputLine.price
database.globalUkedagForbruk[inputLine.weekday] += inputLine.price
return database
def buildDatabaseFromDb(inputType, inputProduct, inputUser):
sdate = raw_input('enter start date (yyyy-mm-dd)? ')
edate = raw_input('enter end date (yyyy-mm-dd)? ')
print 'building database...'
session = Session()
transaction_list = session.query(Transaction).all()
inputLine = InputLine(inputUser, inputProduct, inputType)
startDate = getDateDb(transaction_list[0].time, sdate)
endDate = getDateDb(transaction_list[-1].time, edate)
inputLine.numberOfDays = (endDate-startDate).days
database = Database()
database = clearDatabase(database)
if (inputType==3) or (inputType==4):
database.globalDatoVarer = [0]*(inputLine.numberOfDays+1)
database.globalDatoForbruk = [0]*(inputLine.numberOfDays+1)
database.globalUkedagForbruk = [0]*7
database.pengebeholdning = [0]*(inputLine.numberOfDays+1)
print 'wait for it.... '
for transaction in transaction_list:
if transaction.purchase:
products = map(lambda ent: ent.product.name, transaction.purchase.entries)
else:
products = []
products.append('')
inputLine.dateNum, inputLine.weekday = dateToDateNumDb(transaction.time, startDate)
if inputLine.dateNum<0 or inputLine.dateNum>(inputLine.numberOfDays):
continue
inputLine.user=transaction.user.name
inputLine.price=transaction.amount
for inputLine.product in products:
database=addLineToDatabase(database, inputLine )
inputLine.price = 0;
print 'saving as default.dibblerlog...',
f=open('default.dibblerlog','w')
line_format = '%s|%s|%s|%s|%s|%s\n'
transaction_list = session.query(Transaction).all()
for transaction in transaction_list:
if transaction.purchase:
products = u'¤'.join(map(lambda ent: ent.product.name, transaction.purchase.entries))
description = ''
else:
products = ''
description = transaction.description
line = line_format % ('purchase', transaction.time, products, transaction.user.name, transaction.amount, transaction.description)
f.write(line.encode('utf8'))
session.close()
f.close
#bygg database.pengebeholdning
if (inputType==3) or (inputType==4):
for i in range(inputLine.numberOfDays+1):
if i > 0:
database.pengebeholdning[i] +=database.pengebeholdning[i-1]
#bygg dateLine
day=datetime.timedelta(days=1)
dateLine=[]
dateLine.append(startDate)
for n in range(inputLine.numberOfDays):
dateLine.append(startDate+n*day)
print 'done'
return database, dateLine
def buildDatabaseFromFile(inputFile, inputType, inputProduct, inputUser):
sdate = raw_input('enter start date (yyyy-mm-dd)? ')
edate = raw_input('enter end date (yyyy-mm-dd)? ')
f=open(inputFile)
try:
fileLines=f.readlines()
finally:
f.close()
inputLine = InputLine(inputUser, inputProduct, inputType)
startDate = getDateFile(fileLines[0].partition('|')[2].partition(' ')[0], sdate)
endDate = getDateFile(fileLines[-1].partition('|')[2].partition(' ')[0], edate)
inputLine.numberOfDays = (endDate-startDate).days
database = Database()
database = clearDatabase(database)
if (inputType==3) or (inputType==4):
database.globalDatoVarer = [0]*(inputLine.numberOfDays+1)
database.globalDatoForbruk = [0]*(inputLine.numberOfDays+1)
database.globalUkedagForbruk = [0]*7
database.pengebeholdning = [0]*(inputLine.numberOfDays+1)
for linje in fileLines:
if not (linje[0]=='#') and not (linje=='\n') :
#henter dateNum, products, user, price
restDel = linje.partition('|')
restDel = restDel[2].partition(' ')
inputLine.dateNum, inputLine.weekday = dateToDateNumFile(restDel[0], startDate)
if inputLine.dateNum<0 or inputLine.dateNum>(inputLine.numberOfDays):
continue
restDel=restDel[2].partition('|')
restDel=restDel[2].partition('|')
products = restDel[0]
restDel=restDel[2].partition('|')
inputLine.user=restDel[0]
inputLine.price=int(restDel[2].partition('|')[0])
for inputLine.product in getProducts(products):
database=addLineToDatabase(database, inputLine )
inputLine.price = 0;
#bygg database.pengebeholdning
if (inputType==3) or (inputType==4):
for i in range(inputLine.numberOfDays+1):
if i > 0:
database.pengebeholdning[i] +=database.pengebeholdning[i-1]
#bygg dateLine
day=datetime.timedelta(days=1)
dateLine=[]
dateLine.append(startDate)
for n in range(inputLine.numberOfDays):
dateLine.append(startDate+n*day)
return database, dateLine
def printTopDict(dictionary, n, k):
i=0
for key in sorted(dictionary, key=dictionary.get, reverse=k):
print key, ': ',dictionary[key]
if i<n:
i += 1
else:
break
def printTopDict2(dictionary, dictionary2, n):
print ''
print 'product : price[kr] ( number )'
i=0
for key in sorted(dictionary, key=dictionary.get, reverse=True):
print key, ': ',dictionary[key], ' (', dictionary2[key], ') '
if i<n:
i += 1
else:
break
def printWeekdays(week, days):
if week==[] or days==0:
return
print 'mon: ', '%.2f'%(week[0]*7.0/days), ' tue: ', '%.2f'%(week[1]*7.0/days), ' wen: ', '%.2f'%(week[2]*7.0/days), ' thu: ', '%.2f'%(week[3]*7.0/days), ' fri: ', '%.2f'%(week[4]*7.0/days), ' sat: ','%.2f'%( week[5]*7.0/days), ' sun: ', '%.2f'%(week[6]*7.0/days)
print 'forbruk per dag (snitt): ', '%.2f'%(sum(week)*1.0/days)
print ''
def printBalance(database, user):
forbruk = 0
if (user in database.personVareVerdi):
forbruk = sum([i for i in database.personVareVerdi[user].values()])
print 'totalt kjøpt for: ', forbruk,
if (user in database.personNegTransactions):
print 'kr, totalt lagt til: ', -database.personNegTransactions[user],
forbruk=-database.personNegTransactions[user]-forbruk
if (user in database.personPosTransactions):
print 'kr, totalt tatt fra boks: ', database.personPosTransactions[user],
forbruk=forbruk-database.personPosTransactions[user]
print 'balanse: ', forbruk, 'kr',
print ''
def printUser(database, dateLine, user, n):
printTopDict2(database.personVareVerdi[user], database.personVareAntall[user], n)
print '\nforbruk per ukedag [kr/dag],',
printWeekdays(database.personUkedagVerdi[user], len(dateLine))
printBalance(database, user)
def printProduct(database, dateLine, product, n):
printTopDict(database.varePersonAntall[product], n, 1)
print '\nforbruk per ukedag [antall/dag],',
printWeekdays(database.vareUkedagAntall[product], len(dateLine))
print 'Det er solgt: ', database.globalVareAntall[product], product, 'til en verdi av: ', database.globalVareVerdi[product], 'kr'
def printGlobal(database, dateLine, n):
print '\nmest lagt til: '
printTopDict(database.personNegTransactions, n, 0)
print '\nmest tatt fra:'
printTopDict(database.personPosTransactions, n, 1)
print '\nstørst forbruk:'
printTopDict(database.globalPersonForbruk, n, 1)
printTopDict2(database.globalVareVerdi, database.globalVareAntall, n)
print '\nforbruk per ukedag [kr/dag],',
printWeekdays(database.globalUkedagForbruk, len(dateLine))
print 'Det er solgt varer til en verdi av: ', sum(database.globalDatoForbruk), 'kr, det er lagt til', -sum([i for i in database.personNegTransactions.values()]), 'og tatt fra', sum([i for i in database.personPosTransactions.values()]),
print 'balansen blir:', database.pengebeholdning[len(dateLine)-1], 'der negative verdier representerer at brukere har kreditt tilgjengelig'
def alt4menuTextOnly(database, dateLine):
n=10
while 1:
print '\n1: user-statistics, 2: product-statistics, 3:global-statistics, n: adjust amount of data shown q:quit'
inp = raw_input('')
if inp == 'q':
break
elif inp == '1':
try:
printUser(database, dateLine, getUser(), n)
except:
print '\n\nSomething is not right, (last date prior to first date?)'
elif inp == '2':
try:
printProduct(database, dateLine, getProduct(), n)
except:
print '\n\nSomething is not right, (last date prior to first date?)'
elif inp == '3':
try:
printGlobal(database, dateLine, n)
except:
print '\n\nSomething is not right, (last date prior to first date?)'
elif inp == 'n':
n=int(raw_input('set number to show '));
def statisticsTextOnly():
inputType = 4
product = ''
user = ''
print '\n0: from file, 1: from database, q:quit'
inp = raw_input('')
if inp == '1':
database, dateLine = buildDatabaseFromDb(inputType, product, user)
elif inp=='0' or inp == '':
database, dateLine = buildDatabaseFromFile('default.dibblerlog', inputType, product, user)
if not inp == 'q':
alt4menuTextOnly(database, dateLine)