ATM小程序

一、开发前准备

创建ATM文件夹,并在其下创建readme.md文件,作为说明

# 项目说明书
##项目:ATM+购物车

# 项目需求
    模拟实现一个ATM + 购物商城程序
    1. 额度 15000或自定义         注册功能
    2. 实现购物商城,买东西加入 购物车,调用信用卡接口结账   购物功能,支付功能
    3. 可以提现,手续费5%   提现功能
    4. 支持多账户登录      登录功能
    5. 支持账户间转账      转账功能
    6. 记录日常消费        记录流水功能
    7. 提供还款接口        还款功能
    8. 用户认证用装饰器    登录认证装饰器

# 一个项目如何从无到有
## 一 需求分析
    1. 拿到项目,会先在客户那里一起讨论需求
        商量项目的功能是否能实现,周期与价格,得到一个需求文档
    2. 最后在公司内部开会,得到一个开发文档
        交给不同岗位的程序员进行开发
        - 不同的岗位
            - UI界面设计:
                - 设计软件的布局,会根据软件的外观切成一张张图片
            - 前端
                - 拿到UI交给他的图片,然后去搭建网页
                - 设计一些页面中,哪些位置需要接受数据,需要进行数据交互
            - 后端
                - 直接核心的业务逻辑,调度数据库进行数据的增删查改
            - 测试
                - 会给代码进行全面测试,比如压力测试,界面测试
            - 运维
                - 部署项目

## 二 程序的架构设计
    1. 程序设计的好处
        1. 思路清晰
        2. 不会出现写一半代码时推翻重写
        3. 方便自己或以后的同事更好维护
    2. 三层架构设计的好处
        1. 把每个功能都分为三部分,逻辑清晰
        2. 如果用户更换不同的用户界面或不同的数据存储机制
            都不会影响接口层的核心逻辑代码,扩展性强
        3. 可以在接口层,准确的记录日志和流水
    3. 三层架构
        1. 用户视图层
            用于与用户交互的,可以接受用户的输入,打印接口返回的数据
        2. 逻辑接口层
            接收用户视图层传递过来的参数,根据逻辑判断调用数据层加以处理
            并返回一个结果给用户视图层
        3. 数据处理层
            接受接口层传递过来的参数,做数据的增删查改

## 三 分任务开发
## 四 测试
## 五 上线

用户视图层展示给用户选择的功能
1. 注册功能
2. 登录功能
3. 查看余额
4. 提现功能
5. 还款功能
6. 转账功能
7. 查看流水
8. 购物功能
9. 查看购物车

分层结构示意图
在这里插入图片描述

二、软件目录架构搭建

创建如下目录结构

ATM
	- conf		
		- settings.py   # 存放配置信息
	- core
		- src.py        # 用户视图层
	- db
		- db_handle.py  # 数据处理层
	- interface
		- user_interface # 逻辑接口层,专门处理用户相关逻辑接口
		- bank_interface # 逻辑接口层,专门处理银行相关逻辑接口
		- shop_interface # 逻辑接口层,专门处理购物相关逻辑接口
	- lib
		- common.py      # 存放公共方法
	start.py   			 # 程序入口,项目启动文件

三、代码开发

start.py

'''
程序的入口
'''
import os
import sys

# 添加环境变量
sys.path.append(os.path.dirname(__file__))

from core import src
# 开始执行项目函数
if __name__ == '__main__':
    # 1. 先执行用户视图层
    src.run()

core/src.py

'''
用户视图层
'''

# 1.注册功能
def register():
    pass

# 2.登录功能
def login():
    pass

# 3.查看余额
def check_balance():
    pass

# 4.提现功能
def withdraw():
    pass

# 5.还款功能
def repay():
    pass

# 6.转账功能
def transfer():
    pass

# 7.查看流水
def check_flow():
    pass

# 8.购物功能
def shopping():
    pass

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

# 10.清空购物车
def clean_shop_car():
    pass
        
# 创建函数功能字典
func_dict = {
    '1':register,
    '2':login,
    '3':check_balance,
    '4':withdraw,
    '5':repay,
    '6':transfer,
    '7':check_flow,
    '8':shopping,
    '9':check_shop_car,
    '10':clean_shop_car
}

