Compare commits
	
		
			No commits in common. "0213a8011f323e4ff95de3b07539de1f66be968d" and "4a2d45824f7bb4e4efc86cbeb03eb9f9fca44d50" have entirely different histories.
		
	
	
		
			0213a8011f
			...
			4a2d45824f
		
	
		
					 2 changed files with 9 additions and 323 deletions
				
			
		
							
								
								
									
										19
									
								
								0PLAN.org
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								0PLAN.org
									
										
									
									
									
								
							|  | @ -2,6 +2,15 @@ | |||
| 
 | ||||
| * Plan | ||||
| 
 | ||||
| ** 0.2 | ||||
| 
 | ||||
| - [X] use localStorage to store user | ||||
|   - [X] add barcode scanner to get the user | ||||
|   - [X] allow editing | ||||
|   - [X] add UserSelect component | ||||
| - [X] integrate script for starting build qemu system | ||||
| - [X] add org file to the repository after cleanup | ||||
| 
 | ||||
| ** 0.3 | ||||
| 
 | ||||
| - [ ] versioned schema support | ||||
|  | @ -9,7 +18,6 @@ | |||
|   - [ ] function to check | ||||
|   - [ ] function to set | ||||
|   - [ ] initial creation of tables at version 1 assuming OK if tables exist | ||||
| - [ ] users import from hackerbase | ||||
| 
 | ||||
| ** 0.4 | ||||
| 
 | ||||
|  | @ -49,15 +57,6 @@ | |||
|   - [X] separate module brmbar-data for queries | ||||
|   - [X] separate module api-servlets | ||||
| 
 | ||||
| ** 0.2 | ||||
| 
 | ||||
| - [X] use localStorage to store user | ||||
|   - [X] add barcode scanner to get the user | ||||
|   - [X] allow editing | ||||
|   - [X] add UserSelect component | ||||
| - [X] integrate script for starting build qemu system | ||||
| - [X] add org file to the repository after cleanup | ||||
| 
 | ||||
| * Qemu | ||||
| 
 | ||||
| #+BEGIN_SRC | ||||
|  |  | |||
|  | @ -1,313 +0,0 @@ | |||
| -- | ||||
| -- 0000-init.sql | ||||
| -- | ||||
| -- Initial SQL schema construction as of 2025-04-20 (or so) | ||||
| -- | ||||
| -- ISC License | ||||
| -- | ||||
| -- Copyright 2023-2025 Brmlab, z.s. | ||||
| -- Dominik Pantůček <dominik.pantucek@trustica.cz> | ||||
| -- | ||||
| -- Permission to use, copy, modify, and/or distribute this software | ||||
| -- for any purpose with or without fee is hereby granted, provided | ||||
| -- that the above copyright notice and this permission notice appear | ||||
| -- in all copies. | ||||
| --  | ||||
| -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||||
| -- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||||
| -- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE | ||||
| -- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||||
| -- CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | ||||
| -- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||||
| -- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||||
| -- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
| -- | ||||
| 
 | ||||
| -- To require fully-qualified names | ||||
| SELECT pg_catalog.set_config('search_path', '', false); | ||||
| 
 | ||||
| -- Privileged schema with protected data | ||||
| CREATE SCHEMA IF NOT EXISTS brmbar_privileged; | ||||
| 
 | ||||
| -- Initial versioning | ||||
| CREATE TABLE IF NOT EXISTS brmbar_privileged.brmbar_schema( | ||||
|   ver INTEGER NOT NULL | ||||
| ); | ||||
| 
 | ||||
| -- ---------------------------------------------------------------- | ||||
| -- Legacy Schema Initialization | ||||
| -- ---------------------------------------------------------------- | ||||
| 
 | ||||
| DO $$ | ||||
| DECLARE v INTEGER; | ||||
| BEGIN | ||||
|   SELECT ver FROM brmbar_privileged.brmbar_schema INTO v; | ||||
|   IF v IS NULL THEN | ||||
|     -- -------------------------------- | ||||
|     -- Legacy Types | ||||
| 
 | ||||
|     SELECT COUNT(*) INTO v | ||||
|       FROM pg_catalog.pg_type typ | ||||
|         INNER JOIN pg_catalog.pg_namespace nsp | ||||
|           ON nsp.oid = typ.typnamespace | ||||
|       WHERE nsp.nspname = 'public' | ||||
|         AND typ.typname='exchange_rate_direction'; | ||||
|     IF v=0 THEN | ||||
|     RAISE NOTICE 'Creating type exchange_rate_direction'; | ||||
|     CREATE TYPE public.exchange_rate_direction | ||||
|       AS ENUM ('source_to_target', 'target_to_source'); | ||||
|     ELSE | ||||
|     RAISE NOTICE 'Type exchange_rate_direction already exists'; | ||||
|     END IF; | ||||
| 
 | ||||
