一、模拟实现一个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. wampserver 运行橙色,80端口没有被占用,查看错误日志方法

    wampserver运行时橙色,经检查80端口并没有被占用,试了很多种方法都无效,去查看错误日志吧 1.以管理员身份打开CMD 注意这里必须是管理员身份的CMD ,powershell不行的 进入wa ...

  2. ZGC介绍

    zgc是一款可拓展的低时延,为实现以下几个目标而诞生的垃圾回收器: 停顿时间不超过10ms 停顿时间不会导致堆大小增长 堆大小范围可支持几G到几T 再看一下zgc的标签: region-based ( ...

  3. Windows渗透测试中wmi的利用

    0x01 关于WMI WMI可以描述为一组管理Windows系统的方法和功能.我们可以把它当作API来与Windows系统进行相互交流.WMI在渗透测试中的价值在于它不需要下载和安装, 因为WMI是W ...

  4. 【javascript 伪协议】小结

    [javascript 伪协议] 将javascript代码添加到客户端的方法是把它放置在伪协议说明符javascript:后的URL中.这个特殊的协议类型声明了URL的主体是任意的javascrip ...

  5. 网站是HTTP?10分钟变成HTTPS!域名免费添加配置SSL证书,变成https//环境

    对于小程序request请求需要https域名.navigator.geolocation定位也需要在https环境下才可以生效等问题: 前端开发越来越需要https环境来来测试一下API接口和各类问 ...

  6. 【Redis】Could not get a resource from the pool 实乃集群配置问题

    先说些题外话~自上次确诊为鼻窦炎+过敏性鼻炎到现在已经一个月了,最初那会,从下午到晚上头疼难忍.大概是积劳成疾,以前流鼻涕.打喷嚏的时候从来没有注意过,结果病根一下爆发. 关键在于锁定问题,开始治疗一 ...

  7. 一个基于C++11的单例模板类

    #ifndef _SINGLETON_H_#define _SINGLETON_H_ template<typename T>class Singleton : public Uncopy ...

  8. C++中哪些函数不能声明为virtual?

    首先要明确,virtual是用于支持类多态的关键字,所以出现在类声明之外的地方都是错误的.由此可以断定下文的1. 普通函数(即非类成员函数)不能是virtual的,否则不能通过编译,virtual只能 ...

  9. Dubbo+Zookeeper(一)Zookeeper初识

    前面花了一段时间去学习SpringCloud的相关知识,主要是理解微服务的概念并使用SpringCloud的一系列组件实现微服务落地.学习这些组件本身是简单的,跟着操作一遍基本就会了,这也得益于Spr ...

  10. jmeter-控制业务比例

    方式一: 多线程组 缺点:由于各事务相应时间一般不一致,故只能粗略的控制业务占比 实例:待补充