26.ATM+购物车 项目开发实战(下)

1.配置信息settings.py

conf/settings.py

'''
存放配置信息
'''
import os

# 获取项目根目录路径
BASE_PATH = os.path.dirname(
    os.path.dirname(__file__)
)

# 获取user_data文件夹目录路径
USER_DATA_PATH = os.path.join(
    BASE_PATH, 'db', 'user_data'
)
# print(USER_DATA_PATH)


"""
logging配置
"""

# 定义三种日志输出格式 开始
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'

# 定义日志输出格式 结束
# ****************注意1: log文件的目录
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
logfile_dir = os.path.join(BASE_PATH, 'log')
# print(logfile_dir)

# ****************注意2: log文件名
logfile_name = 'atm.log'

# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
    os.mkdir(logfile_dir)

# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)

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)传递
        },
    },
}

2.通用组件common.py

lib/common.py

'''
存放公共方法
'''
import hashlib
from conf import settings
import logging.config


# md5加密
def get_pwd_md5(password):
    md5_obj = hashlib.md5()
    md5_obj.update(password.encode('utf-8'))
    salt = '一二三四五,Egon上山打老鼠!'
    md5_obj.update(salt.encode('utf-8'))
    return md5_obj.hexdigest()


# 登录认证装饰器
def login_auth(func):
    from core import src

    def inner(*args, **kwargs):
        if src.login_user:
            res = func(*args, **kwargs)
            return res
        else:
            print('未出示证明,无法享受美好的功能服务!')
            src.login()

    return inner


# 添加日志功能: (日志功能在接口层 使用)
def get_logger(log_type):  # log_type ---> user
    '''
    :param log_type: 比如是 user日志,bank日志,购物商城日志
    :return:
    '''
    # 1、加载日志配置信息
    logging.config.dictConfig(
        settings.LOGGING_DIC
    )

    # 2、获取日志对象
    logger = logging.getLogger(log_type)

    return logger

3.各种功能开发

1.注册功能

1.用户视图层src.py中:

# 1、注册功能
def register():
    while True:
        # 1)让用户输入用户名与密码进行校验
        username = input('请输入用户名: ').strip()
        password = input('请输入密码: ').strip()
        re_password = input('请确认密码: ').strip()
        # 可以输入自定义的金额

        # 小的逻辑处理: 比如两次密码是否一致
        if password == re_password:
            # 2) 调用接口层的注册接口,将用户名与密码交给接口层来进行处理

            # res ---> (False, '用户名已存在!')
            # res = user_interface.register_interface(
            # flag, msg ---> (flag---> False, msg --> '用户名已存在!')

            # (True, 用户注册成功),  (False, 注册失败)
            flag, msg = user_interface.register_interface(
                username, password
            )

            # 3) 根据flag判断用户注册是否成功,flag控制break的结束
            if flag:
                print(msg)
                break

            else:
                print(msg)
        else:
            print('两次密码输入不一致。')

2.逻辑接口层interface/user_interface.py:

from db import db_handler
from lib import common


def register_interface(username,password,balance = 15000):
    # 1.调用数据处理层中的select函数会返回用户信息字典或者None
    if db_handler.select(username):
        return False,'用户已存在,请重新输入!'
    else:
        password = common.get_pwd_md5(password)
        #1.组织用户信息,准备注册
        user_dic = {
            'username': username,
            'password': password,
            'balance': balance,
            # 用于记录用户流水的列表
            'flow': [],
            # 用于记录用户购物车
            'shop_car': {},
            # locked:用于记录用户是否被冻结
            # False: 未冻结   True: 已被冻结
            'locked': False
        }
        # 2.调用数据处理层的保存函数将用户信息写入文件
        #密码加密
        db_handler.save(user_dic)
        return True, f'{username} 注册成功!'

3.数据处理层db/db_handler.py:

'''
数据处理层
    - 专门用户处理数据的
'''
import json
import os
from conf import settings


