ATM项目三层结构

0 分析需求

 作业需求:

模拟实现一个ATM + 购物商城程序

额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
支持多账户登录
支持账户间转账
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器

上述需求可以分为下面10个功能

# 登录
# 用户视图:1.接收输入用户名密码,转交逻辑接口
#		  5.输出可视化结果
# 逻辑接口:2.将用户名交给数据处理层,查找数据
# 		  4.得到用户视图及数据处理的用户名密码,进行比较,将结果返回用户视图层
# 数据处理:3.将用户名对应的数据提取出来,交给逻辑接口


# 注册
# 用户视图:1.接收输入用户名密码,转交逻辑接口
#		  6.输出可视化结果
# 逻辑接口:2.将用户名交给数据处理层,查找数据  
#		  4.得到用户名是否存在,若不存在将用户名密码交给数据处理存储,返回用户视图,若存在返回用户视图
# 数据处理:3.查找用户名对应的数据是否存在,结果交给逻辑接口 
#		  5.如果用户名不存在,收到用户名密码,存储数据



# 转账
# 用户视图:1.得到在线用户名,转账的用户名及金额,判断金额有效性
#		  8.输出可视化结果
# 逻辑接口:2.将转账用户名交给数据处理层,查找是否存在
#		  4.将在线用户名交给数据处理层,查看余额是否足够
#		  6.若转账用户名存在且当前用户金额足够,计算结果,操作数据处理保存数据,返回用户视图
# 数据处理:3.查找用户名对应的数据是否存在,若不存在直接将结果交给逻辑接口 
#		  5.查看在线用户余额是否足够,若不足够直接将结果交给逻辑接口 
# 		  7.若满足条件,存储数据


# 提现
# 用户视图:1.得到在线用户名,金额,判断金额有效性
#		  6.输出可视化结果
# 逻辑接口:2.将在线用户名交给数据处理层,查看余额是否足够
#		  4.若当前用户金额足够,计算结果,操作数据处理保存数据,返回用户视图
# 数据处理:3.查看在线用户余额是否足够,若不足够直接将结果交给逻辑接口 
# 		  5.若满足条件,存储数据

# 还款
# 用户视图:1.得到在线用户名,金额,判断金额有效性
#		  4.输出可视化结果
# 逻辑接口:2.计算结果,操作数据处理保存数据,返回用户视图
# 数据处理:3.存储数据

# 查看流水
# 用户视图:1.得到在线用户名
#		  4.输出可视化结果
# 逻辑接口:2.操作数据处理查找数据,得到结果,返回用户视图
# 数据处理:3.查找在线用户流水数据,返回逻辑接口

# 查看余额
# 用户视图:1.得到在线用户名
#		  4.输出可视化结果
# 逻辑接口:2.操作数据处理查找数据,得到结果,返回用户视图
# 数据处理:3.查找在线用户余额数据,返回逻辑接口

# 购物
# 用户视图:1.申请查看货物信息,		5.输出可视化的货物信息,
#		  6.接收在线用户,选择货物编号及数量,简单判断有效性,若有效传入逻辑接口
#		  7.输出可视化结果
# 逻辑接口:2.申请查看货物信息,		4.得到货物信息,返回视图层,
#		  7.调取在线用户信息,更改,传入数据处理	9.得到结果返回用户视图
# 数据处理:3.查找货物信息,返回逻辑接口	8.保存用户数据

# 查看购物车
# 用户视图:1.得到在线用户名		5.输出可视化结果 
#		  6.询问是否结账,简单判断有效性,若有效传入逻辑接口
#		  8.输出可视化结果
# 逻辑接口:2.操作数据处理查找数据,	4得到结果,返回用户视图
#		  5.计算总价,调取在线用户信息,查看金额是否足够,如果足够则扣费,传入数据处理,不足则返回视图层结果
#		  7.得到结果返回用户视图
# 数据处理:3.查找在线用户流水数据,返回逻辑接口	6.保存用户数据,返回结果

