treewide: fix a bunch of lints
This commit is contained in:
+9
-11
@@ -1,8 +1,8 @@
|
|||||||
from typing import Any
|
|
||||||
from pathlib import Path
|
|
||||||
import tomllib
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import tomllib
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
DEFAULT_CONFIG_PATH = Path("/etc/dibbler/dibbler.toml")
|
DEFAULT_CONFIG_PATH = Path("/etc/dibbler/dibbler.toml")
|
||||||
|
|
||||||
@@ -19,11 +19,11 @@ def default_config_path_submissive_and_readable() -> bool:
|
|||||||
and DEFAULT_CONFIG_PATH.stat().st_gid == os.getgid()
|
and DEFAULT_CONFIG_PATH.stat().st_gid == os.getgid()
|
||||||
),
|
),
|
||||||
(DEFAULT_CONFIG_PATH.stat().st_mode & 0o004),
|
(DEFAULT_CONFIG_PATH.stat().st_mode & 0o004),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
config: dict[str, dict[str, Any]] = dict()
|
config: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
|
|
||||||
def load_config(config_path: Path | None = None):
|
def load_config(config_path: Path | None = None):
|
||||||
@@ -49,7 +49,7 @@ def config_db_string() -> str:
|
|||||||
path = Path(config["database"]["sqlite"]["path"])
|
path = Path(config["database"]["sqlite"]["path"])
|
||||||
return f"sqlite:///{path.absolute()}"
|
return f"sqlite:///{path.absolute()}"
|
||||||
|
|
||||||
elif db_type == "postgresql":
|
if db_type == "postgresql":
|
||||||
host = config["database"]["postgresql"]["host"]
|
host = config["database"]["postgresql"]["host"]
|
||||||
port = config["database"]["postgresql"].get("port", 5432)
|
port = config["database"]["postgresql"].get("port", 5432)
|
||||||
username = config["database"]["postgresql"].get("username", "dibbler")
|
username = config["database"]["postgresql"].get("username", "dibbler")
|
||||||
@@ -65,8 +65,6 @@ def config_db_string() -> str:
|
|||||||
|
|
||||||
if host.startswith("/"):
|
if host.startswith("/"):
|
||||||
return f"postgresql+psycopg2://{username}:{password}@/{dbname}?host={host}"
|
return f"postgresql+psycopg2://{username}:{password}@/{dbname}?host={host}"
|
||||||
else:
|
return f"postgresql+psycopg2://{username}:{password}@{host}:{port}/{dbname}"
|
||||||
return f"postgresql+psycopg2://{username}:{password}@{host}:{port}/{dbname}"
|
print(f"Error: unknown database type '{db_type}'")
|
||||||
else:
|
exit(1)
|
||||||
print(f"Error: unknown database type '{db_type}'")
|
|
||||||
exit(1)
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import os
|
|||||||
import pwd
|
import pwd
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Any, Callable, Literal
|
from collections.abc import Callable
|
||||||
|
from typing import Any, Literal
|
||||||
|
|
||||||
from sqlalchemy import and_, not_, or_
|
from sqlalchemy import and_, not_, or_
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
@@ -24,18 +25,17 @@ def search_user(
|
|||||||
)
|
)
|
||||||
if exact_match:
|
if exact_match:
|
||||||
return exact_match
|
return exact_match
|
||||||
user_list = (
|
return (
|
||||||
sql_session.query(User)
|
sql_session.query(User)
|
||||||
.filter(
|
.filter(
|
||||||
or_(
|
or_(
|
||||||
User.name.ilike(f"%{string}%"),
|
User.name.ilike(f"%{string}%"),
|
||||||
User.card.ilike(f"%{string}%"),
|
User.card.ilike(f"%{string}%"),
|
||||||
User.rfid.ilike(f"%{string}%"),
|
User.rfid.ilike(f"%{string}%"),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
return user_list
|
|
||||||
|
|
||||||
|
|
||||||
def search_product(
|
def search_product(
|
||||||
@@ -60,7 +60,7 @@ def search_product(
|
|||||||
Product.name == string,
|
Product.name == string,
|
||||||
not_(Product.hidden),
|
not_(Product.hidden),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ def search_product(
|
|||||||
or_(
|
or_(
|
||||||
Product.bar_code.ilike(f"%{string}%"),
|
Product.bar_code.ilike(f"%{string}%"),
|
||||||
Product.name.ilike(f"%{string}%"),
|
Product.name.ilike(f"%{string}%"),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
@@ -87,7 +87,7 @@ def search_product(
|
|||||||
Product.name.ilike(f"%{string}%"),
|
Product.name.ilike(f"%{string}%"),
|
||||||
not_(Product.hidden),
|
not_(Product.hidden),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
@@ -121,7 +121,7 @@ def guess_data_type(string: str) -> Literal["card", "rfid", "bar_code", "usernam
|
|||||||
|
|
||||||
def argmax(
|
def argmax(
|
||||||
d,
|
d,
|
||||||
all: bool = False,
|
all_: bool = False,
|
||||||
value: Callable[[Any], Any] | None = None,
|
value: Callable[[Any], Any] | None = None,
|
||||||
):
|
):
|
||||||
maxarg = None
|
maxarg = None
|
||||||
@@ -133,7 +133,7 @@ def argmax(
|
|||||||
for key in list(d.keys()):
|
for key in list(d.keys()):
|
||||||
if maxarg is None or d[key] > d[maxarg]:
|
if maxarg is None or d[key] > d[maxarg]:
|
||||||
maxarg = key
|
maxarg = key
|
||||||
if all:
|
if all_:
|
||||||
return [k for k in list(d.keys()) if d[k] == d[maxarg]]
|
return [k for k in list(d.keys()) if d[k] == d[maxarg]]
|
||||||
return maxarg
|
return maxarg
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import os
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
# import barcode
|
# import barcode
|
||||||
# from brother_ql.brother_ql_create import create_label
|
# from brother_ql.brother_ql_create import create_label
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from .helpers import *
|
|
||||||
from ..models import Transaction
|
from ..models import Transaction
|
||||||
|
from .helpers import *
|
||||||
|
|
||||||
|
|
||||||
def getUser(sql_session: Session):
|
def getUser(sql_session: Session):
|
||||||
@@ -176,7 +177,7 @@ def addLineToDatabase(database, inputLine):
|
|||||||
if abs(inputLine.price) > 90000:
|
if abs(inputLine.price) > 90000:
|
||||||
return database
|
return database
|
||||||
# fyller inn for varer
|
# fyller inn for varer
|
||||||
if (not inputLine.product == "") and (
|
if (inputLine.product != "") and (
|
||||||
(inputLine.inputProduct == "") or (inputLine.inputProduct == inputLine.product)
|
(inputLine.inputProduct == "") or (inputLine.inputProduct == inputLine.product)
|
||||||
):
|
):
|
||||||
database.varePersonAntall[inputLine.product][inputLine.user] = (
|
database.varePersonAntall[inputLine.product][inputLine.user] = (
|
||||||
@@ -190,7 +191,7 @@ def addLineToDatabase(database, inputLine):
|
|||||||
database.vareUkedagAntall[inputLine.product][inputLine.weekday] += 1
|
database.vareUkedagAntall[inputLine.product][inputLine.weekday] += 1
|
||||||
# fyller inn for personer
|
# fyller inn for personer
|
||||||
if (inputLine.inputUser == "") or (inputLine.inputUser == inputLine.user):
|
if (inputLine.inputUser == "") or (inputLine.inputUser == inputLine.user):
|
||||||
if not inputLine.product == "":
|
if inputLine.product != "":
|
||||||
database.personVareAntall[inputLine.user][inputLine.product] = (
|
database.personVareAntall[inputLine.user][inputLine.product] = (
|
||||||
database.personVareAntall[inputLine.user].setdefault(inputLine.product, 0) + 1
|
database.personVareAntall[inputLine.user].setdefault(inputLine.product, 0) + 1
|
||||||
)
|
)
|
||||||
@@ -214,7 +215,7 @@ def addLineToDatabase(database, inputLine):
|
|||||||
database.personNegTransactions[inputLine.user] = (
|
database.personNegTransactions[inputLine.user] = (
|
||||||
database.personNegTransactions.setdefault(inputLine.user, 0) + inputLine.price
|
database.personNegTransactions.setdefault(inputLine.user, 0) + inputLine.price
|
||||||
)
|
)
|
||||||
elif not (inputLine.inputType == 1):
|
elif inputLine.inputType != 1:
|
||||||
database.globalVareAntall[inputLine.product] = (
|
database.globalVareAntall[inputLine.product] = (
|
||||||
database.globalVareAntall.setdefault(inputLine.product, 0) + 1
|
database.globalVareAntall.setdefault(inputLine.product, 0) + 1
|
||||||
)
|
)
|
||||||
@@ -225,7 +226,7 @@ def addLineToDatabase(database, inputLine):
|
|||||||
# fyller inn for global statistikk
|
# fyller inn for global statistikk
|
||||||
if (inputLine.inputType == 3) or (inputLine.inputType == 4):
|
if (inputLine.inputType == 3) or (inputLine.inputType == 4):
|
||||||
database.pengebeholdning[inputLine.dateNum] += inputLine.price
|
database.pengebeholdning[inputLine.dateNum] += inputLine.price
|
||||||
if not (inputLine.product == ""):
|
if inputLine.product != "":
|
||||||
database.globalPersonAntall[inputLine.user] = (
|
database.globalPersonAntall[inputLine.user] = (
|
||||||
database.globalPersonAntall.setdefault(inputLine.user, 0) + 1
|
database.globalPersonAntall.setdefault(inputLine.user, 0) + 1
|
||||||
)
|
)
|
||||||
@@ -273,7 +274,7 @@ def buildDatabaseFromDb(inputType, inputProduct, inputUser, sql_session: Session
|
|||||||
inputLine.price = 0
|
inputLine.price = 0
|
||||||
|
|
||||||
print("saving as default.dibblerlog...", end=" ")
|
print("saving as default.dibblerlog...", end=" ")
|
||||||
f = open("default.dibblerlog", "w")
|
f = Path.open("default.dibblerlog", "w")
|
||||||
line_format = "%s|%s|%s|%s|%s|%s\n"
|
line_format = "%s|%s|%s|%s|%s|%s\n"
|
||||||
transaction_list = sql_session.query(Transaction).all()
|
transaction_list = sql_session.query(Transaction).all()
|
||||||
for transaction in transaction_list:
|
for transaction in transaction_list:
|
||||||
@@ -290,7 +291,7 @@ def buildDatabaseFromDb(inputType, inputProduct, inputUser, sql_session: Session
|
|||||||
transaction.description,
|
transaction.description,
|
||||||
)
|
)
|
||||||
f.write(line.encode("utf8"))
|
f.write(line.encode("utf8"))
|
||||||
f.close
|
f.close()
|
||||||
# bygg database.pengebeholdning
|
# bygg database.pengebeholdning
|
||||||
if (inputType == 3) or (inputType == 4):
|
if (inputType == 3) or (inputType == 4):
|
||||||
for i in range(inputLine.numberOfDays + 1):
|
for i in range(inputLine.numberOfDays + 1):
|
||||||
@@ -310,7 +311,7 @@ def buildDatabaseFromFile(inputFile, inputType, inputProduct, inputUser):
|
|||||||
sdate = input("enter start date (yyyy-mm-dd)? ")
|
sdate = input("enter start date (yyyy-mm-dd)? ")
|
||||||
edate = input("enter end date (yyyy-mm-dd)? ")
|
edate = input("enter end date (yyyy-mm-dd)? ")
|
||||||
|
|
||||||
f = open(inputFile)
|
f = Path.open(inputFile)
|
||||||
try:
|
try:
|
||||||
fileLines = f.readlines()
|
fileLines = f.readlines()
|
||||||
finally:
|
finally:
|
||||||
@@ -328,7 +329,7 @@ def buildDatabaseFromFile(inputFile, inputType, inputProduct, inputUser):
|
|||||||
database.globalUkedagForbruk = [0] * 7
|
database.globalUkedagForbruk = [0] * 7
|
||||||
database.pengebeholdning = [0] * (inputLine.numberOfDays + 1)
|
database.pengebeholdning = [0] * (inputLine.numberOfDays + 1)
|
||||||
for linje in fileLines:
|
for linje in fileLines:
|
||||||
if not (linje[0] == "#") and not (linje == "\n"):
|
if linje[0] != "#" and linje != "\n":
|
||||||
# henter dateNum, products, user, price
|
# henter dateNum, products, user, price
|
||||||
restDel = linje.partition("|")
|
restDel = linje.partition("|")
|
||||||
restDel = restDel[2].partition(" ")
|
restDel = restDel[2].partition(" ")
|
||||||
@@ -406,7 +407,7 @@ def printWeekdays(week, days):
|
|||||||
def printBalance(database, user):
|
def printBalance(database, user):
|
||||||
forbruk = 0
|
forbruk = 0
|
||||||
if user in database.personVareVerdi:
|
if user in database.personVareVerdi:
|
||||||
forbruk = sum([i for i in list(database.personVareVerdi[user].values())])
|
forbruk = sum(list(database.personVareVerdi[user].values()))
|
||||||
print("totalt kjøpt for: ", forbruk, end=" ")
|
print("totalt kjøpt for: ", forbruk, end=" ")
|
||||||
if user in database.personNegTransactions:
|
if user in database.personNegTransactions:
|
||||||
print("kr, totalt lagt til: ", -database.personNegTransactions[user], end=" ")
|
print("kr, totalt lagt til: ", -database.personNegTransactions[user], end=" ")
|
||||||
@@ -453,9 +454,9 @@ def printGlobal(database, dateLine, n):
|
|||||||
"Det er solgt varer til en verdi av: ",
|
"Det er solgt varer til en verdi av: ",
|
||||||
sum(database.globalDatoForbruk),
|
sum(database.globalDatoForbruk),
|
||||||
"kr, det er lagt til",
|
"kr, det er lagt til",
|
||||||
-sum([i for i in list(database.personNegTransactions.values())]),
|
-sum(list(database.personNegTransactions.values())),
|
||||||
"og tatt fra",
|
"og tatt fra",
|
||||||
sum([i for i in list(database.personPosTransactions.values())]),
|
sum(list(database.personPosTransactions.values())),
|
||||||
end=" ",
|
end=" ",
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
@@ -470,12 +471,12 @@ def alt4menuTextOnly(database, dateLine, sql_session: Session):
|
|||||||
n = 10
|
n = 10
|
||||||
while 1:
|
while 1:
|
||||||
print(
|
print(
|
||||||
"\n1: user-statistics, 2: product-statistics, 3:global-statistics, n: adjust amount of data shown q:quit"
|
"\n1: user-statistics, 2: product-statistics, 3:global-statistics, n: adjust amount of data shown q:quit",
|
||||||
)
|
)
|
||||||
inp = input("")
|
inp = input("")
|
||||||
if inp == "q":
|
if inp == "q":
|
||||||
break
|
break
|
||||||
elif inp == "1":
|
if inp == "1":
|
||||||
try:
|
try:
|
||||||
printUser(database, dateLine, getUser(sql_session), n)
|
printUser(database, dateLine, getUser(sql_session), n)
|
||||||
except:
|
except:
|
||||||
@@ -505,5 +506,5 @@ def statisticsTextOnly(sql_session: Session):
|
|||||||
database, dateLine = buildDatabaseFromDb(inputType, product, user, sql_session)
|
database, dateLine = buildDatabaseFromDb(inputType, product, user, sql_session)
|
||||||
elif inp == "0" or inp == "":
|
elif inp == "0" or inp == "":
|
||||||
database, dateLine = buildDatabaseFromFile("default.dibblerlog", inputType, product, user)
|
database, dateLine = buildDatabaseFromFile("default.dibblerlog", inputType, product, user)
|
||||||
if not inp == "q":
|
if inp != "q":
|
||||||
alt4menuTextOnly(database, dateLine, sql_session)
|
alt4menuTextOnly(database, dateLine, sql_session)
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ from pathlib import Path
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from dibbler.conf import load_config, config_db_string
|
from dibbler.conf import config_db_string, load_config
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
|||||||
@@ -26,28 +26,28 @@ __all__ = [
|
|||||||
from .addstock import AddStockMenu
|
from .addstock import AddStockMenu
|
||||||
from .buymenu import BuyMenu
|
from .buymenu import BuyMenu
|
||||||
from .editing import (
|
from .editing import (
|
||||||
AddUserMenu,
|
|
||||||
EditUserMenu,
|
|
||||||
AddProductMenu,
|
AddProductMenu,
|
||||||
EditProductMenu,
|
AddUserMenu,
|
||||||
AdjustStockMenu,
|
AdjustStockMenu,
|
||||||
CleanupStockMenu,
|
CleanupStockMenu,
|
||||||
|
EditProductMenu,
|
||||||
|
EditUserMenu,
|
||||||
)
|
)
|
||||||
from .faq import FAQMenu
|
from .faq import FAQMenu
|
||||||
from .helpermenus import Menu
|
from .helpermenus import Menu
|
||||||
from .mainmenu import MainMenu
|
from .mainmenu import MainMenu
|
||||||
from .miscmenus import (
|
from .miscmenus import (
|
||||||
ProductSearchMenu,
|
|
||||||
TransferMenu,
|
|
||||||
AdjustCreditMenu,
|
AdjustCreditMenu,
|
||||||
UserListMenu,
|
|
||||||
ShowUserMenu,
|
|
||||||
ProductListMenu,
|
ProductListMenu,
|
||||||
|
ProductSearchMenu,
|
||||||
|
ShowUserMenu,
|
||||||
|
TransferMenu,
|
||||||
|
UserListMenu,
|
||||||
)
|
)
|
||||||
from .printermenu import PrintLabelMenu
|
from .printermenu import PrintLabelMenu
|
||||||
from .stats import (
|
from .stats import (
|
||||||
ProductPopularityMenu,
|
|
||||||
ProductRevenueMenu,
|
|
||||||
BalanceMenu,
|
BalanceMenu,
|
||||||
LoggedStatisticsMenu,
|
LoggedStatisticsMenu,
|
||||||
|
ProductPopularityMenu,
|
||||||
|
ProductRevenueMenu,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -139,10 +139,10 @@ much money you're due in credits for the purchase when prompted.\n"""
|
|||||||
old_price = product.price
|
old_price = product.price
|
||||||
old_hidden = product.hidden
|
old_hidden = product.hidden
|
||||||
product.price = int(
|
product.price = int(
|
||||||
ceil(float(value) / (max(product.stock, 0) + self.products[product][0]))
|
ceil(float(value) / (max(product.stock, 0) + self.products[product][0])),
|
||||||
)
|
)
|
||||||
product.stock = max(
|
product.stock = max(
|
||||||
self.products[product][0], product.stock + self.products[product][0]
|
self.products[product][0], product.stock + self.products[product][0],
|
||||||
)
|
)
|
||||||
product.hidden = False
|
product.hidden = False
|
||||||
print(
|
print(
|
||||||
|
|||||||
+10
-12
@@ -64,7 +64,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
print("***********************************************************************")
|
print("***********************************************************************")
|
||||||
print("")
|
print("")
|
||||||
print(
|
print(
|
||||||
f"USER {user.name} HAS LOWER CREDIT THAN {config['limits']['low_credit_warning_limit']:d}."
|
f"USER {user.name} HAS LOWER CREDIT THAN {config['limits']['low_credit_warning_limit']:d}.",
|
||||||
)
|
)
|
||||||
print("THIS PURCHASE WILL CHARGE YOUR CREDIT TWICE AS MUCH.")
|
print("THIS PURCHASE WILL CHARGE YOUR CREDIT TWICE AS MUCH.")
|
||||||
print("CONSIDER PUTTING MONEY IN THE BOX TO AVOID THIS.")
|
print("CONSIDER PUTTING MONEY IN THE BOX TO AVOID THIS.")
|
||||||
@@ -74,8 +74,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
if timeout:
|
if timeout:
|
||||||
print("THIS PURCHASE WILL AUTOMATICALLY BE PERFORMED IN 3 MINUTES!")
|
print("THIS PURCHASE WILL AUTOMATICALLY BE PERFORMED IN 3 MINUTES!")
|
||||||
return self.confirm(prompt=">", default=True, timeout=180)
|
return self.confirm(prompt=">", default=True, timeout=180)
|
||||||
else:
|
return self.confirm(prompt=">", default=True)
|
||||||
return self.confirm(prompt=">", default=True)
|
|
||||||
|
|
||||||
def add_thing_to_purchase(
|
def add_thing_to_purchase(
|
||||||
self,
|
self,
|
||||||
@@ -145,7 +144,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
True,
|
True,
|
||||||
True,
|
True,
|
||||||
): "Enter more products or users, or an empty line to confirm",
|
): "Enter more products or users, or an empty line to confirm",
|
||||||
}[(len(self.purchase.transactions) > 0, len(self.purchase.entries) > 0)]
|
}[(len(self.purchase.transactions) > 0, len(self.purchase.entries) > 0)],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Read in a 'thing' (product or user):
|
# Read in a 'thing' (product or user):
|
||||||
@@ -163,16 +162,15 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
if thing is None:
|
if thing is None:
|
||||||
if not self.complete_input():
|
if not self.complete_input():
|
||||||
if self.confirm(
|
if self.confirm(
|
||||||
"Not enough information entered. Abort purchase?", default=True
|
"Not enough information entered. Abort purchase?", default=True,
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
# once we get something in the
|
||||||
# once we get something in the
|
# purchase, we want to protect the
|
||||||
# purchase, we want to protect the
|
# user from accidentally killing it
|
||||||
# user from accidentally killing it
|
self.exit_confirm_msg = "Abort purchase?"
|
||||||
self.exit_confirm_msg = "Abort purchase?"
|
|
||||||
|
|
||||||
# Add the thing to our purchase object:
|
# Add the thing to our purchase object:
|
||||||
if not self.add_thing_to_purchase(thing, amount=num):
|
if not self.add_thing_to_purchase(thing, amount=num):
|
||||||
@@ -221,7 +219,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
string += "(empty)"
|
string += "(empty)"
|
||||||
else:
|
else:
|
||||||
string += ", ".join(
|
string += ", ".join(
|
||||||
[t.user.name + ("*" if not self.credit_check(t.user) else "") for t in transactions]
|
[t.user.name + ("*" if not self.credit_check(t.user) else "") for t in transactions],
|
||||||
)
|
)
|
||||||
string += "\n products: "
|
string += "\n products: "
|
||||||
if len(entries) == 0:
|
if len(entries) == 0:
|
||||||
@@ -229,7 +227,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
|||||||
else:
|
else:
|
||||||
string += "\n "
|
string += "\n "
|
||||||
string += "\n ".join(
|
string += "\n ".join(
|
||||||
[f"{e.amount:d}x {e.product.name} ({e.product.price:d} kr)" for e in entries]
|
[f"{e.amount:d}x {e.product.name} ({e.product.price:d} kr)" for e in entries],
|
||||||
)
|
)
|
||||||
if len(transactions) > 1:
|
if len(transactions) > 1:
|
||||||
string += f"\n price per person: {self.purchase.price_per_transaction():d} kr"
|
string += f"\n price per person: {self.purchase.price_per_transaction():d} kr"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from dibbler.models import User, Product
|
from dibbler.models import Product, User
|
||||||
|
|
||||||
from .helpermenus import Menu, Selector
|
from .helpermenus import Menu, Selector
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from .helpermenus import Menu, MessageMenu
|
from .helpermenus import Menu, MessageMenu
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from collections.abc import Callable, Iterable
|
||||||
from select import select
|
from select import select
|
||||||
from typing import Any, Callable, Iterable, Literal, Self
|
from typing import Any, Literal, Self
|
||||||
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class ExitMenuException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Menu(object):
|
class Menu:
|
||||||
name: str
|
name: str
|
||||||
sql_session: Session
|
sql_session: Session
|
||||||
items: list[Self | tuple | str]
|
items: list[Self | tuple | str]
|
||||||
@@ -111,10 +111,9 @@ class Menu(object):
|
|||||||
def item_name(self, i: int) -> str:
|
def item_name(self, i: int) -> str:
|
||||||
if self.item_is_submenu(i):
|
if self.item_is_submenu(i):
|
||||||
return self.items[i].name
|
return self.items[i].name
|
||||||
elif isinstance(self.items[i], tuple):
|
if isinstance(self.items[i], tuple):
|
||||||
return self.items[i][1]
|
return self.items[i][1]
|
||||||
else:
|
return self.items[i]
|
||||||
return self.items[i]
|
|
||||||
|
|
||||||
def item_value(self, i: int):
|
def item_value(self, i: int):
|
||||||
if isinstance(self.items[i], tuple):
|
if isinstance(self.items[i], tuple):
|
||||||
@@ -189,7 +188,7 @@ class Menu(object):
|
|||||||
):
|
):
|
||||||
if length_range[0] and length_range[1]:
|
if length_range[0] and length_range[1]:
|
||||||
print(
|
print(
|
||||||
f"Value must have length in range [{length_range[0]:d}, {length_range[1]:d}]"
|
f"Value must have length in range [{length_range[0]:d}, {length_range[1]:d}]",
|
||||||
)
|
)
|
||||||
elif length_range[0]:
|
elif length_range[0]:
|
||||||
print(f"Value must have length at least {length_range[0]:d}")
|
print(f"Value must have length at least {length_range[0]:d}")
|
||||||
@@ -231,7 +230,7 @@ class Menu(object):
|
|||||||
else:
|
else:
|
||||||
if result.isdigit():
|
if result.isdigit():
|
||||||
choice = int(result)
|
choice = int(result)
|
||||||
if choice == 0 and 10 <= number_of_choices:
|
if choice == 0 and number_of_choices >= 10:
|
||||||
return 10
|
return 10
|
||||||
if 0 < choice <= number_of_choices:
|
if 0 < choice <= number_of_choices:
|
||||||
return choice
|
return choice
|
||||||
@@ -342,29 +341,28 @@ class Menu(object):
|
|||||||
search_lst = search_str.split(" ")
|
search_lst = search_str.split(" ")
|
||||||
if search_str == "" and empty_input_permitted:
|
if search_str == "" and empty_input_permitted:
|
||||||
return None
|
return None
|
||||||
else:
|
result = self.search_for_thing(
|
||||||
result = self.search_for_thing(
|
search_str,
|
||||||
search_str,
|
permitted_things,
|
||||||
permitted_things,
|
add_nonexisting,
|
||||||
add_nonexisting,
|
find_hidden_products,
|
||||||
find_hidden_products,
|
)
|
||||||
)
|
num = 1
|
||||||
num = 1
|
|
||||||
|
|
||||||
if (result is None) and (len(search_lst) > 1):
|
if (result is None) and (len(search_lst) > 1):
|
||||||
print('Interpreting input as "<number> <product>"')
|
print('Interpreting input as "<number> <product>"')
|
||||||
try:
|
try:
|
||||||
num = int(search_lst[0])
|
num = int(search_lst[0])
|
||||||
result = self.search_for_thing(
|
result = self.search_for_thing(
|
||||||
" ".join(search_lst[1:]),
|
" ".join(search_lst[1:]),
|
||||||
permitted_things,
|
permitted_things,
|
||||||
add_nonexisting,
|
add_nonexisting,
|
||||||
find_hidden_products,
|
find_hidden_products,
|
||||||
)
|
)
|
||||||
# Her kan det legges inn en except ValueError,
|
# Her kan det legges inn en except ValueError,
|
||||||
# men da blir det fort mye plaging av brukeren
|
# men da blir det fort mye plaging av brukeren
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
return result, num
|
return result, num
|
||||||
|
|
||||||
def search_for_thing(
|
def search_for_thing(
|
||||||
@@ -544,7 +542,7 @@ class Menu(object):
|
|||||||
of money PVVVV owes the user. This value decreases with the
|
of money PVVVV owes the user. This value decreases with the
|
||||||
appropriate amount when you register a purchase, and you may increase
|
appropriate amount when you register a purchase, and you may increase
|
||||||
it by putting money in the box and using the "Adjust credit" menu.
|
it by putting money in the box and using the "Adjust credit" menu.
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
def local_help(self):
|
def local_help(self):
|
||||||
@@ -627,17 +625,16 @@ class ConfirmMenu(Menu):
|
|||||||
options = {True: "[y]/n", False: "y/[n]", None: "y/n"}[self.default]
|
options = {True: "[y]/n", False: "y/[n]", None: "y/n"}[self.default]
|
||||||
while True:
|
while True:
|
||||||
result = self.input_str(
|
result = self.input_str(
|
||||||
f"{self.prompt} ({options})", end_prompt=": ", timeout=self.timeout
|
f"{self.prompt} ({options})", end_prompt=": ", timeout=self.timeout,
|
||||||
)
|
)
|
||||||
result = result.lower().strip()
|
result = result.lower().strip()
|
||||||
if result in ["y", "yes"]:
|
if result in ["y", "yes"]:
|
||||||
return True
|
return True
|
||||||
elif result in ["n", "no"]:
|
if result in ["n", "no"]:
|
||||||
return False
|
return False
|
||||||
elif self.default is not None and result == "":
|
if self.default is not None and result == "":
|
||||||
return self.default
|
return self.default
|
||||||
else:
|
print("Please answer yes or no")
|
||||||
print("Please answer yes or no")
|
|
||||||
|
|
||||||
|
|
||||||
class Selector(Menu):
|
class Selector(Menu):
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
@@ -48,18 +47,18 @@ class MainMenu(Menu):
|
|||||||
restart()
|
restart()
|
||||||
pass
|
pass
|
||||||
return True
|
return True
|
||||||
elif result == "c":
|
if result == "c":
|
||||||
os.system(
|
os.system(
|
||||||
'echo -e "\033['
|
'echo -e "\033['
|
||||||
+ str(random.randint(40, 49))
|
+ str(random.randint(40, 49))
|
||||||
+ ";"
|
+ ";"
|
||||||
+ str(random.randint(30, 37))
|
+ str(random.randint(30, 37))
|
||||||
+ ';5m"'
|
+ ';5m"',
|
||||||
)
|
)
|
||||||
os.system("clear")
|
os.system("clear")
|
||||||
self.show_context()
|
self.show_context()
|
||||||
return True
|
return True
|
||||||
elif result == "cs":
|
if result == "cs":
|
||||||
os.system('echo -e "\033[0m"')
|
os.system('echo -e "\033[0m"')
|
||||||
os.system("clear")
|
os.system("clear")
|
||||||
self.show_context()
|
self.show_context()
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import sqlalchemy
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from dibbler.conf import config
|
from dibbler.conf import config
|
||||||
from dibbler.models import Transaction, Product, User
|
|
||||||
from dibbler.lib.helpers import less
|
from dibbler.lib.helpers import less
|
||||||
|
from dibbler.models import Product, Transaction, User
|
||||||
|
|
||||||
from .helpermenus import Menu, Selector
|
from .helpermenus import Menu, Selector
|
||||||
|
|
||||||
@@ -90,10 +90,7 @@ class ShowUserMenu(Menu):
|
|||||||
if t.purchase:
|
if t.purchase:
|
||||||
products = []
|
products = []
|
||||||
for entry in t.purchase.entries:
|
for entry in t.purchase.entries:
|
||||||
if abs(entry.amount) != 1:
|
amount = f"{abs(entry.amount)}x " if abs(entry.amount) != 1 else ""
|
||||||
amount = f"{abs(entry.amount)}x "
|
|
||||||
else:
|
|
||||||
amount = ""
|
|
||||||
product = f"{amount}{entry.product.name}"
|
product = f"{amount}{entry.product.name}"
|
||||||
products.append(product)
|
products.append(product)
|
||||||
string += "purchase ("
|
string += "purchase ("
|
||||||
@@ -215,14 +212,11 @@ class ProductSearchMenu(Menu):
|
|||||||
self.print_header()
|
self.print_header()
|
||||||
self.set_context("Enter (part of) product name or bar code")
|
self.set_context("Enter (part of) product name or bar code")
|
||||||
product = self.input_product()
|
product = self.input_product()
|
||||||
print(
|
print(", ".join([
|
||||||
"Result: %s, price: %d kr, bar code: %s, stock: %d, hidden: %s"
|
f"Result: {product.name}",
|
||||||
% (
|
f"price: {product.price} kr",
|
||||||
product.name,
|
f"bar code: {product.bar_code}",
|
||||||
product.price,
|
f"stock: {product.stock}",
|
||||||
product.bar_code,
|
f"hidden: {'Y' if product.hidden else 'N'}",
|
||||||
product.stock,
|
]))
|
||||||
("Y" if product.hidden else "N"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# self.pause()
|
# self.pause()
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from dibbler.conf import config
|
|
||||||
from dibbler.models import Product, User
|
|
||||||
# from dibbler.lib.printer_helpers import print_bar_code, print_name_label
|
# from dibbler.lib.printer_helpers import print_bar_code, print_name_label
|
||||||
|
|
||||||
from .helpermenus import Menu
|
from .helpermenus import Menu
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ from sqlalchemy import desc, func
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from dibbler.lib.helpers import less
|
from dibbler.lib.helpers import less
|
||||||
from dibbler.models import PurchaseEntry, Product, User
|
|
||||||
from dibbler.lib.statistikkHelpers import statisticsTextOnly
|
from dibbler.lib.statistikkHelpers import statisticsTextOnly
|
||||||
|
from dibbler.models import Product, PurchaseEntry, User
|
||||||
|
|
||||||
from .helpermenus import Menu
|
from .helpermenus import Menu
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Base(DeclarativeBase):
|
|||||||
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
|
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
|
||||||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||||||
"pk": "pk_%(table_name)s",
|
"pk": "pk_%(table_name)s",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@declared_attr.directive
|
@declared_attr.directive
|
||||||
@@ -38,7 +38,7 @@ class Base(DeclarativeBase):
|
|||||||
isinstance(v, InstrumentedList),
|
isinstance(v, InstrumentedList),
|
||||||
isinstance(v, InstrumentedSet),
|
isinstance(v, InstrumentedSet),
|
||||||
isinstance(v, InstrumentedDict),
|
isinstance(v, InstrumentedDict),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return f"<{self.__class__.__name__}({columns})>"
|
return f"<{self.__class__.__name__}({columns})>"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ class Purchase(Base):
|
|||||||
def price_per_transaction(self, round_up: bool = True) -> int:
|
def price_per_transaction(self, round_up: bool = True) -> int:
|
||||||
if round_up:
|
if round_up:
|
||||||
return int(math.ceil(float(self.price) / len(self.transactions)))
|
return int(math.ceil(float(self.price) / len(self.transactions)))
|
||||||
else:
|
return int(math.floor(float(self.price) / len(self.transactions)))
|
||||||
return int(math.floor(float(self.price) / len(self.transactions)))
|
|
||||||
|
|
||||||
def set_price(self, round_up: bool = True) -> None:
|
def set_price(self, round_up: bool = True) -> None:
|
||||||
self.price = 0
|
self.price = 0
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Integer,
|
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
|
Integer,
|
||||||
)
|
)
|
||||||
from sqlalchemy.orm import (
|
from sqlalchemy.orm import (
|
||||||
Mapped,
|
Mapped,
|
||||||
@@ -27,8 +28,8 @@ class PurchaseEntry(Base):
|
|||||||
product_id: Mapped[int] = mapped_column(ForeignKey("products.product_id"))
|
product_id: Mapped[int] = mapped_column(ForeignKey("products.product_id"))
|
||||||
purchase_id: Mapped[int] = mapped_column(ForeignKey("purchases.id"))
|
purchase_id: Mapped[int] = mapped_column(ForeignKey("purchases.id"))
|
||||||
|
|
||||||
product: Mapped[Product] = relationship(back_populates='purchases', lazy="joined")
|
product: Mapped[Product] = relationship(back_populates="purchases", lazy="joined")
|
||||||
purchase: Mapped[Purchase] = relationship(back_populates='entries', lazy="joined")
|
purchase: Mapped[Purchase] = relationship(back_populates="entries", lazy="joined")
|
||||||
|
|
||||||
def __init__(self, purchase, product, amount):
|
def __init__(self, purchase, product, amount):
|
||||||
self.product = product
|
self.product = product
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
DateTime,
|
DateTime,
|
||||||
@@ -18,8 +18,8 @@ from sqlalchemy.orm import (
|
|||||||
from .Base import Base
|
from .Base import Base
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .User import User
|
|
||||||
from .Purchase import Purchase
|
from .Purchase import Purchase
|
||||||
|
from .User import User
|
||||||
|
|
||||||
|
|
||||||
class Transaction(Base):
|
class Transaction(Base):
|
||||||
@@ -36,7 +36,7 @@ class Transaction(Base):
|
|||||||
purchase_id: Mapped[int | None] = mapped_column(ForeignKey("purchases.id"))
|
purchase_id: Mapped[int | None] = mapped_column(ForeignKey("purchases.id"))
|
||||||
|
|
||||||
user: Mapped[User] = relationship(lazy="joined")
|
user: Mapped[User] = relationship(lazy="joined")
|
||||||
purchase: Mapped[Purchase] = relationship(back_populates='transactions', lazy="joined")
|
purchase: Mapped[Purchase] = relationship(back_populates="transactions", lazy="joined")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Integer,
|
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
|
Integer,
|
||||||
)
|
)
|
||||||
from sqlalchemy.orm import (
|
from sqlalchemy.orm import (
|
||||||
Mapped,
|
Mapped,
|
||||||
@@ -14,8 +15,8 @@ from sqlalchemy.orm import (
|
|||||||
from .Base import Base
|
from .Base import Base
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .User import User
|
|
||||||
from .Product import Product
|
from .Product import Product
|
||||||
|
from .User import User
|
||||||
|
|
||||||
|
|
||||||
class UserProducts(Base):
|
class UserProducts(Base):
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
@@ -91,7 +90,9 @@ def main(sql_session: Session):
|
|||||||
exit_confirm_msg="Really quit Dibbler?",
|
exit_confirm_msg="Really quit Dibbler?",
|
||||||
)
|
)
|
||||||
if not config["general"]["quit_allowed"]:
|
if not config["general"]["quit_allowed"]:
|
||||||
main_menu.exit_disallowed_msg = "You can check out any time you like, but you can never leave."
|
main_menu.exit_disallowed_msg = (
|
||||||
|
"You can check out any time you like, but you can never leave."
|
||||||
|
)
|
||||||
while True:
|
while True:
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
@@ -21,7 +20,7 @@ def main(sql_session: Session):
|
|||||||
product_items = []
|
product_items = []
|
||||||
user_items = []
|
user_items = []
|
||||||
|
|
||||||
with open(JSON_FILE) as f:
|
with Path.open(JSON_FILE) as f:
|
||||||
json_obj = json.load(f)
|
json_obj = json.load(f)
|
||||||
|
|
||||||
for product in json_obj["products"]:
|
for product in json_obj["products"]:
|
||||||
|
|||||||
Reference in New Issue
Block a user