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,'','','');