ATM功能实现项目
一、模拟实现一个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源代码:
import os, sys path = os.path.dirname(__file__)
sys.path.append(path)
from core import src if __name__ == '__main__':
src.run()
五、配置文件相关
setting.py源代码:
import os BASE_PATH = os.path.dirname(os.path.dirname(__file__)) # ATM的路径
BASE_DB = os.path.join(BASE_PATH, 'db') # db 文件的路径
BASE_LOG = os.path.join(BASE_PATH, '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') # 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)传递
},
},
}
六、核心逻辑
src.py源代码:
from interface import user, bank, shopping
from lib import common user_data = {
'name': None
# 判断用户是否登入
} def logout():
'''
退出.
:return:
'''
user_data['name'] = None def login():
'''
登入.
:return:
'''
print('登录。。。')
if user_data['name']:
print('你已经登入过了')
count = 0
while True:
name = input('请输入用户名>>:').strip()
if name.lower() == 'q': break
password = input('请输入密码>>:').strip()
flag, msg = user.login_interface(name, password)
if flag:
user_data['name'] = name
print(msg)
break
else:
count += 1
if count == 3:
user.locked_interface(name)
print('错误次数过多,已锁定')
else: print(msg) def register():
'''
注册.
:return:
'''
print('注册。。。')
if user_data['name']:
print('你已经登入过了')
while True:
name = input('请输入用户名>>:').strip()
if name.lower() == 'q': break
password = input('请输入密码>>:').strip()
password2 = input('再次输入密码>>:').strip()
if password == password2:
flag, msg = user.register_interface(name, password)
if flag:
print(msg)
break
else:
print('用户已存在')
else:
print('两次密码不一致') @common.login_auth
def check_balance():
'''
查看余额.
:return:
'''
print('查看余额。。。')
balance = bank.check_balance_interface(user_data['name'])
print(balance) @common.login_auth
def transfer():
'''
转账.
:return:
'''
print('转账。。。')
while True:
to_name = input('输入转账的用户>>:').strip()
balance = input('输入转账金额>>:').strip()
if balance.isdigit():
balance = int(balance)
flag, msg = bank.transfer_interface(user_data['name'], to_name, balance)
if flag:
print(msg)
break
else:
print(msg)
else:
print('必须输入数字') @common.login_auth
def repay():
'''
还款.
:return:
'''
print('还款。。。')
balance = input('请输入还款金额>>:').strip()
if balance.isdigit():
balance = int(balance)
falg, msg = bank.repay_interface(user_data['name'], balance)
if falg:
print(msg)
else:
print(msg)
else:
print('必须输入数字') @common.login_auth
def withdraw():
'''
取款.
:return:
'''
print('取款。。。')
balance = input('输入取款金额>>:').strip()
if balance.isdigit():
balance = int(balance)
falg, msg = bank.withdraw_interface(user_data['name'], balance)
if falg:
print(msg)
else:
print(msg)
else:
print('必须输入数字') @common.login_auth
def check_record():
'''
查看流水.
:return:
'''
print('查看流水。。。')
bankflow = bank.check_bankflow_interface(user_data['name'])
for flow in bankflow:
print(flow) @common.login_auth
def shop():
'''
1 先循环打印出商品
2 用户输入数字选择商品(判断是否是数字,判断输入的数字是否在范围内)
3 取出商品名,商品价格
4 判断用户余额是否大于商品价格
5 余额大于商品价格时,判断此商品是否在购物车里
5.1 在购物车里,个数加1
5.1 不在购物车里,拼出字典放入({‘good’:{‘price’:10,‘count’:1}})
6 用户余额减掉商品价格
7 花费加上商品价格
8 当输入 q时,购买商品
8.1 消费为0 ,直接退出
8.2 打印购物车
8.3 接受用户输入,是否购买 当输入y,直接调购物接口实现购物
:return:
'''
print('购物。。。')
goods_list = [
['coffee', 10],
['chicken', 20],
['iphone', 8000],
['macPro', 15000],
['car', 100000]
]
money = 0
user_balance = bank.check_balance_interface(user_data['name'])
shopping_cart = {}
while True:
for i, v in enumerate(goods_list):
print(f'{i}: {v}')
choice = input('请输入需要购买商品的编号(数字)(q退出)>>:').strip()
if choice.isdigit():
choice = int(choice)
if choice >= len(goods_list):
print('商品不存在')
continue
shop_name = goods_list[choice][0]
shop_price = goods_list[choice][1]
if user_balance >= shop_price:
if shop_name in shopping_cart:
shopping_cart[shop_name]['count'] += 1
else:
shopping_cart[shop_name] = {'price': shop_price, 'count': 1}
user_balance -= shop_price
money += shop_price
print(f'{shop_name}已加入购物车')
else:
print('余额不足')
continue
elif choice.lower() == 'q':
if money == 0:
break
print(shopping_cart)
user = input('是否购买Y/N>>:').strip()
if user.lower() == 'y':
falg, msg = shopping.shopping_interface(user_data['name'], money, shopping_cart)
if falg:
print(msg)
break
else:
print(msg)
break
elif user.lower() == 'n':
print('你什么都没有购买')
break
else:
print('无选项')
continue else:
print('输入非法字符') @common.login_auth
def check_shopping_cart():
'''
查看购物车.
:return:
'''
print('查看购物车。。。')
shoppingcart = shopping.check_shoppingcart(user_data['name'])
if shoppingcart:
print(shoppingcart)
else:
print('无商品') func_dic = {
'': login,
'': register,
'': check_balance,
'': transfer,
'': repay,
'': withdraw,
'': check_record,
'': shop,
'': check_shopping_cart,
'': logout
} def run():
'''
功能选择接口.
:return:
'''
while True:
print('''选择需要的功能:
1、登入
2、注册
3、查看余额
4、转账
5、还款
6、取款
7、查看流水
8、购物
9、查看购买商品
10、退出程序
''')
choice = input('编号>>:').strip()
if choice in func_dic:
func_dic[choice]()
七、用户数据
db_handler.py源代码:
import os
import json
from conf import setting def save(user_dic):
'''
保存用户信息文件.
:param user_dic: 用户信息
:return:
'''
user_path = os.path.join(setting.BASE_DB, '%s.json' % user_dic['name'])
with open(user_path, 'w', encoding='utf-8')as f:
json.dump(user_dic, f)
f.flush() #
def select(name):
"""
查询用户文件.
:param name: str --> 用户名
:return: None, user_dic
"""
user_path = os.path.join(setting.BASE_DB, '%s.json' % name)
if os.path.exists(user_path):
with open(user_path, 'r', encoding='utf-8')as f:
user_dic = json.load(f)
return user_dic
else:
return None
八、银行接口
bank.py源代码:
from db import db_handler
from core import src
from lib import common bank_logger = common.get_logger('bank') def check_balance_interface(name):
'''
查询余额接口.
:param name:账户名
:return:balance
'''
user_dic = db_handler.select(name)
balance = user_dic['balance']
return balance def transfer_interface(from_name, to_name, balance):
'''
转账接口.
:param from_name:转账用户
:param to_name: 收款用户
:param balance: 转账金额
:return:True,False
'''
if from_name == to_name:
return False, '不能给自己转账'
to_dic = db_handler.select(to_name)
if to_dic:
from_dic = db_handler.select(from_name)
if from_dic['balance'] >= balance:
to_dic['balance'] += balance
from_dic['balance'] -= balance
from_dic['bankflow'].append('你向%s转账%s元' % (to_name, balance))
to_dic['bankflow'].append('你收到%s的转账%s元' % (from_name, balance))
bank_logger.info('%s向%s转账%s元' % (from_name, to_name, balance))
db_handler.save(from_dic)
db_handler.save(to_dic)
return True, '转账成功'
else:
return False, '余额不足'
else:
return False, '用户不存在' def repay_interface(name, balance):
'''
还款接口.
:param name: 还款用户
:param balance: 还款金额
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic['balance'] >= balance:
user_dic['balance'] -= balance
user_dic['bankflow'].append('还款%s' % balance)
bank_logger.info('%s还款了%s元' % (name, balance))
db_handler.save(user_dic)
return True, '还款成功'
else:
return False, '余额不足以还款' def withdraw_interface(name, balance):
'''
取款接口.
:param name: 取款用户
:param balance: 取款金额
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic['balance'] >= balance * 1.05: # 0.5%的手续费
user_dic['balance'] -= balance * 1.05
user_dic['bankflow'].append('取款%s,手续费%s' % (balance, balance * 0.05))
bank_logger.info('你取款了%s元,手续费%s元' % (balance, balance * 0.05))
db_handler.save(user_dic)
return True, '取款成功,取出金额%s' % balance
else:
return False, '余额不足' def consume_interface(name, money):
'''
消费接口.
:param name: 消费用户
:param money: 消费金额
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic['balance'] >= money:
user_dic['balance'] -= money
db_handler.save(user_dic)
return True, '扣款成功'
else:
return False, '余额不足' def check_bankflow_interface(name):
'''
银行流水.
:param name: 账户名
:return:user_bankflow
'''
user_dic = db_handler.select(name)
user_bankflow = user_dic['bankflow']
return user_bankflow
九、购物接口
shopping.p源代码:
from db import db_handler
from interface import bank def shopping_interface(name, money, shoppingcart):
'''
购物接口.
:param name:用户名
:param money: 消费金额
:param shoppingcart: 购物车清单
:return:True,False
'''
flag, msg = bank.consume_interface(name, money)
if flag:
user_dic = db_handler.select(name)
user_dic['shoppingcart'] = shoppingcart
db_handler.save(user_dic)
return True, '购买成功'
else:
return False, '余额不足' def check_shoppingcart(name):
'''
查看购物车接口.
:param name: 用户名
:return:user_dic['shoppingcart']
'''
user_dic = db_handler.select(name) return user_dic['shoppingcart']
十、用户信息接口
user.py源代码:
from db import db_handler
from lib import common user_logger = common.get_logger('user') def login_interface(name, password):
'''
登入接口.
:param name:用户名
:param password: 用户密码
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic: # {'name': 'song', 'password': '123'}
if password == user_dic['password'] and not user_dic['locked']:
user_logger.info('用户%s登入了账户' % name)
return True, '登入成功'
else:
return False, '用户名密码错误或被锁定'
else:
return False, '用户不存在' def register_interface(name, password, balance=15000):
'''
注册接口.
:param name:用户名
:param password: 密码
:param balance: 确认密码
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic:
return False, '用户已存在'
else:
user_dic = {'name': name, 'password': password, 'balance': balance,
'locked': False, 'bankflow': [], 'shoppingcart': {}}
db_handler.save(user_dic)
user_logger.info('用户%s注册成功' % name)
return True, '注册成功' def locked_interface(name):
'''
锁定接口.
:param name:用户名
:return:
'''
user_dic = db_handler.select(name)
if user_dic:
user_dic['locked'] = True
db_handler.save(user_dic) def un_locked_interface(name):
'''
解锁用户.
:param name:用户名
:return:
'''
user_dic = db_handler.select(name)
if user_dic:
user_dic['locked'] = False
db_handler.save(user_dic)
十一、模块工具
common.py源代码:
from core import src
import logging.config
from conf import setting def login_auth(func):
'''
装饰器
:param func: 函数名
:return: wrapper
''' def wrapper(*args, **kwargs):
if not src.user_data['name']:
src.login()
else:
return func(*args, **kwargs) return wrapper def get_logger(name):
'''
盗用日志字典.
:param name:日志名字
:return:
'''
logging.config.dictConfig(setting.LOGGING_DIC) # 使用这个日志字典
logger = logging.getLogger('name')
return logger
十二、功能演示:
1、注册:
2、登入:
3、查看余额:
4、转账:
log文件记录的日志:
5、还款:
6、取款:
7、查看流水:
查看song的流水:
8、购物:
9、查看购物车:
10、退出登入(退出后需要重新登入)
感谢观看!记得双击么么哒!
ATM功能实现项目的更多相关文章
- C#Light 再推荐,顺便介绍WP8 功能展示项目
由于在项目中验证了C#Light脚本,C#Light的健壮和稳定程度已经得到了很大的提升. 现在可以更好的把C#Light介绍给大家使用,同时也有更多的自信,告诉大家这是一个已经具有商业价值的类库. ...
- C# RabbitMQ延迟队列功能实战项目演练
一.需求背景 当用户在商城上进行下单支付,我们假设如果8小时没有进行支付,那么就后台自动对该笔交易的状态修改为订单关闭取消,同时给用户发送一份邮件提醒.那么我们应用程序如何实现这样的需求场景呢?在之前 ...
- 用MVC5+EF6+WebApi 做一个小功能(二) 项目需求整理
在一个项目开始前,需求整理大概要占到整个项目周期15%甚至30%的比重,可以说需求理得越清楚,后续开发中返工几率越小.在一个项目中,开发新功能的花费的精力要远远小于修改功能的精力,这基本是一个共识.老 ...
- 用MVC5+EF6+WebApi 做一个小功能(三) 项目搭建
一般一个项目开始之前都会有启动会,需求交底等等,其中会有一个环节,大讲特讲项目的意义,然后取一个高大上的项目名字,咱这是一个小功能谈不上项目,但是名字不能太小气了.好吧,就叫Trump吧.没有任何含义 ...
- 利用Postman和Chrome的开发者功能探究项目
利用Postman和Chrome的开发者功能探究项目 controller层研究 前两天忙着写开题报告,没有来得及做项目,今天继续研究一下这个项目. 上次研究到后端的DAO层,研究了一下后端和数据库交 ...
- 项目1:ATM+购物商城项目
项目1:ATM+购物商城 1.项目介绍 项目需求: # 项目需求如下:'''- 额度 15000或自定义- 实现购物商城,买东西加入购物车,调用信用卡接口结账- 可以提现,手续费5%- 支持多账 ...
- 用MVC5+EF6+WebApi 做一个小功能(四) 项目分层功能以及文件夹命名
在上一节,我们完成了一个项目搭建,我们看到的是一个项目的分层架子,那接下来每一层做什么以及需要引用哪些内容呢?在本节内容我们还逐步拆分每一层的功能,顺带添加package包 Trump.Domain ...
- eclipse Reference 功能之——项目之间的引用
i'm sorry, i forgot this article where i found. that it is referenced. 以前也研究过Eclipse里Web Project引用Ja ...
- ATM购物车程序项目规范(更新到高级版)
ATM购物车程序(高级版) 之前的低级版本已经删除,现在的内容太多,没时间把内容上传,有时间我会把项目源码奉上! 我已经把整个项目源码传到群文件里了,需要的可以加主页qq群号.同时群内也有免费的学习资 ...
随机推荐
- Mac 10.14 安装抓包工具Fiddler
环境安装 第一步: 首先,Mac下需要使用.Net编译后的程序,需要用到跨平台的方案Mono(现阶段微软已推出跨平台的方案.Net Core,不过暂时只支持控制台程序).安装程序可以从http://w ...
- Kubernetes网络分析之Flannel
Flannel是cereos开源的CNI网络插件,下图flannel官网提供的一个数据包经过封包.传输以及拆包的示意图,从这个图片中可以看出两台机器的docker0分别处于不同的段:10.1.20.1 ...
- 程序员IT狗有什么副业可以做呢?
1. 开篇 副业有很多,全网有做什么公众号.闲鱼.手机卡,各种各样的都有,大部分是骗子,小部分是通过自己的努力,获得了成功. 从年初就开始实践如何做一个自由职业者,近大半年有一些感受正好一起分享交流一 ...
- 01 【PMP】组织结构类型
[PMP]组织结构类型 1.简单型 描述:人员并肩工作,所有者/经营者直接做出主要决定并监督执行. PM角色:兼职(协调员) PM权限:极少(无) 项目管理人员:极少(无) 资源可用性:极少(无) ...
- 除法分块 luogu2261 (坑)
除法分块 除法分块 是指使用分块计算的方法求S=∑i=1n⌊ki⌋S=\sum^{n}_{i=1}{\lfloor{\frac{k}{i}}\rfloor}S=i=1∑n⌊ik⌋的值. 举个例子. ...
- Cocos2d-x 学习笔记(8) ActionManager
1. 概述 ActionManager管理所有的action,调度所有的action,删除指定的action.每个action对应一个node对象,action存储在actions中,actions和 ...
- 生产环境中利用软链接避免"rm -rf /"的方法
1.将系统中的rm二进制文件重命名为rm_real:2.编写脚本rm_shell,rm_shell中主要包含以下内容: 2.1)路径转换模块,用于将rm_shell参数中的路径转换为绝对路径 ...
- 工厂模式在mvc模型中的应用
在web开发中我们常用mvc模式进行web应用的开发 当应用进入service 层的时候我们根据不同的业务多逻辑进行处理 当有数据进入controller的时候 public class Virtua ...
- Java虚拟机类加载器及双亲委派机制
所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...
- 判断一字串String中是否包含某一串字符串
String ostype = data.getString("osType").toUpperCase(); //转换为大写 if (ostype.contains(" ...