# 管理员功能
# 用户视图:1.得到在线用户名
#		  2.输出可视化结果
# 逻辑接口:1.操作数据处理查看是否为管理员,得到结果,返回用户视图
#		  2.若为管理员进入管理员功能
# 数据处理:查看在线用户是否为管理员,结果返回逻辑接口

1 用户视图层

主要为输入输出的显示及简单的逻辑判断

from interface import user_interface
from interface import shop_interface
from interface import bank_interface
from interface import admin_interface
from lib import common

online_user = None


# 登录
def login():
    while 1:
        print("登录功能执行中")
        user_name = input("请输入用户名:[温馨提示:输入q退出]")
        if user_name.lower() == "q":
            break
        password = input("请输入密码:")
        flag, msg = user_interface.login_interface(user_name, password)
        if flag is False:
            print(msg)
            continue
        if flag is True:
            print(msg)
            global online_user
            online_user = user_name
            break
        pass


# 注册
def register():
    while 1:
        print("===============注册功能执行中")
        user_name = input("请输入用户名:[温馨提示:输入q退出]")
        if user_name.lower() == "q":
            break
        flag, msg = user_interface.check_name(user_name)
        if flag is False:
            print(msg)
            continue
        password1 = input("请输入密码:")
        password2 = input("请确认密码:")
        if password1 == password2:
            msg = user_interface.new_user(user_name, password1)
            print(msg)
            break
        else:
            print("两次密码不一致")


# 查看余额
@common.identify
def check_balance():
    print("============查询余额功能执行中")
    balance, limit = bank_interface.check_balance_interface(online_user)
    print("您的余额为{}元,您的额度为{}元".format(balance, limit))
    pass


# 提现
@common.identify
def withdraw():
    while 1:
        print("================提现功能执行中")
        money = input("请输入要提现的金额:[温馨提示:输入q退出]")
        if money.lower() == "q":
            break
        if not money.isdigit():
            print("请输入数字")
            continue
        flag, msg = bank_interface.withdraw_interface(online_user, money)
        if flag is False:
            print(msg)
            continue
        else:
            print(msg)
            break


# 转账
@common.identify
def transfer():
    while 1:
        print("=============转账功能执行中")
        money = input("请输入要转账的金额:[温馨提示:输入q退出]")
        if money.lower() == "q":
            break
        if not money.isdigit():
            print("请输入数字")
            continue
        to_user = input("请输入转账的账号:")
        flag, msg = bank_interface.transfer_interface(online_user, to_user, money)
        if flag is False:
            print(msg)
            continue
        else:
            print(msg)
            break


# 还款
@common.identify
def pay_back():
    while 1:
        print("=============还款功能执行中")
        money = input("请输入要还款的金额:[温馨提示:输入q退出]")
        if money.lower() == "q":
            break
        if not money.isdigit():
            print("请输入数字")
            continue
        flag, msg = bank_interface.pay_back_interface(online_user, money)
        if flag is False:
            print(msg)
            continue
        else:
            print(msg)
            break


# 查看流水
@common.identify
def check_record():
    print("================查看流水功能执行中")
    records = bank_interface.check_record_interface(online_user)
    if len(records) == 0:
        print("当前用户无记录")
    for i in records:
        print(i)


# 购物
@common.identify
def shopping():
    while 1:
        print("================购物功能执行中")
        cargo_list = shop_interface.cargo_list_interface()
        # ["mac", 20000]
        for num, cargo in enumerate(cargo_list):
            print("商品编号:[{}]    商品名:[{}]    单价:[{}]".format(num, cargo[0], cargo[1]))
        choose = input("请输入选购的商品的编号:[温馨提示:输入q退出]")
        if choose.lower() == "q":
            break
        if not choose.isdigit():
            print("请输入正确的编号")
            continue
        choose = int(choose)
        if choose not in range(len(cargo_list)):
            print("请输入正确的编号")
            continue
        quantity = input("请输入选购的商品的数量:")
        if not quantity.isdigit():
            print("请输入正确的数量")
            continue
        cargo_info = [cargo_list[choose][0], cargo_list[choose][1], quantity]
        msg = shop_interface.add_cargo_cart(online_user, cargo_info)
        print(msg)


