一、程序需求
模擬實現一個ATM + 購物商城程序:
1.額度 15000或自定義
2.實現購物商城,買東西加入 購物車,調用信用卡接口結賬
3.可以提現,手續費5%
4.每月22號出賬單,每月10號為還款日,過期未還,按欠款總額 萬分之5 每日計息(沒寫)
5.支持多賬戶登錄
6.支持賬戶間轉賬
7.記錄每月日常消費流水
8.提供還款接口
9.ATM記錄操作日志
10.提供管理接口,包括添加賬戶、用戶額度,凍結賬戶等。。。
11.用戶認證用裝飾器
腦圖:
二、目錄

1 ├── ATM #ATM主程目錄 2 │ ├── __init__.py 3 │ ├── bin #ATM 執行文件 目錄 4 │ │ ├── __init__.py 5 │ │ ├── atm.py #ATM 執行程序 6 │ │ ├── manage.py #信用卡管理 7 │ ├── conf #配置文件 8 │ │ ├── __init__.py 9 │ │ └── Settings.py #配置參數 10 │ ├── core #主要程序邏輯都 在這個目錄 里 11 │ │ ├── __init__.py 12 │ │ ├── accounts.py #用於從文件里加載和存儲賬戶數據 13 │ │ ├── auth.py #用戶認證模塊及主要功能函數 14 │ │ ├── db_handler.py #數據庫連接引擎 15 │ │ ├── logger.py #日志記錄模塊 16 │ │ ├── main.py #主邏輯交互程序 17 │ │ ├── transaction.py #記賬\還錢\取錢\與賬戶金額相關的操作,凍結或者鎖定用戶 18 │ ├── db #用戶數據存儲的地方 19 │ │ ├── __init__.py 20 │ │ ├── account_sample.py #生成一個初始的賬戶數據 ,把這個數據 存成一個 以這個賬戶id為文件名的文件,放在accounts目錄 就行了,程序自己去會這里找 21 │ │ └── accounts #存各個用戶的賬戶數據 ,一個用戶一個文件 22 │ │ └── 123.json #新創建的用戶賬戶示例文件 23 │ │ └── 1234.json #一個用戶賬戶示例文件 24 │ │ └── 123456.json #一個用戶賬戶示例文件 25 │ │ └── 6230001.json #管理用戶賬戶示例文件 26 │ └── log #日志目錄 27 │ ├── access.log #用戶訪問和操作的相關日志 28 │ └── login_in.log #登陸日志 29 └── shopping_mall #電子商城程序,需單獨實現,主要實現購物的功能。 30 │ └── __init__.py 31 │ └── product.txt #存放商品的txt文件 32 │ └── shopping_list.txt #存放購物清單的txt.文件 33 │ └── shopping_mall.py #購物商城程序 34 ├── README
三、簡要說明
1.程序從/bin/atm.py開始執行if __name__ == '__main__':
main.run()
2.程序轉到/core/main.py下的run()函數,登陸時調用/core/auth的acc_login()進行登陸驗證:用到了/core/auth下的acc_auth2()方法進行驗證(此時傳入的參數時用戶輸入的賬戶和密碼)
acc_auth2中有調用了/core/db_handler下的db_handler()方法(參數是輸入的賬戶名)在db_handler中只是進行判斷是什么引擎,return file_db_handle(數據庫引擎)解析文件,返回文件執行加載輸入的用戶的賬戶的所有數據
接下來判斷是否為管理者賬戶,或者是否被凍結,若都不是,則判斷輸入的密碼是否與數據庫中的密碼一樣,在判斷到期時間是否過期
所有都通過的話就返回這個賬戶的數據,之前已經創建了一個空字典,里面有是否驗證:用戶數據:用戶賬戶:,判斷是否被驗證過,然后把用戶數據臨時的傳遞到里面,執行主循環函數
可以選擇進入到購物商城,或者信用卡操作或者退出
1)購物商城
調用/shopping_mall/shopping_mall.py文件執行,主循環函數,選擇你是商家還是用戶,
①如果選擇商家,商家有增加商品修改商品的功能
②如果選擇用戶,用戶則有購物,刷信用卡消費的功能,當退出時打印消費清單
2)信用卡操作
調用/core/main.py下interactive(用戶的所有數據)調用主循環函數,可以打印賬戶信息、還款、取款、轉賬、賬單、退出等操作
①賬戶信息
②還款
③取款
④轉賬
⑤賬單
⑥退出
3)若在賬戶登陸的時候進行輸入的時管理員賬戶調用/bin/manage.py則可以對用戶進行管理,解凍 用戶、凍結用戶、申領新卡
①添加賬戶
②凍結賬戶
③解凍賬戶
④退出
四、主程序
1.bin目錄下代碼