# 查看数据
def select(username):
    # 1) 接收接口层传过来的username用户名,拼接用户json文件路径
    user_path = os.path.join(
        settings.USER_DATA_PATH, f'{username}.json'
    )

    # 2)校验用户json文件是否存在
    if os.path.exists(user_path):
        # 3) 打开数据,并返回给接口层
        with open(user_path, 'r', encoding='utf-8') as f:
            user_dic = json.load(f)
            return user_dic

    # 3) 不return,默认return None


# 保存数据(添加新数据或者更新数据)
def save(user_dic):
    # 1) 拼接用户的数据字典
    username = user_dic.get('username')

    # 根据用户的名字,拼接 用户名.json 文件路径
    user_path = os.path.join(
        settings.USER_DATA_PATH, f'{username}.json'
    )

    # 2) 保存用户数据
    with open(user_path, 'w', encoding='utf-8') as f:
        # ensure_ascii=False让文件中的中文数据,显示更美观
        json.dump(user_dic, f, ensure_ascii=False)

2.登录功能

1.用户视图层src.py中:

# 2、登录功能
def login():
    while True:
        name = input('请输入你的账号:').strip()
        password = input('请输入你的密码:').strip()
        # 登录接口:
        # 登录成功返回True,登录成功
        res, tag = user_interface.login_interface(name, password)
        if res:
            global login_user
            login_user = name
            print(tag)
            break
        else:
            print(tag)

2.逻辑接口层interface/user_interface.py:

user_logger = common.get_logger(log_type='user')
# 登录接口
def login_interface(username, password):
    # 1) 先查看当前用户数据是否存在
    # {用户数据字典}  or  None
    user_dic = db_handler.select(username)

    # 2) 判断用户是否存在
    if user_dic:
        # 若有冻结用户,则需要判断是否被锁定
        if user_dic.get('locked'):
            return False, '当前用户已被锁定'

        # 给用户输入的密码做一次加密
        password = common.get_pwd_md5(password)

        # 3) 校验密码是否一致
        if password == user_dic.get('password'):
            msg = f'用户: [{username}] 登录成功!'
            user_logger.info(msg)
            return True, msg

        else:

            msg = f'用户: [{username}]密码错误!'
            user_logger.warn(msg)
            return False, msg

    msg = f'用户: [{username}]用户不存在,请重新输入!!'
    return False, msg

3.查询余额功能

1.用户视图层src.py中:

# 3、查看余额
from lib import common
@common.login_auth
def check_balance():
    # 1.直接调用查看余额接口,获取用户余额
    balance = user_interface.check_bal_interface(
        login_user  # username
    )

    print(f'用户{login_user} 账户余额为: {balance}')

2.逻辑接口层interface/user_interface.py:

# 查看余额接口
def check_bal_interface(username):
    # 根据username查看用户的数据字典
    user_dic = db_handler.select(username)

    return user_dic['balance']

4.提现功能

1.用户视图层src.py中:

from interface import bank_interface
# 4、提现功能
@common.login_auth
def withdraw():
    while True:
        # 1) 让用户输入提现金额
        input_money = input('请输入提现金额: ').strip()

        # 2) 判断用户输入的金额是否是数字
        if not input_money.isdigit():
            print('请重新输入')
            continue

        # 3) 用户提现金额,将提现的金额交付给接口层来处理
        flag, msg = bank_interface.withdraw_interface(
            # 用户名, 提现金额
            login_user, input_money
        )

        if flag:
            print(msg)
            break

        else:
            print(msg)

2.逻辑接口层interface/bank_interface.py:

from db import db_handler
from lib import common

# 根据不同的接口类型传入不同的日志对象
bank_logger = common.get_logger(log_type='bank')


# 提现接口(手续费5%)
def withdraw_interface(username, money):
    # 1) 先获取用户字典
    user_dic = db_handler.select(username)

    # 账户中的金额
    balance = int(user_dic.get('balance'))

    # 提现本金 + 手续费
    money2 = int(money) * 1.05  # ---> float

    # 判断用户金额是否足够
    if balance >= money2:
        # 2)修改用户字典中的金额
        balance -= money2

        user_dic['balance'] = balance

        # 3)记录流水
        flow = f'用户[{username}] 提现金额[{money}$]成功,手续费为: [{money2 - float(money)}$]'
        user_dic['flow'].append(flow)

        # 4)再保存数据,或更新数据
        db_handler.save(user_dic)

        bank_logger.info(flow)

        return True, flow

    return False, '提现金额不足,请重新输入!'