|     SELECT COUNT(*) INTO v | ||||
|       FROM pg_catalog.pg_type typ | ||||
|         INNER JOIN pg_catalog.pg_namespace nsp | ||||
|           ON nsp.oid = typ.typnamespace | ||||
|       WHERE nsp.nspname = 'public' | ||||
|         AND typ.typname='account_type'; | ||||
|     IF v=0 THEN | ||||
|     RAISE NOTICE 'Creating type account_type'; | ||||
|     CREATE TYPE public.account_type | ||||
|       AS ENUM ('cash', 'debt', 'inventory', 'income', 'expense', | ||||
|       	       'starting_balance', 'ending_balance'); | ||||
|     ELSE | ||||
|     RAISE NOTICE 'Type account_type already exists'; | ||||
|     END IF; | ||||
| 
 | ||||
|     SELECT COUNT(*) INTO v | ||||
|       FROM pg_catalog.pg_type typ | ||||
|         INNER JOIN pg_catalog.pg_namespace nsp | ||||
|           ON nsp.oid = typ.typnamespace | ||||
|       WHERE nsp.nspname = 'public' | ||||
|         AND typ.typname='transaction_split_side'; | ||||
|     IF v=0 THEN | ||||
|     RAISE NOTICE 'Creating type transaction_split_side'; | ||||
|     CREATE TYPE public.transaction_split_side | ||||
|       AS ENUM ('credit', 'debit'); | ||||
|     ELSE | ||||
|     RAISE NOTICE 'Type transaction_split_side already exists'; | ||||
|     END IF; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Currencies sequence, table and potential initial data | ||||
| 
 | ||||
|     CREATE SEQUENCE IF NOT EXISTS public.currencies_id_seq | ||||
|       START WITH 2 INCREMENT BY 1; | ||||
|     CREATE TABLE IF NOT EXISTS public.currencies ( | ||||
|       	id INTEGER PRIMARY KEY NOT NULL DEFAULT NEXTVAL('public.currencies_id_seq'::regclass), | ||||
| 	name VARCHAR(128) NOT NULL, | ||||
| 	UNIQUE(name) | ||||
|     ); | ||||
|     INSERT INTO public.currencies (id, name) VALUES (1, 'Kč') | ||||
|       ON CONFLICT DO NOTHING; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Exchange rates table - no initial data required | ||||
| 
 | ||||
|     CREATE TABLE IF NOT EXISTS public.exchange_rates ( | ||||
| 	valid_since TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, | ||||
| 
 | ||||
| 	target INTEGER NOT NULL, | ||||
|         FOREIGN KEY (target) REFERENCES public.currencies (id), | ||||
| 
 | ||||
| 	source INTEGER NOT NULL, | ||||
|         FOREIGN KEY (source) REFERENCES public.currencies (id), | ||||
| 
 | ||||
| 	rate DECIMAL(12,2) NOT NULL, | ||||
| 	rate_dir public.exchange_rate_direction NOT NULL | ||||
|     ); | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Accounts sequence and table and 4 initial accounts | ||||
| 
 | ||||
