ATM+购物车

项目目录搭建

1.bin
start.py    # 存放启动脚本
2.conf
settings.py  # 存放配置文件
3.lib
common      # 存放公共功能
4.log        # 存放项目日志
5.core
src.py      # 展示层
6.interface    # 核心逻辑层
shop_interface # 购物车接口
bank_interface # 银行接口
user_interface # 用户接口
admin_interface # 管理员接口

db
db_handlerl.py # 数据处理层
readme      # 说明

框架搭建(src.py)

is_login= {'username':''}  # 全局变量 保存登录信息

# 用户注册
def register():
    pass
# 用户登录
def login():
    pass

# 查看余额
def check_balance():
    pass
  
# 余额提现
def Withdraw():
    pass

# 账户充值
def pay():
    pass

# 转账
def tranfer():
    pass

# 查看流水
def check_flow():
    pass

# 添加购物车
def add_shop_car():
    pass


# 查看购物车
def check_shop_car():
    pass


# 结算
def pay_shop_car():
    pass

# 管理员
def admin():
    pass

# 功能字典
func_dict = {
    '1': register,
    '2': login,
    '3': look_balance,
    '4': Withdraw,
    '5': pay,
    '6': tranfer,
    '7': cheak_water,
    '8': add_shop_car,
    '9': view_shop_car,
    '10': clear_shop_car,
    '11': admin


}



while True:
    print("""
      1.用户注册
      2.登录功能
      3.查看余额
      4.余额提现
      5.账户充值
      6.金额转账
      7.查看流水
      8.添加购物车
      9.查看购物车
      10.结算购物车
      11.管理员功能
    """)

    choice = input('请输入功能编号>>>:').strip()
    if choice in func_dict:
        func_name = func_dict.get(choice)
        func_name()
    else:
        print('好好输!')

启动文件(start.py文件代码)

import os
import sys

base_dir = os.path.dirname(os.path.dirname(__file__))  # 1.找到根目录
sys.path.append(base_dir)  # 2.在将根目录添加至环境变量,不受用户和路径限制

if __name__ == '__main__':
    from core import src
    src.run()  # 3.调用run()函数,开始展示功能

配置文件

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)


MONETY_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')




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配置
    },
}

公共文件(common文件代码)

"""
代码中加密,装饰器,判断数字是否符合要求,日志都是公共功能,因此放在common中
"""
import hashlib
import logging
import logging.config
from core import src
from conf import settings

def get_hash(user_pwd):
    md5 = hashlib.md5()
    md5.update(user_pwd.encode('utf8'))
    return md5.hexdigest()

def login_auth(func):
    def inner(*args, **kwargs):
        if src.is_login.get('username'):
            res = func(*args, **kwargs)
            return res
        else:
            print('您尚未登陆,请先登陆')
            src.login()
    return inner

def get_num(target_money):
    try:
        target_money = float(target_money)
    except:
        return False, '请输入整数或小数'
    else:
        return True, target_money


def get_logger(msg):
    logging.config.dictConfig(settings.LOGGING_DIC)  # 自动加载字典中的配置
    logger1 = logging.getLogger(msg)
    return logger1

数据库操作相关代码(db_handler文件代码)

"""
此文件主要用于数据库文件的存取,存取需要多次用到,所以直接封成函数放在数据库操作文件中方便使用
"""
import os
import json
from conf import settings

def save(user_dict):
    user_name = user_dict.get('username')
    user_file_path = os.path.join(settings.DB_DIR, f'{user_name}.json')
    with open(user_file_path, 'w', encoding='utf8') as f:
        json.dump(user_dict, f, ensure_ascii=False)

def select(user_name):
    user_file_path = os.path.join(settings.DB_DIR, f'{user_name}.json')
    if os.path.exists(user_file_path):
        with open(user_file_path, 'r', encoding='utf8') as f:
            return json.load(f)

注册功能

