Merge branch 'main' of g.8f.al:ir/budget
This commit is contained in:
commit
446adc1155
5 changed files with 499 additions and 62 deletions
|
@ -5,7 +5,6 @@ CREATE TABLE account (
|
||||||
meta JSONB -- 元数据
|
meta JSONB -- 元数据
|
||||||
);
|
);
|
||||||
-- {"name":"name",
|
-- {"name":"name",
|
||||||
-- time:"2022-02-02",
|
|
||||||
-- “budget": [
|
-- “budget": [
|
||||||
-- {"time":"2022-02","value":20.32},
|
-- {"time":"2022-02","value":20.32},
|
||||||
-- {"time":"2022-01","value":30.32}
|
-- {"time":"2022-01","value":30.32}
|
||||||
|
@ -30,16 +29,15 @@ CREATE TABLE transaction (
|
||||||
t_id SERIAL PRIMARY KEY, -- 流水号
|
t_id SERIAL PRIMARY KEY, -- 流水号
|
||||||
a_id INTEGER REFERENCES account(a_id) NOT NULL, -- 关联账户号
|
a_id INTEGER REFERENCES account(a_id) NOT NULL, -- 关联账户号
|
||||||
c_id INTEGER REFERENCES category(c_id), -- 关联类别号
|
c_id INTEGER REFERENCES category(c_id), -- 关联类别号
|
||||||
s_id INTEGER REFERENCES category(c_id), -- 源账户号
|
s_id INTEGER REFERENCES account(a_id), -- 源账户号
|
||||||
time TIMESTAMP,
|
time TIMESTAMP,
|
||||||
amount MONEY,
|
amount MONEY,
|
||||||
meta JSONB -- 元数据
|
meta JSONB -- 元数据
|
||||||
);
|
);
|
||||||
-- {"discription":"something",(可选)
|
-- {"discription":"something",
|
||||||
-- "type":"in"/"out"/"transfer"/"init"/"modify",
|
-- "type":"in"/"out"/"transfer"/"init",
|
||||||
|
-- "reimburse":{
|
||||||
-- "reimburse":{ (报销)
|
-- "finish": true/false,
|
||||||
-- "finish": true,
|
|
||||||
-- "ref":t_id
|
-- "ref":t_id
|
||||||
-- }
|
-- }
|
||||||
-- "":"something"}
|
-- "":"something"}
|
||||||
|
|
336
scripts/data.sql
Normal file
336
scripts/data.sql
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Dumped from database version 15.3 (Debian 15.3-1.pgdg110+1)
|
||||||
|
-- Dumped by pg_dump version 15.3
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
SET default_tablespace = '';
|
||||||
|
|
||||||
|
SET default_table_access_method = heap;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account; Type: TABLE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.account (
|
||||||
|
a_id integer NOT NULL,
|
||||||
|
balance money,
|
||||||
|
meta jsonb
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.account OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account_a_id_seq; Type: SEQUENCE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.account_a_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.account_a_id_seq OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account_a_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.account_a_id_seq OWNED BY public.account.a_id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category; Type: TABLE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.category (
|
||||||
|
c_id integer NOT NULL,
|
||||||
|
meta jsonb
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.category OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category_c_id_seq; Type: SEQUENCE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.category_c_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.category_c_id_seq OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category_c_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.category_c_id_seq OWNED BY public.category.c_id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction; Type: TABLE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.transaction (
|
||||||
|
t_id integer NOT NULL,
|
||||||
|
a_id integer NOT NULL,
|
||||||
|
c_id integer,
|
||||||
|
s_id integer,
|
||||||
|
"time" timestamp without time zone,
|
||||||
|
amount money,
|
||||||
|
meta jsonb
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.transaction OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction_t_id_seq; Type: SEQUENCE; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.transaction_t_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE public.transaction_t_id_seq OWNER TO budget;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction_t_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.transaction_t_id_seq OWNED BY public.transaction.t_id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account a_id; Type: DEFAULT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.account ALTER COLUMN a_id SET DEFAULT nextval('public.account_a_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category c_id; Type: DEFAULT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.category ALTER COLUMN c_id SET DEFAULT nextval('public.category_c_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction t_id; Type: DEFAULT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction ALTER COLUMN t_id SET DEFAULT nextval('public.transaction_t_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Data for Name: account; Type: TABLE DATA; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
COPY public.account (a_id, balance, meta) FROM stdin;
|
||||||
|
4 $13,040.00 {"name": "储蓄卡(建设银行)", "description": ""}
|
||||||
|
3 $19,250.00 {"name": "工资卡(中国银行)", "description": ""}
|
||||||
|
1 $3,214.43 {"name": "微信", "description": ""}
|
||||||
|
2 $544.10 {"name": "支付宝", "description": ""}
|
||||||
|
\.
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Data for Name: category; Type: TABLE DATA; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
COPY public.category (c_id, meta) FROM stdin;
|
||||||
|
1 {"name": "饮食", "type": "out", "description": ""}
|
||||||
|
2 {"name": "水电", "type": "out", "description": ""}
|
||||||
|
3 {"name": "娱乐", "type": "out", "description": ""}
|
||||||
|
4 {"name": "学习", "type": "out", "description": ""}
|
||||||
|
5 {"name": "工资", "type": "in", "description": ""}
|
||||||
|
6 {"name": "理财", "type": "in", "description": ""}
|
||||||
|
7 {"name": "水电", "type": "out", "description": "低消费"}
|
||||||
|
8 {"name": "医疗", "type": "out", "description": ""}
|
||||||
|
9 {"name": "交通", "type": "out", "description": ""}
|
||||||
|
10 {"name": "购物", "type": "out", "description": ""}
|
||||||
|
\.
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Data for Name: transaction; Type: TABLE DATA; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
COPY public.transaction (t_id, a_id, c_id, s_id, "time", amount, meta) FROM stdin;
|
||||||
|
5 1 1 \N 2023-06-04 14:14:52.541843 -$32.75 {"type": "out", "description": ""}
|
||||||
|
6 2 1 \N 2023-06-04 14:15:03.209135 -$73.20 {"type": "out", "description": ""}
|
||||||
|
7 1 1 \N 2023-06-04 14:15:14.321607 -$57.92 {"type": "out", "description": ""}
|
||||||
|
8 1 2 \N 2023-06-04 14:15:23.770381 -$235.00 {"type": "out", "description": ""}
|
||||||
|
1 1 \N \N 2023-02-04 14:13:06 $3,000.00 {"type": "init", "description": "Initial Balance"}
|
||||||
|
2 2 \N \N 2023-02-04 14:13:22 $600.00 {"type": "init", "description": "Initial Balance"}
|
||||||
|
3 3 \N \N 2023-02-04 14:13:34 $4,000.00 {"type": "init", "description": "Initial Balance"}
|
||||||
|
4 4 \N \N 2023-02-04 14:13:58 $7,000.00 {"type": "init", "description": "Initial Balance"}
|
||||||
|
38 2 7 \N 2023-05-07 19:55:43 -$60.00 {"type": "out", "description": ""}
|
||||||
|
39 2 4 \N 2023-05-06 19:55:59 -$60.00 {"type": "out", "description": ""}
|
||||||
|
9 1 2 \N 2023-05-15 14:15:31 -$235.00 {"type": "out", "description": "电费过多"}
|
||||||
|
10 2 3 \N 2023-06-04 14:36:54.760977 -$50.00 {"type": "out", "description": ""}
|
||||||
|
12 1 6 \N 2023-06-04 14:37:24.994996 $3,000.00 {"type": "in", "description": ""}
|
||||||
|
11 3 5 \N 2023-06-04 14:37:15 $5,000.00 {"type": "in", "description": "主要工资"}
|
||||||
|
13 1 1 \N 2023-06-03 19:11:36 -$200.00 {"type": "out", "description": ""}
|
||||||
|
14 1 2 \N 2023-06-02 19:12:13 -$20.00 {"type": "out", "description": ""}
|
||||||
|
15 2 3 \N 2023-06-01 19:12:49 -$300.00 {"type": "out", "description": ""}
|
||||||
|
16 2 4 \N 2023-05-04 19:14:01 -$20.00 {"type": "out", "description": ""}
|
||||||
|
17 4 5 \N 2023-05-04 19:14:45 $5,000.00 {"type": "in", "description": ""}
|
||||||
|
18 3 5 \N 2023-05-05 19:15:49 $5,000.00 {"type": "in", "description": ""}
|
||||||
|
21 2 6 \N 2023-05-04 19:18:04 $500.00 {"type": "in", "description": ""}
|
||||||
|
23 3 6 \N 2023-06-03 19:19:09 $300.00 {"type": "in", "description": ""}
|
||||||
|
24 4 6 \N 2023-05-03 19:19:39 $500.00 {"type": "in", "description": ""}
|
||||||
|
25 1 4 \N 2023-05-03 19:20:39 -$50.00 {"type": "out", "description": ""}
|
||||||
|
26 3 1 \N 2023-05-04 19:48:58 -$50.00 {"type": "out", "description": ""}
|
||||||
|
27 1 2 \N 2023-05-03 19:49:15 -$60.00 {"type": "out", "description": ""}
|
||||||
|
28 1 3 \N 2023-05-02 19:49:34 -$60.00 {"type": "out", "description": ""}
|
||||||
|
29 4 3 \N 2023-05-01 19:49:53 -$60.00 {"type": "out", "description": ""}
|
||||||
|
30 1 4 \N 2023-05-06 19:50:13 -$50.00 {"type": "out", "description": ""}
|
||||||
|
31 2 4 \N 2023-05-05 19:50:36 -$50.00 {"type": "out", "description": ""}
|
||||||
|
32 1 7 \N 2023-05-07 19:51:01 -$20.00 {"type": "out", "description": ""}
|
||||||
|
33 2 7 \N 2023-05-08 19:51:28 -$30.00 {"type": "out", "description": ""}
|
||||||
|
34 4 6 \N 2023-05-07 19:51:47 $600.00 {"type": "in", "description": ""}
|
||||||
|
35 2 1 \N 2023-05-07 19:53:29 -$60.00 {"type": "out", "description": ""}
|
||||||
|
36 2 3 \N 2023-05-04 19:53:44 -$80.00 {"type": "out", "description": ""}
|
||||||
|
37 1 4 \N 2023-05-04 19:53:59 -$50.00 {"type": "out", "description": ""}
|
||||||
|
40 1 1 \N 2023-05-01 19:56:13 -$300.00 {"type": "out", "description": ""}
|
||||||
|
41 1 3 \N 2023-05-03 19:56:40 -$60.00 {"type": "out", "description": ""}
|
||||||
|
42 1 1 \N 2023-05-04 19:56:58 -$500.00 {"type": "out", "description": ""}
|
||||||
|
43 1 4 \N 2023-05-08 19:57:13 -$50.00 {"type": "out", "description": ""}
|
||||||
|
44 1 1 \N 2023-05-08 19:57:35 -$50.00 {"type": "out", "description": ""}
|
||||||
|
45 1 2 \N 2023-05-08 19:57:47 -$50.00 {"type": "out", "description": ""}
|
||||||
|
46 2 3 \N 2023-05-08 19:58:54 -$60.00 {"type": "out", "description": ""}
|
||||||
|
47 1 6 \N 2023-05-08 19:59:13 $500.00 {"type": "in", "description": ""}
|
||||||
|
48 1 2 \N 2023-05-08 19:59:35 -$800.00 {"type": "out", "description": ""}
|
||||||
|
49 1 4 \N 2023-05-07 19:59:47 -$60.00 {"type": "out", "description": ""}
|
||||||
|
50 3 5 \N 2023-06-04 20:00:04.350207 $5,000.00 {"type": "in", "description": ""}
|
||||||
|
51 2 1 \N 2023-05-07 20:00:30 -$90.00 {"type": "out", "description": ""}
|
||||||
|
52 1 1 \N 2023-06-05 15:30:32.26733 -$8.00 {"type": "out", "description": "水果"}
|
||||||
|
53 1 4 \N 2023-06-05 15:38:53.417778 -$2.90 {"type": "out", "description": "打印作业"}
|
||||||
|
54 1 1 \N 2023-06-03 15:40:01 -$9.00 {"type": "out", "description": "奶茶"}
|
||||||
|
55 2 10 \N 2023-06-05 15:48:41.416907 -$134.00 {"type": "out", "description": "水杯"}
|
||||||
|
56 2 10 \N 2023-06-05 15:49:19.312522 -$39.90 {"type": "out", "description": "纸巾"}
|
||||||
|
57 2 10 \N 2023-06-05 15:49:55.757227 -$56.80 {"type": "out", "description": "仓鼠笼子"}
|
||||||
|
59 1 1 \N 2023-06-03 15:50:51 -$18.00 {"type": "out", "description": "晚餐"}
|
||||||
|
58 1 1 \N 2023-06-03 15:50:33 -$15.00 {"type": "out", "description": "午餐"}
|
||||||
|
60 2 9 \N 2023-06-04 15:51:39 -$4.00 {"type": "out", "description": "地铁"}
|
||||||
|
61 1 9 \N 2023-06-04 15:52:07 -$11.00 {"type": "out", "description": "打车"}
|
||||||
|
62 1 1 \N 2023-06-04 15:52:44 -$21.00 {"type": "out", "description": "午餐"}
|
||||||
|
64 1 1 \N 2023-06-04 15:53:29 -$10.00 {"type": "out", "description": "水果"}
|
||||||
|
63 1 1 \N 2023-06-04 15:53:11 -$19.00 {"type": "out", "description": "晚餐"}
|
||||||
|
65 2 9 \N 2023-04-05 15:54:54 -$58.00 {"type": "out", "description": "动车"}
|
||||||
|
66 1 9 \N 2023-04-06 15:55:25 -$58.00 {"type": "out", "description": "动车"}
|
||||||
|
67 1 7 \N 2023-06-02 15:56:39 -$100.00 {"type": "out", "description": "充水卡"}
|
||||||
|
68 1 5 \N 2023-06-01 15:57:33 $1,000.00 {"type": "in", "description": "生活费"}
|
||||||
|
69 1 1 \N 2023-06-01 15:59:30 -$57.00 {"type": "out", "description": "火锅"}
|
||||||
|
70 1 10 \N 2023-05-07 16:01:31 -$339.00 {"type": "out", "description": "鞋子"}
|
||||||
|
71 1 3 \N 2023-05-06 16:02:10 -$168.00 {"type": "out", "description": "打麻将"}
|
||||||
|
72 1 1 \N 2023-05-19 16:03:41 -$90.00 {"type": "out", "description": "吃小龙虾"}
|
||||||
|
73 1 3 \N 2023-04-13 16:04:37 -$19.00 {"type": "out", "description": "知乎会员"}
|
||||||
|
74 2 \N 1 2023-06-05 18:29:39.788525 $200.00 {"type": "transfer", "description": "Transfer"}
|
||||||
|
19 2 7 \N 2023-06-04 19:16:57 -$30.00 {"type": "out", "description": ""}
|
||||||
|
22 1 1 \N 2023-06-03 19:18:31 -$200.00 {"type": "out", "description": ""}
|
||||||
|
20 2 6 \N 2023-06-01 19:17:22 $500.00 {"type": "in", "description": ""}
|
||||||
|
\.
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account_a_id_seq; Type: SEQUENCE SET; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('public.account_a_id_seq', 4, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category_c_id_seq; Type: SEQUENCE SET; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('public.category_c_id_seq', 10, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction_t_id_seq; Type: SEQUENCE SET; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('public.transaction_t_id_seq', 74, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: account account_pkey; Type: CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.account
|
||||||
|
ADD CONSTRAINT account_pkey PRIMARY KEY (a_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: category category_pkey; Type: CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.category
|
||||||
|
ADD CONSTRAINT category_pkey PRIMARY KEY (c_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction transaction_pkey; Type: CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction
|
||||||
|
ADD CONSTRAINT transaction_pkey PRIMARY KEY (t_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction transaction_a_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction
|
||||||
|
ADD CONSTRAINT transaction_a_id_fkey FOREIGN KEY (a_id) REFERENCES public.account(a_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction transaction_c_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction
|
||||||
|
ADD CONSTRAINT transaction_c_id_fkey FOREIGN KEY (c_id) REFERENCES public.category(c_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction transaction_s_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: budget
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction
|
||||||
|
ADD CONSTRAINT transaction_s_id_fkey FOREIGN KEY (s_id) REFERENCES public.account(a_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump complete
|
||||||
|
--
|
||||||
|
|
|
@ -16,15 +16,23 @@ class AccountTab(TabPage):
|
||||||
self.accountComboBox = QComboBox()
|
self.accountComboBox = QComboBox()
|
||||||
self.accountComboBox.currentIndexChanged.connect(self.onAccountIndexChanged)
|
self.accountComboBox.currentIndexChanged.connect(self.onAccountIndexChanged)
|
||||||
|
|
||||||
|
self.accountBalanceLine = QLineEdit()
|
||||||
|
self.accountBalanceLine.setReadOnly(True)
|
||||||
|
# 默认宽度
|
||||||
|
self.accountBalanceLine.setFixedWidth(150)
|
||||||
self.accountModifyButton = QPushButton('Modify')
|
self.accountModifyButton = QPushButton('Modify')
|
||||||
|
self.accountTransferButton = QPushButton('Transfer')
|
||||||
self.accountAddButton = QPushButton('Add')
|
self.accountAddButton = QPushButton('Add')
|
||||||
self.accountModifyButton.clicked.connect(self.onAccountModifyClicked)
|
self.accountModifyButton.clicked.connect(self.onAccountModifyClicked)
|
||||||
|
self.accountTransferButton.clicked.connect(self.onAccountTransferClicked)
|
||||||
self.accountAddButton.clicked.connect(self.onAccountAddClicked)
|
self.accountAddButton.clicked.connect(self.onAccountAddClicked)
|
||||||
|
|
||||||
# 创建控件布局
|
# 创建控件布局
|
||||||
topLayout = QHBoxLayout()
|
topLayout = QHBoxLayout()
|
||||||
topLayout.addWidget(self.accountComboBox)
|
topLayout.addWidget(self.accountComboBox)
|
||||||
|
topLayout.addWidget(self.accountBalanceLine)
|
||||||
topLayout.addWidget(self.accountModifyButton)
|
topLayout.addWidget(self.accountModifyButton)
|
||||||
|
topLayout.addWidget(self.accountTransferButton)
|
||||||
topLayout.addWidget(self.accountAddButton)
|
topLayout.addWidget(self.accountAddButton)
|
||||||
|
|
||||||
# 创建表格
|
# 创建表格
|
||||||
|
@ -39,42 +47,6 @@ class AccountTab(TabPage):
|
||||||
|
|
||||||
self.setLayout(accountLayout)
|
self.setLayout(accountLayout)
|
||||||
|
|
||||||
def onAccountDeleteClicked(self):
|
|
||||||
|
|
||||||
# 新建对话框,询问是否删除
|
|
||||||
dialog = QDialog(self)
|
|
||||||
dialog.setWindowTitle('Delete Account')
|
|
||||||
|
|
||||||
label1 = QLabel("Are you sure to delete this account?")
|
|
||||||
label2 = QLabel("This action cannot be undone.")
|
|
||||||
|
|
||||||
buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
||||||
buttonBox.accepted.connect(dialog.accept)
|
|
||||||
buttonBox.rejected.connect(dialog.reject)
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.addWidget(label1)
|
|
||||||
layout.addWidget(label2)
|
|
||||||
layout.addWidget(buttonBox)
|
|
||||||
layout.setSpacing(12)
|
|
||||||
layout.setContentsMargins(15, 15, 15, 15)
|
|
||||||
dialog.setMinimumWidth(400)
|
|
||||||
dialog.setLayout(layout)
|
|
||||||
|
|
||||||
# 若确认删除,则执行删除操作
|
|
||||||
if dialog.exec() == QDialog.DialogCode.Accepted:
|
|
||||||
index = self.accountComboBox.currentIndex()
|
|
||||||
if (index == -1):
|
|
||||||
QMessageBox.critical(self, 'Error', 'No account selected')
|
|
||||||
return
|
|
||||||
a_id = self.rows[index][0]
|
|
||||||
self.pg.execute("DELETE FROM account WHERE a_id=%s", (a_id,))
|
|
||||||
self.selected()
|
|
||||||
QMessageBox.information(self, 'Success', 'Account deleted')
|
|
||||||
# 关闭原来的对话框
|
|
||||||
self.aDialog.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def onAccountModifyClicked(self):
|
def onAccountModifyClicked(self):
|
||||||
# 创建添加数据对话框
|
# 创建添加数据对话框
|
||||||
|
@ -114,16 +86,13 @@ class AccountTab(TabPage):
|
||||||
# descriptionLine.setText(self.transData[self.rows[0].row()][6])
|
# descriptionLine.setText(self.transData[self.rows[0].row()][6])
|
||||||
|
|
||||||
button1 = QPushButton("Confirm")
|
button1 = QPushButton("Confirm")
|
||||||
button3 = QPushButton("Delete")
|
|
||||||
button2 = QPushButton("Abort")
|
button2 = QPushButton("Abort")
|
||||||
|
|
||||||
buttonLayout = QHBoxLayout()
|
buttonLayout = QHBoxLayout()
|
||||||
buttonLayout.addWidget(button1)
|
buttonLayout.addWidget(button1)
|
||||||
buttonLayout.addWidget(button3)
|
|
||||||
buttonLayout.addWidget(button2)
|
buttonLayout.addWidget(button2)
|
||||||
|
|
||||||
button1.clicked.connect(self.aDialog.accept)
|
button1.clicked.connect(self.aDialog.accept)
|
||||||
button3.clicked.connect(self.onAccountDeleteClicked)
|
|
||||||
button2.clicked.connect(self.aDialog.reject)
|
button2.clicked.connect(self.aDialog.reject)
|
||||||
|
|
||||||
layout = QFormLayout()
|
layout = QFormLayout()
|
||||||
|
@ -259,11 +228,14 @@ class AccountTab(TabPage):
|
||||||
meta->>'description' FROM transaction \
|
meta->>'description' FROM transaction \
|
||||||
WHERE a_id = %s ORDER BY time DESC", (a_id,))
|
WHERE a_id = %s ORDER BY time DESC", (a_id,))
|
||||||
self.transData = self.pg.fetchall()
|
self.transData = self.pg.fetchall()
|
||||||
self.pg.execute("SELECT a_id, meta ->> 'name' FROM account ORDER BY a_id")
|
self.pg.execute("SELECT a_id, meta ->> 'name', translate(balance::varchar,'$','¥') FROM account ORDER BY a_id")
|
||||||
self.accountData = self.pg.fetchall()
|
self.accountData = self.pg.fetchall()
|
||||||
self.pg.execute("SELECT c_id, meta ->> 'name' FROM category ORDER BY c_id")
|
self.pg.execute("SELECT c_id, meta ->> 'name' FROM category ORDER BY c_id")
|
||||||
self.categoryData = self.pg.fetchall()
|
self.categoryData = self.pg.fetchall()
|
||||||
|
|
||||||
|
# 设置余额
|
||||||
|
self.accountBalanceLine.setText(str(self.accountData[index][2]))
|
||||||
|
|
||||||
# 初始化表格
|
# 初始化表格
|
||||||
self.accountTable.clear()
|
self.accountTable.clear()
|
||||||
self.accountTable.setRowCount(len(self.transData))
|
self.accountTable.setRowCount(len(self.transData))
|
||||||
|
@ -283,3 +255,73 @@ class AccountTab(TabPage):
|
||||||
self.accountTable.setItem(i, 2, QTableWidgetItem(str(self.transData[i][5])))
|
self.accountTable.setItem(i, 2, QTableWidgetItem(str(self.transData[i][5])))
|
||||||
self.accountTable.setItem(i, 3, QTableWidgetItem(self.transData[i][6]))
|
self.accountTable.setItem(i, 3, QTableWidgetItem(self.transData[i][6]))
|
||||||
|
|
||||||
|
|
||||||
|
def onAccountTransferClicked(self):
|
||||||
|
# 创建添加数据对话框
|
||||||
|
self.aDialog = QDialog(self)
|
||||||
|
self.aDialog.setWindowTitle('Transfer')
|
||||||
|
srcLabel = QLabel("Source Account:")
|
||||||
|
srcComboBox = QComboBox()
|
||||||
|
for row in self.rows:
|
||||||
|
data = row[1]
|
||||||
|
srcComboBox.addItem(data)
|
||||||
|
dstLabel = QLabel("Destination Account:")
|
||||||
|
dstComboBox = QComboBox()
|
||||||
|
for row in self.rows:
|
||||||
|
data = row[1]
|
||||||
|
dstComboBox.addItem(data)
|
||||||
|
amountLabel = QLabel("Amount:")
|
||||||
|
amountLine = QLineEdit()
|
||||||
|
amountLine.setText("0.00")
|
||||||
|
# 只允许输入两位小数
|
||||||
|
amountLine.setValidator(QDoubleValidator(0.00, 999999999.99, 2))
|
||||||
|
|
||||||
|
# 按钮
|
||||||
|
button1 = QPushButton("Confirm")
|
||||||
|
button2 = QPushButton("Abort")
|
||||||
|
buttonLayout = QHBoxLayout()
|
||||||
|
buttonLayout.addWidget(button1)
|
||||||
|
buttonLayout.addWidget(button2)
|
||||||
|
|
||||||
|
button1.clicked.connect(self.aDialog.accept)
|
||||||
|
button2.clicked.connect(self.aDialog.reject)
|
||||||
|
|
||||||
|
layout = QFormLayout()
|
||||||
|
layout.addRow(srcLabel,srcComboBox)
|
||||||
|
layout.addRow(dstLabel,dstComboBox)
|
||||||
|
layout.addRow(amountLabel,amountLine)
|
||||||
|
layout.addRow(buttonLayout)
|
||||||
|
layout.setSpacing(12)
|
||||||
|
layout.setContentsMargins(15, 15, 15, 15)
|
||||||
|
self.aDialog.setMinimumWidth(400)
|
||||||
|
self.aDialog.setLayout(layout)
|
||||||
|
|
||||||
|
if self.aDialog.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
try:
|
||||||
|
# 获取账户c_id
|
||||||
|
src_id = self.rows[srcComboBox.currentIndex()][0]
|
||||||
|
dst_id = self.rows[dstComboBox.currentIndex()][0]
|
||||||
|
amount = float(amountLine.text())
|
||||||
|
|
||||||
|
if (amount <= 0):
|
||||||
|
raise Exception('Amount must be greater than zero')
|
||||||
|
if (src_id == dst_id):
|
||||||
|
raise Exception('Source and destination account cannot be the same')
|
||||||
|
|
||||||
|
# 插入数据
|
||||||
|
data = {"type":"transfer", "description": "Transfer"}
|
||||||
|
data = json.dumps(data)
|
||||||
|
self.pg.execute(
|
||||||
|
"INSERT INTO transaction (time, a_id, s_id, amount, meta)\
|
||||||
|
VALUES (now(), %s, %s, %s, %s)", (dst_id, src_id, amount, data,))
|
||||||
|
# 源账户减少
|
||||||
|
self.pg.execute(
|
||||||
|
"UPDATE account SET balance = balance - (%s::NUMERIC)::MONEY WHERE a_id = %s", (amount, src_id,))
|
||||||
|
# 目标账户增加
|
||||||
|
self.pg.execute(
|
||||||
|
"UPDATE account SET balance = balance +(%s::NUMERIC)::MONEY WHERE a_id = %s", (amount, dst_id,))
|
||||||
|
# 刷新表格
|
||||||
|
self.selected()
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
QMessageBox.critical(self, 'Error', str(e))
|
||||||
|
|
|
@ -42,9 +42,6 @@ class CategoryTab(TabPage):
|
||||||
self.setLayout(categoryLayout)
|
self.setLayout(categoryLayout)
|
||||||
|
|
||||||
|
|
||||||
def onCategoryDeleteClicked(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def onCategoryModifyClicked(self):
|
def onCategoryModifyClicked(self):
|
||||||
# 创建添加数据对话框
|
# 创建添加数据对话框
|
||||||
self.cDialog = QDialog(self)
|
self.cDialog = QDialog(self)
|
||||||
|
@ -83,15 +80,12 @@ class CategoryTab(TabPage):
|
||||||
line3.setText(data[0][2])
|
line3.setText(data[0][2])
|
||||||
|
|
||||||
button1 = QPushButton("Confirm")
|
button1 = QPushButton("Confirm")
|
||||||
button3 = QPushButton("Delete")
|
|
||||||
button2 = QPushButton("Abort")
|
button2 = QPushButton("Abort")
|
||||||
buttonLayout = QHBoxLayout()
|
buttonLayout = QHBoxLayout()
|
||||||
buttonLayout.addWidget(button1)
|
buttonLayout.addWidget(button1)
|
||||||
buttonLayout.addWidget(button3)
|
|
||||||
buttonLayout.addWidget(button2)
|
buttonLayout.addWidget(button2)
|
||||||
|
|
||||||
button1.clicked.connect(self.cDialog.accept)
|
button1.clicked.connect(self.cDialog.accept)
|
||||||
button3.clicked.connect(self.onCategoryDeleteClicked)
|
|
||||||
button2.clicked.connect(self.cDialog.reject)
|
button2.clicked.connect(self.cDialog.reject)
|
||||||
|
|
||||||
layout = QFormLayout()
|
layout = QFormLayout()
|
||||||
|
|
|
@ -15,12 +15,15 @@ class TransTab(TabPage):
|
||||||
# 创建顶部控件
|
# 创建顶部控件
|
||||||
transAddButton = QPushButton('Add')
|
transAddButton = QPushButton('Add')
|
||||||
transAddButton.clicked.connect(self.onTransAddClicked)
|
transAddButton.clicked.connect(self.onTransAddClicked)
|
||||||
|
self.transSearchButton = QPushButton('Search')
|
||||||
|
self.transSearchButton.clicked.connect(self.onTransSearchClicked)
|
||||||
transModifyButton = QPushButton('Modify')
|
transModifyButton = QPushButton('Modify')
|
||||||
transModifyButton.clicked.connect(self.onTransModifyClicked)
|
transModifyButton.clicked.connect(self.onTransModifyClicked)
|
||||||
|
|
||||||
# 创建控件布局
|
# 创建控件布局
|
||||||
topLayout = QHBoxLayout()
|
topLayout = QHBoxLayout()
|
||||||
topLayout.addWidget(transAddButton)
|
topLayout.addWidget(transAddButton)
|
||||||
|
topLayout.addWidget(self.transSearchButton)
|
||||||
topLayout.addWidget(transModifyButton)
|
topLayout.addWidget(transModifyButton)
|
||||||
|
|
||||||
self.transTable = QTableWidget()
|
self.transTable = QTableWidget()
|
||||||
|
@ -238,7 +241,8 @@ class TransTab(TabPage):
|
||||||
self.dialogLayout.itemAt(5).widget().addItem(self.accountData[i][1])
|
self.dialogLayout.itemAt(5).widget().addItem(self.accountData[i][1])
|
||||||
|
|
||||||
def selected(self):
|
def selected(self):
|
||||||
self.pg.execute("SELECT t_id, a_id, c_id, s_id, time, translate(amount::varchar,'$','¥'), meta->>'description' FROM transaction ORDER BY time DESC")
|
self.pg.execute("SELECT t_id, a_id, c_id, s_id, time, translate(amount::varchar,'$','¥'), meta->>'description' \
|
||||||
|
FROM transaction ORDER BY time DESC")
|
||||||
self.transData = self.pg.fetchall()
|
self.transData = self.pg.fetchall()
|
||||||
self.pg.execute("SELECT a_id, meta ->> 'name' FROM account ORDER BY a_id")
|
self.pg.execute("SELECT a_id, meta ->> 'name' FROM account ORDER BY a_id")
|
||||||
self.accountData = self.pg.fetchall()
|
self.accountData = self.pg.fetchall()
|
||||||
|
@ -264,3 +268,66 @@ class TransTab(TabPage):
|
||||||
self.transTable.setItem(i, 2, QTableWidgetItem(self.categoryData[self.transData[i][2]-1][1]))
|
self.transTable.setItem(i, 2, QTableWidgetItem(self.categoryData[self.transData[i][2]-1][1]))
|
||||||
self.transTable.setItem(i, 3, QTableWidgetItem(str(self.transData[i][5])))
|
self.transTable.setItem(i, 3, QTableWidgetItem(str(self.transData[i][5])))
|
||||||
self.transTable.setItem(i, 4, QTableWidgetItem(self.transData[i][6]))
|
self.transTable.setItem(i, 4, QTableWidgetItem(self.transData[i][6]))
|
||||||
|
|
||||||
|
def onTransSearchClicked(self):
|
||||||
|
# 若已经搜索,则重置
|
||||||
|
if self.transSearchButton.text() == "Reset":
|
||||||
|
self.selected()
|
||||||
|
self.transSearchButton.setText("Search")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.tDialog = QDialog(self)
|
||||||
|
self.tDialog.setWindowTitle('Search Transaction')
|
||||||
|
discLabel=QLabel("Discription:")
|
||||||
|
discLine=QLineEdit()
|
||||||
|
discLine.setText("")
|
||||||
|
|
||||||
|
cButton = QPushButton("Confirm")
|
||||||
|
aButton = QPushButton("Abort")
|
||||||
|
buttonLayout = QHBoxLayout()
|
||||||
|
buttonLayout.addWidget(cButton)
|
||||||
|
buttonLayout.addWidget(aButton)
|
||||||
|
|
||||||
|
cButton.clicked.connect(self.tDialog.accept)
|
||||||
|
aButton.clicked.connect(self.tDialog.reject)
|
||||||
|
|
||||||
|
dialogLayout = QFormLayout()
|
||||||
|
dialogLayout.addRow(discLabel, discLine)
|
||||||
|
dialogLayout.addRow(buttonLayout)
|
||||||
|
dialogLayout.setSpacing(12)
|
||||||
|
dialogLayout.setContentsMargins(15, 15, 15, 15)
|
||||||
|
|
||||||
|
self.tDialog.setMinimumWidth(400)
|
||||||
|
self.tDialog.setLayout(dialogLayout)
|
||||||
|
|
||||||
|
if self.tDialog.exec() == QDialog.DialogCode.Accepted:
|
||||||
|
discription = discLine.text()
|
||||||
|
self.pg.execute("SELECT t_id, a_id, c_id, s_id, time, translate(amount::varchar,'$','¥'), meta->>'description'\
|
||||||
|
FROM transaction WHERE meta->>'description' LIKE %s ORDER BY time DESC",('%'+discription+'%',))
|
||||||
|
self.transData = self.pg.fetchall()
|
||||||
|
self.pg.execute("SELECT a_id, meta ->> 'name' FROM account ORDER BY a_id")
|
||||||
|
self.accountData = self.pg.fetchall()
|
||||||
|
self.pg.execute("SELECT c_id, meta ->> 'name' FROM category ORDER BY c_id")
|
||||||
|
self.categoryData = self.pg.fetchall()
|
||||||
|
|
||||||
|
# 设置表格
|
||||||
|
self.transTable.clear()
|
||||||
|
self.transTable.setRowCount(len(self.transData))
|
||||||
|
self.transTable.setColumnCount(5) # 时间 账户 类别 金额 描述
|
||||||
|
self.transTable.setHorizontalHeaderLabels(['Time', 'Account', 'Category', 'Amount', 'Description'])
|
||||||
|
# 设置自动调整列宽
|
||||||
|
self.transTable.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
|
||||||
|
|
||||||
|
# 填充表格
|
||||||
|
for i in range(len(self.transData)):
|
||||||
|
self.transTable.setItem(i, 0, QTableWidgetItem(self.transData[i][4].strftime("%Y-%m-%d %H:%M:%S")))
|
||||||
|
self.transTable.setItem(i, 1, QTableWidgetItem(self.accountData[self.transData[i][1]-1][1]))
|
||||||
|
if self.transData[i][2] is None:
|
||||||
|
self.transTable.setItem(i, 2, QTableWidgetItem("None"))
|
||||||
|
else:
|
||||||
|
self.transTable.setItem(i, 2, QTableWidgetItem(self.categoryData[self.transData[i][2]-1][1]))
|
||||||
|
self.transTable.setItem(i, 3, QTableWidgetItem(str(self.transData[i][5])))
|
||||||
|
self.transTable.setItem(i, 4, QTableWidgetItem(self.transData[i][6]))
|
||||||
|
|
||||||
|
# 设置按钮文本为重置
|
||||||
|
self.transSearchButton.setText("Reset")
|
||||||
|
|
Loading…
Reference in a new issue