# 视图层主程序
def run():
    while True:
        print('''
        ========ATM+购物车===========
        1. 注册功能
        2. 登录功能
        3. 查看余额
        4. 提现功能
        5. 还款功能
        6. 转账功能
        7. 查看流水
        8. 购物功能
        9. 查看购物车
        ========ATM+购物车===========
        ''')
        choice = input('请输入功能编号:').strip()
        if choice not in func_dict:
            print('请输入正确的功能编号')
            continue
        func_dict.get(choice)() # func_dict.get('1')() ---> register()

3.1 注册功能

为了方便保存用户信息,在db目录下创建user_data目录,用来保存以用户名.json的文件,该文件用来保存注册用户的相关信息,为了方便查找,在配置文件conf/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'
)

3.1.1 注册功能简单版

'''
用户视图层
'''

# 1.注册功能
def register():
    while True:
        # 1. 让用户输入用户名和密码进行校验
        username = input('请输入用户名').strip()
        password = input('请输入密码').strip()
        re_password = input('请确认密码').strip()
        # 小的逻辑处理:比如两次密码是否一致
        if password == re_password:
            # 2. 查看用户是否存在
            import json
            import os
            from conf import settings
            # 4.2 拼接用户的json文件路径
            user_path = os.path.join(
                settings.USER_DATA_PATH, f'{username}.json'
            )
            # 3. 若用户存在,则让用户重新输入
            if os.path.exists(user_path):
                print('用户已存在,请重新输入')
                continue
            # 4. 若用户不存在,则保存用户数据
            # 4.1 组织用户的数据的字典信息
            user_dic = {
                'username':username,
                'password':password,
                'balance':15000,
                # 用于记录用户流水的列表
                'flow':[],
                # 用于记录用户购物车
                'shop_car':{},
                # locked:用于记录用户是否被冻结
                # False:未冻结  True:已被冻结
                'locked':False
            }
            with open(user_path,'w',encoding='utf-8') as f:
                json.dump(user_dic,f,ensure_ascii=False)
            print('用户注册成功')
            break
        print('密码和确认密码不一致,请重新输入')

3.1.2 将功能分层

core/src.py

from interface import user_interface

def register():
    while True:
        # 1. 让用户输入用户名和密码进行校验
        username = input('请输入用户名').strip()
        password = input('请输入密码').strip()
        re_password = input('请确认密码').strip()
        # 小的逻辑处理:比如两次密码是否一致
        if password == re_password:
            flag,msg = user_interface.register_interface(username,password)
            if flag:
                print(msg)
                break
            print(msg)
            continue
        print('两次密码不一致')

interface/user_interface.py

'''
逻辑接口层
    用户相关接口
'''
from db import db_handle
from lib import common

# 注册接口
def register_interface(username,password,balance=15000):
    # 1. 查看用户是否已经存在
    data = db_handle.select(username)
    # 2. 若用户存在,则让用户重新输入
    if data:
        return False,'用户已存在'
    # 3. 若用户不存在,则保存用户数据
    # 3.1 组织用户的数据的字典信息
    # 对密码加密
    password = common.get_pwd_md5(password)
    user_dic = {
        'username': username,
        'password': password,
        'balance': balance,
        # 用于记录用户流水的列表
        'flow': [],
        # 用于记录用户购物车
        'shop_car': {},
        # locked:用于记录用户是否被冻结
        # False:未冻结  True:已被冻结
        'locked': False
    }
    # 保存用户数据
    db_handle.save(user_dic)
    return True,f'{username}注册成功'

lib/common

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

# md5加密
def get_pwd_md5(password):
    md5_obj = hashlib.md5()
    md5_obj.update(password.encode('utf-8'))
    salt = settings.SALT
    md5_obj.update(salt.encode('utf-8'))
    return md5_obj.hexdigest()

conf/settings.py

# 盐值
SALT = '我是木易'

db/db_handle.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
    # 不return,默认返回None

# 保存数据
def save(user_dic):
    # 1. 拼接用户的数据字典
    username = user_dic.get('username')
    user_path = os.path.join(
        settings.USER_DATA_PATH, f'{username}.json'
    )
    # 2. 保存用户数据
    with open(user_path, 'w', encoding='utf-8') as f:
        json.dump(user_dic, f, ensure_ascii=False)

3.2 登录功能

core/src.py

# 定义全局变量 记录登录用户名
login_user = None