1 '''/bin/atm.py''' 2 3 4 #!/usr/bin/env python 5 #-*- Coding:utf-8 -*- 6 # Author:Eric.Shen 7 import os,sys 8 base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 9 #print(base_dir) 10 sys.path.append(base_dir) 11 from core import main 12 13 14 if __name__ == '__main__': 15 main.run() 16 17 18 19 20 21 22 23 '''/bin/manage.py''' 24 25 26 27 #!/usr/bin/env python 28 #-*- Coding:utf-8 -*- 29 # Author:Eric.Shen 30 #管理端(提供管理接口,包括添加賬戶、用戶額度,凍結賬戶) 31 #解凍賬戶 32 #from core.auth import login_required 33 from core import accounts 34 from core import transaction 35 #解凍賬戶 36 def unblock_account(acc_data): 37 user_input = input("請輸入你要解凍的用戶:") 38 flag = 0 39 #鎖定用戶 40 val = transaction.lock_or_not(user_input,flag) 41 if val == 0: 42 print("解凍成功!") 43 return 44 #凍結賬戶 45 def block_account(acc_data): 46 ''' 47 凍結賬戶初步構想是,在linux里把他的權限改掉; 48 或者將其文件改名 49 :param acc_data: 50 :return: 51 ''' 52 user_input = input("請輸入你要凍結的用戶:") 53 flag = 1 54 #鎖定用戶 55 val = transaction.lock_or_not(user_input,flag) 56 if val == 0: 57 print("凍結成功!") 58 return 59 60 #添加賬戶、用戶額度 61 def add_account(acc_data): 62 account = { 63 "id": None, 64 "balance": None, 65 "expire_date": None, 66 "enroll_date": None, 67 "credit": None, 68 "pay_day": None, 69 "password": None, 70 "status": None 71 } 72 menu = { 73 0: "賬戶(數字):", 74 1: "余額:", 75 2: "到期時間:", 76 3: "辦卡時間:", 77 4: "信用額度:", 78 5: "還款日期:", 79 6: "密碼:", 80 7: "默認:"} 81 menu_user = { 82 0: "id", 83 1: "balance", 84 2: "expire_date", 85 3: "enroll_date", 86 4: "credit", 87 5: "pay_day", 88 6: "password", 89 7: "status" 90 } 91 for i in range(8): 92 data = input("%s" % menu[i]).strip() 93 account['%s' % menu_user[i]] = data 94 accounts.dump_account(account)#寫入文件 95 print("創建成功!") 96 return 97 98 99 100 def logout(acc_data): 101 exit("程序退出!") 102 #管理界面主程序 103 def manage_main(acc_data): 104 105 menu = u''' 106 ---------管理界面--------- 107 1.添加賬戶 108 2.凍結賬戶 109 3.解凍賬戶 110 4.退出''' 111 menu_dic = { 112 '1': add_account, 113 '2': block_account, 114 '3': unblock_account, 115 '4': logout 116 } 117 exit_flag = False 118 while not exit_flag: 119 print(menu) 120 user_option = input("請輸入你的選擇:") 121 if user_option in menu_dic: 122 menu_dic[user_option](acc_data) 123 else: 124 print("\033[31;1m選擇不存在!\033[0m") 125 126 127 128 129 .
2.conf目錄下代碼

1 '''/conf/Settings.py''' 2 3 4 #!/usr/bin/env python 5 #-*- Coding:utf-8 -*- 6 # Author:Eric.Shen 7 #參數配置文件 8 import os,sys,logging 9 10 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#/Atm 11 12 DATABASE = { 13 'engine': 'file_storage', 14 'name': 'accounts', 15 'path': "%s/db" % BASE_DIR#../Atm 16 } 17 18 LOG_LEVEL = logging.INFO 19 LOG_TYPES = { 20 'transaction': 'transaction.log', 21 'access': 'access.log', 22 } 23 24 #發生交易的配置類型 25 TRANSACTION_TYPE = { 26 'repay':{'action':'plus','interest':0},#還款 27 'withdraw':{'action':'minus','interest':0.05},#取現是降低可用余額 28 'transfer':{'action':'minus','interest':0.05},#轉賬是降低可用余額 29 'consume':{'action':'minus','interest':0}, 30 }
3.core目錄下代碼

1 '''/core/accounts.py''' 2 3 4 #!/usr/bin/env python 5 #-*- Coding:utf-8 -*- 6 # Author:Eric.Shen 7 #用於從文件里加載和存儲賬戶數據 8 import json,time 9 from core import db_handler 10 from conf import Settings 11 12 #返回賬戶余額和其他基礎信息(返回最新的數據) 13 def load_current_balance(account_id): 14 ''' 15 返回賬戶余額和其他基礎信息 16 :param account_id: 用戶賬戶的名字 17 :return: 返回最新讀到的數據文件中的最新數據 18 ''' 19 # db_path = db_handler.db_handler(settings.DATABASE) 20 # account_file = "%s/%s.json" %(db_path,account_id) 21 # 22 db_api = db_handler.db_handler() 23 data = db_api("select * from accounts where account=%s" % account_id)#在進行操作的時候在讀取一遍數據中的數據(保證數據的最新) 24 return data#返回讀取到的數據 25 26 # with open(account_file) as f: 27 # acc_data = json.load(f) 28 # return acc_data 29 30 #寫入文件數據 31 def dump_account(account_data): 32 ''' 33 34 :param account_data: 35 :return: 36 ''' 37 db_api = db_handler.db_handler() 38 data = db_api("update accounts where account=%s" % account_data['id'],account_data = account_data) 39 40 # db_path = db_handler.db_handler(settings.DATABASE) 41 # account_file = "%s/%s.json" %(db_path,account_data['id']) 42 # with open(account_file, 'w') as f: 43 # acc_data = json.dump(account_data,f) 44 return True

