ATM+购物车

ATM+购物车

1 需求

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

2 功能

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

3 目录结构

ATM
-bin
  -start.py
-conf
  -settings.py
-db
  -user_data
    -ccc.py
    ...
  -db_handler.py
-interface
  -bank.py
  -user.py
  -shopping.py
-lib
  -common.py
-log
  -atm.log
-view
  -src.py

4 思路及步骤

4.1 环境bin/start.py

程序的入口

4.1.1 将解释器添加到环境变量中

import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

4.1.2 启动主程序

from view import src
if __name__ == '__main__':
    src.run()
# 此时应该在view/src.py中定义主启动函数run()

4.2 配置conf/settings.py

存放配置信息

4.2.1 获取项目根目录路径

import os
BASE_PATH = os.path.dirname(os.path.dirname(__file__))

4.2.2 获取user_data目录路径

import os
USER_DATA_PATH = os.path.join(BASE_PATH, 'db', 'user_data')

4.2.3 获取log目录路径

import os
USER_LOG = os.path.join(BASE_PATH, 'log')

4.3 数据处理db/db_handle.py

数据处理层专门用来处理数据

4.3.1 保存用户信息save

import os
import json
from conf import settings

def save(username, user_dic):
    user_path = os.path.join(settings.USER_DATA_PATH, f'{username}.json')
    with open(user_path, 'wt', encoding='utf-8') as f:
        json.dump(user_dic, f, ensure_ascii=False)
        f.flush()  # 强制刷入硬盘

4.3.2 返回用户信息select

import os
import json
from conf import settings

def select(username):
    user_path = os.path.join(settings.USER_DATA_PATH, f'{username}.json')
    if os.path.exists(user_path):
        with open(user_path, 'rt', encoding='utf-8') as f:
        	user_dic = json.load(f)
        return user_dic

4.4 视图层view/src

用户视图层

4.4.1 主启动函数run()

func_dic = {
    "1": register,
    "2": login,
    "3": check_balance,
    "4": withdrawal,
    "5": repay,
    "6": transfer,
    "7": check_flow,
    "8": shop,
    "9": check_shopping_cart,
    "10": admin,
    "11": logout,
}

def run():
    while True:
        print(
        =======================
             1.注册
			2.登录
			3.查看余额
			4.提现
			5.还款
			6.转账
			7.查看流水
			8.购物
			9.查看购物车
			10.管理员
			11.注销
        =======================
        )
        choice = input("请输入功能编号(按q退出程序):").strip()
        if choice == "q":break
        if choice not in func_dic:
            print("请输入正确的编号!")
            continue
        func_dic.get(choice)()  # 输入1相当于func_dic.get('1')()-->register()

4.4.2 功能实现

4.4.2.1 注册功能register()

from interface import user

user_login = {
    'is_login': False,
    'username': None
}

def register():
    while True:
        if not user_login['is_login']:
            username = input("请输入注册用户名(按q退出):").strip()
            if username == "q":break
            password = input("请输入密码:").strip()
            re_password = input("请再次输入密码:").strip()
            if password == re_password:
                msg = user.register_interface(username, password)
                print(msg)
                break
            else:
                print("两次密码不一致")
	else:
            print("登陆状态不可再注册")
            break

4.4.2.2 登录功能login()

from interface import user

user_login = {
    'is_login': False,
    'username': None
}

def login():
    count = 0
    while True:
        if not user_login['is_login']:
            username = input("请输入登录名(按q退出):").strip()
            if username == "q":break
            user_info = user.get_user_info_interface(username)
            if user_info:
                if not user_info['locked']:
                    if count < 3:
                        password = input("请输入登录密码:").strip()
                        if password == user_info['password']:
                            user_login['is_login'] = True
                            user_login['username'] = username
                            print("登陆成功")
                            break
                        else:
                            count += 1
                            print("密码输入错误")
                    else:
                        user.locked_interface(username)
                        print("该用户密码错误输入次数过多,已被锁定")
                        break
                else:
                    msg = user.unlocked_interface(username)
                    print(msg)
            else:
                print("该用户不存在")
        else:
            print("登录状态下不可再次登录")
            break
            
            
1、判断用户登录状态,非登录状态继续执行代码,否则告诉用户登录情况下不能再次登录
2、用户输入登录名,判断输入是否为q,非q继续执行代码,否则退出
3、判断用户名是否存在,存在继续执行代码,不存在则告诉用户该用户名不存在
4、判断该用户是否被锁,没有则继续执行,被锁则调用解锁接口 等待解锁
5、判断密码输入次数,小于三次则继续执行,否则调用锁定接口 锁定账号
6、用户输入密码,判断密码是否正确,正确则登录,错误则输入次数加1