5.还款功能

1.用户视图层src.py中:

# 5、还款功能
@common.login_auth
def repay():
    '''
    银行卡还款,无论是信用卡或储蓄卡,是否能充任意大小的金额
    :return:
    '''
    while True:
        # 1) 让用户输入还款金额
        input_money = input('请输入需要还款的金额: ').strip()
        # 2)判断用户输入的是否是数字
        if not input_money.isdigit():
            print('请输入正确的金额')
            continue
        input_money = int(input_money)

        # 3) 判断用户输入的金额大于0
        if input_money > 0:
            # 4)调用还款接口
            flag, msg = bank_interface.repay_interface(
                login_user, input_money
            )

            if flag:
                print(msg)
                break
        else:
            print('输入的金额不能小于0')

2.逻辑接口层interface/bank_interface.py:

# 还款接口
def repay_interface(username, money):
    '''
    1.获取用户的金额
    2.给用户的金额做加钱的操作
    :return:
    '''

    # 1.获取用户字典
    user_dic = db_handler.select(username)

    # 2.直接做加钱操作
    # user_dic['balance'] ---> int
    user_dic['balance'] += money

    # 3.记录流水
    flow = f'用户:[{username}]  还款:[{money}]成功!'
    user_dic['flow'].append(flow)

    # 4.调用数据处理层,将修改后的数据更新
    db_handler.save(user_dic)

    return True, flow

6.转账功能

1.用户视图层src.py中:

# 6、转账功能
@common.login_auth
def transfer():
    '''
    1.接收用户输入的 转账目标用户
    2.接收用户输入的 转账金额
    :return:
    '''
    while True:

        # 1)让用户输入转账用户与金额
        to_user = input('请输入转账目标用户: ').strip()
        money = input('请输入转账金额: ').strip()

        # 2)判断用户输入的金额是否是数字或 > 0
        if not money.isdigit():
            print('请输入正确的金额!')
            continue

        money = int(money)

        if money > 0:
            # 3) 调用转账接口
            flag, msg = bank_interface.transfer_interface(
                # 当前用户,目标用户,转账金额
                login_user, to_user, money
            )
            if flag:
                print(msg)
                break
            else:
                print(msg)

        else:
            print('请输入正确的金额!')

2.逻辑接口层interface/bank_interface.py:

# 转账接口
def transfer_interface(login_user, to_user, money):
    '''
    1.获取 "当前用户" 数据
    2.获取 "目标用户" 数据
    3.获取转账金额
    :return:
    '''

    # 1)获取 "当前用户" 字典
    login_user_dic = db_handler.select(login_user)

    # 2) 获取 "目标用户" 字典
    to_user_dic = db_handler.select(to_user)

    # 3) 判断目标用户是否存在
    if not to_user_dic:
        return False, '目标用户不存在'

    # 4)若用户存在,则判断 "当前用户的转账金额" 是否足够
    if login_user_dic['balance'] >= money:
        # 5) 若足够,则开始给目标用户转账
        # 5.1)给当前用户的数据,做减钱操作
        login_user_dic['balance'] -= money

        # 5.2)给目标用户的数据,做加钱操作
        to_user_dic['balance'] += money

        # 5.3) 记录当前用户与目标用户的流水
        # 当前用户流水
        login_user_flow = f'用户: [{login_user}] 给 用户: [{to_user}] 转账: [{money}$] 成功!'
        login_user_dic['flow'].append(login_user_flow)

        # 目标用户流水
        to_user_flow = f'用户: [{to_user}] 接收 用户: [{login_user}] 转账: [{money}$] 成功!'
        to_user_dic['flow'].append(to_user_flow)

        # 6) 保存用户数据
        # 6.1) 调用数据处理层的save功能,保存当前用户数据
        db_handler.save(login_user_dic)

        # 6.2) 调用数据处理层的save功能,保存目标用户数据
        db_handler.save(to_user_dic)

        return True, login_user_flow

    return False, '当前用户转账金额不足!'