"""
注册功能应首先在第一层获取用户输入,简单逻辑判断之后传给第二层,进行逻辑判断,涉及是否已注册功能及存取需要用到db_handler中的函数
"""
src代码:
def register():
    user_name = input('请输入您的用户名>>>:').strip()  # 1.获取用户输入
    user_pwd = input('请输入您的密码>>>:').strip()
    confirm_pwd = input('请再次输入您的密码>>>:').strip()
    if not user_pwd == confirm_pwd:  # 2.将用户两次输入的密码进行对比,如果不一致则退出运行,重新选择任务编号
        print('两次密码输入不一致,请再次输入')
        return
    flag, msg = user_interface.register_interface(user_name, user_pwd)  # 3.用两个变量名接收interface层注册函数的返回值
    """
    由于本项目部分函数需要返回两个返回值,因此统一用两个变量名来接收函数的返回值,部分函数返回值可能用不上,只是为了统一格式
    """
    print(msg)
	
user_interface代码:
def register_interface(user_name, user_pwd):  # 1.定义注册接口函数
    user_dict = db_handler.select(user_name)  # 2.通过db_handler中的select()函数获取函数的返回值
    if user_dict:  # 3.如果有返回值,说明用户已存在,结束注册功能
        return False, f'用户名{user_name}已注册'
    user_pwd = common.get_hash(user_pwd)  # 4.给传入的密码加密
    user_dict = {     # 5.构造字典
        'username': user_name,
        'password': user_pwd,
        'balance': 15000,
        'shop_car': {},
        'is_lock': False,
        'water_flow': []
    }
    db_handler.save(user_dict)  # 6.调用db_handler中的save()函数来保存构造的字典
    logger.info(f'用户{user_name}注册成功')
    return True, f'用户{user_name}注册成功'  # 7.返回返回值

登录功能

src代码:
def login():
    user_name = input('请输入您的用户名>>>:').strip()  # 1.获取用户输入
    user_pwd = input('请输入您的密码>>>:').strip()
    flag, msg = user_interface.login_inrterface(user_name, user_pwd)
    if flag:  # 3.用两个变量名接收interface层注册函数的返回值
        is_login['username'] = user_name  # 4.记录登录状态
    print(msg)

interface代码:
def login_inrterface(user_name, user_pwd):
    user_dict = db_handler.select(user_name)  # 1.通过select()函数来返回用户字典或None
    if not user_dict:  # 2.逻辑判断:如果没有返回字典,说明用户未注册,将合适的返回值返回给用户
        return False, f'用户{user_name}未注册'
    user_pwd = common.get_hash(user_pwd)  # 3.如果用户已注册,先获取加密后的密码
    if user_pwd == user_dict.get('password'):  # 4.将用户输入后的密码和存储的密码进行对比(都是加密后的密码)
        logger.info(f'用户{user_name}登陆成功')
        return True, '登陆成功'
    return False, '密码错误'   # 5.如果对比不成功返回布尔值和密码错误

查看余额


src代码:
@common.login_auth  # 1.通过添加装饰器来限制用户执行该功能前必须先登陆
def check_balance():
    user_name = is_login.get('username')  # 2.因为用户登录成功时修改了登录状态,所以可以直接通过is_login拿到用户的用户名
    flag, msg = bank_interface.check_balance_interface(user_name)  # 3.用2个变量名来接收interface()函数的返回值
    print(msg)  # 4.打印返回的信息
interface代码:
def check_balance_interface(username):
    user_dict = db_handler.select(username)  # 1.通过传入的用户名从select()函数中通过返回值拿到用户字典
    user_balance = user_dict.get('balance')  # 2.获取到用户的余额
    logger.debug(f'用户{username}查看了自己的账户余额')
    return True, f'尊敬的{username},您的账户余额为{user_balance}'  # 3.将布尔值True和账户余额返回给src中的msg

提现功能

src代码:
@common.login_auth
def withdraw():
    user_name = is_login.get('username')  # 1.通过is_login拿到用户的用户名
    target_money = input('请输入您想要提现的金额>>>:').strip()  # 2.获取用户提现金额
    flag, msg = bank_interface.withdraw_interface(user_name, target_money)  # 3.用2个变量名来接收interface()函数的返回值
    print(msg)
	