# 查看购物车
@common.identify
def check_shopping_cart():
    print("======================查看购物车功能执行中")
    shopping_cart = shop_interface.check_cart_interface(online_user)
    # {"臭豆腐": [10, 14], "鸡": [100, 2]}
    sum_price = 0
    for name, info in shopping_cart.items():
        price = info[0] * info[1]
        sum_price += price
        print("商品名:[{}]  数量:[{}]  单价:[{}]   总价:[{}]".format(name, info[0], info[1], price))
    print("=========共计:[{}]元=======".format(sum_price))
    close_choose = input("是否结账:[输入y结账]")
    if close_choose.lower() == "y":
        flag, msg = shop_interface.close_account(online_user, sum_price)
        print(msg)


# 管理员功能
@common.identify
def admin():
    print("=================管理员功能执行中")
    admin_interface.check_admin(online_user)


func_dic = {
    "1": ["注册", register],
    "2": ["登录", login],
    "3": ["转账", transfer],
    "4": ["提现", withdraw],
    "5": ["还款", pay_back],
    "6": ["查询余额", check_balance],
    "7": ["查看流水", check_record],
    "8": ["购物", shopping],
    "9": ["查看购物车", check_shopping_cart],
    "10": ["管理员", admin]
}


def run():
    while 1:
        print("========wu超市========")
        for num, func in func_dic.items():
            print(num, func[0])
        print("======== end ========")
        choose = input("请输入功能编号:[温馨提示:输入q退出]")
        if choose.lower() == "q":
            break
        if choose in func_dic:
            func_dic[choose][1]()
        else:
            print("请输入正确的功能编号!")

2 逻辑接口层

主要为有效的输入数据与存储数据的对比,判断结果

2.1 管理员接口

import logging.config
from db import db_handler
from conf import settings

logging.config.dictConfig(settings.LOGGING_DIC)
logger = logging.getLogger('admin')


# 添加账户、用户额度,冻结账户
def check_admin(online_user):
    user_dic = db_handler.select(online_user)
    if user_dic["admin"] is False:
        print("非管理员,无法使用该功能")
        return
    else:
        run_admin(online_user)


def add_user(online_user):
    from core import src
    src.register()


def change_limit(online_user):
    while 1:
        change_user = input("请输入更改额度的用户名:[温馨提示:输入q退出]")
        if change_user.lower() == "q":
            break
        user_dic = db_handler.select(change_user)
        if not user_dic:
            print("输入的用户名不存在")
            continue
        limit = input("请输入额度:")
        if not limit.isdigit():
            print("只能输入数字")
            continue
        user_dic["limit"] = int(limit)
        db_handler.save_data(user_dic)
        print("更改成功")
        logger.info('{}更改{}额度'.format(online_user, change_user))


def freeze_user(online_user):
    while 1:
        freeze_user = input("请输入冻结的用户名:[温馨提示:输入q退出]")
        if freeze_user.lower() == "q":
            break
        user_dic = db_handler.select(freeze_user)
        if not user_dic:
            print("输入的用户名不存在")
            continue
        user_dic["locked"] = True
        db_handler.save_data(user_dic)
        print("冻结用户{}成功".format(freeze_user))
        logger.info('{}冻结{}'.format(online_user, freeze_user))


admin_func = {"0": ["添加账户", add_user],
              "1": ["更改额度", change_limit],
              "2": ["冻结用户", freeze_user]
              }


def run_admin(online_user):
    while 1:
        for num, func in admin_func.items():
            print("[{}]-----[{}]".format(num, func[0]))
        cmd = input("请输入功能编号:[温馨提示:输入q退出]")
        if cmd.lower() == "q":
            break
        if cmd not in admin_func:
            print("无此功能")
            continue
        admin_func[cmd][1](online_user)

2.2 用户接口

import logging.config
from db import db_handler
from conf import settings

logging.config.dictConfig(settings.LOGGING_DIC)
logger = logging.getLogger('user')
# 检查用户名是否存在
def check_name(user):
    if db_handler.select(user):
        return False,"用户名已存在,请重新输入"
    else:
        return True,""

