ATM+购物车功能

一、项目需求

1.额度15000或自定义     -->  注册功能
2.实现购物商城,买东西加入购物车,调用信用卡接口结账 --> 购物功能、支付功能
3.可以提现,手续费5% --> 提现功能
4.支持多账户登录 --> 登录功能
5.支持账户间转账 --> 转账功能
6.记录日常消费 --> 记录流水功能
7.提供还款接口 --> 还款功能
8.ATM记录操作日志 --> 记录日志功能
9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。 ---> 管理员功能
10.用户认证用装饰器 --> 登录认证装饰器

二、 展示给用户选择的功能

1.注册功能
2.登陆功能
3.查看余额
4.提现功能
5.还款功能
6.转账功能
7.查看流水
8.添加购物车
9.查看购物车
10.结算购物车
11.管理员功能

三、架构流程

采取MVC的架构方式     各层分开,编写接口
1、把每个功能都分层三部分,逻辑清晰
2、如果用户更换不同的用户界面或不同的数据库存储机制,不会影响接口层的核心逻辑代码,扩展性强。
3、可以在接口层,准确的记录日志与流水。

四、代码实现

start.py(程序的入口)

import os
import sys base_dir = os.path.dirname(os.path.dirname(__file__))
sys.path.append(base_dir) if __name__ == '__main__':
from core import src
src.run()

conf

setting.py(log日志的配置文件,项目的环境配置)

import os

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
DB_DIR = os.path.join(BASE_DIR, 'db')
if not os.path.exists(DB_DIR):
os.mkdir(DB_DIR) # 提现手续费
MONEY_RATE = 0.05 # 我偷懒 不改大写了
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' # 自定义文件路径
LOG_DIR = os.path.join(BASE_DIR, 'log')
if not os.path.isdir(LOG_DIR):
os.mkdir(LOG_DIR)
LOGFILE_PATH = os.path.join(LOG_DIR, 'ATM.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': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}

core

src.py

from interface import user_interface, bank_interface, shop_interface
from lib import common is_login = {
'username': ''
} def register():
# 1.获取用户相关数据
username = input('请输入您的用户名>>>:').strip()
password = input('请输入您的密码>>>:').strip()
confirm_pwd = input('请确认您的密码>>>:').strip()
# 2.判断两次密码是否一致
if not password == confirm_pwd:
print('两次密码不一致 请重新输入')
return
# 直接调用用户注册接口
flag, msg = user_interface.register_interface(username, password)
print(msg) def login():
# 1.获取用户相关数据
username = input('请输入您的用户名>>>:').strip()
password = input('请输入您的密码>>>:').strip()
# 2.直接调用用户登录接口
flag, msg = user_interface.login_interface(username, password)
'''登录接口返回的数据值有两个 为了保证接口调用返回值的一致性 应该让所有的接口函数返回值个数保持一致 都应该变成两个'''
if flag:
is_login['username'] = username
print(msg) @common.login_auth
def check_balance():
# 直接调用查看账户余额的接口
flag, msg = bank_interface.check_balance_interface(is_login.get('username'))
print(msg) @common.login_auth
def withdraw():
# 1.获取用户想要提现的具体金额即可
target_money = input('请输入您想要提现的金额>>>:').strip()
# 2.判断用户输入的是否是整数或者小数 100 123.23 正则表达式、代码处理
'''转数字的操作 也可以封装成函数放到common.py中'''
# 3.调用银行接口完成提现操作
flag, msg = bank_interface.withdraw_interface(is_login.get('username'), target_money)
print(msg) @common.login_auth
def pay_back():
# 1.直接获取用户想要充值的钱数
target_money = input('请输入您想要充值的金额>>>:').strip()
# 2.还需要判断是否是整数或者小数
flag, msg = bank_interface.pay_back_interface(is_login.get('username'), target_money)
print(msg) @common.login_auth
def transfer():
# 1.获取想要转账的用户名
target_user = input('请输入您想要转账的用户>>>:').strip()
# 2.获取想要转账的金额
target_money = input('请输入您想要转账的金额>>>:').strip()
# 3.直接调用转账的接口
flag, msg = bank_interface.transfer_interface(is_login.get('username'), target_user, target_money)
print(msg) @common.login_auth
def check_flow():
# 直接调用查看流水的接口即可
flag, msg = bank_interface.check_flow_interface(is_login.get('username'))
if flag: # msg = ['','','']
for data in msg:
print(data)
else:
print(msg) @common.login_auth
def add_shop_car():
"""
1.先获取商品数据
2.打印商品数据并让用户选择
3.用户一旦退出 调用接口完成购物车数据更新
:return:
"""
# 1.直接调用添加购物车接口
flag, msg = shop_interface.add_shop_car_interface(is_login.get('username'))
print(msg) @common.login_auth
def check_shop_car():
# 1.直接调用查看购物车接口
flag, msg = shop_interface.check_shop_car_interface(is_login.get('username'))
if flag: # msg = {'商品名称':[个数,单价]}
for name, data_list in msg.items():
print(f"商品:{name} | 商品个数:{data_list[0]} | 商品单价:{data_list[1]}")
else:
print(msg) @common.login_auth
def pay_shop_car():
flag, msg = shop_interface.pay_shop_car_interface(is_login.get('username'))
print(msg) @common.login_auth
def admin():
pass func_dict = {
'1': register,
'2': login,
'3': check_balance,
'4': withdraw,
'5': pay_back,
'6': transfer,
'7': check_flow,
'8': add_shop_car,
'9': check_shop_car,
'10': pay_shop_car,
'11': admin
} def run():
while True:
print("""
====================ATM+购物车==================
1.注册功能
2.登陆功能
3.查看余额
4.提现功能
5.还款功能
6.转账功能
7.查看流水
8.添加购物车
9.查看购物车
10.结算购物车
11.管理员功能
==============================================
""")
choice_num = input('请输入功能编号>>>:').strip()
if choice_num in func_dict:
func_dict.get(choice_num)()
else:
print('暂无该功能编号')