1 '''/core/auth.py''' 2 3 4 #!/usr/bin/env python 5 #-*- Coding:utf-8 -*- 6 # Author:Eric.Shen 7 #用戶認證模塊 8 import json,time,os 9 from core import db_handler 10 from bin import manage 11 from conf import Settings 12 from core import logger 13 #裝飾器(用於驗證賬戶是否登陸過) 14 def login_required(func): 15 ''' 16 驗證用戶是否登陸 17 :return: 18 ''' 19 def wrapper(*args,**kwargs): 20 if args[0].get('is_authenticated'): 21 return func(*args,**kwargs) 22 else: 23 exit("用戶不能認證") 24 return wrapper 25 26 def acc_auth(account,password): 27 ''' 28 賬戶驗證函數 29 :return: 30 ''' 31 db_path = db_handler.db_handler() 32 account_file = "%s/%s.json" %(db_path,account) 33 print(account_file) 34 if os.path.isfile(account_file): 35 with open(account_file,'r') as f: 36 account_data = json.load(f) 37 if account_data['password'] == password: 38 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d")) 39 if time.time() >exp_time_stamp: 40 print("\033[31;1m[%s]賬戶已經注銷,請重新申領賬戶!\033[0m" % account) 41 else: #passed the authentication 42 return account_data 43 else: 44 print("\033[31;1m賬號或密碼錯誤,請重新輸入!\033[0m") 45 else: 46 print("\033[31;1m[%s]賬戶不存在!\033[0m" % account) 47 48 def acc_auth2(account,password): 49 ''' 50 優化版認證接口 51 :param 52 account:信用卡賬戶 53 password:信用卡密碼 54 :return: 返回讀取到的數據文件的所有賬戶數據 55 ''' 56 db_api = db_handler.db_handler() 57 data = db_api("select * from accounts where account=%s" %account)#此處返回值為db_handler.py中的 58 # 得到的所有數據(讀取到的這個賬戶的所有數據)賦值給data 59 if data["status"] == 2:#判斷是否為管理者 60 manage.manage_main(data) 61 if data['status'] == 1: 62 print("你的賬戶已經被凍結,請聯系管理員!\n") 63 option = input("請按b退出!") 64 if option == "b": 65 exit("程序已經退出!") 66 if data['password'] == password:#判斷data中的password數據是否恆等於輸入的password(此處如果繼續執行,則賬戶密碼完全正確) 67 #time.mktime 返回用秒數來表示時間的浮點數。 68 #實例結果:time.mktime(t) : 1234915418.000000 69 #time.strptime 根據指定的格式把一個時間字符串解析為時間元組 70 #實例結果:time.strptime(string[, format]) 71 exp_time_stamp = time.mktime(time.strptime(data['expire_date'],"%Y-%m-%d"))#將數據文件中的expire_data時間 72 # 轉為以秒計數的時間賦值給exp_time_stamp 73 if time.time() > exp_time_stamp:#判斷當前以秒計算的數據是否大於數據文件中的數據 74 print("\033[31;1m[%s]賬戶以及過期,請重新激活!\033[0m" % account) 75 else: 76 return data#沒有超時,則返回讀取到的數據文件的所有內容 77 else: 78 print("\033[31;1m帳戶名或者密碼錯誤!\033[0m") 79 80 81 def acc_login(user_data,log_obj): 82 ''' 83 賬戶登陸函數 84 :param 85 user_data:用戶信息數據,只存在內存中 86 :return: 賬戶密碼都對的情況下,返回所有賬戶數據 87 ''' 88 retry_count = 0#初始化重試次數 89 while user_data['is_authenticated'] is not True and retry_count < 3:#如果沒有驗證過,或循環此時沒超過三次就執行下面的 90 account = input("\033[32;1m賬戶:\033[0m").strip()#輸入賬戶 91 password = input("\033[32;1m密碼:\033[0m").strip()#輸入密碼 92 auth = acc_auth2(account,password)#解耦,將輸入的賬戶和密碼傳入到acc_auth2函數中,進行驗證 93 # (最后返回的是讀取到的輸入正確賬戶的所有數據)賦值給auth 94 if auth: 95 user_data['is_authenticated'] = True#登陸成功,將只存在與內存中的數據中的是否驗證改為True 96 user_data['account_id'] = account#將只存在與內存中的數據中的賬戶id改為賬戶名字(開始輸入的帳戶名) 97 return auth#這一步操作就是驗證此賬戶是否登陸,然后返回賬戶的所有數據(數據文件中的所有數據) 98 retry_count += 1 99 else: 100 log_obj.error("[%s]賬戶太多次嘗試" % account) 101 exit()

