每次作一點就發出來,大神不要嫌重複mysql
2016/11/4git
今天來搞ATM,反正逃不了的,說來慚愧,這個做業是我10/4號20天前拿到的,當時是萬臉蒙比的,今天又作了一點,如今算是百臉蒙比吧。sql
額度 15000或自定義
實現購物商城,買東西加入 購物車,調用信用卡接口結帳 實際上是兩套單獨程序
能夠提現,手續費5% 提現不能超過總餘額一半
每個月22號出帳單,每個月10號爲還款日,過時未還,按欠款總額 萬分之5 每日計息
支持多帳戶登陸,每一個用戶有單獨信息
支持帳戶間轉帳,
記錄每個月平常消費流水
提供還款接口
ATM記錄操做日誌
提供管理接口,包括添加帳戶、用戶額度,凍結帳戶等。。。數據庫
角色:json
管理員功能:
增刪改查
記錄日誌
基本信息
額度 15000
普通用戶功能:
能夠提現,手續費5%
支持多帳戶登陸
支持帳戶間轉帳
記錄每個月平常消費流水
提供還款接口
ATM記錄操做日誌ide
剛開始的蒙比從不知道文件怎麼建立開始?擦!怎麼多需求,確定不止一兩個文件的,那多個文件又是怎麼建的?我還特的心血來潮花一個早上去圖去館研究一下,最後挺亂的,後來看了視頻,才發現有文件建立上是有開發規範的!學習
bin 用於執行可執行文件測試
conf 配置文件字體
db 用於存放用戶數據spa
log 日誌,記錄相關信息
這裏我每次寫一些,改一些,方便我這種小白看思路,想看最終版的直接拉到文章最後。
今天實現了檢查賬戶是否存在,信用卡是否超期的功能。自我感受良好,哈哈~
1. 如何讓字體打印出來有顏色??
print("\033[31;1mAccount[%s]doesnotexist!\033[0m" % account)
運行結果:Account [qee] does not exist! 打印出來是紅色的
2.如何將一個文件內的字符串形式經過json轉化爲相應的字典格式??
用json.load()就好嘛,不過仍是遇到一點小問題。
#account_file是文件的絕對路徑
with open(account_file, "r", encoding="utf-8") as f: #打開文件
file_data = json.load(account_file) print(file_data)
這樣居然出錯了!! 錯誤信息:AttributeError: 'str' object has no attribute 'read'
因而我去看了下json.load()的源碼。
def load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing a JSON document) to a Python object. ``object_hook`` is an optional function that will be called with the result of any object literal decode (a ``dict``). The return value of ``object_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting). ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders that rely on the order that the key and value pairs are decoded (for example, collections.OrderedDict will remember the order of insertion). If ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. """ return loads(fp.read(), cls=cls, object_hook=object_hook, parse_float=parse_float, parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
注意這一句return loads(fp.read(),……),我覺得搞個文件的絕對路徑就能夠的,結果錯誤信息,固然是路徑沒有read()功能。
#改正: if os.path.isfile(account_file): #若是用戶文件存在(即用戶存在)
with open(account_file, "r", encoding="utf-8") as f: #打開文件
file_data = json.load(f) print(file_data)
運行正確,GOOD!
3.如何把時間字符串轉化爲時間戳(忘了的)
先經過time.strptime()將時間字符串轉成struct_time格式,再經過time.mktime()將struct_time轉成時間戳。
atm.py
""" ATM程序的執行文件 """
import os import sys dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路徑
sys.path.insert(0, dir) #添加路徑
print(dir) #將main.py裏面全部代碼封裝成main變量
from core import main if __name__ == "__main__": #這裏我剛開始用run()就爆錯了
main.run()
settings.py
1 """ 2 初始化的配置 3 """ 4 5 import logging 6 import os 7 8 #到ATM目錄,方便後面建立賬戶文件 9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 11 LOGIN_LEVEL = logging.INFO #初始化日誌級別 12 13 14 DATABASE = { 15 "db_tool":"file_storage", #文件存儲,這裏可拓展成數據庫形式的 16 "name":"accounts", #db下的文件名 17 "path":"%s/db" % BASE_DIR 18 }
auth.py
1 """
2 認證模塊 3 """
4 print("BB") 5 import os 6 import json 7 import time 8
9 from core import db_handle 10 from conf import settings 11
12
13 def access_auth(account, password): 14 """
15 下面的access_login調用access_auth方法,用於登錄 16 :param acount: 用戶名 17 :param password: 密碼 18 :return:若是未超期,返回字典,超期則打印相應提示 19 """
20 db_path = db_handle.handle(settings.DATABASE) #調用db_handle下的handle方法,返回路徑/db/accounts
21 print(db_path) 22 account_file = "%s/%s.json" % (db_path, account) #用戶文件
23 print(account_file) 24 if os.path.isfile(account_file): #若是用戶文件存在(即用戶存在)
25 with open(account_file, "r", encoding="utf-8") as f: #打開文件
26 account_data = json.load(f) #file_data爲字典形式
27 print(account_data) 28 if account_data["password"] == password: 29 expire_time = time.mktime(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 30 print(expire_time) 31 print(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 32 if time.time() > expire_time: #若是信用卡已超期
33 print("\033[31;1mAccount %s had expired,Please contract the bank" % account) 34 else: #信用卡未超期,返回用戶數據的字典
35 print("return") 36 return account_data 37 else: 38 print("\033[31;1mAccount or Passworddoes not correct!\033[0m") 39 else: #用戶不存在
40 print("\033[31;1mAccount [%s] does not exist!\033[0m" % account) 41
42
43
44
45 def access_login(user_data): 46 """
47 用記登錄,當登錄失敗超過三次?? 48 :param user_data: 49 :return: 50 """
51 retry = 0 52 while not user_data["is_authenticated"] and retry < 3: 53 account = input("Account:").strip() 54 password = input("Password:").strip() 55 access_auth(account, password)
db_handle.py
1 """
2 處理與數據庫的交互,如果file_db_storage,返回路徑 3 """
4
5 def file_db_handle(database): 6 """
7 數據存在文件 8 :param database: 9 :return: 返回路徑 ATM/db/accounts 10 """
11 db_path = "%s/%s" % (database["path"], database["name"]) 12 print(db_path) 13 return db_path 14
15
16
17 def mysql_db_handle(database): 18 """
19 處理mysql數據庫,這裏用文件來存數據, 20 保留這個方法主要爲了程序拓展性 21 :return: 22 """
23 pass
24
25
26 def handle(database): 27 """
28 對某種數據庫形式處因而 29 本程序用的是文件處理file_storage 30 :param database: settings裏面的DATABASE 31 :return: 返回路徑 32 """
33 if database["db_tool"] == "file_storage": 34 return file_db_handle(database) 35 if database["db_tool"] == "mysql": 36 return mysql_db_handle(database)
main.py
1 """
2 主邏輯交互模塊 3 """
4 from core import auth 5
6
7 #用戶數據信息
8 user_data = { 9 'account_id':None, #賬號ID
10 'is_authenticated':False, #是否定證
11 'account_data':None #賬號數據
12
13 } 14
15
16 def account_info(): 17 """
18 用戶賬戶信息 19 :return: 20 """
21 pass
22
23
24 def repay(): 25 """
26 還款 27 :return: 28 """
29 pass
30
31
32 def withdraw(): 33 """
34 退出 35 :return: 36 """
37 pass
38
39
40 def transfer(): 41 """
42 轉賬 43 :return: 44 """
45 pass
46
47
48 def paycheck(): 49 """
50 轉賬檢查 51 :return: 52 """
53 pass
54
55
56 def logout(): 57 """
58 退出登錄 59 :return: 60 """
61 pass
62
63
64 def interactive(): 65 """
66 交互 67 :return: 68 """
69 pass
70
71
72
73 def run(): 74 """
75 當程序啓動時調用,用於實現主要交互邏輯 76 :return: 77 """
78 access_data = auth.access_login(user_data) #調用認證模塊,返回用戶文件json.load後的字典
79 print("AA")
zcl.json
{"status": 0, "expire_date": "2021-01-01", "credit": 15000, "pay_day": 22, "balance": 15000, "enroll_date": "2016-01-02", "id": 22, "password": "abc"}
測試結果1:
C:\Users\Administrator\PycharmProjects\laonanhai\ATM BB Account:zcl Password:abc C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json {'id': 22, 'credit': 15000, 'password': 'abc', 'status': 0, 'expire_date': '2012-01-01', 'enroll_date': '2016-01-02', 'pay_day': 22, 'balance': 15000} 1325347200.0 time.struct_time(tm_year=2012, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=1, tm_isdst=-1) Account zcl had expired,Please contract the bank Account:
測試結果2:
C:\Users\Administrator\PycharmProjects\laonanhai\ATM BB Account:zcl Password:abc C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json {'expire_date': '2021-01-01', 'status': 0, 'enroll_date': '2016-01-02', 'balance': 15000, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22} 1609430400.0 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) return Account:
OK, 今日退朝,明日繼續!
1.amt.py運行時調用core目錄下的main.py
2.main.py調用core目錄下的auth.py進行登錄和信用卡認證
3.auth.py調用db_handle.py,返回賬號文件的路徑,進行信用卡賬戶檢查
4.auth.py進行登錄認證,登錄失敗不能超過三次(未徹底實現)
今天完善了登錄功能,實現了日誌功能,寫了一點點交互功能,好比查看賬戶信息,自我感受良好。
1.看下面這段代碼
1 msg = ( 2 """ 3 -------------ZhangChengLiang Bank--------------- 4 \033[31;1m 1. 帳戶信息 5 2. 還款 6 3. 取款 7 4. 轉帳 8 5. 帳單 9 6. 退出 10 \033[0m""" 11 ) 12 menu_dic = { 13 "1":account_info, 14 "2":repay, 15 "3":withdraw, 16 "4":transfer, 17 "5":paycheck, 18 "6":logout 19 } 20 flag = False 21 while not flag: 22 print(msg) 23 choice = input("<<<:").strip() 24 if choice in menu_dic: 25 #很重要!!省了不少代碼,不用像以前一個一個判斷! 26 menu_dic[choice](acc_data) 27 28 else: 29 print("\033[31;1mYou choice doesn't exist!\033[0m")
固然,在面向對象能夠用反射(我尚未過),但這裏我感受用得至關巧!!不用像我以前一個一個用if...else..來判斷。
2.掌握日誌的用法
以前只是知道,寫單獨的一個文件,此次綜合的運用,感受我對日誌的用法已經至關有信心了。
16/11/5 文件目錄
與昨天的基本沒有什麼變化,只是運行時在log包下多了個access.log文件還有在core包下多了log.py文件
atm.py 不變
settings.py
只多了個LOGIN_TYPE字典,用於後面生成access.log日誌文件
1 """
2 初始化的配置 3 """
4
5 import logging 6 import os 7
8 #到ATM目錄,方便後面建立賬戶文件
9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10
11 LOGIN_LEVEL = logging.INFO #初始化日誌級別
12
13 LOGIN_TYPE = { 14 "access":"access.log"
15 } 16
17
18 DATABASE = { 19 "db_tool":"file_storage", #文件存儲,這裏可拓展成數據庫形式的
20 "name":"accounts", #db下的文件名
21 "path":"%s/db" % BASE_DIR 22 }
auth.py
完善了登錄功能,日誌功能
1 """
2 認證模塊 3 """
4 print("BB") 5 import os 6 import json 7 import time 8
9 from core import db_handle 10 from conf import settings 11
12
13 def access_auth(account, password, log_obj): 14 """
15 下面的access_login調用access_auth方法,用於登錄 16 :param acount: 用戶名 17 :param password: 密碼 18 :return:若是未超期,返回字典,超期則打印相應提示 19 """
20 db_path = db_handle.handle(settings.DATABASE) #調用db_handle下的handle方法,返回路徑/db/accounts
21 print(db_path) 22 account_file = "%s/%s.json" % (db_path, account) #用戶文件
23 print(account_file) 24 if os.path.isfile(account_file): #若是用戶文件存在(即用戶存在)
25 with open(account_file, "r", encoding="utf-8") as f: #打開文件
26 account_data = json.load(f) #file_data爲字典形式
27 print(account_data) 28 if account_data["password"] == password: 29 expire_time = time.mktime(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 30 print(expire_time) 31 print(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 32 if time.time() > expire_time: #若是信用卡已超期
33 log_obj.error("Account [%s] had expired,Please contract the bank" % account) 34 print("\033[31;1mAccount [%s] had expired,Please contract the bank" % account) 35 else: #信用卡未超期,返回用戶數據的字典
36 print("return") 37 log_obj.info("Account [%s] logging success" % account) 38 return account_data 39 else: 40 log_obj.error("Account or Passworddoes not correct!") 41 print("\033[31;1mAccount or Passworddoes not correct!\033[0m") 42 else: #用戶不存在
43 log_obj.error("Account [%s] does not exist!" % account) 44 print("\033[31;1mAccount [%s] does not exist!\033[0m" % account) 45
46
47
48
49 def access_login(user_data, log_obj): 50 """
51 用記登錄,當登錄失敗超過三次則退出 52 :param user_data: main.py裏面的字典 53 :return:若用戶賬號密碼正確且信用卡未超期,返回用戶數據的字典 54 """
55 retry = 0 56 while not user_data["is_authenticated"] and retry < 3: 57 account = input("Account:").strip() 58 password = input("Password:").strip() 59 #用戶賬號密碼正確且信用卡未超期,返回用戶數據的字典
60 user_auth_data = access_auth(account, password, log_obj) 61 if user_auth_data: 62 user_data["is_authenticated"] = True #用戶認證爲True
63 user_data["account_id"] = account #用戶賬號ID爲賬號名
64 print("welcome") 65 return user_auth_data 66 retry += 1 #登錄和信用卡認證出錯,則次數加1
67
68 else: #若次數超過三次,打印相關信息並退出
69 print("Account [%s] try logging too many times..." % account) 70 log_obj.error("Account [%s] try logging too many times..." % account) 71 exit()
db_handle.py不變
log.py
實現日誌功能,我裏我先文件和屏幕都有輸出。
1 import logging 2 from conf import settings 3
4
5 def log(logging_type): 6 """
7 main模塊調用access_logger = log.log("access") 8 :param logging_type: "access" 9 :return: 返回logger日誌對象 10 """
11 logger = logging.getLogger(logging_type) #傳日誌用例,生成日誌對象
12 logger.setLevel(settings.LOGIN_LEVEL) #設置日誌級別
13
14 ch = logging.StreamHandler() #日誌打印到屏幕,獲取對象
15 ch.setLevel(settings.LOGIN_LEVEL) 16
17 # 獲取文件日誌對象及日誌文件
18 log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOGIN_TYPE[logging_type]) 19 fh = logging.FileHandler(log_file) 20 fh.setLevel(settings.LOGIN_LEVEL) 21
22 #日誌格式
23 formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s-%(message)s") 24
25 #輸出格式
26 ch.setFormatter(formatter) 27 fh.setFormatter(formatter) 28
29 #把日誌打印到指定的handler
30 logger.addHandler(ch) 31 logger.addHandler(fh) 32
33 return logger #log方法返回logger對象
34
35 # logger.debug('debugmessage')
36 # logger.info('infomessage')
37 # logger.warn('warnmessage')
38 # logger.error('errormessage')
39 # logger.critical('criticalmessage')
main.py
增長了一點用交互功能(未完成)
1 """
2 主邏輯交互模塊 3 """
4 from core import auth 5 from core import log 6
7
8 #用戶數據信息
9 user_data = { 10 'account_id':None, #賬號ID
11 'is_authenticated':False, #是否定證
12 'account_data':None #賬號數據
13
14 } 15
16 #調用log文件下的log方法,返回日誌對象
17 access_logger = log.log("access") 18
19
20 def account_info(acc_data): 21 """
22 查看用戶賬戶信息 23 :return: 24 """
25 print(acc_data) 26
27
28 def repay(acc_data): 29 """
30 還款 31 :return: 32 """
33 pass
34
35
36 def withdraw(): 37 """
38 退出 39 :return: 40 """
41 pass
42
43
44 def transfer(): 45 """
46 轉賬 47 :return: 48 """
49 pass
50
51
52 def paycheck(): 53 """
54 轉賬檢查 55 :return: 56 """
57 pass
58
59
60 def logout(): 61 """
62 退出登錄 63 :return: 64 """
65 pass
66
67
68 def interactive(acc_data): 69 """
70 用戶交互 71 :return: 72 """
73 msg = ( 74 """
75 -------------ZhangChengLiang Bank--------------- 76 \033[31;1m 1. 帳戶信息 77 2. 還款 78 3. 取款 79 4. 轉帳 80 5. 帳單 81 6. 退出 82 \033[0m"""
83 ) 84 menu_dic = { 85 "1":account_info, 86 "2":repay, 87 "3":withdraw, 88 "4":transfer, 89 "5":paycheck, 90 "6":logout 91 } 92 flag = False 93 while not flag: 94 print(msg) 95 choice = input("<<<:").strip() 96 if choice in menu_dic: 97 #很重要!!省了不少代碼,不用像以前一個一個判斷!
98 menu_dic[choice](acc_data) 99
100 else: 101 print("\033[31;1mYou choice doesn't exist!\033[0m") 102
103
104
105 def run(): 106 """
107 當程序啓動時調用,用於實現主要交互邏輯 108 :return: 109 """
110 # 調用認證模塊,返回用戶文件json.load後的字典,傳入access_logger日誌對象
111 access_data = auth.access_login(user_data, access_logger) 112 print("AA") 113 if user_data["is_authenticated"]: #若是用戶認證成功
114 print("has authenticated") 115 #將用戶文件的字典賦給user_data["account_data"]
116 user_data["account_data"] = access_data 117 interactive(user_data) #用戶交互開始
1 C:\Users\Administrator\PycharmProjects\laonanhai\ATM 2 BB 3 Account:123 4 Password:333 5 2016-11-05 23:03:55,210-access-ERROR-Account [123] does not exist! 6 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 7 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 8 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/123.json 9 Account [123] does not exist! 10 Account:zcl 11 Password:abc 12 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 13 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 14 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json 15 {'balance': 15000, 'enroll_date': '2016-01-02', 'expire_date': '2021-01-01', 'status': 0, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22} 16 2016-11-05 23:04:08,977-access-INFO-Account [zcl] logging success 17 1609430400.0 18 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) 19 return 20 welcome 21 AA 22 has authenticated 23 24 -------------ZhangChengLiang Bank--------------- 25 1. 帳戶信息 26 2. 還款 27 3. 取款 28 4. 轉帳 29 5. 帳單 30 6. 退出 31 32 <<<:1 33 {'account_data': {'balance': 15000, 'enroll_date': '2016-01-02', 'expire_date': '2021-01-01', 'status': 0, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22}, 'is_authenticated': True, 'account_id': 'zcl'} 34 35 -------------ZhangChengLiang Bank--------------- 36 1. 帳戶信息 37 2. 還款 38 3. 取款 39 4. 轉帳 40 5. 帳單 41 6. 退出
1.log.py設置日誌級別、生成日誌對象,返回logger日誌對象
2.main.py在調用auth.py認證模塊時,傳logger對象
3.經過logger對象進行一系列操做
4.main.py中run()方法調用interactive交互接口
5.interactive()方法經過用戶選擇進行交互(大部分還未實現)
11/5 OK,明日繼續!
今天都在實現用戶的交互功能,我只實現了存款功能repay,別看只實現了一個,我拓展性搞得還能夠的!其餘未實現,但感受套路都是差很少的。
在實現用戶交互功能之一(存款)時,個人思考以下:
6. 到這裏我大悟,每次用戶調用ATM交互功能,應先將用戶信息讀出來,每個功能結束後都應將信息更新到數據庫中去
1.用戶交易模塊的拓展性驚人
def make_transaction(account_data, transaction_type, amount): 這裏的transaction_type交易類型(存,取,轉…)
在settings.py定義好交易的類型,拓展性很好!
1 #用戶交易類型,每一個類型對應一個字典,包括賬戶金額變更方式,利息
2 TRANSACTION_TYPE = { 3 "repay":{"action":"plus", "interest":0}, #存款
4 "withdraw":{"action":"minus", "interest": 0.05} #取款(提現)
5 }
2. if num == "b" or "back"
這裏我SB了,哈哈~
1 num = input(">>>>:") 2 if num == "b" or "back": 3 print("OK") 4 else: 5 print("ERROR")
這裏我測試時,明明輸入的不是"b" 或者"back", 但結果倒是「OK", 一度讓我懷疑人生,因而我作了上面的測試。
仔細一想, or "back",「back」 不爲0,因此這個判斷爲True, 必定輸出的是"OK". .......之後不再敢了~
與11/5多了transaction.py模塊,account.py模塊,test.py是我本身測試用的,能夠忽略~
main.py
實現了還款功能
1 """ 2 主邏輯交互模塊 3 """ 4 from core import auth 5 from core import log 6 from core import transaction 7 from core import account 8 9 10 #用戶數據信息 11 user_data = { 12 'account_id':None, #賬號ID 13 'is_authenticated':False, #是否定證 14 'account_data':None #賬號數據 15 16 } 17 18 #調用log文件下的log方法,返回日誌對象 19 access_logger = log.log("access") 20 21 22 def account_info(acc_data): 23 """ 24 acc_data:包括ID,is_authenticaed,用戶賬號信息 25 查看用戶賬戶信息 26 :return: 27 """ 28 print(acc_data) 29 30 31 def repay(acc_data): 32 """ 33 acc_data:包括ID,is_authenticaed,用戶賬號信息 34 還款 35 :return: 36 """ 37 print(acc_data) 38 print("??") 39 #調用account模塊的load_account方法,從數據庫從load出用戶信息 40 account_data = account.load_account(acc_data["id"]) 41 print(account_data) 42 current_balance = """ 43 -------------BALANCE INFO-------------- 44 Credit:%s 45 Balance:%s 46 """ % (account_data["credit"], account_data["balance"]) 47 back_flag = False 48 while not back_flag: 49 print(current_balance) 50 repay_amount = input("\033[31;1mInput repay amount(b=back):\033[0m").strip() 51 #若是用戶輸入整型數字 52 if len(repay_amount) > 0 and repay_amount.isdigit(): 53 #調用transaction模塊的方法,參數分別是用戶賬戶信息,交易類型,交易金額 54 new_account_data = transaction.make_transaction(account_data, "repay", repay_amount) 55 if new_account_data: 56 print("\033[42;1mNew Balance:%s\033[0m" % new_account_data["balance"]) 57 58 else: 59 print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % repay_amount) 60 61 if repay_amount =="b" or repay_amount == "back": 62 back_flag = True 63 64 def withdraw(): 65 """ 66 取款 67 :return: 68 """ 69 pass 70 71 72 def transfer(): 73 """ 74 轉賬 75 :return: 76 """ 77 pass 78 79 80 def paycheck(): 81 """ 82 轉賬檢查 83 :return: 84 """ 85 pass 86 87 88 def logout(): 89 """ 90 退出登錄 91 :return: 92 """ 93 pass 94 95 96 def interactive(acc_data): 97 """ 98 用戶交互 99 :return: 100 """ 101 msg = ( 102 """ 103 -------------ZhangChengLiang Bank--------------- 104 \033[31;1m 1. 帳戶信息 105 2. 存款 106 3. 取款 107 4. 轉帳 108 5. 帳單 109 6. 退出 110 \033[0m""" 111 ) 112 menu_dic = { 113 "1":account_info, 114 "2":repay, 115 "3":withdraw, 116 "4":transfer, 117 "5":paycheck, 118 "6":logout 119 } 120 flag = False 121 while not flag: 122 print(msg) 123 choice = input("<<<:").strip() 124 if choice in menu_dic: 125 #很重要!!省了不少代碼,不用像以前一個一個判斷! 126 menu_dic[choice](acc_data) 127 128 else: 129 print("\033[31;1mYou choice doesn't exist!\033[0m") 130 131 132 133 def run(): 134 """ 135 當程序啓動時調用,用於實現主要交互邏輯 136 :return: 137 """ 138 # 調用認證模塊,返回用戶文件json.load後的字典,傳入access_logger日誌對象 139 access_data = auth.access_login(user_data, access_logger) 140 print("AA") 141 if user_data["is_authenticated"]: #若是用戶認證成功 142 print("has authenticated") 143 #將用戶文件的字典賦給user_data["account_data"] 144 user_data["account_data"] = access_data 145 interactive(user_data) #用戶交互開始
settings.py
增長了用戶交易類型TRANSACTION_TYPE{}
1 """ 2 初始化的配置 3 """ 4 5 import logging 6 import os 7 8 #到ATM目錄,方便後面建立賬戶文件 9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 11 LOGIN_LEVEL = logging.INFO #初始化日誌級別 12 13 LOGIN_TYPE = { 14 "access":"access.log" 15 } 16 17 18 DATABASE = { 19 "db_tool":"file_storage", #文件存儲,這裏可拓展成數據庫形式的 20 "name":"accounts", #db下的文件名 21 "path":"%s/db" % BASE_DIR 22 } 23 24 #用戶交易類型,每一個類型對應一個字典,包括賬戶金額變更方式,利息 25 TRANSACTION_TYPE = { 26 "repay":{"action":"plus", "interest":0}, #存款 27 "withdraw":{"action":"minus", "interest": 0.05} #取款(提現) 28 }
transaction.py
處理用戶交易的模塊
1 """ 2 交易模塊,處理用戶金額移動 3 """ 4 import json 5 from conf import settings 6 from core import account 7 8 9 def make_transaction(account_data, transaction_type, amount): 10 """ 11 處理用戶的交易 12 :param account_data:字典,用戶的賬戶信息 13 :param transaction_type:用戶交易類型,repay or withdraw... 14 :param amount:交易金額 15 :return:用戶交易後賬戶的信息 16 """ 17 #將字符串類型轉換爲float類型 18 amount = float(amount) 19 #若是交易類型存在 20 if transaction_type in settings.TRANSACTION_TYPE: 21 #利息金額 22 interest = amount * settings.TRANSACTION_TYPE[transaction_type]["interest"] 23 #用戶原金額 24 old_balace = account_data["balance"] 25 print(interest,old_balace) 26 #若是賬戶金額變化方式是"plus",加錢 27 if settings.TRANSACTION_TYPE[transaction_type]["action"] == "plus": 28 new_balance = old_balace + amount + interest 29 #若是賬戶金額變化方式是"minus",減錢 30 elif settings.TRANSACTION_TYPE[transaction_type]["action"] == "minus": 31 new_balance = old_balace - amount - interest 32 #減錢時對賬戶金額進行檢查,防止超額 33 if new_balance < 0: 34 print("\033[31;1mYour Credit [%s] is not enough for transaction [-%s], and Now your" 35 " current balance is [%s]" % (account_data["credit"], (amount+interest), old_balace)) 36 return 37 38 account_data["balance"] = new_balance 39 #調用core下account模塊將已更改的用戶信息更新到用戶文件 40 account.dump_account(account_data) 41 return account_data 42 43 else: 44 print("\033[31;1mTransaction is not exist!033[0m")
account.py
將用戶信息讀出或寫入的模塊
1 """ 2 用於處理用戶信息的load or dump 3 每進行一個操做就將信息更新到數據庫 4 """ 5 from core import db_handle 6 from conf import settings 7 import json 8 9 def load_account(account_id): 10 """ 11 將用戶信息從文件中load出來 12 :return: 用戶信息的字典 13 """ 14 #返回路徑 ATM/db/accounts 15 db_path = db_handle.handle(settings.DATABASE) 16 account_file = "%s/%s.json" % (db_path, account_id) 17 with open(account_file, "r", encoding="utf-8") as f: 18 account_data = json.load(f) 19 return account_data 20 21 22 def dump_account(account_data): 23 """ 24 將已更改的用戶信息更新到用戶文件 25 :param account_data: 每操做後用戶的信息 26 :return: 27 """ 28 db_path = db_handle.handle(settings.DATABASE) 29 account_file = "%s/%s.json" % (db_path, account_data["id"]) 30 with open(account_file, "w", encoding="utf-8") as f: 31 json.dump(account_data, f) 32 33 print("dump success")
1 C:\Users\Administrator\PycharmProjects\laonanhai\ATM 2 BB 3 Account:zcl 4 Password:abc 5 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 6 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 7 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json 8 {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 9 1609430400.0 10 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) 11 return 12 2016-11-07 13:42:24,678-access-INFO-Account [zcl] logging success 13 welcome 14 AA 15 has authenticated 16 17 -------------ZhangChengLiang Bank--------------- 18 1. 帳戶信息 19 2. 存款 20 3. 取款 21 4. 轉帳 22 5. 帳單 23 6. 退出 24 25 <<<:2 26 {'is_authenticated': True, 'account_data': {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'}, 'account_id': None, 'id': 'zcl'} 27 ?? 28 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 29 {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 30 31 -------------BALANCE INFO-------------- 32 Credit:15000 33 Balance:26000.0 34 35 Input repay amount(b=back):4500 36 0.0 26000.0 37 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 38 dump success 39 New Balance:30500.0 40 41 -------------BALANCE INFO-------------- 42 Credit:15000 43 Balance:26000.0 44 45 Input repay amount(b=back):back 46 back is not valid amount,Only accept interger! 47 48 -------------ZhangChengLiang Bank--------------- 49 1. 帳戶信息 50 2. 存款 51 3. 取款 52 4. 轉帳 53 5. 帳單 54 6. 退出 55 56 <<<:2 57 {'is_authenticated': True, 'account_data': {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'}, 'account_id': None, 'id': 'zcl'} 58 ?? 59 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 60 {'balance': 30500.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 61 62 -------------BALANCE INFO-------------- 63 Credit:15000 64 Balance:30500.0 65 66 Input repay amount(b=back):10000 67 0.0 30500.0 68 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 69 dump success 70 New Balance:40500.0 71 72 -------------BALANCE INFO-------------- 73 Credit:15000 74 Balance:30500.0 75 76 Input repay amount(b=back):
1.repay還款功能調用account.py經過ID讀出用戶信息
2.repay還款功能調用transaction.py交易模塊
3.transaction.py交易模塊調用account.py更新用戶數據到數據庫
4.settings.py裏的TRANSACTION_TYPE字典傳入交易方法,實現拓展性
今日超神,明日繼續實現交互功能或體息一天!
作了還款,取款,轉賬功能,都是套路了,難度不大。
咋晚給舍友看了我作了東西,居然被舍友說,亮點在哪裏。時間有限,生命有限,繼續學習之路,這個小項目就到此爲止了。
ATM壓縮包:http://pan.baidu.com/s/1hrNF5TM