|     CREATE SEQUENCE IF NOT EXISTS public.accounts_id_seq | ||||
|       START WITH 2 INCREMENT BY 1; | ||||
|     CREATE TABLE IF NOT EXISTS public.accounts ( | ||||
| 	id INTEGER PRIMARY KEY NOT NULL DEFAULT NEXTVAL('public.accounts_id_seq'::regclass), | ||||
| 
 | ||||
| 	name VARCHAR(128) NOT NULL, | ||||
| 	UNIQUE (name), | ||||
| 
 | ||||
| 	currency INTEGER NOT NULL, | ||||
|         FOREIGN KEY (currency) REFERENCES public.currencies (id), | ||||
| 
 | ||||
| 	acctype public.account_type NOT NULL, | ||||
| 
 | ||||
| 	active BOOLEAN NOT NULL DEFAULT TRUE | ||||
|     ); | ||||
|     INSERT INTO public.accounts (id, name, currency, acctype) | ||||
|       VALUES (1, 'BrmBar Cash', (SELECT id FROM public.currencies WHERE name='Kč'), 'cash') | ||||
|       ON CONFLICT DO NOTHING; | ||||
|     INSERT INTO public.accounts (name, currency, acctype) | ||||
|       VALUES ('BrmBar Profits', (SELECT id FROM public.currencies WHERE name='Kč'), 'income') | ||||
|       ON CONFLICT DO NOTHING; | ||||
|     INSERT INTO public.accounts (name, currency, acctype) | ||||
|       VALUES ('BrmBar Excess', (SELECT id FROM public.currencies WHERE name='Kč'), 'income') | ||||
|       ON CONFLICT DO NOTHING; | ||||
|     INSERT INTO public.accounts (name, currency, acctype) | ||||
|     VALUES ('BrmBar Deficit', (SELECT id FROM public.currencies WHERE name='Kč'), 'expense') | ||||
|     ON CONFLICT DO NOTHING; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Barcodes | ||||
|      | ||||
|     CREATE TABLE IF NOT EXISTS public.barcodes ( | ||||
| 	barcode VARCHAR(128) PRIMARY KEY NOT NULL, | ||||
| 
 | ||||
| 	account INTEGER NOT NULL, | ||||
|         FOREIGN KEY (account) REFERENCES public.accounts (id) | ||||
|     ); | ||||
|     INSERT INTO public.barcodes (barcode, account) | ||||
|       VALUES ('_cash_', (SELECT id FROM public.accounts WHERE acctype = 'cash')) | ||||
|       ON CONFLICT DO NOTHING; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Transactions | ||||
|      | ||||
|     CREATE SEQUENCE IF NOT EXISTS public.transactions_id_seq | ||||
|       START WITH 1 INCREMENT BY 1; | ||||
|     CREATE TABLE IF NOT EXISTS public.transactions ( | ||||
| 	id INTEGER PRIMARY KEY NOT NULL DEFAULT NEXTVAL('public.transactions_id_seq'::regclass), | ||||
| 	time TIMESTAMP DEFAULT NOW() NOT NULL, | ||||
| 
 | ||||
| 	responsible INTEGER, | ||||
| 	FOREIGN KEY (responsible) REFERENCES public.accounts (id), | ||||
| 
 | ||||
| 	description TEXT | ||||
|     ); | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Transaction splits | ||||
| 
 | ||||
|     CREATE SEQUENCE IF NOT EXISTS public.transaction_splits_id_seq | ||||
|       START WITH 1 INCREMENT BY 1; | ||||
|     CREATE TABLE IF NOT EXISTS public.transaction_splits ( | ||||
| 	id INTEGER PRIMARY KEY NOT NULL DEFAULT NEXTVAL('public.transaction_splits_id_seq'::regclass), | ||||
| 
 | ||||
| 	transaction INTEGER NOT NULL, | ||||
| 	FOREIGN KEY (transaction) REFERENCES public.transactions (id), | ||||
| 
 | ||||
| 	side public.transaction_split_side NOT NULL, | ||||
| 
 | ||||
| 	account INTEGER NOT NULL, | ||||
|         FOREIGN KEY (account) REFERENCES public.accounts (id), | ||||
| 	amount DECIMAL(12,2) NOT NULL, | ||||
| 
 | ||||
| 	memo TEXT | ||||
|     ); | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Account balances view | ||||
| 
 | ||||
|     CREATE OR REPLACE VIEW public.account_balances AS | ||||
|       SELECT ts.account AS id, | ||||
|       accounts.name, | ||||
|       accounts.acctype, | ||||
|       - sum( | ||||
| 	  CASE | ||||
| 	      WHEN ts.side = 'credit'::public.transaction_split_side THEN - ts.amount | ||||
| 	      ELSE ts.amount | ||||
| 	  END) AS crbalance | ||||
|      FROM public.transaction_splits ts | ||||
|        LEFT JOIN public.accounts ON accounts.id = ts.account | ||||
|     GROUP BY ts.account, accounts.name, accounts.acctype | ||||
|     ORDER BY (- sum( | ||||
| 	  CASE | ||||
| 	      WHEN ts.side = 'credit'::public.transaction_split_side THEN - ts.amount | ||||
| 	      ELSE ts.amount | ||||
| 	  END)); | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Transaction nice splits view | ||||
| 
 | ||||
|     CREATE OR REPLACE VIEW public.transaction_nicesplits AS | ||||
|       SELECT ts.id, | ||||
| 	ts.transaction, | ||||
| 	ts.account, | ||||
| 	    CASE | ||||
| 		WHEN ts.side = 'credit'::public.transaction_split_side THEN - ts.amount | ||||
| 		ELSE ts.amount | ||||
| 	    END AS amount, | ||||
| 	a.currency, | ||||
| 	ts.memo | ||||
|       FROM public.transaction_splits ts | ||||
| 	 LEFT JOIN public.accounts a ON a.id = ts.account | ||||
|       ORDER BY ts.id; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Transaction cash sums view | ||||
| 
 | ||||