1 '''/core/db_handler.py''' 2 3 4 5 #!/usr/bin/env python 6 #-*- Coding:utf-8 -*- 7 # Author:Eric.Shen 8 #數據庫連接引擎 9 #處理所有數據庫交互 10 import json,time,os 11 from conf import Settings 12 13 #解析文件數據路徑 14 def file_db_handle(conn_params): 15 ''' 16 解析數據庫文件路徑 17 :return: 18 ''' 19 #print('file db:',conn_params) 20 return file_execute 21 22 #數據庫句柄 23 def db_handler(): 24 ''' 25 連接數據庫 26 :return: 27 ''' 28 conn_params = Settings.DATABASE#把Settings下的DATABASE的數據賦值給conn_params 29 if conn_params['engine'] == 'file_storage':#判斷Settings下的DABASE是什么引擎,這里只用文件文件引擎 30 return file_db_handle(conn_params)#則把Settings下的DABASE的數據傳給file_db_handle並返回 31 elif conn_params['engine'] == 'mysql': 32 pass#支持擴展,此次只作為一個說明 33 34 #文件執行 35 def file_execute(sql,**kwargs): 36 ''' 37 傳入sql語句,及其他變量, 38 :param sql: sql語句操作得到結果 39 :param kwargs: 其他得變量 40 :return: 41 ''' 42 conn_params = Settings.DATABASE#把Settings下的DATABASE的數據賦值給conn_params,再一次賦值意味着得到最新得數據 43 db_path = '%s/%s' % (conn_params['path'],conn_params['name'])#數據庫的文件路徑 ../db/accounts 44 #print(sql,db_path)#sql = select * from accounts where account=%s %account(此時這個account等於程序開始時要求喲用戶輸入得數據) 45 sql_list = sql.split('where')#將上面得sql語句以where分開,(sql_list列表內容:'select * from accounts' ,"account='account' ") 46 #print(sql_list) 47 #startswith() 方法用於檢查字符串是否是以指定子字符串開頭, 48 # 如果是則返回 True,否則返回False。如果參數 beg 和 end 指定值, 49 # 則在指定范圍內檢查。 50 if sql_list[0].startswith('select') and len(sql_list) > 1:#判斷sql_list列表中得第一個字符是select並且列表的長度是大於1的 51 column,val = sql_list[1].strip().split('=')#將sql_list列表第二個數據先去掉默認空格,並且以‘=’為界分開放入--》 52 #-->column = account , val = '此處為開始程序輸入的賬戶' 53 #Python strip() 方法用於移除字符串頭尾指定的字符(默認為空格)。 54 if column == 'account':#判斷是否為account,然后做指定的操作(這里使用的是account) 55 account_file = '%s/%s.json' % (db_path,val)#這一步得到數據文件路徑的文件絕對路徑 56 #print(account_file) 57 if os.path.isfile(account_file):#使用絕對路徑判斷是否為文件,返回True 58 with open(account_file,'r') as f:#以只對的方式打開文件並把文件句柄賦值給f(用with方法打開不用自己寫關閉文件的方法) 59 account_data = json.load(f)#json加載文件賦值給account_data 60 return account_data#返回account_data數據(將.json文件中的數據都都出來返回) 61 else: 62 exit("\033[31;1m[%s]賬戶不存在!\033[0m" % val)#若判斷不是,則返回沒有此用戶 63 #寫入數據 64 elif sql_list[0].startswith('update') and len(sql_list) > 1: 65 column, val = sql_list[1].strip().split('=')#將帳戶名寫入到val中 66 if column == 'account': 67 account_file = "%s/%s.json" % (db_path,val) 68 # if os.path.isfile(account_file): 69 account_data = kwargs.get("account_data")#得到賬戶數據 70 with open(account_file,'w') as f: 71 acc_data = json.dump(account_data,f) 72 #print(acc_data) 73 return True

1 '''/core/logger.py''' 2 3 #!/usr/bin/env python 4 #-*- Coding:utf-8 -*- 5 # Author:Eric.Shen 6 #日志記錄模塊,處理所有日志工作 7 8 import logging 9 from conf import Settings 10 11 def logger(log_type): 12 #創建日志 13 logger = logging.getLogger(log_type) 14 logger.setLevel(Settings.LOG_LEVEL) 15 16 #創建控制台處理程序並將級別設置為調試 17 ch = logging.StreamHandler() 18 ch.setLevel(Settings.LOG_LEVEL) 19 #創建文件處理程序並設置級別為警告 20 log_file = "%s/logs/%s" %(Settings.BASE_DIR,Settings.LOG_TYPES[log_type]) 21 fh = logging.FileHandler(log_file) 22 fh.setLevel(Settings.LOG_LEVEL) 23 #創建格式化程序 24 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levename)s- %(message)s') 25 26 #添加格式化的CH和FH 27 ch.setFormatter(formatter) 28 fh.setFormatter(formatter) 29 30 #添加CH和FH到loggerh 31 logger.addHandler(ch) 32 logger.addHandler(fh) 33 34 return logger 35 36 #應用程序代碼 37 '''logger.debug('debug message') 38 '''

