需求說明:html
1
2
3
4
5
6
7
8
9
10
|
額度
15000
或自定義
實現購物商城,買東西加入 購物車,調用信用卡接口結帳
能夠提現,手續費
5
%
支持多帳戶登陸
支持帳戶間轉帳
記錄每個月平常消費流水
提供還款接口
ATM記錄操做日誌
提供管理接口,包括添加帳戶、用戶額度,凍結帳戶等。。。
用戶認證用裝飾器
|
程序說明:python
主菜單,進入主菜單顯示以下:git
【1】購物商城 【2】用戶中心 【3】信用卡中心 【4】後臺管理 【5】登陸系統 【6】退出json
購物商城:app
顯示各類商品和價格,選擇對應的序號進行購買函數
用戶中心:post
【1】修改密碼 【2】額度查詢 【3】消費記錄 【4】返回編碼
信用卡中心:加密
【1】額度查詢 【2】提現 【3】轉帳 【4】還款 【5】返回url
後臺管理,主要是admin用戶進行管理:
【1】建立用戶 【2】凍結信用卡 【3】解凍用戶
【4】額度調整 【5】退出後臺管理
登陸系統:
未登陸的用戶須要進行登陸
代碼結構
#!/usr/bin/env python #-*- coding:utf-8 -*- # @Time : 2017/10/19 22:18 # @Author : lichuan # @File : creditcard.py from config import template import time from datetime import datetime from module import common import pickle from log import my_log_settings import logging from module.users import Users import os,sys #加在日誌配置模塊 my_log_settings.load_my_logging_cfg() #訪問日誌logger,path=log/access.log acess_logger=logging.getLogger(__name__) #消費日誌logger,path=log/shop.log shop_logger=logging.getLogger('shop') #用戶認證函數 # @wraps def auth(func): ''' 用戶是否已經登陸的認證裝飾器 :param func: :return: ''' def warpper(*args,**kwargs): import pickle # userinfo=pickle.loads(open('.json','rb').read())\ userinfos = load_user() if len(userinfos)!=0: func(*args,**kwargs) else: login() userinfos = load_user() if len(userinfos)!=0: func(*args,**kwargs) return warpper @auth def shop_center(): ''' 購物商城界面選擇 :return: ''' shop={'apple手機':7000,'魅族手機':2000,'小米手機':2500,'華爲手機':4000,'小米筆記本':4000} shop_list=['apple手機','魅族手機','小米手機','華爲手機','小米筆記本'] salary=15000 userinfo=load_user() # print(userinfo) buy_list={} salary=int(userinfo['salary']) shop_flag=True while shop_flag: print(template.shopping_index_menu) choice=input('請選擇:').strip() if not choice.isdigit() or int(choice) not in range(1,7): print('輸入錯誤,請重試!') continue if int(choice) == 6: Users[userinfo['name']]=userinfo dump_user(userinfo) print('退出購物商城,再見!') break else: key=shop_list[int(choice)-1] money=shop[key] if money > salary: print('剩餘額度不夠,請選擇別的商品!') continue else: salary=salary-money username=userinfo['name'] shop_logger.info('[%s]購買%s,花費%d元!' % (username,key,money)) print('%s,價值%d元,已購買!' % (key,money)) print('剩餘額度:%d元' % salary) #更新信息到Users配置文件 userinfo['salary']=salary if key in buy_list: buy_list[key]+=1 else: buy_list[key] = 1 userinfo['buy_list']=buy_list Users[userinfo['name']] = userinfo common.update_users(Users) #從文件加載登陸用戶的信息 def load_user(): ''' 從文件加載登陸用戶的信息 :return: userinfo信息 ''' try: with open('.pkl', 'rb') as read_f: userinfo = {} userinfo = pickle.loads(read_f.read()) # print(userinfo) except (FileNotFoundError,EOFError): pass return userinfo #將登陸用戶信息從新寫入.pkl def dump_user(users): ''' 將users信息從新寫入.pkl文件進行保存。 :param users:users信息是個字典 :return: ''' with open('.pkl', 'w'): pass with open('.pkl', 'wb') as read_f: p = pickle.dumps(users) read_f.write(p) #用戶登陸函數 def login(): ''' 用戶登陸函數,對用戶名密碼進行校驗,用戶密碼採用加密模塊hashlib進行加鹽加密 :return: ''' err_count=0 login_flag=True while login_flag: username=input('please input your username: ').strip() password=input('please input your password: ').strip() if username in Users: if Users[username]['password'] == common.encrypt(password) and Users[username]['islocked'] == 0: userinfo=Users[username] err_count = 0 with open('.pkl','wb') as write_f: p=pickle.dumps(userinfo) write_f.write(p) acess_logger.info(str(username)+' login success!') print(str(username)+' login success!') login_flag=False elif Users[username]['islocked'] != 0: print('user is locked ! cannot login!') err_count = 0 login_flag=False break else: print('name or password is wrong!!!') acess_logger.info(str(username)+' login Falied ,password is wrong') err_count+=1 #錯誤登陸3次以上,鎖定用戶 if err_count >= 3: Users[username]['islocked']=1 acess_logger.info(str(username)+' user locked!') print(str(username)+' user locked!') common.update_users(Users) break else: print('name or password is wrong!') # err_count+=1 @auth def user_center(today,weekday): ''' 用戶登陸後進入的用戶我的中心界面 :param name:用戶名稱 :param today: :param weekday:星期幾 :return: ''' center_flag=True userinfo=load_user() name=userinfo['name'] while center_flag: print(template.index_user_center.format(name,today,weekday)) choice=input('please input your choice:').strip() if not choice.isdigit() or int(choice) not in range(1,5): print('input wrong,please try again!') continue if int(choice) == 4: print('用戶中心和您再見!') center_flag=False break elif int(choice) == 1: common.modify_passwd(userinfo) elif int(choice) == 2: query_salary() elif int(choice) == 3: buylist=common.buy_list(userinfo['name']) for b in buylist: print(b,end='') #額度查詢函數,顯示信用卡基本信息 def query_salary(): status_all=['正常','被鎖定'] userinfo=load_user() salary=userinfo['salary'] total_salary=userinfo['total_salary'] cardno=userinfo['bindcard'] name=userinfo['name'] status=status_all[0] if userinfo['islocked'] ==0 else status_all[1] print(template.card_info.format(cardno,name,total_salary,salary,status)) # print(template.card_info.format(str(cardno),name,str(total_salary),str(salary),status)) #轉帳函數 def forward_cash(): userinfo = load_user() salary = userinfo['salary'] u_card_no = userinfo['bindcard'] card_list=[] print('您如今剩餘的可用額度爲:%d' %salary) card_no=input('請輸入對方的卡號:').strip() money=input('請輸入轉帳的金額:').strip() if not money.isdigit(): print('金額輸入有誤!') return for k in Users: if Users[k]['bindcard'] != u_card_no: card_list.append(Users[k]['bindcard']) if card_no not in card_list: print('卡號有誤') return if int(money) > salary: print('轉帳金額超出你的信用額度!') return #減去本身的額度 salary=salary-int(money) userinfo['salary']=salary dump_user(userinfo) Users[userinfo['name']]['salary']=salary #增長別人的額度 for k in Users: if card_no == Users[k]['bindcard']: Users[k]['salary']+=int(money) common.update_users(Users) print('[%s]轉帳%d元給%s,手續費%d元' % (userinfo['name'],int(money),card_no)) shop_logger.info('[%s]轉帳%d元給%s' % (userinfo['name'],int(money),card_no)) #提現函數 def draw_cash(): cash=input('請輸入提現金額:').strip() if not cash.isdigit() or int(cash) < 0: print('金額輸入錯誤!') return userinfo=load_user() salary=userinfo['salary'] if int(cash) > salary: print('你的額度是%s,額度不夠!' % salary) return else: salary = salary - int(cash)*1.05 userinfo['salary']=salary dump_user(userinfo) Users[userinfo['name']]['salary'] = salary common.update_users(Users) query_salary() shop_logger.info('[%s]取現%d元,手續費%d元!' % (userinfo['name'],int(cash),int(cash)*0.05)) print('[%s]取現%d元,手續費%d元!' % (userinfo['name'],int(cash),int(cash)*0.05)) #信用卡還款 def repay_salary(): repay_money=input('請輸入還款金額:').strip() if not repay_money.isdigit(): print('金額有誤!') return else: repay_money=int(repay_money) userinfo = load_user() userinfo['salary'] = userinfo['salary']+repay_money dump_user(userinfo) Users[userinfo['name']]=userinfo common.update_users(Users) query_salary() shop_logger.info('[%s]還款%d元' % (userinfo['name'], repay_money)) print('[%s]還款%d元' % (userinfo['name'], repay_money)) #信用卡中心程序 @auth def card_center(): ''' 信用卡中心程序 :return: ''' func={ '1': query_salary, '2': draw_cash, '3': forward_cash, '4': repay_salary, } card_flag=True while card_flag: #初始化打印信息 userinfo=load_user() user_name=userinfo['name'] card_no=userinfo['bindcard'] print(template.index_card_center.format(user_name,card_no)) choice=input('請選擇:').strip() if not choice.isdigit() or int(choice) not in range(1,6): print('輸入錯誤,請重試!') continue if int(choice) == 5: print('信用卡中心和您再見!') break else: func[choice]() #後臺管理程序 @auth def manager(): func={ '1':common.create_card, '2':common.lock_card, '3':common.unlock_card, '4':common.modify_salary, } userinfo=load_user() if userinfo['name'] != 'admin': print('只有admin用戶能夠進入後臺管理!') return manager_flag=True while manager_flag: print(template.index_admin.format(userinfo['name'])) choice=input('請選擇:').strip() if not choice.isdigit() or int(choice) not in range(1,6): print('輸入錯誤!') continue if int(choice) == 5: print('後臺管理和您再見!') manager_flag=False break else: func[choice]() if __name__ == '__main__': Flag=True # Flag=False while Flag: userinfo = load_user() # print(userinfo) # print(userinfo['name']) username = '' # username = userinfo['name'] if len(userinfo) != 0 else '' today=time.strftime('%Y-%m-%d',time.localtime()) weekday=common.numTo_characters(datetime.now().weekday()) print(template.index_default_menu.format(username,today,weekday)) choice = input("請選擇:").strip() if not choice.isdigit(): print("輸入錯誤,請從新輸入") continue if int(choice) not in range(1,7): print("輸入錯誤,,請從新輸入") continue if int(choice) == 1: shop_center() elif int(choice) == 2: user_center(today,weekday) elif int(choice) == 3: card_center() elif int(choice) == 4: manager() elif int(choice) == 5: login() elif int(choice) == 6: with open('.pkl','w',encoding='utf-8'): pass print("再見!") Flag=False creditcard.py
#!/usr/bin/env python #-*- coding:utf-8 -*- # @Time : 2017/10/20 15:28 # @Author : lichuan # @File : template.py """ 該模塊用來定義系統的菜單模板,用的網上別人的模板。 """ # 主程序中的主菜單 index_default_menu = ''' ------------------------------------------------------------------------- ATM 模擬程序 {0} 今天 {1} 星期{2} ------------------------------------------------------------------------- 【1】購物商城 【2】用戶中心 【3】信用卡中心 【4】後臺管理 【5】登陸系統 【6】退出 ''' #購物商城界面 shopping_index_menu = ''' ================================================================================== = = = 信用卡購物商城 = = = ================================================================================== 【1】apple手機 7000元 【2】魅族手機 2000元 【3】小米手機 2500元 【4】華爲手機 4000元 【5】小米筆記本 4000元 【6】退出 ''' index_card_center = ''' ------------------------------------------------------------------------------ 信用卡管理中心 用戶:{0} 卡號:{1} ------------------------------------------------------------------------------ 【1】額度查詢 【2】提現 【3】轉帳 【4】還款 【5】返回 ''' # 顯示信用卡基本信息模板 card_info = ''' ----------------------------------------------------------------------------------- 信用卡基本信息 卡號:{0} 全部人:{1} 信用額度:{2} 剩餘額度:{3} 狀態:{4} ----------------------------------------------------------------------------------- ''' index_user_center = ''' ------------------------------------------------------------------------- 用戶中心 當前用戶:{0} 今天 {1} 星期{2} ------------------------------------------------------------------------- 【1】修改密碼 【2】額度查詢 【3】消費記錄 【4】返回 ''' # 後臺管理模板 index_admin = ''' ------------------------------------------------------------------------------ 後臺管理 用戶:{0} ------------------------------------------------------------------------------ 【1】建立用戶 【2】凍結信用卡 【3】解凍用戶 【4】額度調整 【5】退出後臺管理 ''' #'----------------------------------------------------------------------------------------------------------------------------------------------------------------------' template.py
#!/usr/bin/env python #-*- coding:utf-8 -*- # @Time : 2017/10/20 15:46 # @Author : lichuan # @File : common.py import hashlib from module.users import Users import os import re from log import my_log_settings import logging my_log_settings.load_my_logging_cfg() acess_logger=logging.getLogger(__name__) def numTo_characters(num): ''' 傳入數字,轉換成星期幾中的幾 :param num: :return:漢字 ''' if num in range(0,7): week=('一','二','三','四','五','六','日') return week[num] def encrypt(str): ''' 對傳入字符串進行加鹽加密 :param str: 須要進行加密的字符串 :return: 返回加密過的字符串 ''' encrpt=hashlib.md5() encrpt.update(bytes('admin1234nnnnnn',encoding='utf-8')) encrpt.update(bytes(str,encoding='utf-8')) return encrpt.hexdigest() def update_users(Users): ''' 更新Users信息的函數 :param Users: 用戶信息,是個字典 :return: ''' import os user_path=os.path.dirname(os.path.abspath(__file__))+'\\users.py' with open(user_path,'w',encoding='utf-8') as write_f: Users_new='Users='+str(Users) write_f.write(Users_new) #修改密碼 def modify_passwd(userinfo): ''' 用於更新Users用戶密碼信息 :param userinfo: 傳入用戶信息 :param new_passwd: 新的密碼信息 :return: ''' old_passwd=input('請輸入如今密碼:') new_passwd=input('請輸入新密碼:') pattern_new_passwd=input('請再次輸入新密碼:') old_passwd=encrypt(old_passwd) if new_passwd != pattern_new_passwd: print('兩次輸入密碼不一致!') return if old_passwd != userinfo['password']: print('密碼錯誤!') return encrypt_passwd=encrypt(new_passwd) userinfo['password']=encrypt_passwd Users[userinfo['name']]=userinfo update_users(Users) acess_logger.info('%s修改了用戶密碼!' % userinfo['name']) print('修改密碼成功!') #用戶的購物消費信息 def buy_list(username): buy=[] shop_path=os.path.normpath(os.path.join( os.path.abspath(__file__), os.pardir, os.pardir, 'log', 'shop.log' )) with open(shop_path,'r',encoding='utf-8') as read_f: lines=read_f.readlines() r='.*\[%s\].*' %username patern = re.compile(r) for line in lines: if patern.match(line): buy.append(line) return buy #建立信用卡用戶 def create_card(): flag=True while True: username=input('請輸入name:').strip() if len(username) <= 0: print('輸入錯誤!') flag = False break if username in Users: print('用戶已存在!') continue mobile=input('請輸入手機號:').strip() if len(mobile) <= 0: print('輸入錯誤!') flag = False break for i in Users: if Users[i]['mobile'] == mobile: print('手機號已經存在!') flag=False break card_no = input('請輸入卡號:').strip() if len(card_no) <= 0 or not card_no.isdigit(): print('輸入錯誤!') flag = False break for i in Users: if Users[i]['bindcard'] == card_no: print('卡號已經存在!') flag = False break passwd = input('請輸入密碼:').strip() encrypt_passwd=encrypt(passwd) userinfo={ 'isdel': 0, 'name': username, 'password': encrypt_passwd, 'islocked': 0, 'salary': 15000, 'total_salary': 15000, 'bindcard': card_no, 'mobile': mobile, 'buy_list': {} } Users[username]=userinfo update_users(Users) acess_logger.info('新建立用戶%s' % username) print('新建立用戶%s已成功' % username) flag=False #凍結信用卡 def lock_card(): name=input('請輸入要凍結的用戶名:').strip() if name == 'admin': print('不能凍結admin帳號!') return if name in Users: Users[name]['islocked'] = 1 update_users(Users) acess_logger.info('%s用戶被凍結' %name) print('%s用戶被成功凍結' %name) else: print('用戶不存在!') #解凍信用卡 def unlock_card(): name = input('請輸入要解凍的用戶名:').strip() if name in Users: Users[name]['islocked'] = 0 update_users(Users) acess_logger.info('%s用戶被解凍' % name) print('%s用戶被成功解凍' % name) else: print('用戶不存在!') #調整額度 def modify_salary(): name = input('請輸入要調整額度的用戶名:').strip() total_salary=input('請輸入新額度:').strip() if not total_salary.isdigit(): print('額度錯誤!') return if name in Users: Users[name]['salary'] = int(total_salary) - (Users[name]['total_salary']-Users[name]['salary']) Users[name]['total_salary'] = int(total_salary) update_users(Users) acess_logger.info('%s用戶額度調整爲%s' % (name,total_salary)) print('%s用戶額度調整爲%s' % (name,total_salary)) else: print('用戶不存在!') if __name__ == '__main__': # modify_passwd({},'bbb') # print('it is common') r=buy_list('alex') for i in r: print(i,end='') common.py
Users={'alex': {'isdel': 0, 'name': 'alex', 'password': 'bc5b9cb3e4ab483335edab3347f3c102', 'islocked': 0, 'salary': 52187.4, 'total_salary': 15000, 'bindcard': '1001012345', 'mobile': '13511111111', 'buy_list': {'apple手機': 1, '魅族手機': 1, '小米手機': 1, '華爲手機': 1, '小米筆記本': 2}}, 'egon': {'isdel': 0, 'name': 'egon', 'password': 'bc5b9cb3e4ab483335edab3347f3c102', 'islocked': 0, 'salary': 16950, 'total_salary': 15000, 'bindcard': '1001012346', 'mobile': '13511111112', 'buy_list': {}}, 'admin': {'isdel': 0, 'name': 'admin', 'password': 'bc5b9cb3e4ab483335edab3347f3c102', 'islocked': 0, 'salary': 15000, 'total_salary': 15000, 'role': 'admin', 'bindcard': '1001010002', 'mobile': '15257157418'}, 'lit': {'isdel': 0, 'name': 'lit', 'password': 'bc5b9cb3e4ab483335edab3347f3c102', 'islocked': 0, 'salary': 50000, 'total_salary': 50000, 'bindcard': '1001012347', 'mobile': '13520381333', 'buy_list': {}}} users.py
""" logging配置 """ import os import logging.config # 定義三種日誌輸出格式 開始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' shop_format= '[%(asctime)s]%(message)s' # 定義日誌輸出格式 結束 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目錄 logfile_name = 'access.log' # log文件名 # 若是不存在定義的日誌目錄就建立一個 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log文件的全路徑 logfile_path = os.path.join(logfile_dir, logfile_name) shop_path = os.path.join(logfile_dir, 'shop.log') # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'id_simple': { 'format': id_simple_format }, 'shop_format': { 'format': shop_format }, }, 'filters': {}, 'handlers': { #打印到終端的日誌 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, #打印到文件的日誌,收集info及以上的日誌 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日誌文件 'maxBytes': 1024*1024*5, # 日誌大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了 }, 'boss': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': 'boss.log', # 日誌文件 'maxBytes': 1024 * 1024 * 5, # 日誌大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了 }, 'shop': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'shop_format', 'filename': shop_path, # 日誌文件 'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了 }, }, 'loggers': { #logger1=logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default',], # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)傳遞 }, #logger1=logging.getLogger('collect')拿到的logger配置 'collect': { 'handlers': ['boss',], # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)傳遞 }, 'shop': { 'handlers': ['shop'], # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕 'level': 'INFO', 'propagate': True, # 向上(更高level的logger)傳遞 }, }, } def load_my_logging_cfg(): logging.config.dictConfig(LOGGING_DIC) # 導入上面定義的logging配置 # logger = logging.getLogger(__name__) # 生成一個log實例 # logger = logging.getLogger('shopping') # 生成一個log實例 # logger.info('It works2!') # 記錄該文件的運行狀態 if __name__ == '__main__': load_my_logging_cfg() my_log_settings.py