db

user_date (用户存放json的目录)

import os
import json
from conf import setting # 查找数据
def select(username):
user_file_path = os.path.join(setting.DB_DIR,f'{username}.json')
if os.path.exists(user_file_path):
with open(user_file_path,'r',encoding='utf8') as f:
return json.load(f) # 保存数据
def save(user_dict):
username = user_dict.get('username')
user_file_path = os.path.join(setting.DB_DIR, f'{username}.json')
with open(user_file_path, 'w', encoding='utf8') as f:
json.dump(user_dict, f,ensure_ascii=False)

interface

bank_interface.py(银行业务处理接口)

from db import db_handler
from lib import common
from conf import setting
import time def check_balance_interface(username):
# 查询当前登录用户的字典数据
user_dict = db_handler.select(username)
# 从字典中获取余额信息返回给第一层
user_balance = user_dict.get('balance')
return True, f'用户{username}的账户余额是{user_balance}' def withdraw_interface(username, target_money):
flag1, value = common.get_num(target_money)
if not flag1:
return False, '请输入符合要求的金额数字'
# 获取当前登录用户的字典数据
user_dict = db_handler.select(username)
# 获取余额信息及提现手续费
user_balance = user_dict.get('balance')
if user_balance >= value * (1 + setting.MONEY_RATE):
user_dict['balance'] -= value * (1 + setting.MONEY_RATE)
# 添加流水信息
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
user_dict['water_flow'].append(f'时间{ctime}:账户{username}成功提现{value},手续费为{value * setting.MONEY_RATE}')
db_handler.save(user_dict)
return True, f'尊敬的{username},您成功提现{value},手续费为{value * setting.MONEY_RATE},账户余额{user_dict.get("balance")}'
return False, f'尊敬的{username},您账户余额不够提现,请先充值' def pay_back_interface(username, target_money):
flag, value = common.get_num(target_money)
if not flag:
return False, '请输入符合要求的金额数字'
# 获取当前字典数据
user_dict = db_handler.select(username)
# 获取充值钱数
user_dict['balance'] += value
# 添加流水信息
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
user_dict['water_flow'].append(f'时间{ctime}:账户{username}您成功充值{value}目前账户余额为{user_dict.get("balance")}')
# 保存用户数据
db_handler.save(user_dict)
return True, f'尊敬的{username},您成功充值{value},目前账户余额为{user_dict.get("balance")}' def transfer_interface(current_user,target_user,target_money):
# 获取转账用户的信息
target_user_dict = db_handler.select(target_user)
if not target_user_dict:
return False, f'用户{target_user}不存在'
flag, value = common.get_num(target_money)
if not flag:
return False, '请输入符合要求的整数或者小数'
# 获取当前用户的信息
current_user_dict = db_handler.select(current_user)
# 判断余额是否充足
if current_user_dict.get('balance') >= value:
current_user_dict['balance'] -= value
# 扣钱流水
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
current_user_dict['water_flow'].append(f'时间{ctime}:给账户{target_user}转账{value}')
target_user_dict['balance'] += value
# 加钱流水
target_user_dict['water_flow'].append(f'时间{ctime}:收到账户{target_user}转过来账{value}')
db_handler.save(target_user_dict)
db_handler.save(current_user_dict)
return True,f'尊敬的{current_user},您成功向{target_user}转账{value},目前账户余额为{current_user_dict.get("balance")}'
return False,'您当前余额不够转账' def check_flow_interface(username):
# 获取用户对应的用户字典
user_dict = db_handler.select(username)
if user_dict.get('water_flow'):
return True,user_dict.get('water_flow')
return False,'暂无该用户的流水记录'