1 #!/usr/bin/env python 2 #-*- Coding:utf-8 -*- 3 # Author:Eric.Shen 4 #記賬\還錢\取錢\與賬戶金額相關的操作,凍結或者鎖定用戶 5 from conf import Settings 6 from core import accounts 7 from core import logger 8 9 def make_transaction(log_obj,account_data,tran_type,amount,**kwargs): 10 ''' 11 處理所有用戶的所有交易 12 :param log_obj: 13 :param account_data: 用戶最新的數據 14 :param tran_type: 交易類型 15 :param amount: 交易數量 16 :param other: 主要用於日志使用 17 :return: 返回最新的賬戶數據 18 ''' 19 amount = float(amount)#轉換為浮點型 20 if tran_type in Settings.TRANSACTION_TYPE:#判斷傳入的類型是否在配置參數里面 21 interest = amount * Settings.TRANSACTION_TYPE[tran_type]["interest"]#根據交易類型計算利息賦值給interest 22 old_balance = account_data['balance']#讀取數據中賬戶余額 23 #還款操作 24 if Settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':#因為是信用卡,所以還款時提升可使用余額的操作,故計為加plus 25 new_balance = old_balance + amount + interest#執行的是信用卡的還款操作,計算方法是,舊余額+還款的錢和利息=最后的賬戶可用余額 26 #取現\轉賬操作 27 elif Settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':#因為是信用卡,所以取現都是降低可用余額的操作 28 new_balance = old_balance - amount - interest 29 #只屬於轉賬的 30 if kwargs.get('re_account'): 31 #print(kwargs[0],kwargs[1]) 32 re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要轉入賬戶的所有數據 33 re_account_balance = re_account_data['balance'] + amount#得到轉入賬戶余額的最新值 34 re_account_data['balance'] = re_account_balance#將最新的余額全部寫入賬戶的余額中 35 print(re_account_data) 36 accounts.dump_account(re_account_data)#將最新的賬戶所有數據寫入到文件中 37 if new_balance < 0: 38 print("\033[31;1m[%s]賬戶的信用余額不足以支付此次交易[-%s],你當前的余額是[%s]\033[0m" 39 % (account_data['creat'], (amount + interest), old_balance)) 40 return 41 #轉賬 42 ''' 43 elif Settings.TRANSACTION_TYPE[tran_type] == 'transfer' : 44 new_balance = old_balance - amount - interest#自己賬戶的最新余額 45 #讀取轉入的賬戶,寫入轉入金額 46 print(kwargs[0],kwargs[1]) 47 re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要轉入賬戶的所有數據 48 re_account_balance = re_account_data['balance'] + amount#得到轉入賬戶余額的最新值 49 re_account_data['balance'] = re_account_balance#將最新的余額全部寫入賬戶的余額中 50 print(re_account_data) 51 accounts.dump_account(re_account_data)#將最新的賬戶所有數據寫入到文件中 52 ''' 53 54 account_data['balance'] = new_balance#將最新的余額寫入到賬戶數據中 55 print(account_data) 56 accounts.dump_account(account_data)#將最新的賬戶余額寫回文件 57 #寫入日志 58 #log_obj.info('賬戶:%s,操作:%s,數量:%s,利息:%s' %(account_data['id'],tran_type,amount,interest)) 59 return account_data 60 else: 61 print("\033[31;1m%s交易類型不存在\033[0m" % tran_type) 62 #凍結或者鎖定用戶 63 def lock_or_not(account,flag): 64 data = accounts.load_current_balance(account) 65 66 if data["status"] == 1: 67 print("該賬戶已經鎖定!") 68 if data['status']: 69 data["status"] = flag 70 accounts.dump_account(data) 71 return 0