# 2.登录功能
def login():
    while True:
        # 1. 接收用户输入的用户名和密码
        username = input('请输入用户名').strip()
        password = input('请输入密码').strip()
        # 2. 调用接口层进行处理
        flag,msg = user_interface.login_interface(username,password)
        # 用户登录成功,提示信息,退出循环
        if flag:
            print(msg)
            global login_user
            login_user = username
            break
        # 登录失败,提示信息
        print(msg)

interface/user_interface

# 登录接口
def login_interface(username,password):
    # 1. 先查看用户是否存在
    data = db_handle.select(username)
    if data:
    # 2. 用户存在则判断密码是否正确
    	# 先对密码加密
        password = common.get_pwd_md5(password)
        if password == data.get('password'):
            return True,f'{username}登录成功'
        return False,'密码错误'
    # 3. 用户不存在则返回错误
    return False,f'{username}用户不存在'

3.3 登录认证装饰器

lib/common

from core import src

# 登录认证装饰器
def login_auth(func):
    def inner(*args,**kwargs):
        if src.login_user:
            res = func(*args,**kwargs)
            return res
        print('您还未登录,请先登录!')
        src.login()
    return inner

3.4 查看余额功能

core/src.py

from lib import common

# 3.查看余额
@common.login_auth
def check_balance():
    # 直接调用查看余额接口,获取用户余额
    flag,balance = user_interface.check_balance_interface(login_user)
    if flag:
        print(f'用户{login_user}的账户余额为:{balance}')
    else:
        print('这个用户出了点状况')

interface/user_interface.py

# 查看余额接口
def check_balance_interface(username):
    data = db_handle.select(username)
    if data:
        return True,data.get('balance')
    return False,'哦豁,出错了

3.5 提现功能

core/src.py

from interface import bank_interface
from lib import common

# 4.提现功能
@common.login_auth
def withdraw():
    while True:
        # 1. 让用户输入提现金额
        money = input('请输入提现金额:').strip()
        # 2. 判断用户输入的金额是否是数字
        if not money.isdigit():
            print('请重新输入,提现金额必须为数字:')
            continue
        # 3. 调用接口层的接口进行处理
        flag, msg = bank_interface.withdraw_interface(login_user,int(money))
        if flag:
            print(msg)
            break
        else:
            print(msg)

interface/bank_interface.py

'''
逻辑接口层
    银行相关业务接口
'''
from db import db_handle

# 提现金额接口
def withdraw_interface(username,money):
    # 1. 得到用户的相关信息
    data = db_handle.select(username)
    if data:
        # 2. 检验用户的金额是否足够
        balance = int(data.get('balance'))
        money = int(money*1.05)  # 手续费5%
        if balance >= money:
            # 更新用户相关数据
            balance -= money
            data['balance'] = balance
            # 记录流水
            flow = '用户:{}提现:{}成功,手续费为{},当前可用余额为:{}'.format(username,money,money*0.05,data['balance'])
            data['flow'].append(flow)
            db_handle.save(data)
            return True,flow
        return False,'用户余额已不足'
    return False,'用户出现错误'

3.6 还款功能

core/src.py

from interface import bank_interface

# 5.还款功能
@common.login_auth
def repay():
    while True:
        # 1. 接收用户输入还款金额
        money = input('请输入充值金额:').strip()
        # 2. 判断金额是否是数字
        if not money.isdigit():
            print('请重新输入,提现金额必须为正整数:')
            continue
        # 3. 调用还款接口
        flag, msg = bank_interface.repay_interface(login_user, int(money))
        if flag:
            print(msg)
            break
        else:
            print(msg)

interface/bank_interface.py

# 还款接口
def repay_interface(username,money):
    # 1. 得到用户的相关信息
    data = db_handle.select(username)
    if data:
        # 2. 更新用户金额
        data['balance'] += money
        # 记录流水
        flow = '用户:{}充值:{}成功,当前可用余额为{}'.format(username,money,data['balance'])
        data['flow'].append(flow)
        # 3. 保存用户金额
        db_handle.save(data)
        return True, flow
    return False,'用户出现错误'

3.7 转账功能

core/src.py

# 6.转账功能
@common.login_auth
def transfer():
    while True:
        # 1. 接收用户输入的目标用户和转账金额
        to_user = input('请输入对方的用户名:').strip()
        money   = input('请输入转账的金额:').strip()
        # 2. 判断金额是否是数字
        if not money.isdigit():
            print('请重新输入,提现金额必须为正整数:')
            continue
        # 3. 不能自己给自己转账
        if to_user == login_user:
            print('请不要给自己转账')
            continue
        # 3. 调用转账接口
        flag, msg = bank_interface.transfer_interface(login_user,to_user,int(money))
        if flag:
            print(msg)
            break
        else:
            print(msg)