shop_interface.py(购物业务接口处理)

from db import db_handler
from lib import common
import time logger = common.get_logger('购物车模块') def add_shop_car_interface(username):
# 8.构造临时小字典存储商品信息
temp_shop_car = {}
while True:
# 1.获取商品信息(目前是写死的 后期可以动态获取)
good_list = [
['挂壁面', 3],
['印度飞饼', 22],
['极品木瓜', 666],
['土耳其土豆', 999],
['伊拉克拌面', 1000],
['董卓戏张飞公仔', 2000],
['仿真玩偶', 10000]
]
# 2.循环打印商品信息供用户选择
for num, good_data in enumerate(good_list): # 0 []
print(f"商品编号:{num} | 商品名称:{good_data[0]} | 商品单价:{good_data[1]}")
# 3.获取用户输入的商品编号
choice_num = input('请输入您想要购买的商品编号(q)>>>:').strip()
'''10.添加结束标志 用于保存购物车数据'''
if choice_num == 'q':
# 11.获取当前登录用户的字典数据
user_data_dict = db_handler.select(username)
old_shop_car = user_data_dict.get('shop_car') # {'印度飞饼':[10, 22]}
# 12.保存购物车数据
for g_name, g_list in temp_shop_car.items():
if g_name in old_shop_car:
old_shop_car[g_name][0] += temp_shop_car[g_name][0]
else:
old_shop_car[g_name] = g_list
user_data_dict['shop_car'] = old_shop_car
db_handler.save(user_data_dict)
logger.info(f'{username}用户添加购物车成功')
return True, '添加购物车成功 欢迎下次再来'
# 4.判断编号是否是纯数字
if not choice_num.isdigit():
print('商品编号必须是纯数字')
continue
choice_num = int(choice_num)
# 5.判断数字是否超出范围
if choice_num not in range(len(good_list)):
print('商品编号不在已存在的商品编号内 无法选择购买')
continue
# 6.根据商品编号获取商品信息
target_good_list = good_list[choice_num] # ['印度飞饼', 22]
# 7.获取想要购买的商品个数
good_num = input(f'请输入您想要购买的{target_good_list[0]}的商品数量>>>:').strip()
if not good_num.isdigit():
print('商品数量必须是纯数字')
continue
good_num = int(good_num)
# 9.写入临时小字典中
good_name = target_good_list[0] if good_name in temp_shop_car:
temp_shop_car.get(good_name)[0] += good_num
else:
temp_shop_car[good_name] = [good_num, target_good_list[1]] def check_shop_car_interface(username):
# 1.获取当前登录用户的字典数据
user_dict = db_handler.select(username)
# 2.获取当前用户购物车数据
shop_car = user_dict.get('shop_car')
if shop_car:
logger.info(f'用户{username}查看了购物车数据')
return True, shop_car
return False, '暂无购物车数据' def pay_shop_car_interface(username):
user_data_dict = db_handler.select(username)
# 3.获取当前用户购物车数据及账户余额
shop_car = user_data_dict.get('shop_car') # {'印度飞饼':[10, 22],'公仔':[100, 100]}
if not shop_car:
return False, '购物车空空如也'
current_balance = user_data_dict.get('balance')
# 4.统计购物车商品总价
total_money = 0
for g_list in shop_car.values(): # [10, 22] [100, 100]
total_money += g_list[0] * g_list[1]
# 5.比较余额是否充足
if total_money > current_balance:
return False, '你个穷逼 账户余额不够 再想办法 噶腰子去!!!'
user_data_dict['balance'] -= total_money
ctime = time.strftime('%Y-%m-%d %X')
user_data_dict['water_flow'].append(f'时间{ctime}:购物消费了{total_money}')
# 6.清空购物车
user_data_dict['shop_car'] = {}
logger.info(f'{username}疯狂消费了{total_money}')
db_handler.save(user_data_dict)
return True, f'尊敬的{username} 您本次消费{total_money} 卡上余额剩余{user_data_dict.get("balance")} 欢迎下次再来挥霍!!!'