1 #!/usr/bin/env python 2 #-*- Coding:utf-8 -*- 3 # Author:Eric.Shen 4 #主程序句柄模塊,處理所有用戶交互內容 5 from core import auth 6 from core import accounts 7 from core import logger 8 from core import transaction 9 from core.auth import login_required 10 from shopping_mall import shopping_mall 11 from bin import manage 12 import time 13 14 15 #交易日志 16 trans_logger = logger.logger('transaction') 17 #訪問日志 18 access_logger = logger.logger('access') 19 20 #臨時賬戶數據,僅存在於內存中 21 user_data = { 22 'account_id':None, 23 'is_authenticated':False, 24 'account_data':None 25 } 26 27 #賬戶信息 28 def account_info(acc_data): 29 print(user_data) 30 #還款 31 @login_required#裝飾器,判斷用戶是否登陸 32 def repay(acc_data): 33 ''' 34 打印當前余額,讓用戶償還賬單 35 :param acc_data: 36 :return: 37 ''' 38 account_data = accounts.load_current_balance(acc_data['account_id'])#將用戶賬戶名字傳入到load_current_balance中 39 #返回最新的用戶數據賦值給 account_data 40 current_balance = ''' 41 ---------銀行信息---------- 42 信用額度: %s 43 可用余額: %s 44 ''' %(account_data['credit'],account_data['balance']) 45 print(current_balance) 46 back_flag = False 47 while not back_flag: 48 repay_amount = input("\033[33;1m輸入你要還款的金額:\033[0m").strip()#還款金額 49 if len(repay_amount) > 0 and repay_amount.isdigit(): 50 #print('ddd 00') 51 #將數據傳入make_transaction中(交易日志,用戶數據,交易類型,還款金額)進行操作,最后返回的是最新操作之后的賬戶數據 52 new_balance = transaction.make_transaction(trans_logger,account_data,'repay',repay_amount) 53 if new_balance: 54 print('''\033[42;1m最新的余額:%s\033[0m''' %(new_balance['balance'])) 55 else: 56 print('\033[31;1m[%s]是無效的賬戶!\033[0m' % repay_amount) 57 if repay_amount == 'b': 58 back_flag =True 59 #取款 60 @login_required 61 def withdraw(acc_data): 62 ''' 63 打印當前余額,讓用戶執行取款操作 64 :param acc_data: 65 :return: 66 ''' 67 account_data = accounts.load_current_balance(acc_data['account_id']) 68 # 將用戶賬戶名字傳入到load_current_balance中 69 # 返回最新的用戶數據賦值給 account_data 70 current_balance = ''' --------- 銀行信息 -------- 71 信用額度: %s 72 賬戶余額: %s''' % (account_data['credit'], account_data['balance']) 73 print(current_balance) 74 back_flag = False 75 while not back_flag: 76 withdraw_amount = input("\033[33;1m輸入取款金額:\033[0m").strip() 77 if withdraw_amount == 'b': 78 return 79 if len(withdraw_amount) > 0 and withdraw_amount.isdigit(): 80 new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount) 81 if new_balance: 82 print('''\033[42;1m最新余額:%s\033[0m''' %(new_balance['balance'])) 83 else: 84 print('\033[31;1m[%s]是無效的賬戶!\033[0m' % withdraw_amount) 85 86 87 #轉賬 88 @login_required 89 def transfer(acc_data): 90 ''' 91 打印當前余額,轉賬操作函數 92 :param acc_data:用戶數據 93 :return: 94 ''' 95 account_data = accounts.load_current_balance(acc_data['account_id']) 96 # 將用戶賬戶名字傳入到load_current_balance中 97 # 返回最新的用戶數據賦值給 account_data 98 current_balance = ''' --------- 銀行信息 -------- 99 信用額度: %s 100 賬戶余額: %s''' % (account_data['credit'], account_data['balance']) 101 print(current_balance) 102 back_flag = False 103 while not back_flag: 104 reciprocal_account = input("\033[31;1m請輸入對方帳戶名:\033[0m").strip()#輸入對方賬戶信息 105 transfer_amount = input("\033[31;1m轉賬金額:\033[0m").strip()#轉賬金額 106 if reciprocal_account or transfer_amount == 'b' : 107 return 108 if len(transfer_amount) > 0 and transfer_amount.isdigit(): 109 new_balance = transaction.make_transaction(trans_logger,account_data,'transfer', 110 transfer_amount,re_account = reciprocal_account) 111 if new_balance: 112 print("\033[41;1m轉賬成功!\033[0m") 113 print("\033[42;1m您當前的余額為:%s\033[0m" %(new_balance["balance"])) 114 else: 115 print('\033[31;1m[%s] \033[0m') 116 117 118 #賬單 119 @login_required 120 def pay_check(acc_data): 121 pass 122 #退出 123 def logout(acc_data): 124 exit("程序已經退出!") 125 #購物商城 126 def shopping_mall_this(acc_data): 127 shopping_mall.main_menu(acc_data) 128 #管理窗口 129 def goto_manage(): 130 manage.manage_main(user_data) 131 #菜單 132 def interactive(acc_data): 133 ''' 134 與用戶交互 135 :param acc_data: 驗證過的用戶的所用數據 136 :return: 137 ''' 138 menu = u''' 139 -----------銀行---------- 140 \033[32;1m 141 1.賬戶信息 142 2.還款 143 3.取款 144 4.轉賬 145 5.賬單 146 6.退出 147 \033[0m 148 ''' 149 menu_dic = { 150 '1': account_info, 151 '2': repay, 152 '3': withdraw, 153 '4': transfer, 154 '5': pay_check, 155 '6': logout, 156 } 157 exit_flag = False 158 while not exit_flag: 159 print(menu)#打印出菜單,供用戶選擇 160 user_option = input("請輸入你的選擇:").strip()#輸入用戶的選擇,過濾掉空格 161 if user_option == 'b': 162 return 163 if user_option in menu_dic:#用戶的選擇如果在這個菜單里 164 #print('accdata',acc_data) 165 menu_dic[user_option](acc_data)#用戶選擇執行的功能,把acc_data驗證過的用戶的所有數據(數據文件中的數據) 166 else: 167 print("\033[31;1m選擇不存在!\033[0m") 168 #帶有購物商場的主菜單 169 def main_menu(acc_data): 170 main_menu = u''' 171 ----------主菜單--------- 172 \033[32;1m 173 1.購物商城 174 2.銀行卡操作 175 3.退出 176 \033[0m 177 ''' 178 main_menu_dic = { 179 '1':shopping_mall_this, 180 '2':interactive, 181 '3':logout, 182 } 183 exit_flag = False 184 while not exit_flag: 185 print(main_menu) 186 user_option = input("請輸入你的選擇:").strip() 187 if user_option == 'b': 188 return 189 if user_option in main_menu_dic: 190 main_menu_dic[user_option](acc_data) 191 else: 192 print("\033[31;1m選擇不存在!\033[0m") 193 def run(): 194 ''' 195 當程序啟動時,這個程序開始運行,處理關於用戶的所有交互的內容 196 ''' 197 acc_data = auth.acc_login(user_data,access_logger)#程序從這里開始,執行auth下的acc_login函數 198 # (返回的是驗證過的正確的賬戶數據)賦值給acc_data(此時這里的數據為輸入賬戶名字的數據文件的數據) 199 if user_data['is_authenticated']: 200 user_data['account_data'] = acc_data#把賬戶所有信息傳給賬戶開始時的臨時的賬戶數據空字典, 201 # 把所有的數據文件傳給賬戶的賬戶數據里面, 202 #interactive(user_data)#把user_data里的所有數據傳入菜單函數,進行下一步操作 203 main_menu(user_data)
4.db下目錄下代碼
/db/accounts/123.json

1 {"pay_day": "22", "enroll_date": "2018-02-19", "credit": "15000", "balance": "123", "id": "123", "expire_date": "2032-01-01", "password": "123", "status": 0}
5.logs目錄下代碼
/logs/access.log&transaction.log
6.shopping_mall下代碼
/shopping_mall/product.txt&shopping_list.txt