4.4.2.3 查看余额功能check_balance()

# 首先使用登录认证装饰器判断登陆状态
from lib import common
from interface import bank

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def check_balance():
    msg = bank.check_balance_interface(user_login['username'])
    print("%s的余额是%s元" % (user_login['username'], msg))

4.4.2.4 提现功能withdrawal()

from lib import common
from interface import bank

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def withdrawal():
    while True:
        print("""
=============================
        0) 退出
        1) 查看余额
        2) 提现
=============================
        """)
        choice = input("请输入指令:").strip()
        if choice == "0":break
        elif choice == "1":
            msg = bank.check_balance_interface(user_login['username'])
            print(msg)
        elif choice == "2":
            money = input("请输入提现金额:").strip()
            if money.isdigit:
                money = int(money)
                msg = bank.withdrawal_interface(user_login['username'], money)
                print(msg)
                break
            else:
                print("请输入正确的金额")
        else:
            print("请输入正确的提现指令")
            
1、装饰器判断登录状态,未登录则执行登陆程序,登陆则继续
2、用户选择功能,0->退出 1->查看余额 2->提现(循环功能)
3、0直接退出 1调用余额接口
4、2让用户输入提现金额,判断是否为数字,不为数字提示重新输入,为数字继续
5、调用提现接口,打印返回值

4.4.2.5 还款功能repay()

from lib import common
from interface import bank

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def repay():
    while True:
        choice = input("""
=============================
        0) 退出
        1) 查询欠款金额
        2) 还款
=============================
        请输入选项:""").strip()
        if choice == "0":break
        elif choice == "1":
            msg = bank.check_debt_interface(user_login['username'])
            print(msg)
        elif choice == "2":
            money = input("请输入还款金额:").strip()
            if money.isdigit():
                money = int(money)
                msg = bank.repay_interface(user_login['username'], money)
                print(msg)
                break
            else:
                print("请输入正确的金额")
        else:
            print("请输入正确的选项")
            
1、调用登录认证装饰器
2、用户选择还款功能 0退出 1查询欠款金额 2还款
3、1调用查询欠款接口查询
4、2用户输入还款金额,判断是否为数字
5、调用还款接口

4.4.2.6 转账功能transfer()

from lib import common
from interface import bank

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def transfer():
    while True:
        print("""
=============================
        0) 退出
        1) 查看余额
        2) 转账
=============================
        """)
        choice = input("请输入功能选项:").strip()
        if choice == "0":break
        elif choice == "1":
            msg = bank.check_balance_interface(user_login['username'])
            print(msg)
        elif choice == "2":
            to_username = input("请输入被转帐用户名:").strip()
            if to_username == user_login['username']:
                print("不能转账给自己")
                continue
            if user.get_user_info_interface(to_username):
                money = input("请输入转账金额:").strip()
                if money.isdigit():
                    money = int(money)
                    msg = bank.transfer_interface(user_login['username'], to_username, money)
                    print(msg)
                    break
                else:
                    print("请输入正确的金额数")
            else:
                print("被转账用户不存在")
        else:
            print("请输入正确的选项")
            
1、调用登录认证装饰器
2、用户选择功能 0退出 1调用查看余额接口查看余额 2转账
3、2输入被转账用户名,判断是否为自己
4、调用提取信息接口判断用户是否存在,存在则继续,否则提示用户不存在
5、用户输入金额,判断是否为数字,是继续,否则提示输入正确的金额
6、调用转账接口

4.4.2.7 查看流水功能check_flow()

from lib import common
from interface import bank

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def check_flow():
    flow_list = bank.check_flow_interface(user_login['username'])
    for line in flow_list:
        print(line)

4.4.2.8 购物功能shop()