7.查看流水功能

1.用户视图层src.py中:

# 7、查看流水
@common.login_auth
def check_flow():
    # 直接调用查看流水接口
    flow_list = bank_interface.check_flow_interface(
        login_user
    )

    if flow_list:
        for flow in flow_list:
            print(flow)
    else:
        print('当前用户没有流水!')

2.逻辑接口层interface/bank_interface.py:

# 查看流水接口
def check_flow_interface(login_user):
    user_dic = db_handler.select(login_user)
    return user_dic.get('flow')

8.购物功能

1.用户视图层src.py中:

from interface import shop_interface
# 8、购物功能
@common.login_auth
def shopping():
    shop_list = [
        ['上海灌汤包', 30],  # 0
        ['矮跟写真抱枕', 250],  # 1
        ['广东凤爪', 28],
        ['香港地道鱼丸', 15],
        ['坦克', 100000],
        ['macbook', 20000],
    ]

    # 初始化当前购物车:
    shopping_car = {}  # {'商品名称': ['单价', '数量']]}

    while True:
        # 1) 打印商品信息,让用户选择
        # 枚举: enumerate(可迭代对象) ---> (可迭代对象的索引, 索引对应的值)
        # 枚举: enumerate(可迭代对象) ---> (0, ['上海灌汤包', 30])
        print('============欢迎来到有趣用品商城============')
        for index, shop in enumerate(shop_list):
            shop_name, shop_price = shop
            print(f'商品编号为:[{index}]',
                  f'商品名称:[{shop_name}]',
                  f'商品单价:[{shop_price}]')
        print('================24小时服务哦==============')

        # 2) 让用户根据商品编号进行选择
        choice = input('请输入商品编号(是否结账输入y or n): ').strip()

        # 2.1) 输入的是 y 进入支付结算功能
        if choice == 'y':
            if not shopping_car:
                print('购物车是空的,不能支付,请重新输入!')
                continue

            # 6)调用支付接口进行支付
            flag, msg = shop_interface.shopping_interface(
                login_user, shopping_car)

            if flag:
                print(msg)
                break
            else:
                print(msg)

        # 2.2) 输入的是 n 添加购物车
        elif choice == 'n':
            # 判断当前用户是否添加过购物车
            if not shopping_car:
                print('购物车是空的,不能添加,请重新输入!')
                continue

            # 7)调用添加购物车接口
            flag, msg = shop_interface.add_shop_car_interface(
                login_user, shopping_car
            )

            if flag:
                print(msg)
                break

        if not choice.isdigit():
            print('请输入正确的编号!')
            continue

        choice = int(choice)

        # 3) 判断choice是否存在
        if choice not in range(len(shop_list)):
            print('请输入正确的编号!')
            continue

        # 4) 获取商品名称和与单价
        shop_name, shop_price = shop_list[choice]

        # 5)加入购物车
        # 5.1) 判断用户选择的商品是否重复,重复则数量 +1
        if shop_name in shopping_car:
            # [shop_price, 1][1] ---> 1 += 1
            # 添加商品数量
            shopping_car[shop_name][1] += 1

        else:
            # 否则数量默认为1
            # {'商品名称': ['单价', '数量']]}
            shopping_car[shop_name] = [shop_price, 1]

        print('当前购物车: ', shopping_car)

2.逻辑接口层interface/shop_interface.py:

'''
购物商城接口
'''
from db import db_handler
from lib import common

# 根据不同的接口类型传入不同的日志对象log_type=
shop_logger = common.get_logger(log_type='shop')


# 商品准备结算接口
def shopping_interface(login_user, shopping_car):
    # 1) 计算消费总额
    # {'商品名称': []}
    cost = 0
    for price_number in shopping_car.values():
        price, number = price_number
        cost += (price * number)

    # 2)导入银行接口
    from interface import bank_interface
    # 3)逻辑校验成功后,再调用银行的支付接口
    flag = bank_interface.pay_interface(login_user, cost)

    if flag:
        msg = f'用户:[{login_user}]支付 [{cost}$] 成功, 准备发货!'
        shop_logger.info(msg)
        return True, msg

    return False, '支付失败,金额不足'