interface代码:
def withdraw_interface(username, target_money):
    flag, value = common.get_num(target_money)  # 1.通过common中的get_num()函数来判断数字是否符合要求
    if not flag:  # 2.如果不符合将返回值返回给第一层,重新输入
        return False, '请输入符合要求的金额'
    user_dict = db_handler.select(username)  # 3.通过select()获取用户字典,因为此时是从is_login获取到的用户名,所以字典肯定存在,无需判断
    user_balance = user_dict.get('balance')  # 4.获取用户余额
    if user_balance >= value * (1 + settings.MONETY_RATE):  # 5.判断用户余额是否大于提现金额加手续费,因为手续费不常修改,所以放在settings中大写
        user_dict['balance'] -= value * (1 + settings.MONETY_RATE)  # 6.修改用户字典中的余额,考虑手续费
        ctime = time.strftime('%Y-%m-%d %H:%M:%S')  # 7.记录时间,用于记录流水
        user_dict['water_flow'].append(
            f'{username}于{ctime}提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}')
        db_handler.save(user_dict)  # 8.添加流水
        logger.debug(f'用户{username}提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}')
        return True, f'尊敬的{username}成功提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}'
    return False, f'尊敬的{username}, 您的账户余额不足,无法提现'  # 9.通过逻辑判断返回不同的返回值

充值功能

src代码:
@common.login_auth
def pay_back():
    user_name = is_login.get('username')
    target_money = input('请输入您想充值的金额>>>:').strip()
    flag, msg = bank_interface.pay_back_interface(user_name, target_money)
    print(msg)

interface代码:
def pay_back_interface(user_name, target_money):
    flag, value = common.get_num(target_money)
    if not flag:
        return False, '请输入符合要求的金额数字'
    user_dict = db_handler.select(user_name)
    user_dict['balance'] += value
    ctime = time.strftime('%Y-%m-%d %H:%M:%S')
    user_dict['water_flow'].append(f'{user_name}于{ctime}充值{value},账户余额{user_dict.get("balance")}')
    db_handler.save(user_dict)
    logger.debug(f'用户{user_name}充值{value},账户余额{user_dict.get("balance")}')
    return True, f'尊敬的{user_name},您于{ctime}成功充值{value},账户余额{user_dict.get("balance")}'

转账功能

src代码:
@common.login_auth
def transfer():
    user_name = is_login.get('username')
    target_name = input('请输入您想转账的用户名>>>:').strip()
    target_money = input('请输入您想转账的金额>>>:').strip()
    flag, msg = bank_interface.transfer_interface(user_name, target_name, target_money)
    print(msg)

interface代码:
def transfer_interface(user_name, target_name, target_money):
    target_dict = db_handler.select(target_name)
    if not target_dict:
        return False, f'用户{target_name}未注册'
    flag, value = common.get_num(target_money)
    if not flag:
        return False, '请输入符合要求的数字'
    user_dict = db_handler.select(user_name)
    if user_dict.get('balance') >= value:
        user_dict['balance'] -= value
        ctime = time.strftime('%Y-%m-%d %H:%M:%S')
        user_dict['water_flow'].append(
            f'尊敬的{user_name},您于{ctime}给{target_name}转账{value},账户余额{user_dict.get("balance")}')
        target_dict['balance'] += value
        target_dict['water_flow'].append(
            f'尊敬的{target_name},{user_name}于{ctime}给您转账{value},账户余额{target_dict.get("balance")}')
        db_handler.save(user_dict)
        db_handler.save(target_dict)
        logger.debug(
            f'用户{user_name}给{target_name}转账{value},{user_name}账户余额{user_dict.get("balance")},{target_name}账户余额{target_dict.get("balance")}')
        return True, f'尊敬的{user_name}, 您于{ctime}给{target_name}转账{value},账户余额{user_dict.get("balance")}'
    return False, f'您的账户余额不足,无法转账'

查看流水

src代码:
@common.login_auth
def check_flow():
    user_name = is_login.get('username')
    flag, msg = bank_interface.check_flow_interface(user_name)
    if flag:
        for data in msg:
            print(data)
    else:
        print(msg)

interface代码:
def check_flow_interface(username):
    user_dict = db_handler.select(username)
    if user_dict.get('water_flow'):
        logger.debug(f'用户{username}查看了流水')
        return True, user_dict.get('water_flow')
    else:
        logger.debug(f'用户{username}查看了流水')
        return False, '您暂无流水'