user_interface.py(用户业务接口处理)

from db import db_handler

def register_interface(username,password):
is_user = db_handler.select(username)
# 判断用户名是否存在
if is_user:
return False, '用户名已存在'
user_dict = {
'username': username,
'password': password, # 密码后续应该加密
'balance': 15000,
'shop_car': {},
'is_lock': False,
'water_flow': [],
}
db_handler.save(user_dict)
return True,f'用户名{username}注册成功' def login_interface(username,password):
user_dict = db_handler.select(username)
if not user_dict:
return False,'用户名不存在'
if user_dict.get('password') == password:
return True,'登录成功'
else:
return False, '密码错误'

lib

common.py(公用类,盐MD5加密,登录装饰器)

import hashlib
from core import src
import logging
import logging.config
from conf import settings def get_hash(msg):
md5 = hashlib.md5()
md5.update(msg.encode('utf8'))
return md5.hexdigest() def login_auth(func_name):
def inner(*args, **kwargs):
if src.is_login.get('username'):
res = func_name(*args, **kwargs)
return res
else:
print('您暂未登录 请先去登录')
src.login() return inner def get_num(target_money):
try:
target_money = float(target_money)
except ValueError:
return False, '请输入整数或者小数'
else:
return True, target_money def get_logger(msg):
logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
return logger1