interface/bank_interface.py

from db import db_handle

# 转账接口
def transfer_interface(username,to_user,money):
    # 1. 判断目标用户是否存在
    to_user_data = db_handle.select(to_user)
    if to_user_data:
        # 2. 获取用户数据信息
        data = db_handle.select(username)
        # 3. 判断用户金额是否足够
        if data.get('balance') >= money:
            # 4. 给用户做减钱操作,并保存更新数据
            data['balance'] -= money
            # 记录流水
            flow = '给{}转账:{}成功,当前余额为{}'.format(to_user,money,data['balance'])
            data['flow'].append(flow)
            db_handle.save(data)
            # 5. 给目标用户做加钱操作,并保存更新数据
            to_user_data['balance'] += money
            # 记录流水
            to_user_flow = '收到{}的转账{},当前余额为{}'.format(username,money,to_user_data['balance'])
            to_user_data['flow'].append(to_user_flow)
            db_handle.save(to_user_data)
            return True,flow
        return False,'尊敬的用户:{},您当前的余额已不足,当前余额为{}'.format(username,data['balance'])
    return False,'目标用户不存在'

3.8 查看流水

core/src.py

# 7.查看流水
@common.login_auth
def check_flow():
    # 1. 调用接口查看流水
    flag, msg = bank_interface.check_flow_interface(login_user)
    if flag:
        for x in msg:
            print(x)
    else:
        print(msg)

interface/bank_interface.py

# 查看流水接口
def check_flow_interface(username):
    data = db_handle.select(username)
    if data:
        if data.get('flow'):
            return True,data.get('flow')
        return False,'当前用户没有流水'
    return False,'用户不存在'

3.9 购物功能

core/src.py

from interface import shop_interface

# 8.购物功能
@common.login_auth
def shopping():
    # 准备商品数据  列表套列表
    shop_list = [
        ['商品1',1000],
        ['商品2',2000],
        ['商品3',3000],
        ['商品4',4000],
    ]
    # 初始化购物车
    shop_car = {}
    while True:
        # 1. 打印商品信息,让用户选择
        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 加入购物车请输入 a').strip()
        # 输入的是y 进入支付功能
        if choice == 'y':
            # 判断购物车是否为空
            if not shop_car:
                print('当前购物车为空,请先添加商品')
                continue
            # 调用支付接口进行支付
            flag,msg = shop_interface.shopping_interface(login_user,shop_car)
            if flag:
                print(msg)
                break
            print(msg)
            break
        if choice == 'a':
            # 判断购物车是否为空
            if not shop_car:
                print('当前购物车为空,请先添加商品')
                continue
            # 调用购物车接口
            flag, msg = shop_interface.add_shop_car_interface(login_user, shop_car)
            if flag:
                print(msg)
                break
            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. 加入购物车
        # 判断用户选择的商品是否重复,重复则数量+1
        if shop_name in shop_car:
            shop_car[shop_name][1] += 1
        else:
            shop_car[shop_name] = [shop_price,1]
        print('************************************')
        print('当前的购物车中有{}'.format(shop_car))
        print('************************************')

interface/shop_interface.py

'''
逻辑接口层
    购物相关接口
'''
from interface import bank_interface
from db import db_handle

def shopping_interface(username,shop_car):
    # 先校验逻辑,再调用银行的支付接口
    # 1. 先计算总价
    count = 0
    for price_num in shop_car.values():
        price,num = price_num
        count += price*num
    print(count)
    # 2. 调用银行接口进行支付
    flag,msg = bank_interface.pay_interface(username,count)
    if flag:
        return True,msg
    return False,msg

def add_shop_car_interface(username,shop_car):
    # 1. 获取当前用户的购物车
    user_dic = db_handle.select(username)
    # 2. 获取用户文件中的商品的数据
    user_car = user_dic.get('shop_car')
    # 3. 添加购物车
    # 判断当前用户选择的商品是否已经存在
    for shop_name,price_num in shop_car.items():
        # 每个商品的数量
        number = price_num[1]
        print('number',number)
        # 若商品重复,则累加商品数量
        if shop_name in user_car:
            user_dic['shop_car'][shop_name][1] += number
        # 若不是重复的,更新到商品字典中
        else:
            user_dic['shop_car'].update({shop_name:price_num})
    # 保存数据
    db_handle.save(user_dic)
    return True,'添加购物车成功'

