diff --git a/.gitignore b/.gitignore index 3268211..9eccd17 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .*.sw? +*~ diff --git a/brmbar3/.gitignore b/brmbar3/.gitignore index bee8a64..4a5b2ab 100644 --- a/brmbar3/.gitignore +++ b/brmbar3/.gitignore @@ -1 +1,3 @@ __pycache__ +*.log +brmbar/*.pyc diff --git a/brmbar3/PURGE.txt b/brmbar3/PURGE.txt new file mode 100644 index 0000000..c5e5b30 --- /dev/null +++ b/brmbar3/PURGE.txt @@ -0,0 +1,64 @@ +How to "reset" the database - drop all history and keep only accounts with non-zero balance. + +Legend: +> - SQL commands +$ - shell commands + +Run the (full) inventory. + +Get number of the first inventory TX. + +> select id from account_balances where id in (select id from accounts where currency not in (select distinct currency from + transaction_nicesplits where transaction >= NUMBER_HERE and currency != 1 and memo like '%Inventory fix%') and acctype = 'inventory') and crbalance != 0 \g 'vynulovat' +$ ./brmbar-cli.py inventory `cat vynulovat | while read x; do echo $x 0; done` + +Backup the database +$ pg_dump brmbar > backup.sql + +Dump "> SELECT * FROM account_balances;" to file N. + +Dump inventory to file nastavit FIXME. + +Drop all transactions: +> delete from transaction_splits; +> delete from transactions; + +Restore inventory: +$ cat nastavit | while read acc p amt; do ./brmbar-cli.py inventory $acc `echo $amt | grep -oE "^[0-9-]+"`; done + +Restore cash balance: +$ cat N | grep debt | tr -s " " |cut -d \| -f 2,4 | while read acc p amt; do ./brmbar-cli.py changecredit $acc `echo $amt | grep -oE "^[0-9-]+"`; done + +Delete zero-balance accounts: +> delete from accounts where accounts.id not in (select id from account_balances); + +Delete orphaned barcodes: +> delete from barcodes where barcodes.account not in (select id from account_balances); + +Delete orphaned currencies and exchange rates: +> CREATE OR REPLACE VIEW "a_tmp" AS +SELECT ts.account AS id, accounts.name, accounts.acctype, accounts.currency AS fff, (- sum(CASE WHEN (ts.side = 'credit'::transaction_split_side) THEN (- ts.amount) ELSE ts.amount END)) AS crbalance FROM (transaction_splits ts LEFT JOIN accounts ON ((accounts.id = ts.account))) GROUP BY ts.account, accounts.name, accounts.id, accounts.acctype ORDER BY (- sum(CASE WHEN (ts.side = 'credit'::transaction_split_side) THEN (- ts.amount) ELSE ts.amount END)); + +> delete from exchange_rates where source not in (select fff from a_tmp); +> delete from currencies where id not in (select fff from a_tmp); + +> DROP VIEW "a_tmp"; + +Drop obsolete exchange rates: + +> delete from exchange_rates where + valid_since <> (SELECT max(valid_since) + FROM exchange_rates e + WHERE e.target = exchange_rates.target and e.source = exchange_rates.source) + +Restore system accounts: +> INSERT INTO "accounts" ("name", "currency", "acctype", "active") + VALUES ('BrmBar Profits', '1', 'income', '1'); +> INSERT INTO "accounts" ("name", "currency", "acctype", "active") + VALUES ('BrmBar Excess', '1', 'income', '1'); +> INSERT INTO "accounts" ("name", "currency", "acctype", "active") + VALUES ('BrmBar Deficit', '1', 'expense', '1'); +> INSERT INTO "accounts" ("name", "currency", "acctype", "active") + VALUES ('BrmBar Cash', '1', 'cash', '1'); + +Restart brmbar. diff --git a/brmbar3/SQL b/brmbar3/SQL index 7e640a6..a61dba8 100644 --- a/brmbar3/SQL +++ b/brmbar3/SQL @@ -107,10 +107,9 @@ CREATE VIEW transaction_nicesplits AS FROM transaction_splits AS ts LEFT JOIN accounts AS a ON a.id = ts.account ORDER BY ts.id; --- List transactions with summary information regarding their cash element --- (except in case of transfers between cash and debt accounts, which will cancel out). +-- List transactions with summary information regarding their cash element. CREATE VIEW transaction_cashsums AS - SELECT t.id AS id, t.time AS time, SUM(credit_cash) AS cash_credit, SUM(debit_cash) AS cash_debit, t.description AS description + SELECT t.id AS id, t.time AS time, SUM(credit_cash) AS cash_credit, SUM(debit_cash) AS cash_debit, a.name AS responsible, t.description AS description FROM transactions AS t LEFT JOIN (SELECT cts.amount AS credit_cash, cts.transaction AS cts_t FROM transaction_nicesplits AS cts @@ -124,4 +123,5 @@ CREATE VIEW transaction_cashsums AS WHERE a.currency = (SELECT currency FROM accounts WHERE name = 'BrmBar Cash') AND a.acctype IN ('cash', 'debt') AND dts.amount > 0) debit ON dts_t = t.id - GROUP BY t.id ORDER BY t.id; + LEFT JOIN accounts AS a ON a.id = t.responsible + GROUP BY t.id, a.name ORDER BY t.id DESC; diff --git a/brmbar3/USEFUL.txt b/brmbar3/USEFUL.txt new file mode 100644 index 0000000..11c0071 --- /dev/null +++ b/brmbar3/USEFUL.txt @@ -0,0 +1,8 @@ +Accounts with multiple barcodes: + +SELECT accounts.name,barcodes.account,barcodes.barcode +FROM "barcodes" +join accounts on accounts.id = barcodes.account +where barcodes.account in (select a from (select count(*) as c, account as a from barcodes group by account) as dt where c > 1) +ORDER BY "account" DESC + diff --git a/brmbar3/autostock.py b/brmbar3/autostock.py new file mode 100755 index 0000000..0e8afac --- /dev/null +++ b/brmbar3/autostock.py @@ -0,0 +1,42 @@ +#! /usr/bin/env python3 + +import argparse +import brmbar +import math +from brmbar import Database + +def main(): + parser = argparse.ArgumentParser(usage = "File format: EAN amount total_price name, e.g. 4001242002377 6 167.40 Chio Tortillas") + parser.add_argument("filename") + args = parser.parse_args() + + db = Database.Database("dbname=brmbar") + shop = brmbar.Shop.new_with_defaults(db) + currency = shop.currency + + # ... + total = 0 + with open(args.filename) as fin: + for line in fin: + split = line.split(" ") + ean, amount, price_total, name = split[0], int(split[1]), float(split[2]), " ".join(split[3:]) + name = name.strip() + + price_buy = price_total / amount + acct = brmbar.Account.load_by_barcode(db, ean) + if not acct: + print("Creating account for EAN {} '{}'".format(ean, name)) + invcurr = brmbar.Currency.create(db, name) + acct = brmbar.Account.create(db, name, invcurr, "inventory") + acct.add_barcode(ean) + price_sell = max(math.ceil(price_buy * 1.15), price_buy) + acct.currency.update_sell_rate(currency, price_sell) + acct.currency.update_buy_rate(currency, price_buy) + cash = shop.buy_for_cash(acct, amount) + total += cash + print("Increased by {}, take {} from cashbox".format(amount, cash)) + print("Total is {}".format(total)) + +if __name__ == "__main__": + main() + diff --git a/brmbar3/brmbar-cli.py b/brmbar3/brmbar-cli.py index 4ad26ab..cc5c6e3 100755 --- a/brmbar3/brmbar-cli.py +++ b/brmbar3/brmbar-cli.py @@ -97,6 +97,12 @@ def load_item(inp): exit(1) return acct +def load_item_by_barcode(inp): + acct = brmbar.Account.load_by_barcode(db, inp) + if acct.acctype != "inventory": + print("Bad EAN " + inp + " type " + acct.acctype, file=sys.stderr) + exit(1) + return acct db = Database.Database("dbname=brmbar") shop = brmbar.Shop.new_with_defaults(db) @@ -147,9 +153,9 @@ elif sys.argv[1] == "userlog": acct = load_user(sys.argv[2]) timestamp = sys.argv[3] - res = db.execute_and_fetchall("SELECT transactions.time,transactions.description FROM transactions INNER JOIN accounts ON accounts.id=transactions.responsible WHERE accounts.name=%s and time > TIMESTAMP %s ORDER BY time", [acct.name,timestamp]) + res = db.execute_and_fetchall("SELECT * FROM transaction_cashsums WHERE responsible=%s and time > TIMESTAMP %s ORDER BY time", [acct.name,timestamp]) for transaction in res: - print("{}\t{}\t".format(transaction[0],transaction[1])) + print('\t'.join([str(f) for f in transaction])) elif sys.argv[1] == "iteminfo": acct = load_item(sys.argv[2]) @@ -245,16 +251,16 @@ elif sys.argv[1] == "consolidate": else: shop.consolidate() -elif sys.argv[1] == "restock": +elif sys.argv[1] in {"restock", "restock_ean"}: if (len(sys.argv) != 4): print ("Invalid number of parameters, check your parameters.") else: - iacct = load_item(sys.argv[2]) + iacct = (load_item if sys.argv[1] == "restock" else load_item_by_barcode)(sys.argv[2]) oldbal = iacct.balance() amt = int(sys.argv[3]) cash = shop.buy_for_cash(iacct, amt); print("Old amount {}, increased by {}, take {} from cashbox".format(oldbal, amt, cash)) - + else: help() diff --git a/brmbar3/brmbar-gui-qt4.py b/brmbar3/brmbar-gui-qt4.py index a41fd2c..9ca11d0 100755 --- a/brmbar3/brmbar-gui-qt4.py +++ b/brmbar3/brmbar-gui-qt4.py @@ -39,6 +39,14 @@ class ShopAdapter(QtCore.QObject): map["price"] = str(sell) return map + def acct_inventory_map2(self, acct): + buy, sell = 666, 666 + map = acct.__dict__.copy() + map["balance"] = "{:.0f}".format(666) + map["buy_price"] = str(buy) + map["price"] = str(sell) + return map + def acct_cash_map(self, acct): map = acct.__dict__.copy() return map @@ -164,7 +172,7 @@ class ShopAdapter(QtCore.QObject): @QtCore.Slot('QVariant', result='QVariant') def itemList(self, query): - alist = [ self.acct_inventory_map(a) for a in shop.account_list("inventory", like_str="%%"+query+"%%") ] + alist = [ self.acct_inventory_map2(a) for a in shop.account_list("inventory", like_str="%%"+query+"%%") ] db.commit() return alist diff --git a/brmbar3/brmbar-gui-qt4/ChargeCredit.qml b/brmbar3/brmbar-gui-qt4/ChargeCredit.qml index 0ff8dc8..cdcc006 100644 --- a/brmbar3/brmbar-gui-qt4/ChargeCredit.qml +++ b/brmbar3/brmbar-gui-qt4/ChargeCredit.qml @@ -107,7 +107,7 @@ Item { status_text.setStatus("Charged "+amount+"! "+username+"'s credit is "+balance+".", "#ffff7c") } else { balance = shop.withdrawCredit((amount*(-1)), userdbid) - status_text.setStatus("Withdrawn "+amount+"! "+username+"'s credit is "+balance+".", "#ffff7c") + status_text.setStatus("Withdrawn "+amount+"! "+username+"'s credit is "+balance+".", "#ffff7c") } } loadPage("MainPage") diff --git a/brmbar3/brmbar-gui-qt4/MainPage.qml b/brmbar3/brmbar-gui-qt4/MainPage.qml index 6e555eb..d11fd0f 100644 --- a/brmbar3/brmbar-gui-qt4/MainPage.qml +++ b/brmbar3/brmbar-gui-qt4/MainPage.qml @@ -58,6 +58,6 @@ Item { x: 65 y: 438 width: 1150 - text: "* Mroze a Termixy najdes v lednici *" + text: "* Za uklid brmlabu vam nabijeme kredit. *" } } diff --git a/brmbar3/brmbar-gui-qt4/Withdraw.qml b/brmbar3/brmbar-gui-qt4/Withdraw.qml index b37b670..2d8c49b 100644 --- a/brmbar3/brmbar-gui-qt4/Withdraw.qml +++ b/brmbar3/brmbar-gui-qt4/Withdraw.qml @@ -106,7 +106,7 @@ Item { if(amount>=0) { balance = shop.withdrawCredit(amount, userdbid) status_text.setStatus("Withdrawn "+amount+"! "+username+"'s credit is "+balance+".", "#ffff7c") - } else { + } else { balance = shop.chargeCredit((amount*(-1)),userdbid) status_text.setStatus("Charged "+amount+"! "+username+"'s credit is "+balance+".", "#ffff7c") } diff --git a/brmbar3/crontab b/brmbar3/crontab new file mode 100644 index 0000000..2e66748 --- /dev/null +++ b/brmbar3/crontab @@ -0,0 +1,15 @@ +# cleanup bounty +*/5 * * * * ~/brmbar/brmbar3/uklid-watchdog.sh +0 0 * * 1 ~/brmbar/brmbar3/uklid-refill.sh +# overall summary +5 4 * * * ~/brmbar/brmbar3/daily-summary.sh | mail -s "daily brmbar summary" yyy@yyy +# debt track +5 0 * * * ~/brmbar/brmbar3/dluhy.sh 2>/dev/null + +# per-user summary +1 0 * * * /home/brmlab/brmbar/brmbar3/log.sh yyy yyy@yyy + +# backup +6 * * * * echo "SELECT * FROM account_balances;" | psql brmbar | gzip -9 | ssh -Tp 110 -i /home/brmlab/.ssh/id_ecdsa jenda@coralmyn.hrach.eu +16 1 * * * pg_dump brmbar | gzip -9 | ssh -Tp 110 -i /home/brmlab/.ssh/id_ecdsa jenda@coralmyn.hrach.eu + diff --git a/brmbar3/dluhy.sh b/brmbar3/dluhy.sh new file mode 100755 index 0000000..61c2a46 --- /dev/null +++ b/brmbar3/dluhy.sh @@ -0,0 +1,3 @@ +p1=`echo -n "brmbar - dluhy: "; echo "SELECT name, crbalance FROM account_balances WHERE acctype = 'debt' AND crbalance < -100 AND name NOT LIKE '%overflow%' AND name NOT LIKE 'sachyo' ORDER BY crbalance ASC" | psql brmbar | tail -n +3 | grep '|' | tr -s " " | sed -e "s/ |/:/g" -e "s/$/;/" | tr -d "\n"` +p2=`echo "SELECT sum(crbalance) FROM account_balances WHERE acctype = 'debt' AND crbalance < 0 AND name NOT LIKE '%overflow%' AND name NOT LIKE 'sachyo'" | psql brmbar | tail -n +3 | head -n 1 | tr -s " "` +echo "$p1 total$p2 Kc. https://www.elektro-obojky.cz/" | ssh -p 110 -i /home/brmlab/.ssh/id_rsa jenda@coralmyn.hrach.eu diff --git a/brmbar3/log.sh b/brmbar3/log.sh new file mode 100755 index 0000000..b1afbdb --- /dev/null +++ b/brmbar3/log.sh @@ -0,0 +1,6 @@ +#!/bin/bash +p=`/home/brmlab/brmbar/brmbar3/brmbar-cli.py userlog "$1" yesterday` + +if [ -n "$p" ]; then + echo "$p" | mail -s "brmbar report" "$2" +fi diff --git a/brmbar3/uklid-watchdog.sh b/brmbar3/uklid-watchdog.sh index c0fd55b..7f86870 100644 --- a/brmbar3/uklid-watchdog.sh +++ b/brmbar3/uklid-watchdog.sh @@ -13,6 +13,6 @@ if [ ! -z "$RES" ]; then if [ -z "$WINNER" ]; then WINNER="anonymous hunter" fi - echo "Brmlab cleanup bounty was claimed by $WINNER! Thanks!"|ssh jenda@fry.hrach.eu + echo "Brmlab cleanup bounty was claimed by $WINNER! Thanks!"|ssh -p 110 jenda@coralmyn.hrach.eu fi