模拟实现一个ATM + 购物商城程序
一 基本需求
模拟实现一个ATM + 购物商城程序
- 额度 15000或自定义
- 实现购物商城,买东西加入 购物车,调用信用卡接口结账
- 可以提现,手续费5%
- 支持多账户登录
- 支持账户间转账
- 记录日常消费流水
- 提供还款接口
- ATM记录操作日志
- 提供管理接口,包括添加账户、冻结账户等。。。
- 用户认证用装饰器
根据上面需求,我们来实现以下几个功能:
1 注册
2 登录
3 查看余额
4 转账
5 取款
6 还款
7 查看流水
8 购物
9 查看购买商品
二 项目目录结构
bin目录
start.py---》程序启动页
conf目录
setting.py---》用于存放整个项目的配置信息
core目录
src.py---》用户端功能
interface目录
bank.py---》银行相关接口
shop.py---》购物相关接口
user.py---》用户相关接口
db目录
db_handler.py---》对文件的读写操作
用于存放所有用户信息,以json格式存储
lib目录
common.py---》公共方法(用户认证装饰器,获取日志对象等)
log目录
记录日志
三 分模块
start.py
import os,sys path = os.path.dirname(__file__) # print(path) sys.path.append(path) from core import src # print(path) if __name__ == '__main__': src.run()
src.py
from interface import bank,shop,user from lib import common user_dic = { 'name':None } def register(): if user_dic['name']: print('已经登录,不能注册') return print('注册') while True: name = input('请输入名字:').strip() password = input('请输入密码:').strip() conf_password = input('请确认密码:').strip() if password == conf_password: flag,msg = user.register_interface(name,password) if flag: print(msg) break else: print(msg) else: print('两次输入的密码不一致') def login(): if user_dic['name']: print('已经登录') return print('登录') while True: name = input('请输入名字:').strip() password = input('请输入密码:').strip() flag,msg = user.login_interface(name,password) if flag: user_dic['name']=name print(msg) break else: print(msg) @common.login_auth def check_balance(): print('查看余额') balance = bank.check_balance_interface(user_dic['name']) print(balance) @common.login_auth def transfer(): print('转账') while True: to_user = input('请输入对方账户:').strip() account = input('请输入转账金额:').strip() if account.isdigit(): account = int(account) flag,msg = bank.transfer_interface(user_dic['name'],to_user,account) if flag: print(msg) break else: print(msg) else: print('请输入数字') @common.login_auth def repay(): print('还款') while True: account = input('请输入还款金额:').strip() if account.isdigit(): account = int(account) flag,msg = bank.repay_interface(user_dic['name'],account) if flag: print(msg) break else: print(msg) else: print('请输入数字') @common.login_auth def withdraw(): print('取款') while True: account = input('请输入取款金额:').strip() if account.isdigit(): account = int(account) flag,msg = bank.withdraw_interface(user_dic['name'],account) if flag: print(msg) break else: print(msg) else: print('请输入数字') @common.login_auth def check_records(): print('查看流水') records = bank.check_records_interface(user_dic['name']) if records: for record in records: print(record) else: print('暂无流水') @common.login_auth def shopping(): print('购物') goods_list = [ ['coffee',10], ['chicker',20], ['car',100000] ] user_balance = bank.check_balance_interface(user_dic['name']) cost = 0 shoppingcard = { } while True: for i,goods in enumerate(goods_list): print('%s : %s'%(i,goods)) buy = input('请输入要购买的数字(数字)(q退出并购买):').strip() if buy.isdigit(): buy = int(buy) if buy < len(goods_list): goods_name = goods_list[buy][0] goods_price = goods_list[buy][1] if user_balance >= goods_price: if goods_name not in shoppingcard: shoppingcard[goods_name] = {'price':goods_price,'count':1} else: # shoppingcard[goods_name] += 1 shoppingcard[goods_name]['count'] += 1 user_balance -= goods_price cost += goods_price print('%s 添加购物车成功' %goods_name) else: print('余额不足') else: print('请选择存在的商品') elif buy == 'q': if shoppingcard: flag,msg = shop.shopping_interface(user_dic['name'],cost,shoppingcard) if flag: print(msg) break else: print(msg) break else: print('请输入数字') @common.login_auth def check_shoppingcard(): print('查看购物车') shoppingcart = shop.check_shopingcart_interface(user_dic['name']) if shoppingcart: print(shoppingcart) else: print('购物车为空') func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer, '5': repay, '6': withdraw, '7': check_records, '8': shopping, '9': check_shoppingcard } def run(): while True: print(''' 1 注册 2 登录 3 查看余额 4 转账 5 还款 6 取款 7 查看流水 8 购物 9 查看购买商品 ''') choice = input('请选择:') if choice not in func_dic:continue func_dic[choice]()
user.py
from db import db_handler def register_interface(name,password,balance=1500): user_dic = db_handler.select(name) if user_dic: return False,'用户已存在' else: user_dic = { 'name': name, 'password': password, 'lockd': False, 'balance': balance, 'credit': balance, 'bankflow': [], 'shoppingcard': {} } db_handler.save(user_dic) return True,'注册成功' def login_interface(name,password): user_dic = db_handler.select(name) if user_dic: if password == user_dic['password']: return True,'登录成功' else: return False,'密码错误或者已经锁定' else: return False,'用户不存在'
shop.py
from db import db_handler from interface import bank def check_shopingcart_interface(name): user_dic = db_handler.select(name) return user_dic['shoppingcard'] def shopping_interface(name,cost,shoppingcard): flag = bank.consume_interface(name,cost) if flag: user_dic = db_handler.select(name) user_dic['shoppingcard'] = shoppingcard db_handler.save(user_dic) return True,'购买成功' else: return False,'购买失败'
bank.py
import db.db_handler from db import db_handler from lib import common bank_logger = common.get_logger('bank') def check_balance_interface(name): user_dic = db_handler.select(name) return user_dic['balance'] def transfer_interface(from_name,to_name,account): to_user_dic = db_handler.select(to_name) if to_user_dic: from_user_dic = db.db_handler.select(from_name) if from_user_dic['balance'] >= account: from_user_dic['balance'] -= account to_user_dic['balance'] += account from_user_dic['bankflow'].append('%s 向 %s 转账 %s'%(from_name,to_name,account)) to_user_dic['bankflow'].append('%s 收到 %s 转账 %s'%(to_name,from_name,account)) db_handler.save(from_user_dic) db_handler.save(to_user_dic) return True,'转账成功' else: return False,'您的额度不够' else: return False,'对方账户不存在' def repay_interface(name,account): user_dic = db_handler.select(name) user_dic['balance'] += account user_dic['bankflow'].append('还款 %s' %(account)) db_handler.save(user_dic) bank_logger.info('还款成功') return True,'还款成功' def withdraw_interface(name,account): user_dic = db_handler.select(name) account = account*1.05 if user_dic['balance'] >= account: user_dic['balance'] -= account user_dic['bankflow'].append('取款 %s' % (account)) db_handler.save(user_dic) return True,'取款成功' else: return False,'余额不足' def check_records_interface(name): user_dic = db_handler.select(name) return user_dic['bankflow'] def consume_interface(name,account): user_dic = db_handler.select(name) if user_dic['balance'] >= account: user_dic['balance'] -= account user_dic['bankflow'].append('消费 %s' % (account)) db_handler.save(user_dic) return True else: return False
db_handler.py
import os from conf import setting import json def select(name): path = os.path.join(setting.base_db, '%s,json' %name) if os.path.exists(path): with open(path,'r',encoding='utf-8') as f: return json.load(f) else: return None def save(user_dic): path = os.path.join(setting.base_db,'%s,json'%user_dic['name']) with open(path,'w',encoding='utf-8') as f: json.dump(user_dic,f) f.flush()
common.py
import logging.config from conf import setting def login_auth(func): from core import src def wrapper(*args,**kwargs): if not src.user_dic['name']: src.login() else: return func(*args,**kwargs) return wrapper def get_logger(name): logging.config.dictConfig(setting.LOGGING_DIC) my_logger = logging.getLogger(name) return my_logger
setting.py
import os base_dir = os.path.dirname(os.path.dirname(__file__)) base_db = os.path.join(base_dir,'db') base_log = os.path.join(base_dir,'log') 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' # 定义日志输出格式 结束 # 如果不存在定义的日志目录就创建一个 if not os.path.isdir(base_log): os.mkdir(base_log) # log文件的全路径 logfile_path = os.path.join(base_log, 'log.log') logfile_another = os.path.join(base_log, 'another.log') # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_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乱码了 }, }, 'loggers': { # logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'INFO', 'propagate': True, # 向上(更高level的logger)传递 }, }, }