From fc36d540624efa3d0747e548ac876617f95dcc1d Mon Sep 17 00:00:00 2001 From: Ruzicka Pavel Date: Fri, 29 Dec 2017 18:53:46 +0100 Subject: [PATCH] code import --- README.md | 91 ++++++++++++++++++++++- brmbarsap.py | 102 ++++++++++++++++++++++++++ brmbuy.py | 165 ++++++++++++++++++++++++++++++++++++++++++ brmdon.py | 115 +++++++++++++++++++++++++++++ brmeditstock.py | 160 ++++++++++++++++++++++++++++++++++++++++ brmedituser.py | 178 +++++++++++++++++++++++++++++++++++++++++++++ brmlab.svg | 189 ++++++++++++++++++++++++++++++++++++++++++++++++ brmrec.py | 154 +++++++++++++++++++++++++++++++++++++++ brmstock.py | 125 ++++++++++++++++++++++++++++++++ brmtrans.py | 161 +++++++++++++++++++++++++++++++++++++++++ brmusers.py | 105 +++++++++++++++++++++++++++ fce.py | 186 +++++++++++++++++++++++++++++++++++++++++++++++ reports.sh | 17 +++++ schema.sql | 39 ++++++++++ stats.sh | 14 ++++ stock.sql | 2 + userlog.sh | 5 ++ users.sql | 2 + 18 files changed, 1809 insertions(+), 1 deletion(-) mode change 100644 => 100755 README.md create mode 100755 brmbarsap.py create mode 100755 brmbuy.py create mode 100755 brmdon.py create mode 100755 brmeditstock.py create mode 100755 brmedituser.py create mode 100755 brmlab.svg create mode 100755 brmrec.py create mode 100755 brmstock.py create mode 100755 brmtrans.py create mode 100755 brmusers.py create mode 100755 fce.py create mode 100755 reports.sh create mode 100755 schema.sql create mode 100755 stats.sh create mode 100755 stock.sql create mode 100755 userlog.sh create mode 100755 users.sql diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b8f9b1b..038ccf6 --- a/README.md +++ b/README.md @@ -1 +1,90 @@ -# brmbarSAP +=== BRMBARSAP === + +== INSTALLATION == +0) Install required packages: + sqlite3 + python + pyqt + +1) Create sqlite3 database "brmbar.db" in the brmbarSAP directory: + $ sqlite3 ./brmbar.db < ./schema.sql + $ sqlite3 ./brmbar.db < ./stock.sql + $ sqlite3 ./brmbar.db < ./users.sql + + +== MIGRATION FROM brmbar3 == + +1) Export users from brmbar3 (spaghetti oneliner): + $ echo "SELECT name,crbalance FROM account_balances where acctype='debt';" | psql brmbar | head -n -2 | tail -n +3 | sed -r -e 's/[\ ]*\|[\ ]*/,/g' | sed -e "s/[a-zA-Z0-9-]*,/\'&\'/g" | sed -e "s/''//g" | sed -e "s/'-'/-/g" | sed -e "s/,'/',/g" | sed -e 's/^/INSERT INTO users VALUES (NULL,/g' | sed -e "s/$/,NULL,'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e','');/g" | sqlite3 ./brmbar.db + +2) Fixup: + $ sqlite3 ./brmbar.db "UPDATE users SET code=name;" + +3) Stock migration is not possible (yet) - aspon se udela inventura + +== EXECUTION == + +1) Run "$ python ./brmbarsap.py" + +== DESCRIPTION == + +DB tables: + users - Users defined in the system (some internal only) + stock - Stuff to be bought (some internal only) + barcodes - Barcodes assigned to particular stuff. Each item can have multiple barcodes assigned (1-n relation). + NOTE: Users have their barcodes directly in "users" table (1-1 relation). + transactions - Log of events (changes in user's credit, stock replenishment, bought stuff) + transhuman - Human readable view of "transactions" table + rechuman - Human readable view of "receipts" table + +Files: + README.brm - Read it for more information + + brmbarsap.py - Main application + brmstock.py - List of items in the stock + brmstockedit.py - Stock editor + brmuser.py - List of users + brmuseredit.py - User editor + brmtrans.py - Transfer credit from one user to another - easier way of negative and positive charge + brmdon.py - Donate money to brmlab + brmbuy.py - Consume, then die + brmrec.py - Receipts + fce.py - Common functions and settings + brmbar.db - sqlite3 database + /dev/shm/brmbarsap_msg - Temporary file for internal communication + schema.sql - CREATE TABLE statements + stock.sql - Default stock entries (internal ONLY) + users.sql - Default user entries (internal ONLY) + brmlab.svg - The logo (c)(r)(tm)(brm) + +Scripts around: + userlog.sh USERNAME - Print out daily transaction log for given user + reports.sh - Send daily report to users which have set the email address (add it to your daily-midnight CRON) + stats.sh - Display statistics + +== MICS == + +Backup: + Just copy out the brmbar.db database +Debt limit: + Users can be limited NOT to buy/transfer/donate if their credit is lower than BUY_LIMIT constant (set in fce.py) + To disable the limit, set BUY_LIMIT to insanly low value (like -999999) + Note: negative value means that the user can have DEBT up to that value +Password protection: + Users can set password to prevent unauthorized transactions + To clear password, store value of NULL512 (see fce.py) to appropriate user in "users" table +Negative sell price: + Negative price of items can NOT be set in GUI due to its "accidental enrichment" potential + You can set it manually in the "stock" table +Receipts: + Receipts can be made ONLY if profit is bigger than sum of user's credit to avoid "run on brmbar" situation. + The value of the receipt is added to the responsible user's credit +Overflow accounts: + Overflow accounts are meant for cash holders and basicaly always have negative credit (as they withdrawn money from brmbar). + Such users can withdrawn regardless of BUY_LIMIT and are listed in "brmedituser.py" in the middle of fce "brmStoreUser()". + Sum(-credit) on such accounts is equal to brmbar's disponible money. +Reports: + Users can set an email to which daily reports of their transactions will be sent (add reports.sh to your CRON) + +== TODO == + Scripts around (IRC yelling, backups, ...) diff --git a/brmbarsap.py b/brmbarsap.py new file mode 100755 index 0000000..0e0c3dc --- /dev/null +++ b/brmbarsap.py @@ -0,0 +1,102 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=1 + +app=QApplication(sys.argv) +msg=QLabel("") +t=QTimer() + +def brmStock(): + if DEBUG: print("brmStock") + rc=os.system(str("python ./brmstock.py")) + brmParseRC(rc,msg,t) + return +def brmUsers(): + if DEBUG: print("brmUsers") + rc=os.system(str("python ./brmusers.py")) + brmParseRC(rc,msg,t) + return +def brmBuy(wat=""): + if DEBUG: print("brmBuy: '"+wat+"'") + rc=os.system(str("python ./brmbuy.py '"+wat+"'")) + brmParseRC(rc,msg,t) + return +def brmTransfer(): + if DEBUG: print("brmTransfer") + rc=os.system(str("python ./brmtrans.py")) + brmParseRC(rc,msg,t) + return +def brmDonate(): + if DEBUG: print("brmTansfer") + rc=os.system(str("python ./brmdon.py")) + brmParseRC(rc,msg,t) + return +def brmReceipt(): + if DEBUG: print("brmReceipt") + rc=os.system(str("python ./brmrec.py")) + brmParseRC(rc,msg,t) + return + +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP") +mainWidget.setStyleSheet(STYLE_WIDGET) + +v1=QVBoxLayout() +brmAddButton(v1,"Stock",brmStock) +v1.addStretch(1) +brmAddButton(v1,"Users",brmUsers) + +v2=QVBoxLayout() +v2.addStretch(1) +brmAddButton(v2,"Receipt",brmReceipt) +v2.addStretch(1) + +v3=QVBoxLayout() +brmAddButton(v3,"Transfer",brmTransfer) +v3.addStretch(1) +brmAddButton(v3,"Donation",brmDonate) + +bbox=QHBoxLayout() +bbox.addStretch(1) +bbox.addLayout(v1) +bbox.addStretch(1) +bbox.addLayout(v2) +bbox.addStretch(1) +bbox.addLayout(v3) +bbox.addStretch(1) + +msgbox=QHBoxLayout() +msgbox.addStretch(1) +msg.setStyleSheet(STYLE_MSG) +msgbox.addWidget(msg) +msgbox.addStretch(1) + +hbox=QHBoxLayout() +hbox.addStretch(1) +hlp=QLabel("Buy item by scanning its barcode\n\n" + "Read the buttons and gues what they do :)") +hlp.setStyleSheet(STYLE_HELP) +hbox.addWidget(hlp) +hbox.addStretch(1) + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Welcome in BrmBar!") +screenbox.addLayout(msgbox) +screenbox.addStretch(1) +screenbox.addLayout(hbox) +screenbox.addStretch(3) +screenbox.addLayout(bbox) +screenbox.addStretch(1) +brmAddLine(screenbox,"",'T',STYLE_LE,brmBuy,c=1,foc=1) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +app.exec_() diff --git a/brmbuy.py b/brmbuy.py new file mode 100755 index 0000000..c21e2c4 --- /dev/null +++ b/brmbuy.py @@ -0,0 +1,165 @@ +#!/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +db=sqlite3.connect(BRMDB) +dbc=db.cursor() +dbc.execute("SELECT * FROM stock WHERE id=(" + "SELECT stock FROM barcodes WHERE code='"+brmSatanize(sys.argv[1])+"')" + "LIMIT 1;") +dbrec=dbc.fetchone() +db.close() +if DEBUG: print("DBREC="+str(dbrec)) +if dbrec==None: + sys.exit(EXIT_NOBARCODE) + +app=QApplication(sys.argv) +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - BuyScreen") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmSetAmount(foo=None): + if DEBUG: print("brmSetAmount") + res=mainWidget.findChildren(QLineEdit) + if res[0].text()=="0": + res[0].setStyleSheet(res[0].styleSheet()+STYLE_BADLE) + else: + res[0].setStyleSheet(res[0].styleSheet()+STYLE_OKLE) + QTimer.singleShot(0,res[-1],SLOT('setFocus()')) + +def brmPayCash(dbrec=None,a=None): + ale=a.findChildren(QLineEdit)[0] + le=str(ale.text()) + sum=str(int(le)*int(dbrec[4])) + profit=str(int(sum)-(int(le)*int(dbrec[3]))) + if DEBUG: print("brmPayCash: a="+le+"\n" + " "+str(dbrec[0])) + + if int(le)==0: + ale.setStyleSheet(ale.styleSheet()+STYLE_BADLE) + return + else: + ale.setStyleSheet(ale.styleSheet()+STYLE_OKLE) + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP," + "0,"+str(dbrec[0])+","+le+","+sum+","+profit+");") + dbc.execute("UPDATE stock SET quan=quan-"+le+" WHERE id="+str(dbrec[0])+";") + db.commit() + db.close() + + brmPassMsg("Sold! Put "+str(int(le)*dbrec[4])+" to cashbox") + sys.exit(EXIT_MSG) + +def brmPayMember(dbrec=None,a=None): + ale=a.findChildren(QLineEdit)[0] + le=str(ale.text()) + apswd=a.findChildren(QLineEdit)[1] + pswd=brmSatanize(apswd.text()) + + sum=str(int(le)*int(dbrec[4])) + profit=str(int(sum)-(int(le)*int(dbrec[3]))) + who=brmSatanize((a.findChildren(QLineEdit)[-1]).text()) + if DEBUG: print("brmPayMember: a="+le+" who='"+who+"'\n" + " "+str(dbrec)) + if who=="": # Just enter, ignore + return + if int(le)==0: + ale.setStyleSheet(ale.styleSheet()+STYLE_BADLE) + return + else: + ale.setStyleSheet(ale.styleSheet()+STYLE_OKLE) + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + dbc.execute("SELECT * FROM users WHERE code='"+who+"' LIMIT 1;") + whoid=dbc.fetchone() + if DEBUG: print(" whoid="+str(whoid)) + if whoid==None: + db.close() + apswd.setText("") + return + if hashlib.sha512(pswd).hexdigest()!=whoid[4]: + db.close() + apswd.setText("") + apswd.setStyleSheet(apswd.styleSheet()+STYLE_BADLE) + return + else: + apswd.setStyleSheet(apswd.styleSheet()+STYLE_OKLE) + + if whoid[2]0: # Allow buy negative price (ex. uklid) + db.close() + sys.exit(EXIT_NOCREDIT) + + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP," + " "+str(whoid[0])+","+str(dbrec[0])+","+le+","+sum+","+profit+");") + dbc.execute("UPDATE stock SET quan=quan-"+le+" WHERE id="+str(dbrec[0])+";") + dbc.execute("UPDATE users SET cash=cash-("+sum+") " + "WHERE id='"+str(whoid[0])+"';") + db.commit() + db.close() + + brmPassMsg("'"+brmSatanize(dbrec[1])+"' sold to '"+brmSatanize(whoid[1])+"'") + sys.exit(EXIT_MSG) + + +sbox=QHBoxLayout() +wl=QLabel(brmSatanize(dbrec[1])) +wl.setStyleSheet(STYLE_TEXT) +sbox.addWidget(wl) +sbox.addStretch(1) +wp=QLabel(str(dbrec[4])+" * ") +wp.setStyleSheet(STYLE_TEXT) +sbox.addWidget(wp) +brmAddLine(sbox,"1",'N1',STYLE_LE,brmSetAmount,c=0) + +pbox=QHBoxLayout() +pl=QLabel("Password (if set)") +pl.setStyleSheet(STYLE_TEXT) +pbox.addWidget(pl) +pbox.addStretch(1) +brmAddLine(pbox,"","T",STYLE_LE,lambda:QTimer.singleShot(0, + mainWidget.findChildren(QLineEdit)[-1],SLOT('setFocus()')),c=0) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"Pay by cash",lambda:brmPayCash(dbrec,mainWidget)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +hbox=QHBoxLayout() +hbox.addStretch(1) +hlp=QLabel("Set the required amount you want to buy.\n\n" + "You can either 'Pay by cash', or scan your barcode to pay by credit\n\n" + "Invalid value is indicated by red background color") +hlp.setStyleSheet(STYLE_HELP) +hbox.addWidget(hlp) +hbox.addStretch(1) + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Transaction overview") +screenbox.addStretch(1) +screenbox.addLayout(sbox) +screenbox.addStretch(1) +screenbox.addLayout(pbox) +screenbox.addStretch(1) +screenbox.addLayout(hbox) +screenbox.addStretch(3) +screenbox.addLayout(bbox) +brmAddLine(screenbox,"",'T',STYLE_HIDDEN,lambda:brmPayMember(dbrec,mainWidget)) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +mainWidget.findChildren(QLineEdit)[1].setEchoMode(2) # Password masking + +app.exec_() +sys.exit(EXIT_CANCEL) + diff --git a/brmdon.py b/brmdon.py new file mode 100755 index 0000000..a17b2eb --- /dev/null +++ b/brmdon.py @@ -0,0 +1,115 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +app=QApplication(sys.argv) +mainWidget=QWidget() + +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Donation") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmDonate(mw=None,c=0): + if DEBUG: print("brmDonate") + les=mw.findChildren(QLineEdit) + cash=str(les[0].text()) + pswd=hashlib.sha512(brmSatanize(les[1].text())).hexdigest() + code=brmSatanize(les[-1].text()) + + if cash=="0": + les[0].setStyleSheet(les[0].styleSheet()+STYLE_BADLE) + return + else: + les[0].setStyleSheet(les[0].styleSheet()+STYLE_OKLE) + + if code=="" and c==1: + return # Accidental double-enter + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + if code!="": + dbc.execute("SELECT id,cash,pass FROM users WHERE" + " code='"+code+"' LIMIT 1;") + usr=dbc.fetchone() + if usr==None: + les[-1].setText("") + db.close() + return + if usr[1]<=BUY_LIMIT: + db.close() + sys.exit(EXIT_NOCREDIT) + if usr[2]!=pswd: + db.close() + les[1].setStyleSheet(les[1].styleSheet()+STYLE_BADLE) + return + else: + les[1].setStyleSheet(les[1].styleSheet()+STYLE_OKLE) + + dbc.execute("UPDATE users SET cash=cash-"+cash+" WHERE id="+str(usr[0])+"" + " LIMIT 1;") + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP" + ","+str(usr[0])+",1,1,"+cash+","+cash+");") + else: + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP" + ",0,1,1,"+cash+","+cash+");") + db.commit() + db.close() + + sys.exit(EXIT_DONATION) + +sbox=QHBoxLayout() +al=QLabel("Amount") +al.setStyleSheet(STYLE_TEXT) +sbox.addWidget(al) +sbox.addStretch(1) +brmAddLine(sbox,"0",'N0',STYLE_LE,lambda:QTimer.singleShot(0, + mainWidget.findChildren(QLineEdit)[-1],SLOT('setFocus()')),c=0) + +pbox=QHBoxLayout() +pl=QLabel("User password (if set)") +pl.setStyleSheet(STYLE_TEXT) +pbox.addWidget(pl) +pbox.addStretch(1) +brmAddLine(pbox,"","T",STYLE_LE,lambda:QTimer.singleShot(0, + mainWidget.findChildren(QLineEdit)[-1],SLOT('setFocus()')),c=0) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"Donate cash",lambda:brmDonate(mainWidget,0)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +hbox=QHBoxLayout() +hbox.addStretch(1) +hlp=QLabel("Set the required amount you want to donate to brmlab.\n\n" + "You can either 'Donate cash', or scan your barcode to donate credit\n\n" + "Invalid value is indicated by red background color") +hlp.setStyleSheet(STYLE_HELP) +hbox.addWidget(hlp) +hbox.addStretch(1) + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Donation to brmlab") +screenbox.addStretch(1) +screenbox.addLayout(sbox) +screenbox.addStretch(1) +screenbox.addLayout(pbox) +screenbox.addStretch(1) +screenbox.addLayout(hbox) +screenbox.addStretch(3) +screenbox.addLayout(bbox) +brmAddLine(screenbox,"",'T',STYLE_HIDDEN,lambda:brmDonate(mainWidget,1)) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +mainWidget.findChildren(QLineEdit)[1].setEchoMode(2) # Password masking + +app.exec_() +sys.exit(EXIT_CANCEL) diff --git a/brmeditstock.py b/brmeditstock.py new file mode 100755 index 0000000..d2819ac --- /dev/null +++ b/brmeditstock.py @@ -0,0 +1,160 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +app=QApplication(sys.argv) +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Edit stuff") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmStoreStock(mw=None): + if DEBUG: print("brmStoreStock") + s=mw.findChildren(QLineEdit) + sname=brmSatanize(s[0].text()) + sam=int(s[1].text()) + sbuy=float(s[2].text()) + ssell=float(s[3].text()) + scode=s[4].text() # do NOT satanize! + sid=brmSatanize(s[5].text()) + + if ssell2*sbuy: # Check reasonable profit + s[3].setStyleSheet(s[3].styleSheet()+STYLE_BADLE) + return + else: + s[3].setStyleSheet(s[3].styleSheet()+STYLE_OKLE) + + if sname=="": # Name required + s[0].setStyleSheet(s[0].styleSheet()+STYLE_BADLE) + return + else: + s[0].setStyleSheet(s[0].styleSheet()+STYLE_OKLE) + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + + # Prevent 2 items with same name + dbc.execute("SELECT id FROM stock WHERE name='"+sname+"';") + dbn=dbc.fetchone() + if dbn!=None and str(dbn[0])!=sid: + db.close() + s[0].setStyleSheet(s[0].styleSheet()+STYLE_BADLE) + return + else: + s[0].setStyleSheet(s[0].styleSheet()+STYLE_OKLE) + + if sid=="0": + dbc.execute("INSERT INTO stock VALUES (NULL,'"+sname+"'," + " "+str(sam)+","+str(sbuy)+","+str(ssell)+");") + lst=str(dbc.lastrowid) + else: + dbc.execute("UPDATE stock SET name='"+sname+"'," + "quan=quan+("+str(sam)+"),buyprice="+str(sbuy)+"," + "sellprice="+str(ssell)+" WHERE id="+str(sid)+" LIMIT 1;") + lst=sid + dbc.execute("DELETE FROM barcodes WHERE stock="+sid+";") + + if scode!="": + codes=scode.split(';') + for cde in codes: + dbc.execute("INSERT INTO barcodes VALUES (NULL,"+lst+",'"+str(cde)+"');") + + dbc.execute("INSERT INTO TRANSACTIONS VALUES(NULL,CURRENT_TIMESTAMP,1," + " "+sid+","+str(sam)+","+str(sbuy*sam)+",0);") + + db.commit() + db.close() + brmPassMsg("Stock saved! Take "+str(int(sam*sbuy))+" Kc") + sys.exit(EXIT_MSG) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"Save",lambda:brmStoreStock(mainWidget)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +ename=QHBoxLayout() +ename.addStretch(1) +brmAddLine(ename,brmSatanize(sys.argv[2]),'T',STYLE_LE,None,c=0,foc=0,w=600) +ename.addStretch(1) + +equan=QHBoxLayout() +al=QLabel("Restock (now "+str(int(brmSatanize(sys.argv[3])))+")") +al.setStyleSheet(STYLE_TEXT) +equan.addWidget(al) +equan.addStretch(1) +brmAddLine(equan,"0","N",STYLE_LE,None,c=0,foc=0) + +ebuy=QHBoxLayout() +bl=QLabel("Buy price") +bl.setStyleSheet(STYLE_TEXT) +ebuy.addWidget(bl) +ebuy.addStretch(1) +brmAddLine(ebuy,str(float(brmSatanize(sys.argv[4]))), + "Q+",STYLE_LE,None,c=0,foc=0) + +esell=QHBoxLayout() +sl=QLabel("Sell price") +sl.setStyleSheet(STYLE_TEXT) +esell.addWidget(sl) +esell.addStretch(1) +brmAddLine(esell,str(float(brmSatanize(sys.argv[5]))), + "Q+",STYLE_LE,None,c=0,foc=0) + +ecode=QHBoxLayout() +cl=QLabel("Barcodes") +cl.setStyleSheet(STYLE_TEXT) +ecode.addWidget(cl) +ecode.addStretch(1) +brmAddLine(ecode,"","T",STYLE_LE,None,c=0,foc=0) + +hbox=QHBoxLayout() +hbox.addStretch(1) +hlp=QLabel("Restock existing stuff or enter new one\n\n" + "'Buy price' is the price you want to get back for 1 item\n" + "'Sell price' is the price for which brmbar will sell 1 item\n" + "Set 'Sell' higher than 'Buy price' - give brmbar reasonable profit\n\n" + "Put cursor to 'Barcodes' and scan the barcode of the item\n" + "If there are more different barcodes, split them by ';'\n\n" + "Invalid value is indicated by red background color") +hlp.setStyleSheet(STYLE_HELP) +hbox.addWidget(hlp) +hbox.addStretch(1) + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Edit item") +screenbox.addLayout(ename) +screenbox.addLayout(equan) +screenbox.addLayout(ebuy) +screenbox.addLayout(esell) +screenbox.addLayout(ecode) +screenbox.addStretch(1) +screenbox.addLayout(hbox) +screenbox.addStretch(3) +screenbox.addLayout(bbox) +# Stores ID of the stock or NULL if new stuff - do nothing, button does it +brmAddLine(screenbox,brmSatanize(sys.argv[1]),'T',STYLE_HIDDEN,None) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +levalue4=mainWidget.findChildren(QLineEdit)[4] + +db=sqlite3.connect(BRMDB) +dbc=db.cursor() +for c in dbc.execute("SELECT code FROM barcodes WHERE stock=" + ""+brmSatanize(sys.argv[1])+";"): + if levalue4.text()=="": + levalue4.setText(brmSatanize(str(c[0]))) + else: + levalue4.setText(levalue4.text()+","+brmSatanize(c[0])) +db.close() + +app.exec_() +sys.exit(EXIT_CANCEL) diff --git a/brmedituser.py b/brmedituser.py new file mode 100755 index 0000000..b63c3cd --- /dev/null +++ b/brmedituser.py @@ -0,0 +1,178 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +app=QApplication(sys.argv) +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Edit user") +mainWidget.setStyleSheet(STYLE_WIDGET) + +said=str(int(sys.argv[1])) +san=brmSatanize(sys.argv[2]) +sac=str(float(sys.argv[3])) +sam=brmSatanize(sys.argv[4]) + +def brmStoreUser(mw=None): + if DEBUG: print("brmStoreUser") + + le=mw.findChildren(QLineEdit) + leid=str(le[-1].text()) + lename=brmSatanize(le[0].text()) + lecash=str(le[1].text()) + lepass=hashlib.sha512(brmSatanize(le[2].text())).hexdigest() + lenewpass=hashlib.sha512(brmSatanize(le[3].text())).hexdigest() + lemail=str(le[4].text()) + + if lename=="": + le[0].setStyleSheet(le[0].styleSheet()+STYLE_BADLE) + return + else: + le[0].setStyleSheet(le[0].styleSheet()+STYLE_OKLE) + if lecash=="": + lecash="0" + + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + + # Usename already used? + dbc.execute("SELECT id FROM users WHERE name='"+lename+"';") + cname=dbc.fetchone() + if cname!=None and str(cname[0])!=leid: + db.close() + le[0].setStyleSheet(le[0].styleSheet()+STYLE_BADLE) + return + else: + le[0].setStyleSheet(le[0].styleSheet()+STYLE_OKLE) + + if leid=="0": # New user? + dbc.execute("INSERT INTO users VALUES (NULL,'"+lename+"',"+lecash+"," + "'"+lename+"','"+lenewpass+"','"+lemail+"');") + db.commit() # Sync required before next insert + if lecash!="0": # New credit? + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP," + "(SELECT id FROM users WHERE name='"+lename+"' LIMIT 1)," + "0,1,"+lecash+",0);") + else: # Existing user + dbc.execute("SELECT pass,cash FROM users WHERE id="+leid+" LIMIT 1;") + pswddb=dbc.fetchone() + if lepass!=pswddb[0] and pswddb[0]!=NULL512: + db.close() + le[2].setText("") + le[2].setStyleSheet(le[2].styleSheet()+STYLE_BADLE) + return + else: + le[2].setStyleSheet(le[2].styleSheet()+STYLE_OKLE) + + if lename!="sachy_overflow": # Allow overflowers ignore the limit + if ((int(pswddb[1]) +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/brmrec.py b/brmrec.py new file mode 100755 index 0000000..e9287d8 --- /dev/null +++ b/brmrec.py @@ -0,0 +1,154 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +app=QApplication(sys.argv) +mainWidget=QWidget() + +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Receipt") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmReceipt(mw=None): + if DEBUG:print("brmReceipt") + le=mw.findChildren(QLineEdit) + led=brmSatanize(le[0].text()) + lea=str(int(le[1].text())) + leu=brmSatanize(le[2].text()) + lep=hashlib.sha512(brmSatanize(le[3].text())).hexdigest() + + if led=="": + le[0].setStyleSheet(le[0].styleSheet()+STYLE_BADLE) + return + else: + le[0].setStyleSheet(le[0].styleSheet()+STYLE_OKLE) + if int(lea)<=0: + le[1].setStyleSheet(le[1].styleSheet()+STYLE_BADLE) + return + else: + le[1].setStyleSheet(le[1].styleSheet()+STYLE_OKLE) + if leu=="": + le[2].setStyleSheet(le[2].styleSheet()+STYLE_BADLE) + return + else: + le[2].setStyleSheet(le[2].styleSheet()+STYLE_OKLE) + + + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + dbc.execute("SELECT id,pass,name FROM users WHERE code='"+leu+"' LIMIT 1;") + usr=dbc.fetchone() + if DEBUG:print(" "+str(usr)) + if usr==None: + db.close() + le[2].setStyleSheet(le[2].styleSheet()+STYLE_BADLE) + return + else: + le[2].setStyleSheet(le[2].styleSheet()+STYLE_OKLE) + if usr[1]!=lep: + db.close() + le[3].setText("") + le[3].setStyleSheet(le[3].styleSheet()+STYLE_BADLE) + return + else: + le[3].setStyleSheet(le[3].styleSheet()+STYLE_OKLE) + + dbc.execute("SELECT (SELECT sum(profit) FROM transactions WHERE what=1)-" + "(SELECT sum(cash) FROM users WHERE id>1);") + ac=dbc.fetchone() + if ac==None or float(ac[0])<1: + db.close() + brmPassMsg("No available money to spend") + sys.exit(EXIT_MSG) + + if float(ac[0]) New stuff + # code="xyz" -> Edit existing stuff + if code=="": + usr=[0,"Stuff",0,0,0] + else: + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + if id!=None: # If ID is known, use it + dbc.execute("SELECT * FROM stock WHERE id="+str(int(id))+" LIMIT 1;") + else: # If code is known, use it + dbc.execute("SELECT * FROM stock WHERE id=(" + "SELECT stock FROM barcodes WHERE code='"+code+"' LIMIT 1) " + "LIMIT 1;") + usr=dbc.fetchone() + db.close() + if usr==None: + return + if DEBUG: print(" "+str(usr)) + + rc=os.system(str("python ./brmeditstock.py " + "'"+str(usr[0])+"' " + "'"+brmSatanize(usr[1])+"' " + "'"+str(usr[2])+"' " + "'"+str(usr[3])+"' " + "'"+str(usr[4])+"'")) + brmParseRC(rc,msg,t,foc=le) + print("aaaaaaa") + (mw.findChildren(QLineEdit)[-1]).setFocus(True) +# sys.exit(rc>>8) + +def brmAddListLayout(p=None,wat=None): + if DEBUG: print("brmAddListLayout: '"+str(wat)+"'") + line=QHBoxLayout() + if wat==None: + nif=QLabel("No items found!") + nif.setStyleSheet(STYLE_TEXT) + line.addWidget(nif) + else: + brmAddButton(line,brmSatanize(wat[1]), + lambda:brmEditStock(mainWidget,str(wat[3]),str(wat[0]),mainWidget), + s="margin-left:100px;") + line.addStretch(1) + pl=QLabel(str(wat[4])+" Kc; #"+str(wat[2])) + pl.setStyleSheet(STYLE_TEXT+"margin-right:100px;") + line.addWidget(pl) + p.addLayout(line) + +msgbox=QHBoxLayout() +msgbox.addStretch(1) +msg.setStyleSheet(STYLE_MSG) +msg.setFocusPolicy(0) +msgbox.addWidget(msg) +msgbox.addStretch(1) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"New stuff",lambda:brmEditStock(None,None,None,mainWidget)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +db=sqlite3.connect(BRMDB) +dbc=db.cursor() +# id=0 -> Charge credit +# id=1 -> Donation +dbusr=dbc.execute("SELECT * FROM stock WHERE id>1 ORDER BY name ASC;") + +sbox=QScrollArea() +sbox.setWidgetResizable(True) +sbox.setFocusPolicy(0) +sboxList=QWidget(sbox) +sboxList.setFocusPolicy(0) +sboxLayout=QVBoxLayout(sboxList) +sboxList.setLayout(sboxLayout) +for row in dbusr: + brmAddListLayout(sboxLayout,row) +sbox.setWidget(sboxList) +sbox.setStyleSheet(sbox.styleSheet()+"max-width:1200px") +db.close() # Must be closed AFTER the list is completed + + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Stock") +screenbox.addLayout(msgbox) +screenbox.addWidget(sbox) +screenbox.addLayout(bbox) +brmAddLine(screenbox,"",'T',STYLE_HIDDEN, + lambda:brmEditStock(mainWidget,None,None,mainWidget),foc=1) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + + + +app.exec_() +sys.exit(EXIT_CANCEL) diff --git a/brmtrans.py b/brmtrans.py new file mode 100755 index 0000000..25bc224 --- /dev/null +++ b/brmtrans.py @@ -0,0 +1,161 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +scb="Scan barcode now" + +app=QApplication(sys.argv) +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Transfer credit") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmTransfer(mw=None): + if DEBUG: print("brmTransfer") + lbls=mw.findChildren(QLabel) + fr=lbls[-5] + to=lbls[-2] + le=mw.findChildren(QLineEdit) + pswd=hashlib.sha512(brmSatanize(le[0].text())).hexdigest() + amount=str(le[1].text()) + + if amount=="0": + le[1].setStyleSheet(le[1].styleSheet()+STYLE_BADLE) + return + else: + le[1].setStyleSheet(le[1].styleSheet()+STYLE_OKLE) + + # users set? + if fr.text()==to.text() or fr.text()[0]=="<" or to.text()[0]=="<": + return + + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + dbc.execute("SELECT id,cash,pass FROM users WHERE" + " name='"+brmSatanize(fr.text())+"' LIMIT 1;") + frdb=dbc.fetchone() + if DEBUG: print(" "+str(frdb)) + + if frdb[1]<=BUY_LIMIT: + db.close() + sys.exit(EXIT_NOCREDIT) + if frdb[2]!=pswd: + db.close() + le[0].setStyleSheet(le[0].styleSheet()+STYLE_BADLE) + le[0].setText("") + return + else: + le[0].setStyleSheet(le[0].styleSheet()+STYLE_OKLE) + + dbc.execute("UPDATE users SET cash=cash-("+amount+") WHERE" + " name='"+brmSatanize(fr.text())+"' LIMIT 1;") + dbc.execute("UPDATE users SET cash=cash+("+amount+") WHERE" + " name='"+brmSatanize(to.text())+"' LIMIT 1;") + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP," + "(SELECT id FROM users WHERE name='"+str(fr.text())+"' LIMIT 1),0,1," + "-("+amount+"),0);") + dbc.execute("INSERT INTO transactions VALUES (NULL,CURRENT_TIMESTAMP," + "(SELECT id FROM users WHERE name='"+str(to.text())+"' LIMIT 1),0,1," + "+("+amount+"),0);") + db.commit() + db.close() + sys.exit(EXIT_TRANSFERRED) + + +def brmSetWho(val=""): + if DEBUG: print("brmSetWho: code='"+val+"'") + #le=mainWidget.findChildren(QLineEdit)[-1] + if val=="": + return + + lbls=mainWidget.findChildren(QLabel) + fr=lbls[-5] + to=lbls[-2] + + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + dbc.execute("SELECT name FROM users WHERE code='"+brmSatanize(val)+"" + "' LIMIT 1;") + rec=dbc.fetchone() + + if DEBUG: print(" "+str(rec)) + if rec==None: + return + print(" "+fr.text()) + if fr.text()==scb: + fr.setText(brmSatanize(rec[0])) + to.setText(scb) + else: + to.setText(brmSatanize(rec[0])) + db.close() + + +fbox=QHBoxLayout() +cf=QLabel("Credit from:") +cf.setStyleSheet(STYLE_TEXT) +fbox.addWidget(cf) +fbox.addStretch(1) +cf2=QLabel(scb) +cf2.setStyleSheet(STYLE_MSG+"margin-right:100px;") +fbox.addWidget(cf2) + +pbox=QHBoxLayout() +pl=QLabel("Password (if set)") +pl.setStyleSheet(STYLE_TEXT) +pbox.addWidget(pl) +pbox.addStretch(1) +brmAddLine(pbox,"",'T',STYLE_LE, + lambda:QTimer.singleShot(0,mainWidget.findChildren(QLineEdit)[-1], + SLOT('setFocus()')),c=0) + +tbox=QHBoxLayout() +ct=QLabel("Credit to:") +ct.setStyleSheet(STYLE_TEXT) +tbox.addWidget(ct) +tbox.addStretch(1) +ct2=QLabel("") +ct2.setStyleSheet(STYLE_MSG+"margin-right:100px;") +tbox.addWidget(ct2) + +cbox=QHBoxLayout() +al=QLabel("Amount:") +al.setStyleSheet(STYLE_TEXT) +cbox.addWidget(al) +cbox.addStretch(1) +brmAddLine(cbox,"0","N1",STYLE_LE, + lambda:QTimer.singleShot(0,mainWidget.findChildren(QLineEdit)[-1], + SLOT('setFocus()')),c=0) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"Transfer",lambda:brmTransfer(mainWidget)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Transfer credit") +screenbox.addStretch(1) +screenbox.addLayout(fbox) +screenbox.addLayout(pbox) +screenbox.addStretch(1) +screenbox.addLayout(tbox) +screenbox.addStretch(1) +screenbox.addLayout(cbox) +screenbox.addStretch(5) +screenbox.addLayout(bbox) +brmAddLine(screenbox,"",'T',STYLE_HIDDEN,brmSetWho) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +mainWidget.findChildren(QLineEdit)[0].setEchoMode(2) # Password masking + +app.exec_() +sys.exit(EXIT_CANCEL) diff --git a/brmusers.py b/brmusers.py new file mode 100755 index 0000000..6ffa85a --- /dev/null +++ b/brmusers.py @@ -0,0 +1,105 @@ +#!/usr/bin/python + +import sys +import sqlite3 +from fce import * +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +DEBUG=0 + +app=QApplication(sys.argv) +mainWidget=QWidget() +mainWidget.resize(1280,1024) +mainWidget.setWindowTitle("BrmbarSAP - Manage users") +mainWidget.setStyleSheet(STYLE_WIDGET) + +def brmEditUser(widget=None,code=None,id=None): + if code==None: # Invoked from scanner? + if widget==None: # Actually... new user? + code="" + else: + code=brmSatanize((widget.findChildren(QLineEdit)[0]).text()) + if DEBUG: print("brmEditUser code="+str(code)) + if code==None: # scanner passed EOL only (no data) + return + # code="" -> New user + # code="xyz" -> Edit existing user + + if code=="": + usr=[0,"New user",0,""] + else: + db=sqlite3.connect(BRMDB) + dbc=db.cursor() + if id!=None: # If ID is known, use it + dbc.execute("SELECT id,name,cash,mail FROM users " + "WHERE id="+str(int(id))+" LIMIT 1;") + else: + dbc.execute("SELECT id,name,cash,mail FROM users " + "WHERE code='"+code+"' LIMIT 1;") + usr=dbc.fetchone() + db.close() + if usr==None: + return + if DEBUG: print(" "+str(usr)) + rc=os.system(str("python ./brmedituser.py " + "'"+str(int(usr[0]))+"' " + "'"+brmSatanize(usr[1])+"' " + "'"+str(float(usr[2]))+"' " + "'"+brmSatanize(usr[3])+"'")) + sys.exit(rc>>8) + +def brmAddListLayout(p=None,wat=None): + if DEBUG: print("brmAddListLayout: '"+str(wat)+"'") + line=QHBoxLayout() + if wat==None: + nu=QLabel("No users found!") + nu.setStyleSheet(STYLE_TEXT) + line.addWidget(nu) + else: + brmAddButton(line,brmSatanize(wat[1]), + lambda:brmEditUser(mainWidget,str(wat[3]),str(wat[0])), + s="margin-left:100px;") + line.addStretch(1) + cl=QLabel(str(float(wat[2]))) + cl.setStyleSheet(STYLE_TEXT+"margin-right:100px;") + line.addWidget(cl) + p.addLayout(line) + +bbox=QHBoxLayout() +bbox.addStretch(1) +brmAddButton(bbox,"New user",lambda:brmEditUser(None,None,None)) +bbox.addStretch(1) +brmAddButton(bbox,"Cancel",lambda:sys.exit(EXIT_CANCEL)) +bbox.addStretch(1) + +db=sqlite3.connect(BRMDB) +dbc=db.cursor() +# Ignore "Cash" and "Replenishment" users (internal only) +dbusr=dbc.execute("SELECT * FROM users WHERE id>1 ORDER BY name ASC;") + +sbox=QScrollArea() +sbox.setWidgetResizable(True) +sbox.setFocusPolicy(0) +sboxList=QWidget(sbox) +sboxList.setFocusPolicy(0) +sboxLayout=QVBoxLayout(sboxList) +sboxList.setLayout(sboxLayout) +for row in dbusr: + brmAddListLayout(sboxLayout,row) +sbox.setWidget(sboxList) +db.close() # Must be closed AFTER the list is completed + +screenbox=QVBoxLayout() +brmLabelBox(screenbox,"Users") +screenbox.addWidget(sbox) +screenbox.addLayout(bbox) +brmAddLine(screenbox,"",'T',STYLE_HIDDEN, + lambda:brmEditUser(mainWidget,None,None)) + +mainWidget.setLayout(screenbox) +mainWidget.showFullScreen() + +app.exec_() + +sys.exit(EXIT_CANCEL) diff --git a/fce.py b/fce.py new file mode 100755 index 0000000..d39b49e --- /dev/null +++ b/fce.py @@ -0,0 +1,186 @@ +import os +import sys +import sqlite3 +import hashlib +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.QtSvg import * +from datetime import datetime + +STYLE_BTN=("background-color:rgba(0,0,0,100);color:yellow;font-size:48px;" + "border: 1px solid #217777;padding:5px;") +#STYLE_DESC="color:green;font-size:48px" +STYLE_LABEL="color:green;font-size:64px;" +STYLE_LE=("background-color:white;color:black;font-size:48px;" + "margin-right:100px;") +STYLE_BADLE="background-color:red;" # Invalid data indicator +STYLE_OKLE="background-color:white;" # Fixed data indicator +#STYLE_ITEM="color:white;font-size:64px" +STYLE_HIDDEN="background-color:rgba(0,0,0,255);color:white;" #rgba(0,0,0,255);" +STYLE_WIDGET="background-color:black;color:white;" +STYLE_MSG="background-color:black;color:yellow;font-size:32px;" +STYLE_TEXT=("background-color:black;color:white;font-size:48px;" + "margin-left:100px;") +STYLE_HELP=("background-color:black;color:#217777;font-size:32px;") + + +EXIT_OK=0 +EXIT_CANCEL=1 +EXIT_MSG=2 +EXIT_NOBARCODE=3 +EXIT_NOCREDIT=4 +EXIT_USER=5 +EXIT_STOCKSAVED=6 +EXIT_TRANSFERRED=7 +EXIT_DONATION=8 + +MSGS=["Done!", + "Transaction cancelled", + "", # Reserved for external msg + "Unknown barcode", + "FAIL! Credit too low\nPlease recharge", + "User saved", + "Stock saved", + "Credit transferred", + "Thanks for the donation!"] +MSGFILE="/dev/shm/brmbarsap_msg" + +BRMDB="./brmbar.db" + +BUY_LIMIT=-200 + +# hashlib.sha512(brmSatanize("")).hexdigest() +NULL512=("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce" + "9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") + +DEBUG=1 + +# ==================================================================== + +def brmParseRC(rc=0,msg=None,t=None,foc=None): + # Magic ahead: + # The Return Code is 16bit integer but we need only the HIGH byte + rc=rc>>8 + if DEBUG: print("brmParseRC="+str(rc)+"='"+MSGS[rc]+"'") + if rc==EXIT_MSG: + fr=open(MSGFILE,"r") + fmsg=fr.readline() + if DEBUG: print(" FILEMSG: '"+fmsg+"'") + msg.setText(fmsg) + fr.close() + os.remove(MSGFILE) + else: + msg.setText(MSGS[rc]) + t.start(5000) + t.timeout.connect(lambda:msg.setText("")) + if foc!=None: + if DEBUG:print(str(foc)) + QTimer.singleShot(0,foc,SLOT('setFocus()')) + return + +# Sanitize string +def brmSatanize(s=""): + ss="" + sss="" + try: + ss=s.toAscii() + except: + for c in s: + ss=ss+c.encode("ascii","ignore") + + for c in ss: + if ord(c) > 31 and ord(c) < 127: + sss=sss+c + ss=sss + ss=ss.replace("'","") + ss=ss.replace("\"","") + ss=ss.replace(";","") + ss=ss.replace("`","") + ss=ss.replace("<","") + ss=ss.replace(">","") + ss=ss.replace("$(","$ (") + if DEBUG: print("brmSatanize:\n "+ss) + return str(ss); + +# Clear Lineedit And Pass +def brmCLAP(le=None,f=None,c=1,foc=1): + if DEBUG: print("brmCLAP") + a=le.text() + if c==1: + le.setText("") + try: + f(a) + except: # Revert the value + le.setText(a) + f() + if c==1: + le.setText("") + if foc==1: + QTimer.singleShot(0,le,SLOT('setFocus()')) + le.setFocus(True) + +timetimer=QTimer() +def brmLabelBox(p=None,lbl=""): + if DEBUG: print("brmLabelBox: '"+lbl+"'") + b=QHBoxLayout() + b.addWidget(QSvgWidget("./brmlab.svg")) + b.addStretch(1) + b.addWidget(QLabel(""+lbl+"")) + b.addStretch(1) + timetext=("" + ""+datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M:%S')+"") + timewidget=QLabel(timetext) + timetimer.timeout.connect( + lambda:timewidget.setText("" + ""+datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M:%S')+"")) + timetimer.start(1000) + b.addWidget(timewidget) + p.addLayout(b) +def brmAddButton(p=None,lbl="",f=exit,w=0,s=""): + if DEBUG: print("addBrmButton: '"+lbl+"'") + butt=QPushButton(lbl) + if int(w)>0: + butt.setStyleSheet(STYLE_BTN+s+"text-align:left;" + "width:"+str(int(w))+"px;max-width:"+str(int(w))+"px;") + else: + butt.setStyleSheet(STYLE_BTN+s) + butt.connect(butt,SIGNAL('pressed()'),f) + butt.setAutoDefault(0) + butt.setFocusPolicy(0) + p.addWidget(butt) + +def brmAddLine(p=None,lbl="",r='T',s="",f=exit,w=200,c=1,foc=1): + if DEBUG: print("addBrmLine: '"+str(lbl)+"'") + l=QLineEdit(str(lbl)) + l.setStyleSheet(s+"width:"+str(w)+"px;max-width:"+str(w)+"px;") + +# if r=="T": +# l.setValidator(QRegExpValidator(QRegExp("^[\d\s\w]*$"))) + if r=="Q": + l.setValidator(QRegExpValidator(QRegExp("^-?[0-9]{1,5}(\.[0-9]{1,2})?$"))) + if r=="Q+": + l.setValidator(QRegExpValidator(QRegExp("^[0-9]{1,5}(\.[0-9]{0,2})?$"))) + if r=="N": +# l.setValidator(QIntValidator(-100000,100000)) + l.setValidator(QRegExpValidator(QRegExp("^-?[0-9]{1,5}$"))) + if r=="N1": +# l.setValidator(QIntValidator(1,100000)) + l.setValidator(QRegExpValidator(QRegExp("^[1-9]{1}[0-9]{0,4}$"))) + if r=="N0": +# l.setValidator(QIntValidator(0,100000)) + l.setValidator(QRegExpValidator(QRegExp("^[0-9]{1,5}$"))) + if r=="M": + l.setValidator(QRegExpValidator( + QRegExp("^[0-9A-Za-z\._-]{1,}@[0-9a-zA-Z\._-{1,}\.[a-zA-Z0-9]{1,}$"))) + + l.connect(l,SIGNAL('returnPressed()'),lambda:brmCLAP(l,f,c,foc)) + if s==STYLE_HIDDEN: + l.setFocusPolicy(Qt.StrongFocus) + QTimer.singleShot(0,l,SLOT('setFocus()')) + p.addWidget(l) + +def brmPassMsg(s=""): + fw=open(MSGFILE,"w") + fw.write(s) + fw.close() + diff --git a/reports.sh b/reports.sh new file mode 100755 index 0000000..577a37f --- /dev/null +++ b/reports.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Send reports to all users with filled mail (from last midnight) + +db="./brmbar.db" + +usr=$(echo "SELECT name FROM users where mail!='';" | sqlite3 $db) + +for u in $usr +do + m=$(echo "SELECT mail FROM users where name='"$u"';" | sqlite3 $db) + l=$(echo ".headers on +SELECT * FROM transhuman WHERE strftime('%Y-%m-%d',age)=date('now','localtime') AND user='$u';" | sqlite3 $db) + + if [ -n "$l" ]; then + echo "$l" | mail -s "brmbar report" "$m" + fi +done diff --git a/schema.sql b/schema.sql new file mode 100755 index 0000000..99f3f6f --- /dev/null +++ b/schema.sql @@ -0,0 +1,39 @@ +CREATE TABLE stock ( + id INTEGER PRIMARY KEY ON CONFLICT IGNORE AUTOINCREMENT, + name TEXT DEFAULT 'Junkfood', + quan INTEGER DEFAULT 0, + buyprice FLOAT DEFAULT 0, + sellprice FLOAT DEFAULT 1); + +CREATE TABLE users ( + id INTEGER PRIMARY KEY ON CONFLICT IGNORE AUTOINCREMENT, + name TEXT NOT NULL DEFAULT 'Muaddib', + cash REAL DEFAULT 0, + code INTEGER DEFAULT 0, + pass TEXT DEFAULT NULL, + mail TEXT DEFAULT NULL); + +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + age TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, + who INTEGER DEFAULT 0, + what INTEGER DEFAULT 0, + amount INTEGER DEFAULT 0, + cash INTEGER DEFAULT 0, + profit INTEGER DEFAULT 0); + +CREATE TABLE barcodes ( + id INTEGER PRIMARY KEY ON CONFLICT IGNORE AUTOINCREMENT, + stock INTEGER DEFAULT 0, + code INTEGER DEFAULT 0); + +CREATE TABLE receipts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tid INTEGER DEFAULT 0, + comment TEXT DEFAULT NULL); + +CREATE VIEW transhuman AS SELECT transactions.id AS tid,age,users.name AS user,stock.name AS stuff,amount,transactions.cash AS price,profit FROM transactions,users,stock WHERE transactions.who=users.id AND transactions.what=stock.id ORDER BY transactions.id DESC; + +CREATE VIEW rechuman AS SELECT receipts.id AS rid, transactions.age AS happened, transactions.cash AS price, users.name AS responsible, comment FROM transactions,users,receipts WHERE transactions.who=users.id AND receipts.tid=transactions.id ORDER BY happened DESC; + + diff --git a/stats.sh b/stats.sh new file mode 100755 index 0000000..41412ea --- /dev/null +++ b/stats.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Display various stats from brmbar + +DB="./brmbar.db" + +overflow=$(echo "SELECT sum(cash)*(-1) FROM users WHERE name like '%overflow';" | sqlite3 $DB) +cash=$(echo "SELECT (SELECT sum(profit) FROM transactions)-($overflow);" | sqlite3 $DB) +inv=$(echo "SELECT sum(quan*buyprice) FROM stock;" | sqlite3 $DB) +mate=$(echo "SELECT sum(amount) FROM transhuman WHERE strftime('%Y-%m-%d',age)=date('now','localtime') AND (stuff like '%mate%' OR stuff like '%Mate%');" | sqlite3 $DB) + +echo "Overflow: $overflow" +echo "Cash: $cash" +echo "Inventory: $inv" +echo "Clubmate sold today: $mate bottles" diff --git a/stock.sql b/stock.sql new file mode 100755 index 0000000..3ff1e51 --- /dev/null +++ b/stock.sql @@ -0,0 +1,2 @@ +INSERT INTO stock VALUES(0,'Charge credit',0,0.0,0.0); +INSERT INTO stock VALUES(1,'Donation',0,0.0,0.0); diff --git a/userlog.sh b/userlog.sh new file mode 100755 index 0000000..5850e4b --- /dev/null +++ b/userlog.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Print out the log for specified user from last midnight + +echo ".headers on +SELECT * FROM transhuman WHERE strftime('%Y-%m-%d',age)=date('now','localtime') AND user='$1';" | sqlite3 ./brmbar.db diff --git a/users.sql b/users.sql new file mode 100755 index 0000000..932a82e --- /dev/null +++ b/users.sql @@ -0,0 +1,2 @@ +INSERT INTO users VALUES(0,'Cash',0.0,'','',''); +INSERT INTO users VALUES(1,'Replenishment',0.0,'','','');