ATM+购物车功能的更多相关文章

  1. Python 入门基础16 -- ATM + 购物车

    ATM + 购物车 1.需求分析 2.设计程序以及程序的架构 设计程序的好处: - 扩展性强 - 逻辑清晰 3.分任务开发 4.测试 黑盒: 白盒: 对程序性能的测试 5.上线运行 # Tank -- ...

  2. python以ATM+购物车剖析一个项目的由来及流程

    ATM+购物车 一个项目是如何从无到有的 ''' 项目的由来,几个阶段 0.采集项目需求 1.需求分析 2.程序的架构设计 3.分任务开发 4.测试 5.上线运行 ''' 需求分析: # 对项目需求进 ...

  3. Python实战之ATM+购物车

    ATM + 购物车 需求分析 ''' - 额度 15000或自定义 - 实现购物商城,买东西加入 购物车,调用信用卡接口结账 - 可以提现,手续费5% - 支持多账户登录 - 支持账户间转账 - 记录 ...

  4. 阶段性项目 ATM+购物车项目

    ATM + 购物车https://www.cnblogs.com/kermitjam/articles/10687180.html readme 内容前戏: 一个项目是如何从无到有的. 一 需求分析 ...

  5. ATM购物车+三层结构项目设计

    ATM购物车项目 模拟实现一个ATM + 购物商城程序. 该程序实现普通用户的登录注册.提现充值还款等功能,并且支持到网上商城购物的功能. 账户余额足够支付商品价格时,扣款支付:余额不足时,无法支付, ...

  6. ATM + 购物车项目

    ''' 存放配置文件 ''' import os #获取项目根目录 BASE_PATH=os.path.dirname(os.path.dirname(__file__)) #获取用户目录 USER_ ...

  7. 项目: ATM+购物车

    ATM+购物车 项目文件: 介绍 以下为文件夹层次和内容: readme.md 1. 需求 模拟银行取款 + 购物全过程 1.注册 2.登录 3.提现 4.还款 5.转账 6.查看余额 7.查看购物车 ...

  8. Android 购物车功能的实现

    首先,众所周知,ListView是Android最常用的控件,可以说是最简单的控件,也可以说是最复杂的控件. 作为一个Android初级开发者,可能会简单的ListView展示图文信息. 作为一个有一 ...

  9. 【JSP】Cookie的使用及保存中文,并用Cookie实现购物车功能

    Cookie是服务器存放在客户端的一些数据,比如密码,以及你曾经访问过的一些数据. 设置Cookie //设置cookie Cookie cookie = new Cookie("TOM&q ...

  10. 给destoon商城的列表中和首页添加购物车功能

    如何给destoon商城的列表中和首页添加购物车功能? 目前加入购物车的功能只存在商城的详细页面里,有时候我们需要批量购买的时候,希望在列表页就能够使用这个加入购物车的功能. 修改步骤见下: 例如在商 ...

随机推荐

  1. Mybatis笔记02-----MyBatis的核心配置文件以及模糊查询的实现

    认识MyBatis核心配置文件mybatis-config.xml 这个文件名是随意可以起,但为了规范一般都命名为mybatis-config.xml:配置文件与MyBatis的行为和属性信息息息相关 ...

  2. 万字详解JVM,让你一文吃透

    摘要:本文将带大家详细地了解关于JVM的一些知识点. 本文分享自华为云社区<[JVM]关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列>,作者: 冰 河 . JDK 是什么? JDK ...

  3. JIRA操作之 基本说明

    官方说明:https://docs.atlassian.com/software/jira/docs/api/7.6.1/ 项目(Project) Project是一组问题单(Issue)的集合,每个 ...

  4. hutool包的DateUtil工具类

    [首先引入依赖 ] <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core& ...

  5. 4.drf-版本管理

    根据RESTful规范,后端API中需要体现出版本,DRF中支持5种版本的设置,常见的三种如下 1. URL的GET中传递参数 在视图类中定义 from rest_framework.versioni ...

  6. cookie中 防止重复存值 (可用于历史记录等)

    function makeCookie($key,$val){ // 查看cookie中是否已经存过键为history_ids if(Cookie::has($key)){ // 已经存过了 $jso ...

  7. golang基础语法学习

    1.函数作为一等公民 2.驼峰命名法/大小写决定是否在包外见 3.包名应该是小写的单个单词命名 4. 包名应为其源码的基础名称,如encoding/base64,包名应为base64而不是encodi ...

  8. 01-Docker实战,搭建NodeJs环境

    目的 实现简单的docker的nodejs容器,使用Dockerfile构建我们的使用nodejs开发的系统 技术栈 Docker Nodejs Express Linux step1 下拉nodej ...

  9. 8、将两个字符串s1,s2进行比较,如果s1>s2,则输出一个正数。如果s1 = s2,输出零。如果s1 < s2, 输出一个负数,不用strcmp函数,输出的正数或者负数的绝对值应该是比较两字符串相应字符的ascii码的差值。

    /* 将两个字符串s1,s2进行比较,如果s1>s2,则输出一个正数.如果s1 = s2,输出零.如果s1 < s2, 输出一个负数,不用strcmp函数,输出的正数或者负数的绝对值应该是 ...

  10. 集群部署看过来,低代码@AWS智能集群的架构与搭建方案

    为了帮助充分利用AWS的托管服务快速构建起一套集群环境,彻底去掉"单一故障点",实现最高的可用性,我们准备了<低代码智能集群@AWS的架构与搭建方案>看完本文,带你掌握 ...