1 #!/usr/bin/env python 2 #-*- Coding:utf-8 -*- 3 # Author:Eric.Shen 4 # !/usr/bin/env python 5 # -*- Coding:utf-8 -*- 6 # Author:Eric.Shen 7 # 2018.02.06 8 # path python3.5 9 # 優化版的購物車 10 # 用戶入口: 11 # 1.商品的信息存到文件里 12 # 2.已購商品,余額記錄 13 # 商家入口: 14 # 1.可以添加商品 2.修改商品價格 15 # 存儲商品列表 16 import fileinput 17 from core import accounts 18 19 product_list = [] 20 f = open("D:\\Python_train\\day4\\Atm\\shopping_mall\\product.txt", "r") # 打開文件 21 for line in f.readlines(): 22 line = line.strip() # 去掉最后一個換行符 23 index, item = line.split(":") # 以冒號分割得到前后兩個數據 24 product_list.append((index, item)) # 添加的數據 25 f.close() 26 27 28 def print_product_list(): 29 for index, item in enumerate(product_list): 30 print(index, item) 31 32 33 # 用戶入口 34 # 用戶購物 35 def user_shopping(account_data): 36 #salary = input("請輸入你的薪水:") 37 salary = account_data['account_data']['balance'] 38 print_product_list() 39 if salary > 0: 40 shopping_list = [] # 存放用戶購物車清單 41 while True: 42 option = input("喜歡那個就買哪個(對應的標號):") 43 if option.isdigit(): 44 option = int(option) 45 if option >= 0 and option <= len(product_list): 46 p_item = product_list[option] # 用戶選擇的商品 47 # print(product_list) 48 # print(p_item[1]) 49 c_num = int(p_item[1]) 50 if salary >= c_num: 51 shopping_list.append(p_item) 52 salary -= c_num 53 print("添加購物車成功,你的余額還有%s" % (salary)) 54 else: 55 print("你的余額不足,只剩%s元" % (salary)) 56 else: 57 print("輸入錯誤,請重新輸入!") 58 elif option == "q": 59 print("----------------購物清單---------------") 60 for s_list in shopping_list: 61 print(s_list) 62 print("你的余額為%s" % (salary)) 63 account_data['account_data']['balance'] = salary 64 #print(account_data) 65 accounts.dump_account(account_data['account_data'])#寫入文件 66 print("..........exit.........") 67 exit() 68 else: 69 print("無效的輸入") 70 else: 71 exit("余額不足!") 72 73 74 # 商家入口 75 # 商家添加商品 76 def add_product(): 77 name_of_product = input("請輸入你要添加的商品名字:") 78 price_of_product = input("請輸入你要添加商品的價格:") 79 f = open("product.txt", "a") 80 f.write(str("\n" + name_of_product) + ": %s" % (price_of_product)) 81 f.close() 82 print("添加成功!\nexit----------") 83 84 85 # 修改商品價格 86 def change_price(): 87 print_product_list() # 打印商品列表 88 choice = input("請輸入你的選擇:") 89 # name_of_change = input("請輸入你要改變的商品名字") 90 price_of_change = input("請輸入你要改變商品的價格:") 91 if choice.isdigit(): 92 choice = int(choice) 93 if choice >= 0 and choice <= len(product_list): 94 p_item = product_list[choice] # 選擇的商品 95 # c_num = int(p_item[1])#轉換成int類型 96 for line in fileinput.input("product.txt", inplace="%s" % (choice)): # 對輸入的選擇行進行修改 97 line = line.replace("%s" % (p_item[1]), "%s" % (price_of_change)).strip() 98 print(line) 99 exit("修改成功!") 100 else: 101 print("輸入無效") 102 else: 103 if choice == "q": 104 exit("退出") 105 106 107 def main_menu(account_data): 108 print("--------------------------" 109 "--------------------------" 110 "\n" 111 " 歡迎進入購物菜單 " 112 "\n" 113 "\n" 114 "商家請按b,用戶請按c\n" 115 "--------------------------" 116 "--------------------------") 117 c_num = input("請輸入你的選擇:") # 使用者選擇 118 if c_num == "b": 119 print("--------------------------" 120 "--------------------------" 121 "\n" 122 " 歡迎進入商家界面 " 123 "\n" 124 "\n" 125 "添加商品請按a,修改價格請按c\n" 126 "--------------------------" 127 "--------------------------") 128 c_num2 = input("請輸入你的選擇:") 129 if c_num2 == "a": 130 # 實現添加商品功能 131 add_product() 132 if c_num2 == "c": 133 # 實現商品價格修改功能 134 change_price() 135 else: 136 print("輸入有誤!") 137 if c_num == "c": 138 print("--------------------------" 139 "--------------------------" 140 "\n" 141 " 歡迎進入用戶界面 " 142 "\n" 143 "\n" 144 145 "--------------------------" 146 "--------------------------") 147 # 購物功能 148 print(account_data) 149 user_shopping(account_data) 150 else: 151 print("輸入有誤程序退出!")
五、README