# 创建新用户
def new_user(user_name,password,limit = 15000):
    password = db_handler.encrypt(password)
    user_dic = {"user":user_name,"password":password,"balance":0,"limit":limit,"locked":False,"current_account":[],"shopping_cart":{},"admin":False}
    db_handler.save_data(user_dic)
    logger.info('{}注册'.format(user_name))
    return "注册成功"

# 登录接口
def login_interface(user,password):
    user_dic = db_handler.select(user)
    if not user_dic:
        return False,"用户名不存在,请重新输入"
    if user_dic["locked"]:
        return False,"该用户已被锁定"
    password = db_handler.encrypt(password)
    if user_dic["password"] == password:
        logger.info('{}登录'.format(user))
        return True,"登陆成功"
    else:
        return False,"密码错误,请重新输入"

2.3 银行接口

import logging.config
from db import db_handler
from conf import settings

logging.config.dictConfig(settings.LOGGING_DIC)
logger = logging.getLogger('bank')

def check_balance_interface(online_user):
    user_dic = db_handler.select(online_user)
    balance = user_dic["balance"]
    limit = user_dic["limit"]
    logger.info('{}查询余额'.format(online_user))
    return balance, limit


def withdraw_interface(online_user, money):
    user_dic = db_handler.select(online_user)
    balance = user_dic["balance"]
    money = float(money)
    balance = float(balance)
    cost = money * 1.05
    if cost > balance:
        return False, "余额不足,无法提现"
    new_balance = balance - cost
    user_dic["balance"] = new_balance
    fee = cost - money
    user_dic["current_account"].append("提现[{}]元,手续费[{}]".format(money, fee))
    db_handler.save_data(user_dic)
    logger.info('{}提现{}手续费{}'.format(online_user,money, fee))
    return True, "[{}]提现[{}]成功,手续费为[{}]".format(online_user, money, fee)


def transfer_interface(online_user, to_user, money):
    to_user_dic = db_handler.select(to_user)
    if not to_user_dic:
        return False, "转账用户不存在,请重新输入"
    online_user_dic = db_handler.select(online_user)
    online_user_balance = online_user_dic["balance"]
    money = float(money)
    balance = float(online_user_balance)
    if money > balance:
        return False, "余额不足,无法转账"
    online_user_dic["balance"] -= money
    to_user_dic["balance"] += money
    online_user_dic["current_account"].append("转账[{}]元给[{}]".format(money, to_user))
    to_user_dic["current_account"].append("收到[{}]转账[{}]元".format(online_user, money))
    db_handler.save_data(online_user_dic)
    db_handler.save_data(to_user_dic)
    logger.info('{}转账给{}-{}'.format(online_user,to_user,money))
    return True, "[{}]转账[{}]元成功".format(online_user, money)


def pay_back_interface(online_user, money):
    user_dic = db_handler.select(online_user)
    balance = user_dic["balance"]
    money = float(money)
    balance = float(balance)
    balance += money
    user_dic["balance"] = balance
    user_dic["current_account"].append("还款[{}]".format(money))
    db_handler.save_data(user_dic)
    logger.info('{}还款{}'.format(online_user,money))
    return True, "[{}]还款[{}]".format(online_user, money)


def check_record_interface(online_user):
    user_dic = db_handler.select(online_user)
    records = user_dic["current_account"]
    return records


def charge(online_user, sum_price):
    user_dic = db_handler.select(online_user)
    balance = user_dic["balance"]
    limit = user_dic["limit"]
    if balance + limit < sum_price:
        return False
    user_dic["balance"] -= sum_price
    user_dic["current_account"].append("购买消费[{}]".format(sum_price))
    db_handler.save_data(user_dic)
    logger.info("[{}]消费[{}]".format(online_user, sum_price))
    return True

2.4 商店接口

from db import db_handler
from interface import bank_interface


def cargo_list_interface():
    cargo_list = db_handler.get_cargo_list()
    return cargo_list


