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
|
@ -1,11 +1,10 @@
|
|||
-- 账户表
|
||||
CREATE TABLE account (
|
||||
a_id SERIAL PRIMARY KEY, -- 账户号
|
||||
balance MONEY, -- 余额
|
||||
meta JSONB -- 元数据
|
||||
balance MONEY, -- 余额
|
||||
meta JSONB -- 元数据
|
||||
);
|
||||
-- {"name":"name",
|
||||
-- time:"2022-02-02",
|
||||
-- “budget": [
|
||||
-- {"time":"2022-02","value":20.32},
|
||||
-- {"time":"2022-01","value":30.32}
|
||||
|
@ -14,8 +13,8 @@ CREATE TABLE account (
|
|||
|
||||
-- 类别表
|
||||
CREATE TABLE category (
|
||||
c_id SERIAL PRIMARY KEY, -- 类别号
|
||||
meta JSONB -- 元数据
|
||||
c_id SERIAL PRIMARY KEY, -- 类别号
|
||||
meta JSONB -- 元数据
|
||||
);
|
||||
-- {"name":"name",
|
||||
-- "type":"in"/"out",
|
||||
|
@ -27,19 +26,18 @@ CREATE TABLE category (
|
|||
|
||||
-- 流水表
|
||||
CREATE TABLE transaction (
|
||||
t_id SERIAL PRIMARY KEY, -- 流水号
|
||||
t_id SERIAL PRIMARY KEY, -- 流水号
|
||||
a_id INTEGER REFERENCES account(a_id) NOT NULL, -- 关联账户号
|
||||
c_id INTEGER REFERENCES category(c_id), -- 关联类别号
|
||||
s_id INTEGER REFERENCES category(c_id), -- 源账户号
|
||||
c_id INTEGER REFERENCES category(c_id), -- 关联类别号
|
||||
s_id INTEGER REFERENCES account(a_id), -- 源账户号
|
||||
time TIMESTAMP,
|
||||
amount MONEY,
|
||||
meta JSONB -- 元数据
|
||||
);
|
||||
-- {"discription":"something",(可选)
|
||||
-- "type":"in"/"out"/"transfer"/"init"/"modify",
|
||||
|
||||
-- "reimburse":{ (报销)
|
||||
-- "finish": true,
|
||||
-- {"discription":"something",
|
||||
-- "type":"in"/"out"/"transfer"/"init",
|
||||
-- "reimburse":{
|
||||
-- "finish": true/false,
|
||||
-- "ref":t_id
|
||||
-- }
|
||||
-- "":"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.currentIndexChanged.connect(self.onAccountIndexChanged)
|
||||
|
||||
self.accountBalanceLine = QLineEdit()
|
||||
self.accountBalanceLine.setReadOnly(True)
|
||||
# 默认宽度
|
||||
self.accountBalanceLine.setFixedWidth(150)
|
||||
self.accountModifyButton = QPushButton('Modify')
|
||||
self.accountTransferButton = QPushButton('Transfer')
|
||||
self.accountAddButton = QPushButton('Add')
|
||||
self.accountModifyButton.clicked.connect(self.onAccountModifyClicked)
|
||||
self.accountTransferButton.clicked.connect(self.onAccountTransferClicked)
|
||||
self.accountAddButton.clicked.connect(self.onAccountAddClicked)
|
||||
|
||||
# 创建控件布局
|
||||
topLayout = QHBoxLayout()
|
||||
topLayout.addWidget(self.accountComboBox)
|
||||
topLayout.addWidget(self.accountBalanceLine)
|
||||
topLayout.addWidget(self.accountModifyButton)
|
||||
topLayout.addWidget(self.accountTransferButton)
|
||||
topLayout.addWidget(self.accountAddButton)
|
||||
|
||||
# 创建表格
|
||||
|
@ -39,42 +47,6 @@ class AccountTab(TabPage):
|
|||
|
||||
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):
|
||||
# 创建添加数据对话框
|
||||
|
@ -114,16 +86,13 @@ class AccountTab(TabPage):
|
|||
# descriptionLine.setText(self.transData[self.rows[0].row()][6])
|
||||
|
||||
button1 = QPushButton("Confirm")
|
||||
button3 = QPushButton("Delete")
|
||||
button2 = QPushButton("Abort")
|
||||
|
||||
buttonLayout = QHBoxLayout()
|
||||
buttonLayout.addWidget(button1)
|
||||
buttonLayout.addWidget(button3)
|
||||
buttonLayout.addWidget(button2)
|
||||
|
||||
button1.clicked.connect(self.aDialog.accept)
|
||||
button3.clicked.connect(self.onAccountDeleteClicked)
|
||||
button2.clicked.connect(self.aDialog.reject)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
@ -259,11 +228,14 @@ class AccountTab(TabPage):
|
|||
meta->>'description' FROM transaction \
|
||||
WHERE a_id = %s ORDER BY time DESC", (a_id,))
|
||||
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.pg.execute("SELECT c_id, meta ->> 'name' FROM category ORDER BY c_id")
|
||||
self.categoryData = self.pg.fetchall()
|
||||
|
||||
# 设置余额
|
||||
self.accountBalanceLine.setText(str(self.accountData[index][2]))
|
||||
|
||||
# 初始化表格
|
||||
self.accountTable.clear()
|
||||
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, 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)
|
||||
|
||||
|
||||
def onCategoryDeleteClicked(self):
|
||||
pass
|
||||
|
||||
def onCategoryModifyClicked(self):
|
||||
# 创建添加数据对话框
|
||||
self.cDialog = QDialog(self)
|
||||
|
@ -83,15 +80,12 @@ class CategoryTab(TabPage):
|
|||
line3.setText(data[0][2])
|
||||
|
||||
button1 = QPushButton("Confirm")
|
||||
button3 = QPushButton("Delete")
|
||||
button2 = QPushButton("Abort")
|
||||
buttonLayout = QHBoxLayout()
|
||||
buttonLayout.addWidget(button1)
|
||||
buttonLayout.addWidget(button3)
|
||||
buttonLayout.addWidget(button2)
|
||||
|
||||
button1.clicked.connect(self.cDialog.accept)
|
||||
button3.clicked.connect(self.onCategoryDeleteClicked)
|
||||
button2.clicked.connect(self.cDialog.reject)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
|
|
@ -15,12 +15,15 @@ class TransTab(TabPage):
|
|||
# 创建顶部控件
|
||||
transAddButton = QPushButton('Add')
|
||||
transAddButton.clicked.connect(self.onTransAddClicked)
|
||||
self.transSearchButton = QPushButton('Search')
|
||||
self.transSearchButton.clicked.connect(self.onTransSearchClicked)
|
||||
transModifyButton = QPushButton('Modify')
|
||||
transModifyButton.clicked.connect(self.onTransModifyClicked)
|
||||
|
||||
# 创建控件布局
|
||||
topLayout = QHBoxLayout()
|
||||
topLayout.addWidget(transAddButton)
|
||||
topLayout.addWidget(self.transSearchButton)
|
||||
topLayout.addWidget(transModifyButton)
|
||||
|
||||
self.transTable = QTableWidget()
|
||||
|
@ -238,7 +241,8 @@ class TransTab(TabPage):
|
|||
self.dialogLayout.itemAt(5).widget().addItem(self.accountData[i][1])
|
||||
|
||||
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.pg.execute("SELECT a_id, meta ->> 'name' FROM account ORDER BY a_id")
|
||||
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, 3, QTableWidgetItem(str(self.transData[i][5])))
|
||||
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