1 作者:Eric.shen 2 此次系統的設計僅用來學習python,開始於2018.2.13-19完(此系統,日志部分沒有完善留着日后補充現在還沒學到) 3 作業需求: 4 5 模擬實現一個ATM + 購物商城程序: 6 1.額度 15000或自定義 7 2.實現購物商城,買東西加入 購物車,調用信用卡接口結賬 8 3.可以提現,手續費5% 9 4.每月22號出賬單,每月10號為還款日,過期未還,按欠款總額 萬分之5 每日計息(沒寫) 10 5.支持多賬戶登錄 11 6.支持賬戶間轉賬 12 7.記錄每月日常消費流水 13 8.提供還款接口 14 9.ATM記錄操作日志 15 10.提供管理接口,包括添加賬戶、用戶額度,凍結賬戶等。。。 16 11.用戶認證用裝飾器 17 18 一、軟件定位,軟件的基本功能。 19 實現一個簡單的atm與購物車程序, 20 二、運行代碼的方法: 安裝環境、啟動命令等。 21 用Python3.5寫的,語法就是至此之前所學的,直接打開運行即可 22 三、目錄結構。 23 24 ├── ATM #ATM主程目錄 25 │ ├── __init__.py 26 │ ├── bin #ATM 執行文件 目錄 27 │ │ ├── __init__.py 28 │ │ ├── atm.py #ATM 執行程序 29 │ │ ├── manage.py #信用卡管理 30 │ ├── conf #配置文件 31 │ │ ├── __init__.py 32 │ │ └── Settings.py #配置參數 33 │ ├── core #主要程序邏輯都 在這個目錄 里 34 │ │ ├── __init__.py 35 │ │ ├── accounts.py #用於從文件里加載和存儲賬戶數據 36 │ │ ├── auth.py #用戶認證模塊及主要功能函數 37 │ │ ├── db_handler.py #數據庫連接引擎 38 │ │ ├── logger.py #日志記錄模塊 39 │ │ ├── main.py #主邏輯交互程序 40 │ │ ├── transaction.py #記賬\還錢\取錢\與賬戶金額相關的操作,凍結或者鎖定用戶 41 │ ├── db #用戶數據存儲的地方 42 │ │ ├── __init__.py 43 │ │ ├── account_sample.py #生成一個初始的賬戶數據 ,把這個數據 存成一個 以這個賬戶id為文件名的文件,放在accounts目錄 就行了,程序自己去會這里找 44 │ │ └── accounts #存各個用戶的賬戶數據 ,一個用戶一個文件 45 │ │ └── 123.json #新創建的用戶賬戶示例文件 46 │ │ └── 1234.json #一個用戶賬戶示例文件 47 │ │ └── 123456.json #一個用戶賬戶示例文件 48 │ │ └── 6230001.json #管理用戶賬戶示例文件 49 │ └── log #日志目錄 50 │ ├── access.log #用戶訪問和操作的相關日志 51 │ └── login_in.log #登陸日志 52 └── shopping_mall #電子商城程序,需單獨實現,主要實現購物的功能。 53 │ └── __init__.py 54 │ └── product.txt #存放商品的txt文件 55 │ └── shopping_list.txt #存放購物清單的txt.文件 56 │ └── shopping_mall.py #購物商城程序 57 ├── README 58 四、簡要說明,更詳細點可以說明軟件的基本原理。 59 1.程序從/bin/atm.py開始執行if __name__ == '__main__': 60 main.run() 61 2.程序轉到/core/main.py下的run()函數,登陸時調用/core/auth的acc_login()進行登陸驗證:用到了/core/auth下的acc_auth2()方法進行驗證(此時傳入的參數時用戶輸入的賬戶和密碼) 62 acc_auth2中有調用了/core/db_handler下的db_handler()方法(參數是輸入的賬戶名)在db_handler中只是進行判斷是什么引擎,return file_db_handle(數據庫引擎)解析文件,返回文件執行加載輸入的用戶的賬戶的所有數據 63 接下來判斷是否為管理者賬戶,或者是否被凍結,若都不是,則判斷輸入的密碼是否與數據庫中的密碼一樣,在判斷到期時間是否過期 64 所有都通過的話就返回這個賬戶的數據,之前已經創建了一個空字典,里面有是否驗證:用戶數據:用戶賬戶:,判斷是否被驗證過,然后把用戶數據臨時的傳遞到里面,執行主循環函數 65 可以選擇進入到購物商城,或者信用卡操作或者退出 66 1)購物商城 67 調用/shopping_mall/shopping_mall.py文件執行,主循環函數,選擇你是商家還是用戶, 68 ①如果選擇商家,商家有增加商品修改商品的功能 69 ②如果選擇用戶,用戶則有購物,刷信用卡消費的功能,當退出時打印消費清單 70 2)信用卡操作 71 調用/core/main.py下interactive(用戶的所有數據)調用主循環函數,可以打印賬戶信息、還款、取款、轉賬、賬單、退出等操作 72 ①賬戶信息 73 ②還款 74 ③取款 75 ④轉賬 76 ⑤賬單 77 ⑥退出 78 3)若在賬戶登陸的時候進行輸入的時管理員賬戶調用/bin/manage.py則可以對用戶進行管理,解凍用戶、凍結用戶、申領新卡 79 ①添加賬戶 80 ②凍結賬戶 81 ③解凍賬戶 82 ④退出 83 五、常見問題說明。 84 日志沒有實現,賬單沒有實現
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
product.txt
iphone: 5288 Mac pro: 12000 Bike: 800 Watch: 36000 Coffe: 39 Python book: 120 Book: 100
shopping_list.txt
('Coffe', 39) ('Pychon book', 120)
長風破浪會有時,直掛雲帆濟滄海。
歡迎多多提提意見