513 lines
18 KiB
Python
513 lines
18 KiB
Python
#! /usr/bin/env python
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
import datetime
|
|
from collections import defaultdict
|
|
|
|
from .helpers import *
|
|
from ..models import Transaction
|
|
from ..db import Session
|
|
|
|
|
|
def getUser():
|
|
while 1:
|
|
string = 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(input("enter number:"))
|
|
except:
|
|
print("invalid input, restarting")
|
|
continue
|
|
if (n > -1) and (n < i):
|
|
return user[n].name
|
|
|
|
|
|
def getProduct():
|
|
while 1:
|
|
string = 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(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 = 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 = input("enter start date (yyyy-mm-dd)? ")
|
|
edate = 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 = [ent.product.name for ent in 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...", end=" ")
|
|
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 = "¤".join([ent.product.name for ent in transaction.purchase.entries])
|
|
else:
|
|
products = ""
|
|
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 = input("enter start date (yyyy-mm-dd)? ")
|
|
edate = 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 list(database.personVareVerdi[user].values())])
|
|
print("totalt kjøpt for: ", forbruk, end=" ")
|
|
if user in database.personNegTransactions:
|
|
print("kr, totalt lagt til: ", -database.personNegTransactions[user], end=" ")
|
|
forbruk = -database.personNegTransactions[user] - forbruk
|
|
if user in database.personPosTransactions:
|
|
print("kr, totalt tatt fra boks: ", database.personPosTransactions[user], end=" ")
|
|
forbruk = forbruk - database.personPosTransactions[user]
|
|
print("balanse: ", forbruk, "kr", end=" ")
|
|
print("")
|
|
|
|
|
|
def printUser(database, dateLine, user, n):
|
|
printTopDict2(database.personVareVerdi[user], database.personVareAntall[user], n)
|
|
print("\nforbruk per ukedag [kr/dag],", end=" ")
|
|
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],", end=" ")
|
|
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],", end=" ")
|
|
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 list(database.personNegTransactions.values())]),
|
|
"og tatt fra",
|
|
sum([i for i in list(database.personPosTransactions.values())]),
|
|
end=" ",
|
|
)
|
|
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 = 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(input("set number to show "))
|
|
|
|
|
|
def statisticsTextOnly():
|
|
inputType = 4
|
|
product = ""
|
|
user = ""
|
|
print("\n0: from file, 1: from database, q:quit")
|
|
inp = 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)
|