interface/bank_interface.py

# 支付接口
def pay_interface(username,count):
    # 1. 获取用户信息
    data = db_handle.select(username)
    # 2. 获取用户余额
    money = data.get('balance')
    # 3. 判断余额是否足够
    if money >= count:
        # 进行减钱操作
        data['balance'] -= count
        # 添加流水
        flow = '{}支付成功,支付金额为{},当前余额为{}'.format(username,count,data['balance'])
        data['flow'].append(flow)
        # 保存更新数据
        db_handle.save(data)
        return True,flow
    # 余额不够
    return False,'尊敬的{}您的当前余额不足,无法支付,当前余额为{}'.format(username,data['balance'])

3.10 查看购物车

core/src.py

# 9.查看购物车
@common.login_auth
def check_shop_car():
    flag, msg = shop_interface.check_shop_car_interface(login_user)
    if flag:
        for shop_name,price_num in msg.items():
            print('当前购物车有{}件{},商品单价为{}'.format(price_num[1],shop_name,price_num[0]))
    else:
        print(msg)

interface/shop_interface.py

# 查看购物车
def check_shop_car_interface(username):
    # 1. 获取用户相关信息
    data = db_handle.select(username)
    # 2. 获取用户购物车信息
    if data.get('shop_car'):
        return True,data.get('shop_car')
    return False,'当前购物车没有商品'

3.11 清空购物车

core/src.py

# 10.清空购物车
@common.login_auth
def clean_shop_car():
    flag,msg = shop_interface.clean_shop_car_interface(login_user)
    print(msg)

interface/shop_interface.py

# 清空购物车
def clean_shop_car_interface(username):
    # 1. 先获取用户信息
    data = db_handle.select(username)
    # 2. 查看用户购物车是否有商品
    car_data = data.get('shop_car')
    if car_data:
        # 3. 计算所有商品的价格
        count = 0
        for shop_name, price_num in car_data.items():
            count += price_num[0]*price_num[1]
        # 4. 判断用户余额是否足够
        if data.get('balance') >= count:
            # 做减钱操作
            data['balance'] -= count
            # 清空购物车
            data['shop_car'] = {}
            # 保存数据
            db_handle.save(data)
            return True,'购物车已清空,当前余额为{}'.format(data['balance'])
        return False,'当前用户余额不足,请先充值'
    return False,'当前购物车没有商品,请先添加商品'
A: 首先,在python中创建一个ATM类,该类将包含以下方法: 1. __init__: 用于初始化ATM类对象的构造函数,接受账户余额作为参数。 2. check_balance: 检查账户余额的方法。 3. withdraw: 用于从账户中提取指定数量的现金的方法。 4. deposit: 用于向账户中存入现金的方法。 下面是一个简单的ATM类实现: ```python class ATM: def __init__(self, balance): self.balance = balance def check_balance(self): print("Your account balance is: $", self.balance) def withdraw(self, amount): if amount > self.balance: print("Insufficient funds in your account!") else: self.balance -= amount print("$", amount, "withdrawn. Remaining balance is: $", self.balance) def deposit(self, amount): self.balance += amount print("$", amount, "deposited. Updated balance is: $", self.balance) ``` 现在,我们可以在主函数中使用该类来编写ATM小程序: ```python balance = 1000 myATM = ATM(balance) print("Welcome to the ATM!") while True: print("\nSelect an option:") print("1. Check balance") print("2. Withdraw") print("3. Deposit") print("4. Exit") choice = int(input("Enter your choice: ")) if choice == 1: myATM.check_balance() elif choice == 2: amount = int(input("Enter the amount to be withdrawn: $")) myATM.withdraw(amount) elif choice == 3: amount = int(input("Enter the amount to be deposited: $")) myATM.deposit(amount) elif choice == 4: print("Thank you for using the ATM!") break else: print("Invalid choice! Please select a valid option.") ``` 该程序将显示一个欢迎消息,接着会一直询问你想做什么,直到你选择退出为止。根据你选择的选项,它会调用相应的ATM类方法来执行特定的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值