添加购物车

"""
添加购物车主要功能可以写在第二层,第一层主药方用户交互功能
"""
src代码:
@common.login_auth
def add_shop_car():
    user_name = is_login.get('username')
    flag, msg = shop_interface.add_shop_car_interface(user_name)
    print(msg)

interface代码:
def add_shop_car_interface(user_name):
    tem_list = {}
    while True:
        good_list = [
            ['挂壁面', 3],
            ['印度飞饼', 22],
            ['极品木瓜', 666],
            ['土耳其土豆', 999],
            ['伊拉克拌面', 1000],
            ['董卓戏张飞公仔', 2000],
            ['仿真玩偶', 10000]
        ]
        for i, j in enumerate(good_list, start=1):
            print(f"""
            商品编号:{i} | 商品名称:{j[0]} | 商品单价:{j[1]}
            """)
        choice = input('请输入您的商品编号(q)>>>:').strip()
        if choice == 'q':
            user_dict = db_handler.select(user_name)
            shop_car = user_dict.get('shop_car')
            for i in tem_list:
                if i in shop_car:
                    shop_car.get(i)[0] += tem_list.get(i)[0]
                else:
                    shop_car[i] = tem_list.get(i)
            user_dict['shop_car'] = shop_car
            db_handler.save(user_dict)
            logger.info(f'用户{user_name}添加了购物车')
            return True, f'用户{user_name}购物车添加完毕'

        if not choice.isdigit():
            print('商品编号必须是纯数字')
            continue
        choice = int(choice)
        if not choice in range(1, len(good_list) + 1):
            print('没有该商品')
            continue
        num = input(f'请输入您购买{good_list[choice - 1][0]}的数量>>>:')
        if not num.isdigit():
            print('商品数量必须是纯数字')
            continue
        num = int(num)
        target_list = good_list[choice - 1]
        target_good = target_list[0]
        if target_good in tem_list:
            tem_list.get(target_good)[0] += num
        else:
            tem_list[target_good] = [num, target_list[1]]

查看购物车功能

src.py代码:
@common.login_auth
def check_shop_car():
    user_name = is_login.get('username')
    flag, msg = shop_interface.check_shop_car_interface(user_name)
    if flag:
        for i in msg:
            print(f"""
            商品名称:{i} | 商品数量:{msg.get(i)[0]} | 商品单价:{msg.get(i)[1]}
            """)
    else:
        print(msg)

interface代码:
def check_shop_car_interface(user_name):
    user_dict = db_handler.select(user_name)
    shop_car = user_dict.get('shop_car')
    if shop_car:
        logger.info(f'用户{user_name}查看了购物车')
        return True, shop_car
    else:
        logger.info(f'用户{user_name}查看了购物车')
        return False, '您的购物车为空'

结算购物车功能

src代码:
@common.login_auth
def pay_shop_car():
    user_name = is_login.get('username')
    flag, msg = shop_interface.pay_shop_car_interface(user_name)
    print(msg)
	
interface代码:
def pay_shop_car_interface(user_name):
    user_dict = db_handler.select(user_name)
    shop_car = user_dict.get('shop_car')  # {'极品木瓜': [9, 666], '伊拉克拌面': [5, 1000]}
    current_balance = user_dict.get('balance')
    money = 0
    for i in shop_car.values():  # i:[9, 666]
        money += i[0] * i[1]
    if money > current_balance:
        return False, f'您的账户余额不足,无法结算'
    current_balance -= money
    shop_car = {}
    user_dict['balance'] = current_balance
    user_dict['shop_car'] = {}
    user_dict['water_flow'].append(f'{user_name},您本次消费{money},账户余额{user_dict.get("balance")}')
    db_handler.save(user_dict)
    logger.info(f'用户{user_name}结算了购物车,本次消费{money},账户余额{user_dict.get("balance")}')
    return True, f'尊敬的{user_name},您本次消费{money},账户余额{user_dict.get("balance")}'
posted @ 2022-10-31 22:35  wwwxxx123  阅读(30)  评论(0编辑  收藏  举报