treewide: types, types and more types
This commit is contained in:
@@ -4,7 +4,8 @@ import tomllib
|
||||
import os
|
||||
import sys
|
||||
|
||||
DEFAULT_CONFIG_PATH = Path('/etc/dibbler/dibbler.toml')
|
||||
DEFAULT_CONFIG_PATH = Path("/etc/dibbler/dibbler.toml")
|
||||
|
||||
|
||||
def default_config_path_submissive_and_readable() -> bool:
|
||||
return DEFAULT_CONFIG_PATH.is_file() and any(
|
||||
@@ -21,8 +22,10 @@ def default_config_path_submissive_and_readable() -> bool:
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
config: dict[str, dict[str, Any]] = dict()
|
||||
|
||||
|
||||
def load_config(config_path: Path | None = None):
|
||||
global config
|
||||
if config_path is not None:
|
||||
@@ -32,9 +35,13 @@ def load_config(config_path: Path | None = None):
|
||||
with DEFAULT_CONFIG_PATH.open("rb") as file:
|
||||
config = tomllib.load(file)
|
||||
else:
|
||||
print("Could not read config file, it was neither provided nor readable in default location", file=sys.stderr)
|
||||
print(
|
||||
"Could not read config file, it was neither provided nor readable in default location",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def config_db_string() -> str:
|
||||
db_type = config["database"]["type"]
|
||||
|
||||
@@ -54,7 +61,7 @@ def config_db_string() -> str:
|
||||
elif "password" in config["database"]["postgresql"]:
|
||||
password = config["database"]["postgresql"]["password"]
|
||||
else:
|
||||
password = ''
|
||||
password = ""
|
||||
|
||||
if host.startswith("/"):
|
||||
return f"postgresql+psycopg2://{username}:{password}@/{dbname}?host={host}"
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import pwd
|
||||
import subprocess
|
||||
import os
|
||||
import pwd
|
||||
import signal
|
||||
import subprocess
|
||||
from typing import Any, Callable, Literal
|
||||
|
||||
from sqlalchemy import or_, and_
|
||||
from sqlalchemy import and_, not_, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models import User, Product
|
||||
from ..models import Product, User
|
||||
|
||||
|
||||
def search_user(string, sql_session: Session, ignorethisflag=None):
|
||||
def search_user(
|
||||
string: str,
|
||||
sql_session: Session,
|
||||
ignorethisflag=None,
|
||||
):
|
||||
assert sql_session is not None
|
||||
string = string.lower()
|
||||
exact_match = (
|
||||
sql_session.query(User)
|
||||
@@ -32,7 +38,12 @@ def search_user(string, sql_session: Session, ignorethisflag=None):
|
||||
return user_list
|
||||
|
||||
|
||||
def search_product(string, sql_session: Session, find_hidden_products=True):
|
||||
def search_product(
|
||||
string: str,
|
||||
sql_session: Session,
|
||||
find_hidden_products: bool = True,
|
||||
):
|
||||
assert sql_session is not None
|
||||
if find_hidden_products:
|
||||
exact_match = (
|
||||
sql_session.query(Product)
|
||||
@@ -45,7 +56,10 @@ def search_product(string, sql_session: Session, find_hidden_products=True):
|
||||
.filter(
|
||||
or_(
|
||||
Product.bar_code == string,
|
||||
and_(Product.name == string, Product.hidden is False),
|
||||
and_(
|
||||
Product.name == string,
|
||||
not_(Product.hidden),
|
||||
),
|
||||
)
|
||||
)
|
||||
.first()
|
||||
@@ -65,11 +79,14 @@ def search_product(string, sql_session: Session, find_hidden_products=True):
|
||||
)
|
||||
else:
|
||||
product_list = (
|
||||
sql_ession.query(Product)
|
||||
sql_session.query(Product)
|
||||
.filter(
|
||||
or_(
|
||||
Product.bar_code.ilike(f"%{string}%"),
|
||||
and_(Product.name.ilike(f"%{string}%"), Product.hidden is False),
|
||||
and_(
|
||||
Product.name.ilike(f"%{string}%"),
|
||||
not_(Product.hidden),
|
||||
),
|
||||
)
|
||||
)
|
||||
.all()
|
||||
@@ -77,7 +94,7 @@ def search_product(string, sql_session: Session, find_hidden_products=True):
|
||||
return product_list
|
||||
|
||||
|
||||
def system_user_exists(username):
|
||||
def system_user_exists(username: str) -> bool:
|
||||
try:
|
||||
pwd.getpwnam(username)
|
||||
except KeyError:
|
||||
@@ -88,7 +105,7 @@ def system_user_exists(username):
|
||||
return True
|
||||
|
||||
|
||||
def guess_data_type(string):
|
||||
def guess_data_type(string: str) -> Literal["card", "rfid", "bar_code", "username"] | None:
|
||||
if string.startswith("ntnu") and string[4:].isdigit():
|
||||
return "card"
|
||||
if string.isdigit() and len(string) == 10:
|
||||
@@ -102,7 +119,11 @@ def guess_data_type(string):
|
||||
return None
|
||||
|
||||
|
||||
def argmax(d, all=False, value=None):
|
||||
def argmax(
|
||||
d,
|
||||
all: bool = False,
|
||||
value: Callable[[Any], Any] | None = None,
|
||||
):
|
||||
maxarg = None
|
||||
if value is not None:
|
||||
dd = d
|
||||
@@ -117,7 +138,7 @@ def argmax(d, all=False, value=None):
|
||||
return maxarg
|
||||
|
||||
|
||||
def less(string):
|
||||
def less(string: str) -> None:
|
||||
"""
|
||||
Run less with string as input; wait until it finishes.
|
||||
"""
|
||||
|
||||
@@ -11,6 +11,7 @@ from ..models import Transaction
|
||||
|
||||
|
||||
def getUser(sql_session: Session):
|
||||
assert sql_session is not None
|
||||
while 1:
|
||||
string = input("user? ")
|
||||
user = search_user(string, sql_session)
|
||||
@@ -38,6 +39,7 @@ def getUser(sql_session: Session):
|
||||
|
||||
|
||||
def getProduct(sql_session: Session):
|
||||
assert sql_session is not None
|
||||
while 1:
|
||||
string = input("product? ")
|
||||
product = search_product(string, sql_session)
|
||||
@@ -237,6 +239,7 @@ def addLineToDatabase(database, inputLine):
|
||||
|
||||
|
||||
def buildDatabaseFromDb(inputType, inputProduct, inputUser, sql_session: Session):
|
||||
assert sql_session is not None
|
||||
sdate = input("enter start date (yyyy-mm-dd)? ")
|
||||
edate = input("enter end date (yyyy-mm-dd)? ")
|
||||
print("building database...")
|
||||
@@ -463,6 +466,7 @@ def printGlobal(database, dateLine, n):
|
||||
|
||||
|
||||
def alt4menuTextOnly(database, dateLine, sql_session: Session):
|
||||
assert sql_session is not None
|
||||
n = 10
|
||||
while 1:
|
||||
print(
|
||||
@@ -491,6 +495,7 @@ def alt4menuTextOnly(database, dateLine, sql_session: Session):
|
||||
|
||||
|
||||
def statisticsTextOnly(sql_session: Session):
|
||||
assert sql_session is not None
|
||||
inputType = 4
|
||||
product = ""
|
||||
user = ""
|
||||
|
||||
@@ -10,12 +10,13 @@ from dibbler.models import (
|
||||
Transaction,
|
||||
User,
|
||||
)
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
||||
|
||||
class AddStockMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Add stock and adjust credit", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Add stock and adjust credit", sql_session)
|
||||
self.help_text = """
|
||||
Enter what you have bought for PVVVV here, along with your user name and how
|
||||
much money you're due in credits for the purchase when prompted.\n"""
|
||||
@@ -110,7 +111,12 @@ much money you're due in credits for the purchase when prompted.\n"""
|
||||
print(f"{self.products[product][0]}".rjust(width - len(product.name)))
|
||||
print(width * "-")
|
||||
|
||||
def add_thing_to_pending(self, thing, amount, price):
|
||||
def add_thing_to_pending(
|
||||
self,
|
||||
thing: User | Product,
|
||||
amount: int,
|
||||
price: int,
|
||||
):
|
||||
if isinstance(thing, User):
|
||||
self.users.append(thing)
|
||||
elif thing in list(self.products.keys()):
|
||||
|
||||
@@ -14,8 +14,11 @@ from .helpermenus import Menu
|
||||
|
||||
|
||||
class BuyMenu(Menu):
|
||||
superfast_mode: bool
|
||||
purchase: Purchase
|
||||
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Buy", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Buy", sql_session)
|
||||
self.superfast_mode = False
|
||||
self.help_text = """
|
||||
Each purchase may contain one or more products and one or more buyers.
|
||||
@@ -27,7 +30,7 @@ addition, and you can type 'what' at any time to redisplay it.
|
||||
When finished, write an empty line to confirm the purchase.\n"""
|
||||
|
||||
@staticmethod
|
||||
def credit_check(user):
|
||||
def credit_check(user: User):
|
||||
"""
|
||||
|
||||
:param user:
|
||||
@@ -38,7 +41,11 @@ When finished, write an empty line to confirm the purchase.\n"""
|
||||
|
||||
return user.credit > config["limits"]["low_credit_warning_limit"]
|
||||
|
||||
def low_credit_warning(self, user, timeout=False):
|
||||
def low_credit_warning(
|
||||
self,
|
||||
user: User,
|
||||
timeout: bool = False,
|
||||
):
|
||||
assert isinstance(user, User)
|
||||
|
||||
print("***********************************************************************")
|
||||
@@ -70,7 +77,11 @@ When finished, write an empty line to confirm the purchase.\n"""
|
||||
else:
|
||||
return self.confirm(prompt=">", default=True)
|
||||
|
||||
def add_thing_to_purchase(self, thing, amount=1):
|
||||
def add_thing_to_purchase(
|
||||
self,
|
||||
thing: User | Product,
|
||||
amount: int = 1,
|
||||
) -> bool:
|
||||
if isinstance(thing, User):
|
||||
if thing.is_anonymous():
|
||||
print("---------------------------------------------")
|
||||
@@ -79,7 +90,10 @@ When finished, write an empty line to confirm the purchase.\n"""
|
||||
print("---------------------------------------------")
|
||||
|
||||
if not self.credit_check(thing):
|
||||
if self.low_credit_warning(user=thing, timeout=self.superfast_mode):
|
||||
if self.low_credit_warning(
|
||||
user=thing,
|
||||
timeout=self.superfast_mode,
|
||||
):
|
||||
Transaction(thing, purchase=self.purchase, penalty=2)
|
||||
else:
|
||||
return False
|
||||
@@ -94,7 +108,10 @@ When finished, write an empty line to confirm the purchase.\n"""
|
||||
PurchaseEntry(self.purchase, thing, amount)
|
||||
return True
|
||||
|
||||
def _execute(self, initial_contents=None):
|
||||
def _execute(
|
||||
self,
|
||||
initial_contents: list[tuple[User | Product, int]] | None = None,
|
||||
):
|
||||
self.print_header()
|
||||
self.purchase = Purchase()
|
||||
self.exit_confirm_msg = None
|
||||
|
||||
@@ -17,7 +17,7 @@ __all__ = [
|
||||
|
||||
class AddUserMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Add user", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Add user", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -41,7 +41,7 @@ class AddUserMenu(Menu):
|
||||
|
||||
class EditUserMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Edit user", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Edit user", sql_session)
|
||||
self.help_text = """
|
||||
The only editable part of a user is its card number and rfid.
|
||||
|
||||
@@ -80,7 +80,7 @@ user, then rfid (write an empty line to remove the card number or rfid).
|
||||
|
||||
class AddProductMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Add product", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Add product", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -99,7 +99,7 @@ class AddProductMenu(Menu):
|
||||
|
||||
class EditProductMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Edit product", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Edit product", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -108,6 +108,7 @@ class EditProductMenu(Menu):
|
||||
while True:
|
||||
selector = Selector(
|
||||
f"Do what with {product.name}?",
|
||||
sql_session=self.sql_session,
|
||||
items=[
|
||||
("name", "Edit name"),
|
||||
("price", "Edit price"),
|
||||
@@ -152,7 +153,7 @@ class EditProductMenu(Menu):
|
||||
|
||||
class AdjustStockMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Adjust stock", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Adjust stock", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -182,7 +183,7 @@ class AdjustStockMenu(Menu):
|
||||
|
||||
class CleanupStockMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Stock Cleanup", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Stock Cleanup", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .helpermenus import MessageMenu, Menu
|
||||
from .helpermenus import Menu, MessageMenu
|
||||
|
||||
|
||||
class FAQMenu(Menu):
|
||||
def __init__(self):
|
||||
Menu.__init__(self, "Frequently Asked Questions")
|
||||
def __init__(self, sql_session: Session):
|
||||
super().__init__("Frequently Asked Questions", sql_session)
|
||||
self.items = [
|
||||
MessageMenu(
|
||||
"What is the meaning with this program?",
|
||||
@@ -17,19 +18,25 @@ class FAQMenu(Menu):
|
||||
|
||||
Dibbler stores a "credit" amount for each user. When you register a
|
||||
purchase in Dibbler, this amount is decreased. To increase your
|
||||
credit, purchase products for dibbler, and register them using "Add
|
||||
stock and adjust credit".
|
||||
credit, purchase products for dibbler, and register them using "Add
|
||||
stock and adjust credit".
|
||||
Alternatively, add money to the money box and use "Adjust credit" to
|
||||
tell Dibbler about it.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"Can I still pay for stuff using cash?",
|
||||
"""
|
||||
Please put money in the money box and use "Adjust Credit" so that
|
||||
Please put money in the money box and use "Adjust Credit" so that
|
||||
dibbler can keep track of credit and purchases.""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"How do I exit from a submenu/dialog/thing?",
|
||||
'Type "exit", "q", or ^d.',
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu("How do I exit from a submenu/dialog/thing?", 'Type "exit", "q", or ^d.'),
|
||||
MessageMenu(
|
||||
'What does "." mean?',
|
||||
"""
|
||||
@@ -41,6 +48,7 @@ class FAQMenu(Menu):
|
||||
line containing only a period, you should read the lines above and
|
||||
then press enter to continue.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"Why is the user interface so terribly unintuitive?",
|
||||
@@ -52,25 +60,30 @@ class FAQMenu(Menu):
|
||||
|
||||
Answer #3: YOU are unintuitive.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"Why is there no help command?",
|
||||
'There is. Have you tried typing "help"?',
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
'Where are the easter eggs? I tried saying "moo", but nothing happened.',
|
||||
'Don\'t say "moo".',
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"Why does the program speak English when all the users are Norwegians?",
|
||||
"Godt spørsmål. Det virket sikkert som en god idé der og da.",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"Why does the screen have strange colours?",
|
||||
"""
|
||||
Type "c" on the main menu to change the colours of the display, or
|
||||
Type "c" on the main menu to change the colours of the display, or
|
||||
"cs" if you are a boring person.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"I found a bug; is there a reward?",
|
||||
@@ -101,6 +114,7 @@ class FAQMenu(Menu):
|
||||
6. Type "restart" in Dibbler to replace the running process by a new
|
||||
one using the updated files.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
MessageMenu(
|
||||
"My question isn't listed here; what do I do?",
|
||||
@@ -125,5 +139,6 @@ class FAQMenu(Menu):
|
||||
5. Type "restart" in Dibbler to replace the running process by a new
|
||||
one using the updated files.
|
||||
""",
|
||||
sql_session,
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,46 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import re
|
||||
import sys
|
||||
from select import select
|
||||
from typing import Any, Callable, Iterable, Literal, Self
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dibbler.models import User
|
||||
from dibbler.lib.helpers import (
|
||||
search_user,
|
||||
search_product,
|
||||
guess_data_type,
|
||||
argmax,
|
||||
guess_data_type,
|
||||
search_product,
|
||||
search_user,
|
||||
)
|
||||
from dibbler.models import Product, User
|
||||
|
||||
exit_commands = ["exit", "abort", "quit", "bye", "eat flaming death", "q"]
|
||||
help_commands = ["help", "?"]
|
||||
context_commands = ["what", "??"]
|
||||
local_help_commands = ["help!", "???"]
|
||||
exit_commands: list[str] = ["exit", "abort", "quit", "bye", "eat flaming death", "q"]
|
||||
help_commands: list[str] = ["help", "?"]
|
||||
context_commands: list[str] = ["what", "??"]
|
||||
local_help_commands: list[str] = ["help!", "???"]
|
||||
|
||||
|
||||
class ExitMenu(Exception):
|
||||
class ExitMenuException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Menu(object):
|
||||
name: str
|
||||
sql_session: Session
|
||||
items: list[Self | tuple | str]
|
||||
prompt: str | None
|
||||
end_prompt: str | None
|
||||
return_index: bool
|
||||
exit_msg: str | None
|
||||
exit_confirm_msg: str | None
|
||||
exit_disallowed_msg: str | None
|
||||
help_text: str | None
|
||||
context: str | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
items=None,
|
||||
prompt=None,
|
||||
end_prompt="> ",
|
||||
return_index=True,
|
||||
exit_msg=None,
|
||||
exit_confirm_msg=None,
|
||||
exit_disallowed_msg=None,
|
||||
help_text=None,
|
||||
uses_db=False,
|
||||
sql_session: Session | None=None,
|
||||
name: str,
|
||||
sql_session: Session,
|
||||
items: list[Self | tuple[Any, str] | str] | None = None,
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = "> ",
|
||||
return_index: bool = True,
|
||||
exit_msg: str | None = None,
|
||||
exit_confirm_msg: str | None = None,
|
||||
exit_disallowed_msg: str | None = None,
|
||||
help_text: str | None = None,
|
||||
):
|
||||
self.name = name
|
||||
self.name: str = name
|
||||
self.sql_session: Session = sql_session
|
||||
self.items = items if items is not None else []
|
||||
self.prompt = prompt
|
||||
self.end_prompt = end_prompt
|
||||
@@ -50,48 +61,54 @@ class Menu(object):
|
||||
self.exit_disallowed_msg = exit_disallowed_msg
|
||||
self.help_text = help_text
|
||||
self.context = None
|
||||
self.uses_db = uses_db
|
||||
self.sql_session: Session | None = sql_session
|
||||
|
||||
assert not (self.uses_db and self.sql_session is None)
|
||||
assert name is not None
|
||||
assert self.sql_session is not None
|
||||
|
||||
def exit_menu(self):
|
||||
def exit_menu(self) -> None:
|
||||
if self.exit_disallowed_msg is not None:
|
||||
print(self.exit_disallowed_msg)
|
||||
return
|
||||
if self.exit_confirm_msg is not None:
|
||||
if not self.confirm(self.exit_confirm_msg, default=True):
|
||||
return
|
||||
raise ExitMenu()
|
||||
raise ExitMenuException()
|
||||
|
||||
def at_exit(self):
|
||||
def at_exit(self) -> None:
|
||||
if self.exit_msg:
|
||||
print(self.exit_msg)
|
||||
|
||||
def set_context(self, string, display=True):
|
||||
def set_context(
|
||||
self,
|
||||
string: str | None,
|
||||
display: bool = True,
|
||||
) -> None:
|
||||
self.context = string
|
||||
if self.context is not None and display:
|
||||
print(self.context)
|
||||
|
||||
def add_to_context(self, string):
|
||||
self.context += string
|
||||
def add_to_context(self, string: str) -> None:
|
||||
if self.context is not None:
|
||||
self.context += string
|
||||
else:
|
||||
self.context = string
|
||||
|
||||
def printc(self, string):
|
||||
def printc(self, string: str) -> None:
|
||||
print(string)
|
||||
if self.context is None:
|
||||
self.context = string
|
||||
else:
|
||||
self.context += "\n" + string
|
||||
|
||||
def show_context(self):
|
||||
def show_context(self) -> None:
|
||||
print(self.header())
|
||||
if self.context is not None:
|
||||
print(self.context)
|
||||
|
||||
def item_is_submenu(self, i):
|
||||
def item_is_submenu(self, i: int) -> bool:
|
||||
return isinstance(self.items[i], Menu)
|
||||
|
||||
def item_name(self, i):
|
||||
def item_name(self, i: int) -> str:
|
||||
if self.item_is_submenu(i):
|
||||
return self.items[i].name
|
||||
elif isinstance(self.items[i], tuple):
|
||||
@@ -99,7 +116,7 @@ class Menu(object):
|
||||
else:
|
||||
return self.items[i]
|
||||
|
||||
def item_value(self, i):
|
||||
def item_value(self, i: int):
|
||||
if isinstance(self.items[i], tuple):
|
||||
return self.items[i][0]
|
||||
if self.return_index:
|
||||
@@ -108,11 +125,11 @@ class Menu(object):
|
||||
|
||||
def input_str(
|
||||
self,
|
||||
prompt=None,
|
||||
end_prompt=None,
|
||||
regex=None,
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
regex: str | None = None,
|
||||
length_range=(None, None),
|
||||
empty_string_is_none=False,
|
||||
empty_string_is_none: bool = False,
|
||||
timeout=None,
|
||||
default=None,
|
||||
):
|
||||
@@ -181,7 +198,7 @@ class Menu(object):
|
||||
continue
|
||||
return result
|
||||
|
||||
def special_input_options(self, result):
|
||||
def special_input_options(self, result) -> bool:
|
||||
"""
|
||||
Handles special, magic input for input_str
|
||||
|
||||
@@ -191,7 +208,7 @@ class Menu(object):
|
||||
"""
|
||||
return False
|
||||
|
||||
def special_input_choice(self, in_str):
|
||||
def special_input_choice(self, in_str: str) -> bool:
|
||||
"""
|
||||
Handle choices which are not simply menu items.
|
||||
|
||||
@@ -201,7 +218,12 @@ class Menu(object):
|
||||
"""
|
||||
return False
|
||||
|
||||
def input_choice(self, number_of_choices, prompt=None, end_prompt=None):
|
||||
def input_choice(
|
||||
self,
|
||||
number_of_choices: int,
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
):
|
||||
while True:
|
||||
result = self.input_str(prompt, end_prompt)
|
||||
if result == "":
|
||||
@@ -216,7 +238,7 @@ class Menu(object):
|
||||
if not self.special_input_choice(result):
|
||||
self.invalid_menu_choice(result)
|
||||
|
||||
def invalid_menu_choice(self, in_str):
|
||||
def invalid_menu_choice(self, in_str: str):
|
||||
print("Please enter a valid choice.")
|
||||
|
||||
def input_int(
|
||||
@@ -256,32 +278,40 @@ class Menu(object):
|
||||
except ValueError:
|
||||
print("Please enter an integer")
|
||||
|
||||
def input_user(self, prompt=None, end_prompt=None):
|
||||
def input_user(
|
||||
self,
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
) -> User:
|
||||
user = None
|
||||
while user is None:
|
||||
user = self.retrieve_user(self.input_str(prompt, end_prompt))
|
||||
return user
|
||||
|
||||
def retrieve_user(self, search_str):
|
||||
def retrieve_user(self, search_str: str) -> User | None:
|
||||
return self.search_ui(search_user, search_str, "user")
|
||||
|
||||
def input_product(self, prompt=None, end_prompt=None):
|
||||
def input_product(
|
||||
self,
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
) -> Product:
|
||||
product = None
|
||||
while product is None:
|
||||
product = self.retrieve_product(self.input_str(prompt, end_prompt))
|
||||
return product
|
||||
|
||||
def retrieve_product(self, search_str):
|
||||
def retrieve_product(self, search_str: str) -> Product | None:
|
||||
return self.search_ui(search_product, search_str, "product")
|
||||
|
||||
def input_thing(
|
||||
self,
|
||||
prompt=None,
|
||||
end_prompt=None,
|
||||
permitted_things=("user", "product"),
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
permitted_things: Iterable[str] = ("user", "product"),
|
||||
add_nonexisting=(),
|
||||
empty_input_permitted=False,
|
||||
find_hidden_products=True,
|
||||
empty_input_permitted: bool = False,
|
||||
find_hidden_products: bool = True,
|
||||
):
|
||||
result = None
|
||||
while result is None:
|
||||
@@ -289,19 +319,22 @@ class Menu(object):
|
||||
if search_str == "" and empty_input_permitted:
|
||||
return None
|
||||
result = self.search_for_thing(
|
||||
search_str, permitted_things, add_nonexisting, find_hidden_products
|
||||
search_str,
|
||||
permitted_things,
|
||||
add_nonexisting,
|
||||
find_hidden_products,
|
||||
)
|
||||
return result
|
||||
|
||||
def input_multiple(
|
||||
self,
|
||||
prompt=None,
|
||||
end_prompt=None,
|
||||
permitted_things=("user", "product"),
|
||||
prompt: str | None = None,
|
||||
end_prompt: str | None = None,
|
||||
permitted_things: Iterable[str] = ("user", "product"),
|
||||
add_nonexisting=(),
|
||||
empty_input_permitted=False,
|
||||
find_hidden_products=True,
|
||||
):
|
||||
empty_input_permitted: bool = False,
|
||||
find_hidden_products: bool = True,
|
||||
) -> tuple[User | Product, int] | None:
|
||||
result = None
|
||||
num = 0
|
||||
while result is None:
|
||||
@@ -311,7 +344,10 @@ class Menu(object):
|
||||
return None
|
||||
else:
|
||||
result = self.search_for_thing(
|
||||
search_str, permitted_things, add_nonexisting, find_hidden_products
|
||||
search_str,
|
||||
permitted_things,
|
||||
add_nonexisting,
|
||||
find_hidden_products,
|
||||
)
|
||||
num = 1
|
||||
|
||||
@@ -333,12 +369,15 @@ class Menu(object):
|
||||
|
||||
def search_for_thing(
|
||||
self,
|
||||
search_str,
|
||||
search_str: str,
|
||||
permitted_things=("user", "product"),
|
||||
add_non_existing=(),
|
||||
find_hidden_products=True,
|
||||
):
|
||||
search_fun = {"user": search_user, "product": search_product}
|
||||
find_hidden_products: bool = True,
|
||||
) -> User | Product | None:
|
||||
search_fun = {
|
||||
"user": search_user,
|
||||
"product": search_product,
|
||||
}
|
||||
results = {}
|
||||
result_values = {}
|
||||
for thing in permitted_things:
|
||||
@@ -357,10 +396,14 @@ class Menu(object):
|
||||
return self.search_add(search_str)
|
||||
# print('No match found for "%s".' % search_str)
|
||||
return None
|
||||
return self.search_ui2(search_str, results[selected_thing], selected_thing)
|
||||
return self.search_ui2(
|
||||
search_str,
|
||||
results[selected_thing],
|
||||
selected_thing,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def search_result_value(result):
|
||||
def search_result_value(result) -> Literal[0, 1, 2, 3]:
|
||||
if result is None:
|
||||
return 0
|
||||
if not isinstance(result, list):
|
||||
@@ -371,7 +414,7 @@ class Menu(object):
|
||||
return 2
|
||||
return 1
|
||||
|
||||
def search_add(self, string):
|
||||
def search_add(self, string: str) -> User | None:
|
||||
type_guess = guess_data_type(string)
|
||||
if type_guess == "username":
|
||||
print(f'"{string}" looks like a username, but no such user exists.')
|
||||
@@ -383,6 +426,7 @@ class Menu(object):
|
||||
if type_guess == "card":
|
||||
selector = Selector(
|
||||
f'"{string}" looks like a card number, but no user with that card number exists.',
|
||||
self.sql_session,
|
||||
[
|
||||
("create", f"Create user with card number {string}"),
|
||||
("set", f"Set card number of an existing user to {string}"),
|
||||
@@ -409,11 +453,21 @@ class Menu(object):
|
||||
print(f'"{string}" looks like the bar code for a product, but no such product exists.')
|
||||
return None
|
||||
|
||||
def search_ui(self, search_fun, search_str, thing):
|
||||
def search_ui(
|
||||
self,
|
||||
search_fun: Callable[[str, Session], list[Any] | Any],
|
||||
search_str: str,
|
||||
thing: str,
|
||||
) -> Any:
|
||||
result = search_fun(search_str, self.sql_session)
|
||||
return self.search_ui2(search_str, result, thing)
|
||||
|
||||
def search_ui2(self, search_str, result, thing):
|
||||
def search_ui2(
|
||||
self,
|
||||
search_str: str,
|
||||
result: list[Any] | Any,
|
||||
thing: str,
|
||||
) -> Any:
|
||||
if not isinstance(result, list):
|
||||
return result
|
||||
if len(result) == 0:
|
||||
@@ -433,21 +487,37 @@ class Menu(object):
|
||||
else:
|
||||
select_header = f'{len(result):d} {thing}s matching "{search_str}"'
|
||||
select_items = result
|
||||
selector = Selector(select_header, items=select_items, return_index=False)
|
||||
selector = Selector(
|
||||
select_header,
|
||||
self.sql_session,
|
||||
items=select_items,
|
||||
return_index=False,
|
||||
)
|
||||
return selector.execute()
|
||||
|
||||
@staticmethod
|
||||
def confirm(prompt, end_prompt=None, default=None, timeout=None):
|
||||
return ConfirmMenu(prompt, end_prompt=None, default=default, timeout=timeout).execute()
|
||||
def confirm(
|
||||
self,
|
||||
prompt: str,
|
||||
end_prompt: str | None = None,
|
||||
default: bool | None = None,
|
||||
timeout: int | None = None,
|
||||
) -> bool:
|
||||
return ConfirmMenu(
|
||||
self.sql_session,
|
||||
prompt,
|
||||
end_prompt=None,
|
||||
default=default,
|
||||
timeout=timeout,
|
||||
).execute()
|
||||
|
||||
def header(self):
|
||||
def header(self) -> str:
|
||||
return f"[{self.name}]"
|
||||
|
||||
def print_header(self):
|
||||
def print_header(self) -> None:
|
||||
print("")
|
||||
print(self.header())
|
||||
|
||||
def pause(self):
|
||||
def pause(self) -> None:
|
||||
self.input_str(".", end_prompt="")
|
||||
|
||||
@staticmethod
|
||||
@@ -489,7 +559,7 @@ class Menu(object):
|
||||
self.set_context(None)
|
||||
try:
|
||||
return self._execute(**kwargs)
|
||||
except ExitMenu:
|
||||
except ExitMenuException:
|
||||
self.at_exit()
|
||||
return None
|
||||
finally:
|
||||
@@ -515,8 +585,17 @@ class Menu(object):
|
||||
|
||||
|
||||
class MessageMenu(Menu):
|
||||
def __init__(self, name, message, pause_after_message=True):
|
||||
Menu.__init__(self, name)
|
||||
message: str
|
||||
pause_after_message: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
message: str,
|
||||
sql_session: Session,
|
||||
pause_after_message: bool = True,
|
||||
):
|
||||
super().__init__(name, sql_session)
|
||||
self.message = message.strip()
|
||||
self.pause_after_message = pause_after_message
|
||||
|
||||
@@ -529,10 +608,17 @@ class MessageMenu(Menu):
|
||||
|
||||
|
||||
class ConfirmMenu(Menu):
|
||||
def __init__(self, prompt="confirm? ", end_prompt=": ", default=None, timeout=0):
|
||||
Menu.__init__(
|
||||
self,
|
||||
def __init__(
|
||||
self,
|
||||
sql_session: Session,
|
||||
prompt: str = "confirm? ",
|
||||
end_prompt: str | None = ": ",
|
||||
default: bool | None = None,
|
||||
timeout: int | None = 0,
|
||||
):
|
||||
super().__init__(
|
||||
"question",
|
||||
sql_session,
|
||||
prompt=prompt,
|
||||
end_prompt=end_prompt,
|
||||
exit_disallowed_msg="Please answer yes or no",
|
||||
@@ -560,7 +646,8 @@ class ConfirmMenu(Menu):
|
||||
class Selector(Menu):
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
name: str,
|
||||
sql_session: Session,
|
||||
items=None,
|
||||
prompt="select",
|
||||
return_index=True,
|
||||
@@ -570,15 +657,22 @@ class Selector(Menu):
|
||||
):
|
||||
if items is None:
|
||||
items = []
|
||||
Menu.__init__(self, name, items, prompt, return_index=return_index, exit_msg=exit_msg)
|
||||
super().__init__(
|
||||
name,
|
||||
sql_session,
|
||||
items,
|
||||
prompt,
|
||||
return_index=return_index,
|
||||
exit_msg=exit_msg,
|
||||
)
|
||||
|
||||
def header(self):
|
||||
def header(self) -> str:
|
||||
return self.name
|
||||
|
||||
def print_header(self):
|
||||
def print_header(self) -> None:
|
||||
print(self.header())
|
||||
|
||||
def local_help(self):
|
||||
def local_help(self) -> None:
|
||||
if self.help_text is None:
|
||||
print("This is a selection menu. Enter one of the listed numbers, or")
|
||||
print("'exit' to go out and do something else.")
|
||||
|
||||
@@ -19,7 +19,7 @@ def restart():
|
||||
|
||||
|
||||
class MainMenu(Menu):
|
||||
def special_input_choice(self, in_str):
|
||||
def special_input_choice(self, in_str: str) -> bool:
|
||||
mv = in_str.split()
|
||||
if len(mv) == 2 and mv[0].isdigit():
|
||||
num = int(mv[0])
|
||||
@@ -35,9 +35,9 @@ class MainMenu(Menu):
|
||||
return True
|
||||
return False
|
||||
|
||||
def special_input_options(self, result):
|
||||
def special_input_options(self, result: str) -> bool:
|
||||
if result in faq_commands:
|
||||
FAQMenu().execute()
|
||||
FAQMenu(self.sql_session).execute()
|
||||
return True
|
||||
if result in restart_commands:
|
||||
if self.confirm("Restart Dibbler?"):
|
||||
@@ -62,5 +62,5 @@ class MainMenu(Menu):
|
||||
return True
|
||||
return False
|
||||
|
||||
def invalid_menu_choice(self, in_str):
|
||||
def invalid_menu_choice(self, in_str: str) -> None:
|
||||
print(self.show_context())
|
||||
|
||||
@@ -10,7 +10,7 @@ from .helpermenus import Menu, Selector
|
||||
|
||||
class TransferMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Transfer credit between users", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Transfer credit between users", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -42,7 +42,7 @@ class TransferMenu(Menu):
|
||||
|
||||
class ShowUserMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Show user", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Show user", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -53,6 +53,7 @@ class ShowUserMenu(Menu):
|
||||
print(f"Credit: {user.credit} kr")
|
||||
selector = Selector(
|
||||
f"What do you want to know about {user.name}?",
|
||||
self.sql_session,
|
||||
items=[
|
||||
(
|
||||
"transactions",
|
||||
@@ -75,7 +76,7 @@ class ShowUserMenu(Menu):
|
||||
print("What what?")
|
||||
|
||||
@staticmethod
|
||||
def print_transactions(user, limit=None):
|
||||
def print_transactions(user: User, limit: int | None = None) -> None:
|
||||
num_trans = len(user.transactions)
|
||||
if limit is None:
|
||||
limit = num_trans
|
||||
@@ -99,13 +100,13 @@ class ShowUserMenu(Menu):
|
||||
string += ")"
|
||||
if t.penalty > 1:
|
||||
string += f" * {t.penalty:d}x penalty applied"
|
||||
else:
|
||||
elif t.description is not None:
|
||||
string += t.description
|
||||
string += "\n"
|
||||
less(string)
|
||||
|
||||
@staticmethod
|
||||
def print_purchased_products(user):
|
||||
def print_purchased_products(user: User) -> None:
|
||||
products = []
|
||||
for ref in user.products:
|
||||
product = ref.product
|
||||
@@ -125,7 +126,7 @@ class ShowUserMenu(Menu):
|
||||
|
||||
class UserListMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "User list", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("User list", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -146,7 +147,7 @@ class UserListMenu(Menu):
|
||||
|
||||
class AdjustCreditMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Adjust credit", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Adjust credit", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -176,7 +177,7 @@ class AdjustCreditMenu(Menu):
|
||||
|
||||
class ProductListMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Product list", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Product list", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -206,7 +207,7 @@ class ProductListMenu(Menu):
|
||||
|
||||
class ProductSearchMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Product search", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Product search", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
|
||||
@@ -11,7 +11,7 @@ from .helpermenus import Menu
|
||||
|
||||
class PrintLabelMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Print a label", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Print a label", sql_session)
|
||||
self.help_text = """
|
||||
Prints out a product bar code on the printer
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ __all__ = [
|
||||
|
||||
class ProductPopularityMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Products by popularity", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Products by popularity", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -50,7 +50,7 @@ class ProductPopularityMenu(Menu):
|
||||
|
||||
class ProductRevenueMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Products by revenue", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Products by revenue", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -88,7 +88,7 @@ class ProductRevenueMenu(Menu):
|
||||
|
||||
class BalanceMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Total balance of PVVVV", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Total balance of PVVVV", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
@@ -121,7 +121,7 @@ class BalanceMenu(Menu):
|
||||
|
||||
class LoggedStatisticsMenu(Menu):
|
||||
def __init__(self, sql_session: Session):
|
||||
Menu.__init__(self, "Statistics from log", sql_session=sql_session, uses_db=True)
|
||||
super().__init__("Statistics from log", sql_session)
|
||||
|
||||
def _execute(self):
|
||||
statisticsTextOnly(self.sql_session)
|
||||
|
||||
@@ -36,12 +36,19 @@ class Product(Base):
|
||||
name_re = r".+"
|
||||
name_length = 45
|
||||
|
||||
def __init__(self, bar_code, name, price, stock=0, hidden=False):
|
||||
def __init__(
|
||||
self,
|
||||
bar_code: str,
|
||||
name: str,
|
||||
price: int,
|
||||
stock: int = 0,
|
||||
hidden: bool = False,
|
||||
):
|
||||
self.name = name
|
||||
self.bar_code = bar_code
|
||||
self.price = price
|
||||
self.stock = stock
|
||||
self.hidden = hidden
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
@@ -36,16 +36,16 @@ class Purchase(Base):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def is_complete(self):
|
||||
def is_complete(self) -> bool:
|
||||
return len(self.transactions) > 0 and len(self.entries) > 0
|
||||
|
||||
def price_per_transaction(self, round_up=True):
|
||||
def price_per_transaction(self, round_up: bool = True) -> int:
|
||||
if round_up:
|
||||
return int(math.ceil(float(self.price) / len(self.transactions)))
|
||||
else:
|
||||
return int(math.floor(float(self.price) / len(self.transactions)))
|
||||
|
||||
def set_price(self, round_up=True):
|
||||
def set_price(self, round_up: bool = True) -> None:
|
||||
self.price = 0
|
||||
for entry in self.entries:
|
||||
self.price += entry.amount * entry.product.price
|
||||
@@ -53,16 +53,16 @@ class Purchase(Base):
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
|
||||
def perform_purchase(self, ignore_penalty=False, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
def perform_purchase(self, ignore_penalty: bool = False, round_up: bool = True) -> None:
|
||||
self.time = datetime.now()
|
||||
self.set_price(round_up=round_up)
|
||||
for t in self.transactions:
|
||||
t.perform_transaction(ignore_penalty=ignore_penalty)
|
||||
for entry in self.entries:
|
||||
entry.product.stock -= entry.amount
|
||||
|
||||
def perform_soft_purchase(self, price, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
def perform_soft_purchase(self, price: int, round_up: bool = True) -> None:
|
||||
self.time = datetime.now()
|
||||
self.price = price
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
|
||||
@@ -38,15 +38,22 @@ class Transaction(Base):
|
||||
user: Mapped[User] = relationship(lazy="joined")
|
||||
purchase: Mapped[Purchase] = relationship(lazy="joined")
|
||||
|
||||
def __init__(self, user, amount=0, description=None, purchase=None, penalty=1):
|
||||
def __init__(
|
||||
self,
|
||||
user: User,
|
||||
amount: int = 0,
|
||||
description: str | None = None,
|
||||
purchase: Purchase | None = None,
|
||||
penalty: int = 1,
|
||||
):
|
||||
self.user = user
|
||||
self.amount = amount
|
||||
self.description = description
|
||||
self.purchase = purchase
|
||||
self.penalty = penalty
|
||||
|
||||
def perform_transaction(self, ignore_penalty=False):
|
||||
self.time = datetime.datetime.now()
|
||||
def perform_transaction(self, ignore_penalty: bool = False) -> None:
|
||||
self.time = datetime.now()
|
||||
if not ignore_penalty:
|
||||
self.amount *= self.penalty
|
||||
self.user.credit -= self.amount
|
||||
|
||||
@@ -25,14 +25,20 @@ class User(Base):
|
||||
card: Mapped[str | None] = mapped_column(String(20))
|
||||
rfid: Mapped[str | None] = mapped_column(String(20))
|
||||
|
||||
products: Mapped[set[UserProducts]] = relationship(back_populates="user")
|
||||
transactions: Mapped[set[Transaction]] = relationship(back_populates="user")
|
||||
products: Mapped[list[UserProducts]] = relationship(back_populates="user")
|
||||
transactions: Mapped[list[Transaction]] = relationship(back_populates="user")
|
||||
|
||||
name_re = r"[a-z]+"
|
||||
card_re = r"(([Nn][Tt][Nn][Uu])?[0-9]+)?"
|
||||
rfid_re = r"[0-9a-fA-F]*"
|
||||
|
||||
def __init__(self, name, card, rfid=None, credit=0):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
card: str | None,
|
||||
rfid: str | None = None,
|
||||
credit: int = 0,
|
||||
):
|
||||
self.name = name
|
||||
if card == "":
|
||||
card = None
|
||||
|
||||
@@ -4,25 +4,56 @@
|
||||
import random
|
||||
import sys
|
||||
import traceback
|
||||
from signal import (
|
||||
SIG_IGN,
|
||||
SIGQUIT,
|
||||
SIGTSTP,
|
||||
)
|
||||
from signal import (
|
||||
signal as set_signal_handler,
|
||||
)
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..conf import config
|
||||
from ..lib.helpers import *
|
||||
from ..menus import *
|
||||
from ..menus import (
|
||||
AddProductMenu,
|
||||
AddStockMenu,
|
||||
AddUserMenu,
|
||||
AdjustCreditMenu,
|
||||
AdjustStockMenu,
|
||||
BalanceMenu,
|
||||
BuyMenu,
|
||||
CleanupStockMenu,
|
||||
EditProductMenu,
|
||||
EditUserMenu,
|
||||
FAQMenu,
|
||||
LoggedStatisticsMenu,
|
||||
MainMenu,
|
||||
Menu,
|
||||
PrintLabelMenu,
|
||||
ProductListMenu,
|
||||
ProductPopularityMenu,
|
||||
ProductRevenueMenu,
|
||||
ProductSearchMenu,
|
||||
ShowUserMenu,
|
||||
TransferMenu,
|
||||
UserListMenu,
|
||||
)
|
||||
|
||||
random.seed()
|
||||
|
||||
|
||||
def main(sql_session: Session):
|
||||
if not config["general"]["stop_allowed"]:
|
||||
signal.signal(signal.SIGQUIT, signal.SIG_IGN)
|
||||
set_signal_handler(SIGQUIT, SIG_IGN)
|
||||
|
||||
if not config["general"]["stop_allowed"]:
|
||||
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
|
||||
set_signal_handler(SIGTSTP, SIG_IGN)
|
||||
|
||||
main = MainMenu(
|
||||
"Dibbler main menu",
|
||||
sql_session,
|
||||
items=[
|
||||
BuyMenu(sql_session),
|
||||
ProductListMenu(sql_session),
|
||||
@@ -33,6 +64,7 @@ def main(sql_session: Session):
|
||||
AddStockMenu(sql_session),
|
||||
Menu(
|
||||
"Add/edit",
|
||||
sql_session,
|
||||
items=[
|
||||
AddUserMenu(sql_session),
|
||||
EditUserMenu(sql_session),
|
||||
@@ -45,6 +77,7 @@ def main(sql_session: Session):
|
||||
ProductSearchMenu(sql_session),
|
||||
Menu(
|
||||
"Statistics",
|
||||
sql_session,
|
||||
items=[
|
||||
ProductPopularityMenu(sql_session),
|
||||
ProductRevenueMenu(sql_session),
|
||||
@@ -52,7 +85,7 @@ def main(sql_session: Session):
|
||||
LoggedStatisticsMenu(sql_session),
|
||||
],
|
||||
),
|
||||
FAQMenu(),
|
||||
FAQMenu(sql_session),
|
||||
PrintLabelMenu(sql_session),
|
||||
],
|
||||
exit_msg="happy happy joy joy",
|
||||
|
||||
Reference in New Issue
Block a user