一、模拟实现一个ATM + 购物商城程序
1、额度 15000或自定义
2、实现购物商城,买东西加入 购物车,调用信用卡接口结账
3、可以提现,手续费5%
4、支持多账户登录
5、支持账户间转账
6、记录每月日常消费流水
7、提供还款接口
8、ATM记录操作日志
9、提供管理接口,包括添加账户、用户额度,冻结账户等。。。
10、用户认证用装饰器
示例代码 https://github.com/triaquae/py3_training/tree/master/atm
简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329
二、首先画一个流程图让思路更清晰:
三、目录结构图:
四、启动文件
start.py源代码:
1 import os, sys 2 3 path = os.path.dirname(__file__) 4 sys.path.append(path) 5 from core import src 6 7 if __name__ == '__main__': 8 src.run()
五、配置文件相关
setting.py源代码:
1 import os 2 3 BASE_PATH = os.path.dirname(os.path.dirname(__file__)) # ATM的路径 4 BASE_DB = os.path.join(BASE_PATH, 'db') # db 文件的路径 5 BASE_LOG = os.path.join(BASE_PATH, 'log') # 日志路径 6 7 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ 8 '[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字 9 10 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 11 12 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' 13 14 # 定义日志输出格式 结束 15 16 # 如果不存在定义的日志目录就创建一个 17 if not os.path.isdir(BASE_LOG): 18 os.mkdir(BASE_LOG) 19 20 # log文件的全路径 21 logfile_path = os.path.join(BASE_LOG, 'log.log') 22 23 # log配置字典 24 LOGGING_DIC = { 25 'version': 1, 26 'disable_existing_loggers': False, 27 'formatters': { 28 'standard': { 29 'format': standard_format 30 }, 31 'simple': { 32 'format': simple_format 33 }, 34 }, 35 'filters': {}, 36 'handlers': { 37 # 打印到终端的日志 38 'console': { 39 'level': 'DEBUG', 40 'class': 'logging.StreamHandler', # 打印到屏幕 41 'formatter': 'simple' 42 }, 43 # 打印到文件的日志,收集info及以上的日志 44 'default': { 45 'level': 'DEBUG', 46 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 47 'formatter': 'standard', 48 'filename': logfile_path, # 日志文件 49 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 50 'backupCount': 5, 51 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 52 }, 53 54 }, 55 'loggers': { 56 # logging.getLogger(__name__)拿到的logger配置 57 '': { 58 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 59 'level': 'INFO', 60 'propagate': True, # 向上(更高level的logger)传递 61 }, 62 }, 63 }
六、核心逻辑
src.py源代码:
1 from interface import user, bank, shopping 2 from lib import common 3 4 user_data = { 5 'name': None 6 # 判断用户是否登入 7 } 8 9 10 def logout(): 11 ''' 12 退出. 13 :return: 14 ''' 15 user_data['name'] = None 16 17 18 def login(): 19 ''' 20 登入. 21 :return: 22 ''' 23 print('登录。。。') 24 if user_data['name']: 25 print('你已经登入过了') 26 count = 0 27 while True: 28 name = input('请输入用户名>>:').strip() 29 if name.lower() == 'q': break 30 password = input('请输入密码>>:').strip() 31 flag, msg = user.login_interface(name, password) 32 if flag: 33 user_data['name'] = name 34 print(msg) 35 break 36 else: 37 count += 1 38 if count == 3: 39 user.locked_interface(name) 40 print('错误次数过多,已锁定') 41 else: 42 43 print(msg) 44 45 46 def register(): 47 ''' 48 注册. 49 :return: 50 ''' 51 print('注册。。。') 52 if user_data['name']: 53 print('你已经登入过了') 54 while True: 55 name = input('请输入用户名>>:').strip() 56 if name.lower() == 'q': break 57 password = input('请输入密码>>:').strip() 58 password2 = input('再次输入密码>>:').strip() 59 if password == password2: 60 flag, msg = user.register_interface(name, password) 61 if flag: 62 print(msg) 63 break 64 else: 65 print('用户已存在') 66 else: 67 print('两次密码不一致') 68 69 70 @common.login_auth 71 def check_balance(): 72 ''' 73 查看余额. 74 :return: 75 ''' 76 print('查看余额。。。') 77 balance = bank.check_balance_interface(user_data['name']) 78 print(balance) 79 80 81 @common.login_auth 82 def transfer(): 83 ''' 84 转账. 85 :return: 86 ''' 87 print('转账。。。') 88 while True: 89 to_name = input('输入转账的用户>>:').strip() 90 balance = input('输入转账金额>>:').strip() 91 if balance.isdigit(): 92 balance = int(balance) 93 flag, msg = bank.transfer_interface(user_data['name'], to_name, balance) 94 if flag: 95 print(msg) 96 break 97 else: 98 print(msg) 99 else: 100 print('必须输入数字') 101 102 103 @common.login_auth 104 def repay(): 105 ''' 106 还款. 107 :return: 108 ''' 109 print('还款。。。') 110 balance = input('请输入还款金额>>:').strip() 111 if balance.isdigit(): 112 balance = int(balance) 113 falg, msg = bank.repay_interface(user_data['name'], balance) 114 if falg: 115 print(msg) 116 else: 117 print(msg) 118 else: 119 print('必须输入数字') 120 121 122 @common.login_auth 123 def withdraw(): 124 ''' 125 取款. 126 :return: 127 ''' 128 print('取款。。。') 129 balance = input('输入取款金额>>:').strip() 130 if balance.isdigit(): 131 balance = int(balance) 132 falg, msg = bank.withdraw_interface(user_data['name'], balance) 133 if falg: 134 print(msg) 135 else: 136 print(msg) 137 else: 138 print('必须输入数字') 139 140 141 @common.login_auth 142 def check_record(): 143 ''' 144 查看流水. 145 :return: 146 ''' 147 print('查看流水。。。') 148 bankflow = bank.check_bankflow_interface(user_data['name']) 149 for flow in bankflow: 150 print(flow) 151 152 153 @common.login_auth 154 def shop(): 155 ''' 156 1 先循环打印出商品 157 2 用户输入数字选择商品(判断是否是数字,判断输入的数字是否在范围内) 158 3 取出商品名,商品价格 159 4 判断用户余额是否大于商品价格 160 5 余额大于商品价格时,判断此商品是否在购物车里 161 5.1 在购物车里,个数加1 162 5.1 不在购物车里,拼出字典放入({‘good’:{‘price’:10,‘count’:1}}) 163 6 用户余额减掉商品价格 164 7 花费加上商品价格 165 8 当输入 q时,购买商品 166 8.1 消费为0 ,直接退出 167 8.2 打印购物车 168 8.3 接受用户输入,是否购买 当输入y,直接调购物接口实现购物 169 :return: 170 ''' 171 print('购物。。。') 172 goods_list = [ 173 ['coffee', 10], 174 ['chicken', 20], 175 ['iphone', 8000], 176 ['macPro', 15000], 177 ['car', 100000] 178 ] 179 money = 0 180 user_balance = bank.check_balance_interface(user_data['name']) 181 shopping_cart = {} 182 while True: 183 for i, v in enumerate(goods_list): 184 print(f'{i}: {v}') 185 choice = input('请输入需要购买商品的编号(数字)(q退出)>>:').strip() 186 if choice.isdigit(): 187 choice = int(choice) 188 if choice >= len(goods_list): 189 print('商品不存在') 190 continue 191 shop_name = goods_list[choice][0] 192 shop_price = goods_list[choice][1] 193 if user_balance >= shop_price: 194 if shop_name in shopping_cart: 195 shopping_cart[shop_name]['count'] += 1 196 else: 197 shopping_cart[shop_name] = {'price': shop_price, 'count': 1} 198 user_balance -= shop_price 199 money += shop_price 200 print(f'{shop_name}已加入购物车') 201 else: 202 print('余额不足') 203 continue 204 elif choice.lower() == 'q': 205 if money == 0: 206 break 207 print(shopping_cart) 208 user = input('是否购买Y/N>>:').strip() 209 if user.lower() == 'y': 210 falg, msg = shopping.shopping_interface(user_data['name'], money, shopping_cart) 211 if falg: 212 print(msg) 213 break 214 else: 215 print(msg) 216 break 217 elif user.lower() == 'n': 218 print('你什么都没有购买') 219 break 220 else: 221 print('无选项') 222 continue 223 224 else: 225 print('输入非法字符') 226 227 228 @common.login_auth 229 def check_shopping_cart(): 230 ''' 231 查看购物车. 232 :return: 233 ''' 234 print('查看购物车。。。') 235 shoppingcart = shopping.check_shoppingcart(user_data['name']) 236 if shoppingcart: 237 print(shoppingcart) 238 else: 239 print('无商品') 240 241 242 func_dic = { 243 '1': login, 244 '2': register, 245 '3': check_balance, 246 '4': transfer, 247 '5': repay, 248 '6': withdraw, 249 '7': check_record, 250 '8': shop, 251 '9': check_shopping_cart, 252 '10': logout 253 } 254 255 256 def run(): 257 ''' 258 功能选择接口. 259 :return: 260 ''' 261 while True: 262 print('''选择需要的功能: 263 1、登入 264 2、注册 265 3、查看余额 266 4、转账 267 5、还款 268 6、取款 269 7、查看流水 270 8、购物 271 9、查看购买商品 272 10、退出程序 273 ''') 274 choice = input('编号>>:').strip() 275 if choice in func_dic: 276 func_dic[choice]()
七、用户数据
db_handler.py源代码:
1 import os 2 import json 3 from conf import setting 4 5 6 def save(user_dic): 7 ''' 8 保存用户信息文件. 9 :param user_dic: 用户信息 10 :return: 11 ''' 12 user_path = os.path.join(setting.BASE_DB, '%s.json' % user_dic['name']) 13 with open(user_path, 'w', encoding='utf-8')as f: 14 json.dump(user_dic, f) 15 f.flush() 16 17 18 # 19 def select(name): 20 """ 21 查询用户文件. 22 :param name: str --> 用户名 23 :return: None, user_dic 24 """ 25 user_path = os.path.join(setting.BASE_DB, '%s.json' % name) 26 if os.path.exists(user_path): 27 with open(user_path, 'r', encoding='utf-8')as f: 28 user_dic = json.load(f) 29 return user_dic 30 else: 31 return None
八、银行接口
bank.py源代码:
1 from db import db_handler 2 from core import src 3 from lib import common 4 5 bank_logger = common.get_logger('bank') 6 7 8 def check_balance_interface(name): 9 ''' 10 查询余额接口. 11 :param name:账户名 12 :return:balance 13 ''' 14 user_dic = db_handler.select(name) 15 balance = user_dic['balance'] 16 return balance 17 18 19 def transfer_interface(from_name, to_name, balance): 20 ''' 21 转账接口. 22 :param from_name:转账用户 23 :param to_name: 收款用户 24 :param balance: 转账金额 25 :return:True,False 26 ''' 27 if from_name == to_name: 28 return False, '不能给自己转账' 29 to_dic = db_handler.select(to_name) 30 if to_dic: 31 from_dic = db_handler.select(from_name) 32 if from_dic['balance'] >= balance: 33 to_dic['balance'] += balance 34 from_dic['balance'] -= balance 35 from_dic['bankflow'].append('你向%s转账%s元' % (to_name, balance)) 36 to_dic['bankflow'].append('你收到%s的转账%s元' % (from_name, balance)) 37 bank_logger.info('%s向%s转账%s元' % (from_name, to_name, balance)) 38 db_handler.save(from_dic) 39 db_handler.save(to_dic) 40 return True, '转账成功' 41 else: 42 return False, '余额不足' 43 else: 44 return False, '用户不存在' 45 46 47 def repay_interface(name, balance): 48 ''' 49 还款接口. 50 :param name: 还款用户 51 :param balance: 还款金额 52 :return:True,False 53 ''' 54 user_dic = db_handler.select(name) 55 if user_dic['balance'] >= balance: 56 user_dic['balance'] -= balance 57 user_dic['bankflow'].append('还款%s' % balance) 58 bank_logger.info('%s还款了%s元' % (name, balance)) 59 db_handler.save(user_dic) 60 return True, '还款成功' 61 else: 62 return False, '余额不足以还款' 63 64 65 def withdraw_interface(name, balance): 66 ''' 67 取款接口. 68 :param name: 取款用户 69 :param balance: 取款金额 70 :return:True,False 71 ''' 72 user_dic = db_handler.select(name) 73 if user_dic['balance'] >= balance * 1.05: # 0.5%的手续费 74 user_dic['balance'] -= balance * 1.05 75 user_dic['bankflow'].append('取款%s,手续费%s' % (balance, balance * 0.05)) 76 bank_logger.info('你取款了%s元,手续费%s元' % (balance, balance * 0.05)) 77 db_handler.save(user_dic) 78 return True, '取款成功,取出金额%s' % balance 79 else: 80 return False, '余额不足' 81 82 83 def consume_interface(name, money): 84 ''' 85 消费接口. 86 :param name: 消费用户 87 :param money: 消费金额 88 :return:True,False 89 ''' 90 user_dic = db_handler.select(name) 91 if user_dic['balance'] >= money: 92 user_dic['balance'] -= money 93 db_handler.save(user_dic) 94 return True, '扣款成功' 95 else: 96 return False, '余额不足' 97 98 99 def check_bankflow_interface(name): 100 ''' 101 银行流水. 102 :param name: 账户名 103 :return:user_bankflow 104 ''' 105 user_dic = db_handler.select(name) 106 user_bankflow = user_dic['bankflow'] 107 return user_bankflow
九、购物接口
shopping.p源代码:
1 from db import db_handler 2 from interface import bank 3 4 5 def shopping_interface(name, money, shoppingcart): 6 ''' 7 购物接口. 8 :param name:用户名 9 :param money: 消费金额 10 :param shoppingcart: 购物车清单 11 :return:True,False 12 ''' 13 flag, msg = bank.consume_interface(name, money) 14 if flag: 15 user_dic = db_handler.select(name) 16 user_dic['shoppingcart'] = shoppingcart 17 db_handler.save(user_dic) 18 return True, '购买成功' 19 else: 20 return False, '余额不足' 21 22 23 def check_shoppingcart(name): 24 ''' 25 查看购物车接口. 26 :param name: 用户名 27 :return:user_dic['shoppingcart'] 28 ''' 29 user_dic = db_handler.select(name) 30 31 return user_dic['shoppingcart']
十、用户信息接口
user.py源代码:
1 from db import db_handler 2 from lib import common 3 4 user_logger = common.get_logger('user') 5 6 7 def login_interface(name, password): 8 ''' 9 登入接口. 10 :param name:用户名 11 :param password: 用户密码 12 :return:True,False 13 ''' 14 user_dic = db_handler.select(name) 15 if user_dic: # {'name': 'song', 'password': '123'} 16 if password == user_dic['password'] and not user_dic['locked']: 17 user_logger.info('用户%s登入了账户' % name) 18 return True, '登入成功' 19 else: 20 return False, '用户名密码错误或被锁定' 21 else: 22 return False, '用户不存在' 23 24 25 def register_interface(name, password, balance=15000): 26 ''' 27 注册接口. 28 :param name:用户名 29 :param password: 密码 30 :param balance: 确认密码 31 :return:True,False 32 ''' 33 user_dic = db_handler.select(name) 34 if user_dic: 35 return False, '用户已存在' 36 else: 37 user_dic = {'name': name, 'password': password, 'balance': balance, 38 'locked': False, 'bankflow': [], 'shoppingcart': {}} 39 db_handler.save(user_dic) 40 user_logger.info('用户%s注册成功' % name) 41 return True, '注册成功' 42 43 44 def locked_interface(name): 45 ''' 46 锁定接口. 47 :param name:用户名 48 :return: 49 ''' 50 user_dic = db_handler.select(name) 51 if user_dic: 52 user_dic['locked'] = True 53 db_handler.save(user_dic) 54 55 56 def un_locked_interface(name): 57 ''' 58 解锁用户. 59 :param name:用户名 60 :return: 61 ''' 62 user_dic = db_handler.select(name) 63 if user_dic: 64 user_dic['locked'] = False 65 db_handler.save(user_dic)
十一、模块工具
common.py源代码:
1 from core import src 2 import logging.config 3 from conf import setting 4 5 6 def login_auth(func): 7 ''' 8 装饰器 9 :param func: 函数名 10 :return: wrapper 11 ''' 12 13 def wrapper(*args, **kwargs): 14 if not src.user_data['name']: 15 src.login() 16 else: 17 return func(*args, **kwargs) 18 19 return wrapper 20 21 22 def get_logger(name): 23 ''' 24 盗用日志字典. 25 :param name:日志名字 26 :return: 27 ''' 28 logging.config.dictConfig(setting.LOGGING_DIC) # 使用这个日志字典 29 logger = logging.getLogger('name') 30 return logger
十二、功能演示:
1、注册:
2、登入:
3、查看余额:
4、转账:
log文件记录的日志:
5、还款:
6、取款:
7、查看流水:
查看song的流水:
8、购物:
9、查看购物车:
10、退出登入(退出后需要重新登入)
感谢观看!记得双击么么哒!