from lib import common
from interface import shopping

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def shop():
    good_list = [
        ['tesla', 10000],
        ['mac', 8000],
        ['thinkpad', 6000],
        ['火锅', 580],
        ['烧烤', 320],
        ['串串', 280],
        ['包子', 8],
        ['矿泉水',5]
    ]
    good_cart = {}
    balance = bank.check_balance_interface(user_login['username'])
    amount_spend = 0
    while True:
        for i,line in enumerate(good_list):
            print("%s 商品名:%s 单价:%s" % (i, line[0], line[1]))
        choice = input("请输入商品序号(按q退出并购买):").strip()
        if choice.isdigit():
            choice = int(choice)
            if 0 <= choice <= len(good_list)-1:
                good_name = good_list[choice][0]
                good_price = good_list[choice][1]
                if balance >= good_price:
                    if good_name in good_cart:
                        good_cart[good_name]['count'] += 1
                    else:
                        good_cart[good_name] = {'price': good_price, 'count': 1}
                    amount_spend += good_price
                    balance -= good_price
                    print("%s已被加入购物车" % good_name)
                    print("目前购物车有:%s" % good_list)
                    print("余额:%s元" % balance)
                else:
                    print("余额不足,剩余%s" % balance)
            else:
                print("该商品尚未上架")
        elif choice == "q":
            while True:
                choice = input("请输入 y)结算 或 n)退出:").strip()
                if choice == "y":
                    if amount_spend > 0:
                        password = input("请输入密码:").strip()
                        file_password = user.get_user_info_interface(user_login['username'])['password']
                        if password == file_password:
                            msg = shopping.buy_goods_interface(user_login['username'], good_cart, amount_spend)
                            print(msg)
                            break
                        else:
                            print("密码错误")
                    else:
                        print("没买东西结什么账啊")
                        break
                elif choice == "n":
                    print("白加这么多东西在购物车")
                    break
                else:
                    print("请输入正确的选项")
            break
        else:
            print("请输入数字")

4.4.2.9 查看购物车功能check_shopping_cart()

from lib import common
from interface import shopping

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def check_shopping_cart():
    msg = shopping.check_shopping_cart_interface(user_login['username'])
    print(msg)

4.4.2.10 管理员功能admin()

def admin():
    pass

4.4.2.11 注销功能logout()

from lib import common

user_login = {
    'is_login': False,
    'username': None
}

@common.check_login
def logout():
    if user_login['is_login']:
        user_login['is_login'] = False
        print("注销成功")
    else:
        print("请先登录")

4.5 公共lib/common

存放公共登陆方法,登录认证装饰器及日志模块

4.5.1 登陆认证装饰器

from view import src

# 登录认证装饰器
def check_login(func):
    def inner(*args, **kwargs):
        if src.user_login['is_login']:
            res = func(*args, **kwargs)
            return res
        else:
            print("暂未登录,请先登录后在使用本功能")
            src.login()
    return inner

4.5.2 日志

import os
import logging.config
from conf import settings

# 日志模块
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'

# 定义日志输出格式 结束

logfile_dir = settings.USER_LOG  # log文件的目录

logfile_name = 'atm.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': '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)传递
        },
    },
}


def make_log(name):
    logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
    logger = logging.getLogger(name)  # 生成一个log实例

    return logger

4.6 接口interface

4.6.1 银行相关bank.py

4.6.1.1 查看余额接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 查看余额接口
def check_balance_interface(username):
    user_info = db_handler.select(username)
    res = user_info['balance']
    # 记录日志
    logger_bank.info("%s查看了余额" % username)
    return res

4.6.1.2 提现接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 提现接口
def  withdrawal_interface(username, money):
    user_info = db_handler.select(username)
    if user_info['balance'] >= money*1.05:
        user_info['balance'] -= money*1.05
        # 查看流水
        user_info['flow'].append("%s成功提现%s元,扣除手续费%s元" % (username, money, money*0.05))
        db_handler.save(username, user_info)
        # 记录日志
        logger_bank.info("%s成功提现%s元,扣除手续费%s元" % (username, money, money*0.05))
        return "%s成功提现%s元,扣除手续费%s元" % (username, money, money*0.05)
    else:
        return "%s账户余额不足" % username

4.6.1.3 查询欠款接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 查询欠款接口
def check_debt_interface(username):
    user_info = db_handler.select(username)
    res = user_info['credit'] - user_info['balance']
    if res > 0:
        # 记录日志
        logger_bank.info("%s查看了欠款" % username)
    	return "%s当前欠款%s元" % (username, res)
    else:
        return "%s当前并未欠款" % username

4.6.1.4 还款接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 还款接口
def repay_interface(username, money):
    user_info = db_handler.select(username)
    res = user_info['credit'] - user_info['balance']
    if res >= money:
        user_info['balance'] += money
        # 记录流水
        user_info['flow'].append("%s成功还款%s元" % (username, money))
        db_handler.save(username, user_info)
        # 记录日志
        logger_bank.info("%s成功还款%s元" % (username, money))
        return "%s成功还款%s元" % (username, money)
    else:
        return "还款金额超过欠款额度"