def add_cargo_cart(online_user, cargo_info):
    '''

    :param online_user: 用户
    :param cargo_info: [商品名,价格,数量]
    :return:
    '''
    cargo_info[1] = int(cargo_info[1])
    cargo_info[2] = int(cargo_info[2])
    user_dic = db_handler.select(online_user)
    if cargo_info[0] not in user_dic["shopping_cart"]:
        user_dic["shopping_cart"][cargo_info[0]] = [cargo_info[1], cargo_info[2]]
    else:
        user_dic["shopping_cart"][cargo_info[0]][1] += cargo_info[2]
    db_handler.save_data(user_dic)
    return "商品[{}]  [{}]个已成功加入购物车".format(cargo_info[0], cargo_info[2])


def check_cart_interface(online_user):
    user_dic = db_handler.select(online_user)
    shopping_cart = user_dic["shopping_cart"]
    return shopping_cart


def close_account(online_user, sum_price):
    res = bank_interface.charge(online_user, sum_price)
    if res is False:
        return False, "余额以及额度不足,无法结账"
    else:
        user_dic = db_handler.select(online_user)
        user_dic["shopping_cart"] = {}
        db_handler.save_data(user_dic)
        return True, "结账成功,扣除{}元".format(sum_price)

3 数据处理层

主要为存储数据的提取,存储等

import os
import json
import hashlib
from conf import settings


def select(user):
    user_file = os.path.join(settings.DB_USER_DATA_PATH, "{}.json".format(user))
    if os.path.exists(user_file):
        with open(user_file, "rb") as f:
            user_dic = json.load(f)
        return user_dic


def save_data(user_dic):
    user = user_dic["user"]
    user_file = os.path.join(settings.DB_USER_DATA_PATH, r"{}.json".format(user))
    with open(user_file, "w",encoding="utf-8") as f:
        json.dump(user_dic, f, ensure_ascii=False)
        return True


def encrypt(password):
    md5 = hashlib.md5()
    md5.update(password.encode("utf-8"))
    salt = "tank真帅"
    md5.update(salt.encode("utf-8"))
    res = md5.hexdigest()
    return res


def get_cargo_list():
    with open(settings.DB_CARGO_LIST_PATH,"rb") as f:
        res = json.load(f)
        return res
# def add_cargo():
#     cargo = [["苹果",2],["mac",20000],["鸡",100],["臭豆腐",10]]
#     with open(settings.DB_CARGO_LIST_PATH,"w",encoding="utf-8") as f:
#         json.dump(cargo,f)
# add_cargo()

4 其他文件

4.1 配置文件

import os


BASE_PATH = os.path.dirname(os.path.dirname(__file__))
DB_PATH = os.path.join(BASE_PATH,"db")
DB_USER_DATA_PATH = os.path.join(DB_PATH,"user_data")
DB_CARGO_DATA_PATH = os.path.join(DB_PATH,"cargo_data")
DB_CARGO_LIST_PATH = os.path.join(DB_CARGO_DATA_PATH,"cargo_list.json")
LOG_PATH = os.path.join(BASE_PATH,"log")
LOG_LOG_PATH = os.path.join(LOG_PATH,"log.log")


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'

test_format = '%(asctime)s] %(message)s'

LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
        'test': {
            'format': test_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件的日志,收集info及以上的日志
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
            'formatter': 'standard',
            # 可以定制日志文件路径
            # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
            # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
            'filename': LOG_LOG_PATH,  # 日志文件
            'maxBytes': 1024*1024*50,  # 日志大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
        'other': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件
            'formatter': 'test',
            'filename': LOG_LOG_PATH,
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
        },
        '专门的采集': {
            'handlers': ['other',],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}

4.2 通用文件

# 用户认证用装饰器

def identify(func):
    def wrapper(*args,**kwargs):
        from core.src import online_user
        if online_user:
            res = func(*args,**kwargs)
            return res
        else:
            print("请先登录")
            from core import src
            src.login()
    return wrapper

4.3 启动文件

from core import src


if __name__ == '__main__':
    src.run()
 posted on 2020-04-02 21:22  wwwpy  阅读(225)  评论(0编辑  收藏  举报