# 购物车添加接口
def add_shop_car_interface(login_user, shopping_car):
    # 1) 获取当前用户的购物车
    user_dic = db_handler.select(login_user)

    # 获取用户文件中的商品的数据
    shop_car = user_dic.get('shop_car')

    # 2) 添加购物车
    # 2.1)判断当前用户选择的商品是否已经存在
    # shopping_car  --> {'商品名': []}
    for shop_name, price_number in shopping_car.items():
        # 每个商品的数量
        number = price_number[1]

        # 2.2) 若商品重复,则累加商品数量
        if shop_name in shop_car:
            # [单价, 数量][1] ---> 数量
            user_dic['shop_car'][shop_name][1] += number

        else:
            # 2.3)若不是重复的,更新到商品字典中
            user_dic['shop_car'].update(
                {shop_name: price_number}
            )

    # 保存用户数据
    db_handler.save(user_dic)

    return True, '添加购物车成功!'

9.查看购物车

1.用户视图层src.py中:

# 9、查看购物车
@common.login_auth
def check_shop_car():
    # 直接调用查看购物车接口
    shop_car = shop_interface.check_shop_car_interface(
        login_user)
    print(shop_car)

2.逻辑接口层interface/shop_interface.py:

# 查看购物车接口
def check_shop_car_interface(username):
    user_dic = db_handler.select(username)
    return user_dic.get('shop_car')

10.管理员功能

管理员需要有的功能分析如下:

1.添加用户

2.修改用户额度

3.冻结用户

1.用户视图层src.py中:

# 10、管理员功能
@common.login_auth
def admin():
    from core import admin
    admin.admin_run()

2.在core/admin.py中:

from core import src
from interface import admin_interface


# 添加用户
def add_user():
    src.register()


# 修改用户额度
def change_balance():
    while True:
        # 1) 输入需要修改的用户名
        change_user = input('请输入需要修改额度的用户: ').strip()

        # 2)修改的用户用户额度
        money = input('请输入需要修改的用户额度: ').strip()
        if not money.isdigit():
            continue

        # 3)调用修改额度接口
        flag, msg = admin_interface.change_balance_interface(
            change_user, money
        )

        if flag:
            print(msg)
            break

        else:
            print(msg)


# 冻结账户
def lock_user():
    while True:
        # 1) 输入需要冻结的用户名
        change_user = input('请输入需要修改额度的用户: ').strip()

        flag, msg = admin_interface.lock_user_interface(
            change_user)

        if flag:
            print(msg)
            break
        else:
            print(msg)


# 管理员功能字典
admin_func = {
    '1': add_user,
    '2': change_balance,
    '3': lock_user,
}


def admin_run():
    while True:
        print('''
            1、添加账户
            2、修改额度
            3、冻结账户
            ''')
        choice = input('请输入管理员功能编号: ').strip()

        # 判断功能编号是否存在
        if choice not in admin_func:
            print('请输入正确的功能编号!')
            continue

        # 调用用于选择的功能函数
        admin_func.get(choice)()

3.逻辑接口层interface/admin_interface.py:

from db import db_handler
from lib import common

# 根据不同的接口类型传入不同的日志对象
admin_logger = common.get_logger(log_type='admin')


# 修改额度接口
def change_balance_interface(username, money):
    user_dic = db_handler.select(username)

    if user_dic:
        # 修改额度
        user_dic['balance'] = int(money)

        # 保存修改后的用户数据
        db_handler.save(user_dic)
        msg = f'管理员修改用户: [{username}]额度修改成功!'
        admin_logger.info(msg)

        return True, msg

    return False, '修改额度用户不存在!'


# 冻结账户接口
def lock_user_interface(username):
    user_dic = db_handler.select(username)
    if user_dic:
        # 将locked的默认值改为True
        user_dic['locked'] = True
        db_handler.save(user_dic)
        msg = f'用户{username}冻结成功!'
        admin_logger.info(msg)
        return True, msg

    return False, '冻结用户不存在!'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值