Restructure project #3
|
@ -1,2 +1,4 @@
|
|||
result
|
||||
result-*
|
||||
result-*
|
||||
|
||||
dist
|
30
ALTER
30
ALTER
|
@ -1,30 +0,0 @@
|
|||
torjehoa_dibblerdummy=> ALTER TABLE products ADD stock integer;
|
||||
|
||||
Table "torjehoa_dibblerdummy.products"
|
||||
Column | Type | Modifiers
|
||||
----------+-----------------------+-----------
|
||||
bar_code | character varying(13) | not null
|
||||
name | character varying(45) |
|
||||
price | integer |
|
||||
Indexes:
|
||||
"products_pkey" PRIMARY KEY, btree (bar_code)
|
||||
|
||||
torjehoa_dibblerdummy=> ALTER TABLE products ADD stock integer;
|
||||
ALTER TABLE
|
||||
torjehoa_dibblerdummy=> UPDATE products SET stock = 0;
|
||||
UPDATE 102
|
||||
torjehoa_dibblerdummy=> ALTER TABLE products ALTER stock SET NOT NULL;
|
||||
ALTER TABLE
|
||||
torjehoa_dibblerdummy=> \d products
|
||||
Table "torjehoa_dibblerdummy.products"
|
||||
Column | Type | Modifiers
|
||||
----------+-----------------------+-----------
|
||||
bar_code | character varying(13) | not null
|
||||
name | character varying(45) |
|
||||
price | integer |
|
||||
stock | integer | not null
|
||||
Indexes:
|
||||
"products_pkey" PRIMARY KEY, btree (bar_code)
|
||||
|
||||
torjehoa_dibblerdummy=>
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
{ pkgs ? import <nixos-unstable> { } }:
|
||||
|
||||
rec {
|
||||
|
||||
{
|
||||
dibbler = pkgs.callPackage ./nix/dibbler.nix { };
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import argparse
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
help="Path to the config file",
|
||||
type=str,
|
||||
required=False,
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
config.read(args.config)
|
||||
|
||||
import dibbler.text_based as text_based
|
||||
|
||||
text_based.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,6 @@
|
|||
# This module is supposed to act as a singleton and be filled
|
||||
# with config variables by cli.py
|
||||
|
||||
import configparser
|
||||
|
||||
config = configparser.ConfigParser()
|
|
@ -1,10 +1,12 @@
|
|||
from db import *
|
||||
from sqlalchemy import or_, and_
|
||||
import pwd
|
||||
import subprocess
|
||||
import os
|
||||
import signal
|
||||
|
||||
from sqlalchemy import or_, and_
|
||||
|
||||
from .models.db import *
|
||||
|
||||
def search_user(string, session, ignorethisflag=None):
|
||||
string = string.lower()
|
||||
exact_match = session.query(User).filter(or_(User.name == string, User.card == string, User.rfid == string)).first()
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
import db
|
||||
from .models.db import db
|
||||
|
||||
db.Base.metadata.create_all(db.engine)
|
|
@ -1,8 +1,15 @@
|
|||
from math import ceil
|
||||
|
||||
import sqlalchemy
|
||||
from db import Product, User, Transaction, PurchaseEntry, Purchase
|
||||
from text_interface.helpermenus import Menu
|
||||
|
||||
from dibbler.models.db import (
|
||||
Product,
|
||||
Purchase,
|
||||
PurchaseEntry,
|
||||
Transaction,
|
||||
User,
|
||||
)
|
||||
from .helpermenus import Menu
|
||||
|
||||
|
||||
class AddStockMenu(Menu):
|
|
@ -1,7 +1,15 @@
|
|||
import conf
|
||||
import sqlalchemy
|
||||
from db import User, Purchase, PurchaseEntry, Transaction, Product
|
||||
from text_interface.helpermenus import Menu
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import (
|
||||
Product,
|
||||
Purchase,
|
||||
PurchaseEntry,
|
||||
Transaction,
|
||||
User,
|
||||
)
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
||||
|
||||
class BuyMenu(Menu):
|
||||
|
@ -29,7 +37,7 @@ When finished, write an empty line to confirm the purchase.\n'''
|
|||
"""
|
||||
assert isinstance(user, User)
|
||||
|
||||
return user.credit > conf.low_credit_warning_limit
|
||||
return user.credit > config.getint('limits', 'low_credit_warning_limit')
|
||||
|
||||
def low_credit_warning(self, user, timeout=False):
|
||||
assert isinstance(user, User)
|
||||
|
@ -49,7 +57,7 @@ When finished, write an empty line to confirm the purchase.\n'''
|
|||
print("***********************************************************************")
|
||||
print("***********************************************************************")
|
||||
print("")
|
||||
print(f"USER {user.name} HAS LOWER CREDIT THAN {conf.low_credit_warning_limit:d}.")
|
||||
print(f"USER {user.name} HAS LOWER CREDIT THAN {config.getint('limits', 'low_credit_warning_limit'):d}.")
|
||||
print("THIS PURCHASE WILL CHARGE YOUR CREDIT TWICE AS MUCH.")
|
||||
print("CONSIDER PUTTING MONEY IN THE BOX TO AVOID THIS.")
|
||||
print("")
|
||||
|
@ -158,8 +166,8 @@ When finished, write an empty line to confirm the purchase.\n'''
|
|||
for t in self.purchase.transactions:
|
||||
if not t.user.is_anonymous():
|
||||
print(f"User {t.user.name}'s credit is now {t.user.credit:d} kr")
|
||||
if t.user.credit < conf.low_credit_warning_limit:
|
||||
print(f'USER {t.user.name} HAS LOWER CREDIT THAN {conf.low_credit_warning_limit:d},',
|
||||
if t.user.credit < config.getint('limits', 'low_credit_warning_limit'):
|
||||
print(f'USER {t.user.name} HAS LOWER CREDIT THAN {config.getint("limits", "low_credit_warning_limit"):d},',
|
||||
'AND SHOULD CONSIDER PUTTING SOME MONEY IN THE BOX.')
|
||||
|
||||
# Superfast mode skips a linebreak for some reason.
|
|
@ -1,6 +1,7 @@
|
|||
import sqlalchemy
|
||||
from db import User, Product
|
||||
from text_interface.helpermenus import Menu, Selector
|
||||
|
||||
from dibbler.models.db import User, Product
|
||||
from .helpermenus import Menu, Selector
|
||||
|
||||
__all__ = ["AddUserMenu", "AddProductMenu", "EditProductMenu", "AdjustStockMenu", "CleanupStockMenu", "EditUserMenu"]
|
||||
|
|
@ -5,10 +5,20 @@ import re
|
|||
import sys
|
||||
from select import select
|
||||
|
||||
import conf
|
||||
from db import User, Session
|
||||
from helpers import search_user, search_product, guess_data_type, argmax
|
||||
from text_interface import context_commands, local_help_commands, help_commands, exit_commands
|
||||
from dibbler.models.db import User, Session
|
||||
from dibbler.helpers import (
|
||||
search_user,
|
||||
search_product,
|
||||
guess_data_type,
|
||||
argmax,
|
||||
)
|
||||
|
||||
from . import (
|
||||
context_commands,
|
||||
local_help_commands,
|
||||
help_commands,
|
||||
exit_commands,
|
||||
)
|
||||
|
||||
|
||||
class ExitMenu(Exception):
|
|
@ -4,11 +4,12 @@ import os
|
|||
import random
|
||||
import sys
|
||||
|
||||
from db import Session
|
||||
from text_interface import faq_commands, restart_commands
|
||||
from text_interface.buymenu import BuyMenu
|
||||
from text_interface.faq import FAQMenu
|
||||
from text_interface.helpermenus import Menu
|
||||
from dibbler.models.db import Session
|
||||
|
||||
from . import faq_commands, restart_commands
|
||||
from .buymenu import BuyMenu
|
||||
from .faq import FAQMenu
|
||||
from .helpermenus import Menu
|
||||
|
||||
|
||||
def restart():
|
|
@ -1,8 +1,10 @@
|
|||
import conf
|
||||
import sqlalchemy
|
||||
from db import Transaction, Product, User
|
||||
from helpers import less
|
||||
from text_interface.helpermenus import Menu, Selector
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import Transaction, Product, User
|
||||
from dibbler.helpers import less
|
||||
|
||||
from .helpermenus import Menu, Selector
|
||||
|
||||
|
||||
class TransferMenu(Menu):
|
||||
|
@ -53,12 +55,12 @@ class ShowUserMenu(Menu):
|
|||
print(f'Credit: {user.credit} kr')
|
||||
selector = Selector(f'What do you want to know about {user.name}?',
|
||||
items=[('transactions', 'Recent transactions (List of last ' + str(
|
||||
conf.user_recent_transaction_limit) + ')'),
|
||||
config.getint('limits', 'user_recent_transaction_limit')) + ')'),
|
||||
('products', f'Which products {user.name} has bought, and how many'),
|
||||
('transactions-all', 'Everything (List of all transactions)')])
|
||||
what = selector.execute()
|
||||
if what == 'transactions':
|
||||
self.print_transactions(user, conf.user_recent_transaction_limit)
|
||||
self.print_transactions(user, config.getint('limits', 'user_recent_transaction_limit'))
|
||||
elif what == 'products':
|
||||
self.print_purchased_products(user)
|
||||
elif what == 'transactions-all':
|
|
@ -0,0 +1,45 @@
|
|||
import re
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import Product, User
|
||||
from dibbler.printer_helpers import print_bar_code, print_name_label
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
||||
|
||||
class PrintLabelMenu(Menu):
|
||||
def __init__(self):
|
||||
Menu.__init__(self, 'Print a label', uses_db=True)
|
||||
self.help_text = '''
|
||||
Prints out a product bar code on the printer
|
||||
|
||||
Put it up somewhere in the vicinity.
|
||||
'''
|
||||
|
||||
def _execute(self):
|
||||
self.print_header()
|
||||
|
||||
thing = self.input_thing('Product/User')
|
||||
|
||||
if isinstance(thing, Product):
|
||||
if re.match(r"^[0-9]{13}$", thing.bar_code):
|
||||
bar_type = "ean13"
|
||||
elif re.match(r"^[0-9]{8}$", thing.bar_code):
|
||||
bar_type = "ean8"
|
||||
else:
|
||||
bar_type = "code39"
|
||||
print_bar_code(
|
||||
thing.bar_code,
|
||||
thing.name,
|
||||
barcode_type=bar_type,
|
||||
rotate=config.getboolean('printer', 'rotate'),
|
||||
printer_type="QL-700",
|
||||
label_type=config.get('printer', 'label_type'),
|
||||
)
|
||||
elif isinstance(thing, User):
|
||||
print_name_label(
|
||||
text=thing.name,
|
||||
label_type=config.get('printer', 'label_type'),
|
||||
rotate=config.getboolean('printer', 'rotate'),
|
||||
printer_type="QL-700"
|
||||
)
|
|
@ -1,10 +1,10 @@
|
|||
import sqlalchemy
|
||||
from db import PurchaseEntry, Product, User
|
||||
from helpers import less
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy import func
|
||||
from statistikkHelpers import statisticsTextOnly
|
||||
from text_interface.helpermenus import Menu
|
||||
from sqlalchemy import desc, func
|
||||
|
||||
from dibbler.helpers import less
|
||||
from dibbler.models.db import PurchaseEntry, Product, User
|
||||
from dibbler.statistikkHelpers import statisticsTextOnly
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
||||
__all__ = ["ProductPopularityMenu", "ProductRevenueMenu", "BalanceMenu", "LoggedStatisticsMenu"]
|
||||
|
||||
|
@ -77,8 +77,8 @@ class BalanceMenu(Menu):
|
|||
for p in product_list:
|
||||
total_value += p.stock * p.price
|
||||
|
||||
total_positive_credit = self.session.query(sqlalchemy.func.sum(User.credit)).filter(User.credit > 0).first()[0]
|
||||
total_negative_credit = self.session.query(sqlalchemy.func.sum(User.credit)).filter(User.credit < 0).first()[0]
|
||||
total_positive_credit = self.session.query(func.sum(User.credit)).filter(User.credit > 0).first()[0]
|
||||
total_negative_credit = self.session.query(func.sum(User.credit)).filter(User.credit < 0).first()[0]
|
||||
|
||||
total_credit = total_positive_credit + total_negative_credit
|
||||
total_balance = total_value - total_credit
|
|
@ -1,15 +1,16 @@
|
|||
from math import ceil, floor
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine, DateTime, Boolean
|
||||
from sqlalchemy.orm import sessionmaker, relationship, backref
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from math import ceil, floor
|
||||
import datetime
|
||||
import conf
|
||||
|
||||
engine = create_engine(conf.db_url)
|
||||
from dibbler.conf import config
|
||||
|
||||
engine = create_engine(config.get('database', 'url'))
|
||||
Base = declarative_base()
|
||||
Session = sessionmaker(bind=engine)
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'users'
|
||||
name = Column(String(10), primary_key=True)
|
|
@ -1,16 +1,13 @@
|
|||
import os
|
||||
import datetime
|
||||
|
||||
import barcode
|
||||
import datetime
|
||||
from PIL import Image
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageFont
|
||||
from brother_ql import BrotherQLRaster
|
||||
from brother_ql import create_label
|
||||
from brother_ql import BrotherQLRaster, create_label
|
||||
from brother_ql.backends import backend_factory
|
||||
from brother_ql.devicedependent import label_type_specs
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
from barcode_helpers import BrotherLabelWriter
|
||||
from .barcode_helpers import BrotherLabelWriter
|
||||
|
||||
|
||||
def print_name_label(text, margin=10, rotate=False, label_type="62", printer_type="QL-700",):
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from dibbler.models.db import *
|
||||
|
||||
def main():
|
||||
# Start an SQL session
|
||||
session=Session()
|
||||
# Let's find all users with a negative credit
|
||||
slabbedasker=session.query(User).filter(User.credit<0).all()
|
||||
|
||||
for slubbert in slabbedasker:
|
||||
print(f"{slubbert.name}, {slubbert.credit}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,203 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
# -*- coding: UTF-8 -*-
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.dates as mdates
|
||||
|
||||
from dibbler.statistikkHelpers import *
|
||||
|
||||
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 getDateFile(date, n):
|
||||
try:
|
||||
if n==0:
|
||||
inp = input('start date? (yyyy-mm-dd) ')
|
||||
elif n==-1:
|
||||
inp = input('end date? (yyyy-mm-dd) ')
|
||||
year = inp.partition('-')
|
||||
month = year[2].partition('-')
|
||||
return datetime.date(int(year[0]), int(month[0]), int(month[2]))
|
||||
except:
|
||||
print('invalid date, setting start start date')
|
||||
if n==0:
|
||||
print('to date found on first line')
|
||||
elif n==-1:
|
||||
print('to date found on last line')
|
||||
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 getProducts(products):
|
||||
product = []
|
||||
products = products.partition('¤')
|
||||
product.append(products[0])
|
||||
while (products[1]=='¤'):
|
||||
products = products[2].partition('¤')
|
||||
product.append(products[0])
|
||||
return product
|
||||
|
||||
|
||||
def piePlot(dictionary, n):
|
||||
keys = []
|
||||
values = []
|
||||
i=0
|
||||
for key in sorted(dictionary, key=dictionary.get, reverse=True):
|
||||
values.append(dictionary[key])
|
||||
if i<n:
|
||||
keys.append(key)
|
||||
i += 1
|
||||
else:
|
||||
keys.append('')
|
||||
plt.pie(values, labels=keys)
|
||||
|
||||
|
||||
def datePlot(array, dateLine):
|
||||
if (not array == []):
|
||||
plt.bar(dateLine, array)
|
||||
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
|
||||
|
||||
def dayPlot(array, days):
|
||||
if (not array == []):
|
||||
for i in range(7):
|
||||
array[i]=array[i]*7.0/days
|
||||
plt.bar(list(range(7)), array)
|
||||
plt.xticks(list(range(7)),[' mon',' tue',' wed',' thu',' fri',' sat',' sun'])
|
||||
|
||||
def graphPlot(array, dateLine):
|
||||
if (not array == []):
|
||||
plt.plot(dateLine, array)
|
||||
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
|
||||
|
||||
|
||||
def plotUser(database, dateLine, user, n):
|
||||
printUser(database, dateLine, user, n)
|
||||
plt.subplot(221)
|
||||
piePlot(database.personVareAntall[user], n)
|
||||
plt.xlabel('antall varer kjøpt gjengitt i antall')
|
||||
plt.subplot(222)
|
||||
datePlot(database.personDatoVerdi[user], dateLine)
|
||||
plt.xlabel('penger brukt over dato')
|
||||
plt.subplot(223)
|
||||
piePlot(database.personVareVerdi[user], n)
|
||||
plt.xlabel('antall varer kjøpt gjengitt i verdi')
|
||||
plt.subplot(224)
|
||||
dayPlot(database.personUkedagVerdi[user], len(dateLine))
|
||||
plt.xlabel('forbruk over ukedager')
|
||||
plt.show()
|
||||
|
||||
|
||||
def plotProduct(database, dateLine, product, n):
|
||||
printProduct(database, dateLine, product, n)
|
||||
plt.subplot(221)
|
||||
piePlot(database.varePersonAntall[product], n)
|
||||
plt.xlabel('personer som har handler produktet')
|
||||
plt.subplot(222)
|
||||
datePlot(database.vareDatoAntall[product], dateLine)
|
||||
plt.xlabel('antall produkter handlet per dag')
|
||||
#plt.subplot(223)
|
||||
plt.subplot(224)
|
||||
dayPlot(database.vareUkedagAntall[product], len(dateLine))
|
||||
plt.xlabel('antall over ukedager')
|
||||
plt.show()
|
||||
|
||||
def plotGlobal(database, dateLine, n):
|
||||
printGlobal(database, dateLine, n)
|
||||
plt.subplot(231)
|
||||
piePlot(database.globalVareVerdi, n)
|
||||
plt.xlabel('varer kjøpt gjengitt som verdi')
|
||||
plt.subplot(232)
|
||||
datePlot(database.globalDatoForbruk, dateLine)
|
||||
plt.xlabel('forbruk over dato')
|
||||
plt.subplot(233)
|
||||
graphPlot(database.pengebeholdning, dateLine)
|
||||
plt.xlabel('pengebeholdning over tid (negativ verdi utgjør samlet kreditt)')
|
||||
plt.subplot(234)
|
||||
piePlot(database.globalPersonForbruk, n)
|
||||
plt.xlabel('penger brukt av personer')
|
||||
plt.subplot(235)
|
||||
dayPlot(database.globalUkedagForbruk, len(dateLine))
|
||||
plt.xlabel('forbruk over ukedager')
|
||||
plt.show()
|
||||
|
||||
|
||||
def alt4menu(database, dateLine, useDatabase):
|
||||
n=10
|
||||
while 1:
|
||||
print('\n1: user-statistics, 2: product-statistics, 3:global-statistics, n: adjust amount of data shown q:quit')
|
||||
try:
|
||||
inp = input('')
|
||||
except:
|
||||
continue
|
||||
if inp == 'q':
|
||||
break
|
||||
elif inp == '1':
|
||||
if i=='0':
|
||||
user = input('input full username: ')
|
||||
else:
|
||||
user = getUser()
|
||||
plotUser(database, dateLine, user, n)
|
||||
elif inp == '2':
|
||||
if i=='0':
|
||||
product = input('input full product name: ')
|
||||
else:
|
||||
product = getProduct()
|
||||
plotProduct(database, dateLine, product, n)
|
||||
elif inp == '3':
|
||||
plotGlobal(database, dateLine, n)
|
||||
elif inp == 'n':
|
||||
try:
|
||||
n=int(input('set number to show '));
|
||||
except:
|
||||
pass
|
||||
|
||||
def main():
|
||||
inputType=getInputType()
|
||||
i = input('0:fil, 1:database \n? ')
|
||||
if (inputType == 1):
|
||||
if i=='0':
|
||||
user = input('input full username: ')
|
||||
else:
|
||||
user = getUser()
|
||||
product = ''
|
||||
elif (inputType == 2):
|
||||
if i=='0':
|
||||
product = input('input full product name: ')
|
||||
else:
|
||||
product = getProduct()
|
||||
user = ''
|
||||
else :
|
||||
product = ''
|
||||
user = ''
|
||||
if i=='0':
|
||||
inputFile=input('logfil? ')
|
||||
if inputFile=='':
|
||||
inputFile='default.dibblerlog'
|
||||
database, dateLine = buildDatabaseFromFile(inputFile, inputType, product, user)
|
||||
else:
|
||||
database, dateLine = buildDatabaseFromDb(inputType, product, user)
|
||||
|
||||
if (inputType==1):
|
||||
plotUser(database, dateLine, user, 10)
|
||||
if (inputType==2):
|
||||
plotProduct(database, dateLine, product, 10)
|
||||
if (inputType==3):
|
||||
plotGlobal(database, dateLine, 10)
|
||||
if (inputType==4):
|
||||
alt4menu(database, dateLine, i)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,11 +1,11 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
import operator
|
||||
from helpers import *
|
||||
import sys
|
||||
import db
|
||||
|
||||
from .helpers import *
|
||||
from .models.db import *;
|
||||
|
||||
def getUser():
|
||||
while 1:
|
|
@ -5,26 +5,36 @@ import random
|
|||
import sys
|
||||
import traceback
|
||||
|
||||
from helpers import *
|
||||
from text_interface.addstock import AddStockMenu
|
||||
from text_interface.buymenu import BuyMenu
|
||||
from text_interface.editing import *
|
||||
from text_interface.faq import FAQMenu
|
||||
from text_interface.helpermenus import Menu
|
||||
from text_interface.mainmenu import MainMenu
|
||||
from text_interface.miscmenus import ProductSearchMenu, TransferMenu, AdjustCreditMenu, UserListMenu, ShowUserMenu, \
|
||||
ProductListMenu
|
||||
from text_interface.printermenu import PrintLabelMenu
|
||||
from text_interface.stats import *
|
||||
from .helpers import *
|
||||
from .menus.addstock import AddStockMenu
|
||||
from .menus.buymenu import BuyMenu
|
||||
from .menus.editing import *
|
||||
from .menus.faq import FAQMenu
|
||||
from .menus.helpermenus import Menu
|
||||
from .menus.mainmenu import MainMenu
|
||||
|
||||
from .menus.miscmenus import (
|
||||
ProductSearchMenu,
|
||||
TransferMenu,
|
||||
AdjustCreditMenu,
|
||||
UserListMenu,
|
||||
ShowUserMenu,
|
||||
ProductListMenu,
|
||||
)
|
||||
|
||||
from .menus.printermenu import PrintLabelMenu
|
||||
from .menus.stats import *
|
||||
|
||||
from .conf import config
|
||||
|
||||
random.seed()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not conf.stop_allowed:
|
||||
def main():
|
||||
if not config.getboolean('general', 'stop_allowed'):
|
||||
signal.signal(signal.SIGQUIT, signal.SIG_IGN)
|
||||
|
||||
if not conf.stop_allowed:
|
||||
if not config.getboolean('general', 'stop_allowed'):
|
||||
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
|
||||
|
||||
main = MainMenu('Dibbler main menu',
|
||||
|
@ -53,7 +63,7 @@ if __name__ == '__main__':
|
|||
],
|
||||
exit_msg='happy happy joy joy',
|
||||
exit_confirm_msg='Really quit Dibbler?')
|
||||
if not conf.quit_allowed:
|
||||
if not config.getboolean('general', 'quit_allowed'):
|
||||
main.exit_disallowed_msg = 'You can check out any time you like, but you can never leave.'
|
||||
while True:
|
||||
# noinspection PyBroadException
|
||||
|
@ -65,8 +75,12 @@ if __name__ == '__main__':
|
|||
except:
|
||||
print('Something went wrong.')
|
||||
print(f'{sys.exc_info()[0]}: {sys.exc_info()[1]}')
|
||||
if conf.show_tracebacks:
|
||||
if config.getboolean('general', 'show_tracebacks'):
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
else:
|
||||
break
|
||||
print('Restarting main menu.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,18 @@
|
|||
[general]
|
||||
quit_allowed = true
|
||||
stop_allowed = false
|
||||
show_tracebacks = true
|
||||
input_encoding = 'utf8'
|
||||
|
||||
[database]
|
||||
url = postgresql://robertem@127.0.0.1/pvvvv
|
||||
|
||||
[limits]
|
||||
low_credit_warning_limit = -100
|
||||
user_recent_transaction_limit = 100
|
||||
|
||||
# See https://pypi.org/project/brother_ql/ for label types
|
||||
# Set rotate to False for endless labels
|
||||
[printer]
|
||||
label_type = "62"
|
||||
label_rotate = false
|
30
flake.lock
30
flake.lock
|
@ -1,12 +1,15 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"lastModified": 1692799911,
|
||||
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -17,11 +20,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1674839022,
|
||||
"narHash": "sha256-8F1U06t9glkgBC8gBfjoA2eeUb9MYRRp6NMKY3c0VEI=",
|
||||
"lastModified": 1693145325,
|
||||
"narHash": "sha256-Gat9xskErH1zOcLjYMhSDBo0JTBZKfGS0xJlIRnj6Rc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "14b6cf7602c341e525a8fe17ac2349769376515e",
|
||||
"rev": "cddebdb60de376c1bdb7a4e6ee3d98355453fe56",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -34,6 +37,21 @@
|
|||
"flake-utils": "flake-utils", |