4.6.1.5 转账接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 转账功能接口
def transfer_interface(username, to_username, money):
    user_info = db_handler.select(username)
    to_user_info = db_handler.select(to_username)
    if user_info['balance'] >= money:
        user_info['balance'] -= money
        to_user_info['balance'] += money
        # 记录流水
        user_info['flow'].append("您向%s转账%s元" % (to_username, money))
        to_user_info['flow'].append("%s向您转账%s元" % (username, money))
        
        db_handler.save(username, user_info)
        db_handler.save(to_username, to_user_info)
        
        # 记录日志
        logger_bank.info("%s向%s转账%s元" % (username, to_username, money))
        return "%s向%s转账%s元" % (username, to_username, money)
    else:
        return "%s账户余额不足" % username

4.6.1.6 查看流水接口

from db import db_handler
from lib import common
logger_bank = common.make_log('bank')

# 查看流水接口
def check_flow_interface(username):
    user_info = db_handler.select(username)
    # 查看流水
    logger_bank.info("%s查看了流水" % username)
    return user_info['flow']

4.6.1.7 消费接口

from db import db_handle
from lib import common
logger_bank = common.make_log('bank')

def consume_interface(username, money):
    user_info = db_handler.select(username)
    user_info['balance'] -= money
    # 记录流水
    user_info['flow'].append("%s消费了%s元" % (username, money))
    db_handler.save(username, user_info)
	# 记录日志
    logger_bank.info("%s消费了%s元" % (username, money))

4.6.2 购物相关shopping.py

4.6.2.1 购买商品接口

from db import db_handler
from interface import bank
from lib import common
logger_shopping = common.make_log('shopping')

def buy_goods_interface(username, good_cart, money):
    user_info = db_handler.select(username)
    bank.consume_interface(username, money)
    user_info['shopping_cart'] = good_cart
    db_handler.save(username, user_info)
    # 记录日志
    logger_shopping.info("%s成功购买%s" % (username, good_cart))
    return "%s成功购买%s" % (username, good_cart)

4.6.2.2 查看购物车接口

from db import db_handler
from lib import common
logger_shopping = common.make_log('shopping')

def check_shopping_cart_interface(username):
    user_info = db_handler.select(username)
    res = user_info['shopping_cart']
    # 记录日志
    logger_shopping.info("%s查看了购物车" % username)
    return res

4.6.3 用户相关user.py

4.6.3.1 注册接口

from db import db_handler
from lib import common
logger_user = common.make_log('user')

# 注册接口
def register_interface(username, password, balance=15000):
    user = db_handler.select(username)  # 取到user_info = user_dic
    if user:  # 判断该用户名是否存在
        return "该用户名已存在"
    else:
        user_dic = {
            'username': username,
            'password': password,
            'credit': balance,
            'balance': balance,
            'locked': False,
            'time': 0,
            'flow': [],
            'shopping_cart': {}
        }
        db_handler.save(username, user_dic)
        # 记录日志
        logger_user.info("%s注册成功" % username)
        return "%s注册成功" % username

4.6.3.2 提取用户信息接口

from db import db_handler

# 提取用户信息
def get_user_info_interface(username):
    user_info = db_handler.select(username)
    return user_info

4.6.3.3 锁定用户接口

import time
from db import db_handler
from lib import common
logger_user = common.make_log('user')

# 锁定用户
def locked_interface(username):
    user_info = db_handler.select(username)
    user_info['locked'] = True
    user_info['time'] = time.time()+20
    db_handler.save(username, user_info)
    # 记录日志
    logger_user.info("%s被锁定了" % username)

4.6.3.4 解锁用户接口

import time
from db import db_handler
from lib import common
logger_user = common.make_log('user')

# 解锁用户接口
def unlocked_interface(username):
    user_info = db_handler.select(username)
    last_time = user_info['time'] - time.time()
    if user_info['time'] <= time.time():
        user_info['locked'] = False
        db_handler.save(username, user_info)
    	# 记录日志
    	logger_user.info("%s用户已解锁" % username)
        return "%s用户已经解锁,请重新登陆" % username
    else:
        return "%s用户已被锁,剩余锁定时间%s" % (username, last_time)
posted @ 2020-12-18 02:15  drrug  阅读(117)  评论(0编辑  收藏  举报