|     CREATE OR REPLACE VIEW public.transaction_cashsums AS | ||||
|       SELECT t.id, | ||||
| 	 t."time", | ||||
| 	 sum(credit.credit_cash) AS cash_credit, | ||||
| 	 sum(debit.debit_cash) AS cash_debit, | ||||
| 	 a.name AS responsible, | ||||
| 	 t.description | ||||
| 	FROM public.transactions t | ||||
| 	  LEFT JOIN ( SELECT cts.amount AS credit_cash, | ||||
| 		 cts.transaction AS cts_t | ||||
| 		FROM public.transaction_nicesplits cts | ||||
| 		  LEFT JOIN public.accounts a_1 ON a_1.id = cts.account OR a_1.id = cts.account | ||||
| 	       WHERE a_1.currency = (( SELECT accounts.currency | ||||
| 			FROM public.accounts | ||||
| 		       WHERE accounts.name::text = 'BrmBar Cash'::text)) | ||||
| 		       AND (a_1.acctype = ANY (ARRAY['cash'::public.account_type, 'debt'::public.account_type])) | ||||
| 		       AND cts.amount < 0::numeric) credit ON credit.cts_t = t.id | ||||
| 	  LEFT JOIN ( SELECT dts.amount AS debit_cash, | ||||
| 		 dts.transaction AS dts_t | ||||
| 		FROM public.transaction_nicesplits dts | ||||
| 		  LEFT JOIN public.accounts a_1 ON a_1.id = dts.account OR a_1.id = dts.account | ||||
| 	       WHERE a_1.currency = (( SELECT accounts.currency | ||||
| 			FROM public.accounts | ||||
| 		       WHERE accounts.name::text = 'BrmBar Cash'::text)) | ||||
| 		       AND (a_1.acctype = ANY (ARRAY['cash'::public.account_type, 'debt'::public.account_type])) | ||||
| 		       AND dts.amount > 0::numeric) debit ON debit.dts_t = t.id | ||||
| 	  LEFT JOIN public.accounts a ON a.id = t.responsible | ||||
|        GROUP BY t.id, a.name | ||||
|        ORDER BY t.id DESC; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     -- Function to check schema version (used in migrations) | ||||
| 
 | ||||
|     CREATE OR REPLACE FUNCTION brmbar_privileged.has_exact_schema_version( | ||||
| 	    IN i_ver INTEGER | ||||
|     ) RETURNS INTEGER | ||||
|     VOLATILE  NOT LEAKPROOF  LANGUAGE plpgsql AS $x$ | ||||
|     DECLARE | ||||
| 	    v_ver INTEGER; | ||||
|     BEGIN | ||||
| 	    SELECT ver INTO v_ver FROM brmbar_privileged.brmbar_schema; | ||||
| 	    IF v_ver is NULL THEN | ||||
| 	      RETURN false; | ||||
| 	    ELSE | ||||
| 	      RETURN v_ver = i_ver; | ||||
| 	    END IF; | ||||
|     END; | ||||
|     $x$; | ||||
| 
 | ||||
|     -- -------------------------------- | ||||
|     --  | ||||
| 
 | ||||
|     CREATE OR REPLACE FUNCTION brmbar_privileged.upgrade_schema_version_to( | ||||
| 	    IN i_ver INTEGER | ||||
|     ) RETURNS INTEGER | ||||
|     VOLATILE  NOT LEAKPROOF  LANGUAGE plpgsql AS $x$ | ||||
|     DECLARE | ||||
| 	    v_ver INTEGER; | ||||
|     BEGIN | ||||
|       SELECT ver FROM brmbar_privileged.brmbar_schema INTO v_ver; | ||||
|       IF v_ver=(i_ver-1) THEN | ||||
|         UPDATE brmbar_privileged.brmbar_schema SET ver = i_ver; | ||||
|       ELSE | ||||
|         RAISE EXCEPTION 'Invalid brmbar schema version transition (% -> %)', v_ver, i_ver; | ||||
|       END IF; | ||||
|     END; | ||||
|     $x$; | ||||
| 
 | ||||
|     -- Initialize version 1 | ||||
|     INSERT INTO brmbar_privileged.brmbar_schema(ver) VALUES(1); | ||||
|   END IF; | ||||
| END; | ||||
| $$; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue