如何写ATM程序?
Python写的ATM程序
需求说明:
|
1
2
3
4
5
6
7
8
9
10
|
额度 15000或自定义实现购物商城,买东西加入 购物车,调用信用卡接口结账可以提现,手续费5%支持多账户登录支持账户间转账记录每月日常消费流水提供还款接口ATM记录操作日志提供管理接口,包括添加账户、用户额度,冻结账户等。。。用户认证用装饰器 |
程序说明:
主菜单,进入主菜单显示如下:
【1】购物商城 【2】用户中心 【3】信用卡中心 【4】后台管理 【5】登录系统 【6】退出
购物商城:
显示各种商品和价格,选择对应的序号进行购买
用户中心:
【1】修改密码 【2】额度查询 【3】消费记录 【4】返回
信用卡中心:
【1】额度查询 【2】提现 【3】转账 【4】还款 【5】返回
后台管理,主要是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

浙公网安备 33010602011771号