61.ATM+购物车
ATM+购物车
一、项目设计步骤
项目需求:
模拟实现一个ATM + 购物商城程序
额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
支持多账户登录
支持账户间转账
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器
- 开发软件的公司:帮甲方开发软件的公司
- 客户:某些服务行业的公司,需要找人开发软件(甲方)
- 用户:甲方软件上线后,供我们(用户)使用
科普知识:
一个项目如何从无到有:
1.需求分析
①:拿到项目,会在客户那里一起讨论需求
商量项目的需求是否可以实现,周期与价格,得到一个需求文档
②:最后公司内部进行开会,得到最终的开发文档,交给不同岗位的程序员进行开发
python 后端,爬虫
不同的岗位:
UI界面护设计
设计软件的布局,会分局软件的外观,切成一张张图片
前端
拿到UI交给他们的软件,然后去搭建网页
设计一些页面中哪些位置会会需要接收数据,需要进行数据交互
后端
直接核心的业务逻辑,调度数据库进行增删改查
测试
会给代码进行压力测试,比如压力测试,界面测试
运维
部署项目
需求文档:
额度15000或自定义 1.注册功能
实现购物商城,买东西加入购物车,调用信用卡接口结账 2.购物功能 3.支付功能
可以提现手续费5% 4.提现功能
支持多账户登录 5.登录功能
支持账户间转账 6.转账功能
记录每月日常消费流水 7.记录消费流水
提供还款接口 8.还款概念
ATM记录操作日志 9.记录软件的使用日志功能
提供管理接口,包括添加账户、用户额度,冻结账户等 10.管理员功能
用户认证用装饰器 11.登录验证装饰器
功能提取:
1.注册
2.购物
3.支付
4.提现
5.登录
6.转账
7.记录消费流水
8.还款
9.记录软件使用日志
10.管理员功能
11.登录验证
2.软件的架构分析(*******)
设计为三层架构:
第一层:用户视图层:提供给用户进行功能选择的界面 src
第二层:逻辑接口层:所有核心逻辑相关的都放在接口层,供用户视图层进行调用 interface
第三层:数据处理层:接收接口层传来的数据,返回相应的数据给接口层,或者保存
对数据进行:增加,删除,更新,查看
3.分任务开发
多人协同开发项目,高效开发项目
4.测试
手动测试
自动测试
5.上线运行
用户可以选择的功能:
1.注册
2.登录
3.查看金额
4.提现
5.还款
6.转账
7.购物车功能
8.查看流水
9.查看购物车
二、目录格式
三、源码
2.1 settings
import os
import logging.config
###
# 功能字典#
##
FUNC_MSG = {
'0': '注销',
'1': '登录',
'2': '注册',
'3': '查看余额',
'4': '转账',
'5': '还款',
'6': '取款',
'7':'查看流水',
'8': '购物',
'9': '购物车',
'q': '退出'
}
####
# db/log文件夹路径#
#######
ATM_PATH = os.path.dirname(os.path.dirname(__file__))
DB_PATH = os.path.join(ATM_PATH, 'db')
LOG_PATH = os.path.join(ATM_PATH, 'log')
GOODS_INFO_PATH = os.path.join(DB_PATH, 'goods_info.xlsx')
###
# logging配置#
#########
# 定义三种日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]'
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定义日志输出格式 结束
logfile_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
logfile_dir = os.path.join(logfile_dir, 'log')
logfile_name = 'log.log'
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
# 打印到终端的日志
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志,收集info及以上的日志
'default': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8',
},
},
'loggers': {
'': {
'handlers': ['d'
''
'efault', 'console'],
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)传递
},
},
}
2.2 db_handler
import os
import json
import numpy as np
import pandas as pd
from conf import settings
def save_json(username: str, content: dict):
"""保存json文件"""
user_path = os.path.join(settings.DB_PATH, f'{username}.json')
with open(user_path, 'w', encoding='utf8') as fw:
json.dump(content, fw)
def read_json(username: str) -> dict:
"""读取json文件"""
user_path = os.path.join(settings.DB_PATH, f'{username}.json')
with open(user_path, 'r', encoding='utf8') as fr:
data = json.load(fr)
return data
def save_excel(df, filename):
"""保存excel"""
df.to_excel(filename)
def read_excel(filename):
"""读取excel"""
df = pd.read_excel(filename, index_col=0, header=0)
return df
if __name__ == '__main__':
save_json('nick', {'name': 'nick'})
data = read_json('nick')
print(data)
arr = np.random.rand(3, 4)
df = pd.DataFrame(arr)
save_excel(df)
data = read_excel(settings.GOODS_INFO_PATH)
print(data)
2.3 bank
import os
from conf import settings
from db import db_handler
def check_extra_interface(username):
"""检查余额接口"""
data = db_handler.read_json(username)
return data['extra']
def transfer_interface(from_username, to_username, money):
from_username_data = db_handler.read_json(from_username)
to_username_data = db_handler.read_json(to_username)
if from_username_data['extra'] > money:
to_username_data['extra'] += money
from_username_data['extra'] -= money
db_handler.save_json(from_username, from_username_data)
db_handler.save_json(to_username, to_username_data)
return True, '转账成功'
return False, '转账失败'
def repay_interface(username):
username_data = db_handler.read_json(username)
extra = username_data['extra']
if extra >= 15000:
return True, '无需还款'
else:
username_data['extra'] = 15000
db_handler.save_json(username, username_data)
return True, f'还款{(15000-extra)*1.005}成功'
def withdraw_interface(username, money):
username_data = db_handler.read_json(username)
if username_data['extra'] > money:
username_data['extra'] -= money
db_handler.save_json(username, username_data)
return True, f'取现{money}成功'
return False, f'余额不足'
def history_interface(username):
filename = os.path.join(settings.LOG_PATH, 'log.log')
with open(filename, 'r', encoding='utf8') as fr:
s = ''
for i in fr:
if i.split('[')[-1].startswith(username):
s += i
return s
2.4 store
from db import db_handler
from conf import settings
from lib import common
shopping_car_dict = dict()
def read_goods_interface():
df = db_handler.read_excel(settings.GOODS_INFO_PATH)
return df
df = read_goods_interface()
def shopping_interface():
while True:
print(df)
common.goods_visualize(df)
# 打印商品信息
goods = df.columns
goods_choice = input('请选择你需要的商品,输入q退出>>>').strip()
if goods_choice == 'q':
break
if goods_choice in goods:
count_choice = input('请输入你需要购买的商品数量,输入q退出>>>').strip()
if count_choice == 'q':
break
count_choice = int(count_choice)
if int(df.loc['amount', goods_choice]) < count_choice:
print('傻逼,库存不足')
continue
else:
goods_price = int(df.loc['price', goods_choice])
if shopping_car_dict.get(goods_choice):
shopping_car_dict[goods_choice] += (count_choice * goods_price)
else:
shopping_car_dict[goods_choice] = (count_choice * goods_price)
print(f'已经把{goods_choice}*{count_choice}加入购物车')
df.loc['amount', goods_choice] -= count_choice
else:
print('傻逼,中文看不懂,英文也看不懂')
return f'已加入购物车{shopping_car_dict}'
def shopping_car_interface(shopping_car_dict, username):
goods_price = sum(shopping_car_dict.values())
username_data = db_handler.read_json(username)
if username_data['extra'] >= goods_price:
username_data['extra'] -= goods_price
username_data.update(shopping_car_dict)
db_handler.save_json(username, username_data)
new_shopping_car_dict = shopping_car_dict.copy()
shopping_car_dict.clear()
# 保存为excel文件
db_handler.save_excel(df, settings.GOODS_INFO_PATH)
return True, f'购物成功{new_shopping_car_dict}'
else:
shopping_car_dict.clear()
return False, '穷逼也购物'
if __name__ == '__main__':
read_goods_interface()
2.5 user
from lib import common
from db import db_handler
def register_interface(username, pwd):
"""注册接口"""
flag = common.check_user(username)
if flag:
return False, '用户已经存在'
else:
content = {'username': username, 'pwd': pwd, 'extra': 15000, 'locked': 0}
db_handler.save_json(username, content)
return True, '用户注册成功'
def login_interface(username, pwd):
# 判断用户是否存在
flag = common.check_user(username)
if not flag:
return False, '用户不存在', 1
# 判断用户是否锁定
data = db_handler.read_json(username)
if data['locked']:
return False, '用户已经锁定,去解锁', 2
# 判断密码
if pwd == data['pwd']:
return True, '登陆成功', 0
return False, '密码错误', 3
def locked_interface(username):
"""输入密码错误就锁"""
data = db_handler.read_json(username)
data['locked'] = 1
db_handler.save_json(username, data)
2.6 common
import os
import hashlib
import logging
import logging.config
from conf import settings
from interface import store
def login_auth(func):
from core import src
def wrapper(*args, **kwargs):
# 判断是否登陆
if not src.user_auth.get('username'):
src.login()
res = func(*args, **kwargs)
return res
res = func(*args, **kwargs)
return res
return wrapper
def load_logging_config(name):
logging.config.dictConfig(settings.LOGGING_DIC)
logger = logging.getLogger(name)
return logger
def check_user(username):
"""注册接口"""
username_filename = os.path.join(settings.DB_PATH, f'{username}.json')
if os.path.exists(username_filename):
return True
def input_username_pwd():
username = input('请输入你的用户名>>>').strip()
pwd = input('请输入你的密码>>>').strip()
# 密码加密
m = hashlib.md5()
m.update(pwd.encode('utf8'))
pwd = m.hexdigest()
return username, pwd
def goods_visualize(df):
"""想写就写"""
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
font = FontProperties(fname='F:\文件\Python\实战项目\就是要多敲几次\ATM第四次\lib\MSYH.TTF')
goods_columns = df.columns.to_list()
goods_price = df.loc['price', :].to_list()
price_index = list(range(len(goods_price)))
goods_amount = df.loc['amount', :].to_list()
amount_index = list(range(len(goods_amount)))
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.bar(price_index, goods_price,color='yellow')
ax1.set_title('价格表', fontproperties=font)
plt.xticks(amount_index, goods_columns, fontproperties=font, rotation=45)
for i in amount_index:
plt.text(amount_index[i],goods_price[i],s=goods_price[i])
ax2 = fig.add_subplot(122)
ax2.bar(amount_index, goods_amount,color='green')
ax2.set_title('数量表', fontproperties=font)
plt.xticks(amount_index,goods_columns,fontproperties=font,rotation=45)
for i in amount_index:
plt.text(amount_index[i],goods_amount[i],s=goods_amount[i])
plt.suptitle('商品信息表', fontproperties=font, fontsize=15, weight='bold')
plt.show()
if __name__ == '__main__':
goods_visualize()
2.7 run
from core import src
if __name__ == '__main__':
src.run()