一、模拟实现一个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功能实现项目的更多相关文章

  1. C#Light 再推荐,顺便介绍WP8 功能展示项目

    由于在项目中验证了C#Light脚本,C#Light的健壮和稳定程度已经得到了很大的提升. 现在可以更好的把C#Light介绍给大家使用,同时也有更多的自信,告诉大家这是一个已经具有商业价值的类库. ...

  2. C# RabbitMQ延迟队列功能实战项目演练

    一.需求背景 当用户在商城上进行下单支付,我们假设如果8小时没有进行支付,那么就后台自动对该笔交易的状态修改为订单关闭取消,同时给用户发送一份邮件提醒.那么我们应用程序如何实现这样的需求场景呢?在之前 ...

  3. 用MVC5+EF6+WebApi 做一个小功能(二) 项目需求整理

    在一个项目开始前,需求整理大概要占到整个项目周期15%甚至30%的比重,可以说需求理得越清楚,后续开发中返工几率越小.在一个项目中,开发新功能的花费的精力要远远小于修改功能的精力,这基本是一个共识.老 ...

  4. 用MVC5+EF6+WebApi 做一个小功能(三) 项目搭建

    一般一个项目开始之前都会有启动会,需求交底等等,其中会有一个环节,大讲特讲项目的意义,然后取一个高大上的项目名字,咱这是一个小功能谈不上项目,但是名字不能太小气了.好吧,就叫Trump吧.没有任何含义 ...

  5. 利用Postman和Chrome的开发者功能探究项目

    利用Postman和Chrome的开发者功能探究项目 controller层研究 前两天忙着写开题报告,没有来得及做项目,今天继续研究一下这个项目. 上次研究到后端的DAO层,研究了一下后端和数据库交 ...

  6. 项目1:ATM+购物商城项目

    项目1:ATM+购物商城 1.项目介绍 项目需求: # 项目需求如下:'''- 额度 15000或自定义​- 实现购物商城,买东西加入购物车,调用信用卡接口结账​- 可以提现,手续费5%​- 支持多账 ...

  7. 用MVC5+EF6+WebApi 做一个小功能(四) 项目分层功能以及文件夹命名

    在上一节,我们完成了一个项目搭建,我们看到的是一个项目的分层架子,那接下来每一层做什么以及需要引用哪些内容呢?在本节内容我们还逐步拆分每一层的功能,顺带添加package包 Trump.Domain ...

  8. eclipse Reference 功能之——项目之间的引用

    i'm sorry, i forgot this article where i found. that it is referenced. 以前也研究过Eclipse里Web Project引用Ja ...

  9. ATM购物车程序项目规范(更新到高级版)

    ATM购物车程序(高级版) 之前的低级版本已经删除,现在的内容太多,没时间把内容上传,有时间我会把项目源码奉上! 我已经把整个项目源码传到群文件里了,需要的可以加主页qq群号.同时群内也有免费的学习资 ...

随机推荐

  1. Kotlin 中的伴生对象和静态成员

    用了一段时间kotlin,越用越觉得好用,爱不释手啊,留点笔记. Kotlin 中,在类中定义的对象(object)声明,可使用 companion 修饰,这样此对象(object)就是伴生对象了.类 ...

  2. Flask中多APP应用以及admin后台系统

    一.多APP from werkzeug.wsgi import DispatcherMiddleware from werkzeug.serving import run_simple from f ...

  3. JVM参数的配置及意义

    JVM参数设置.分析 因为在工作中遇到了JVM参数的配置,不明白,网上搜索发现一篇好文,转载至:https://www.cnblogs.com/redcreen/archive/2011/05/04/ ...

  4. wwindows权限认识(用户及用户组)

    windows权限认识(用户及用户组) Windows系统内置了许多本地用户组,这些用户组本身都已经被赋予一些权限(permissions),它们具有管理本地计算机或访问本地资源的权限.只要用户账户加 ...

  5. HDU 3873 Invade the Mars(带限制条件的Dijkstra)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=3873 思路: 军队可以先等待在城市外面,等保护该城市的城市都被攻破后,直接进城(即进城不用耗费时间). ...

  6. “selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities“解决办法

    问题: 原因:firefox浏览器版本和浏览器驱动版本不匹配 解决办法:卸载高版本浏览器,安装低版本浏览器 下载地址:http://ftp.mozilla.org/pub/firefox/releas ...

  7. javascript实用代码片段

    持续积累中~ 拓展原型 Function.prototype.method = function(name, extend) { if(!this.prototype[name]) { this.pr ...

  8. 记录一次诡异的Maven Profile不生效的问题

    记录一次诡异的Maven Profile不生效的问题 现象 maven 打包之后,复制的 profile对应的resource文件总是不正确的. 即便是加了 mvn clean package -P ...

  9. Nginx 热部署和日志切割,你学会了吗?

    上篇文章,我们已经安装好 Nginx,并且配置好 Nginx 文件后,这个时候我就需要操作 Nginx 的命令行了,这篇文章主要讲解 Nginx 命令行相关知识,并通过日常遇到的热部署.切割日志文件场 ...

  10. vue-cli3安装jQuery

    注:vue-cli3.0 没有了 webpack.config.js 配置文件,取而代之的是集合在 vue.config.js文件 内进行配置 默认已经安装好vue-cli3.0项目 step1:命令 ...