• Python实战之ATM+购物车


    ATM + 购物车

    需求分析

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

    一个项目是如何从无到有的

    # 1、需求分析:
    '''
        开发项目前,都必须找到相应的客户,让客户给企业提出项目的需求,以及需要实现的功能有哪些,拿到需求后再提取出一些列功能。
    '''
    
    # 2、设计程序以及程序的架构
    '''
        在所有一线开发的企业里,在一个项目开发前,都应该设计程序,那样会让程序解开耦合,从而提高项目的管理以及开发的效率。
    '''
    
    # 3、分任务开发
    '''
        在公司里面,开发项目需要这几种岗位人才:
            UI设计: 软件的外观设计者,通过一些炫酷的设计,提高用户的对软件的体验感。
            前端开发: UI设计仅仅只是把一些外观图设计出来,那前端开发需要把UI的设计图拿到之后,对软件界面的进行排版。
            后端开发(python):  项目里业务以及功能的逻辑处理!
    '''
            
    # 4、项目测试
    '''
        测试工程师: 对后端以及前端开发好的项目进行功能和性能测试,测试的过程中出现bug就会立即让开发人员去修整,待整个项目几乎没有bug,以及性能达到项目实际的预期,就会准备上线运行。
    
            测试分为两种:
            1.黑盒测试:
                通过对软件界面的功能进行测试,测试一些能让用户看到的bug。(例如穿越火线的卡箱子等等...)
            2.白盒测试:
                对软件进行性能测试,例如每秒钟能承受多少用户量的访问等...
    '''
    
    # 5、上线运行
    '''
        运维工程师(linux):  拿到前面整个项目编写完的代码,部署到服务器,上线运行!
    '''
    

    程序架构

    img

    程序目录设计

    # 接下来我们写的功能都在按照这个文件目录来写,请认真阅读这个目录所对应的功能。
    
    '''
    - ATM
      - conf 配置文件文件夹
        - setting.py
    
      - lib 公共方法文件夹
        - common.py  公共方法文件
    
      - interface 接口层文件夹
        - user.py  用户接口文件
        - bank.py  银行接口文件
    
      - core 用户功能文件夹
        - src.py  视图文件
    
      - db 数据处理层文件夹
        - db_handler.py  数据处理功能文件
    
      - start.py  程序的入口文件,启动文件
    
      - readme  程序的说明文件
    
    '''
    

    程序模块

    # confs
    ## settings.py(主要存一些常量,主要是功能界面,商品列表,日志路径,数据路径)
    
    import os
    import sys
    
    ########
    #功能展示#
    #########
    FUNC_MSG = {
        '0': "注销",
        '1': "登录",
        '2': "注册",
        '3': "查看余额",
        '4': "转账",
        '5': "还款",
        '6': "取现",
        '7': "查看流水",
        '8': "购物",
        '9': "购物车",
    }
    
    SHOP_DIST = [
        ['饼干', 10],
        ['薯片', 10],
        ['火腿肠', 20],
        ['雪糕', 10],
        ['别墅', 1000000]
    ]
    # LOG_PATH = os.path
    ATM_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    DB_PATH = os.path.join(ATM_PATH, 'db')
    
    #core
    ## src.py(主界面,主要是和用户交互的界面)
    from libs import common 
    from db import db_handler
    from interface import user
    from interface import bank
    from confs import settings
    
    
    
    #设置一个字典类型的全局变量,用于判断是否登录
    user_info = {
        'user': None
    } 
    
    
    
    # 注销功能
    def logout():
        user_info['user'] = None   # 将values值设置为空
        print('注销成功')
    
    # 登录模块
    def login():
        count = 0 #计数,连续三次注册失败,退出功能
        print("欢迎来到登录功能")
        while True:
            username, pwd = common.input_username_pwd() # 调用输入接口,接收输入信息
            flag = common.check_user(username) # 调用核对用户接口,验证用户是否已经存在
            if not flag:
                print('未注册')
                break
            flag, msg = user.login_interface(username, pwd)
            if flag:
                user_info['user'] = username #登录成功,赋值
                print(user_info['user'])
                print(msg)
                break
            else:
                print(msg)
                count += 1
            if count == 3:
                break
    
    #注册模块
    def register():
        print("欢迎来到注册模块")
    
        username, pwd = common.input_username_pwd()
        flag = common.check_user(username) #先判断是否存在
        if flag:
            print("无需注册,用户已经存在")
        else:
            msg = user.register_interface(username, pwd) # 调用注册接口
            print(msg)
    
    @common.login_auth   # 加语法糖,查看余额前先登录
    def check_extra():
        print("欢迎来到查看余额模块")
        msg = user.check_extra(user_info.get('user'))  # 调用查看余额接口
        print(msg)
    
    # 转账,需要有发起人,接收人和钱
    @common.login_auth
    def transfer():
        print("欢迎来到转账模块")
    
        while True:
            from_username = user_info.get('user')
            to_username = input('请输入你要转账的用户名:')
            flag = common.check_user(to_username) #先判断用户是否存在
            if flag:
                money = input("请输入你要转账的金额").strip()
                if not money.isdigit():
                    print("请输入数字")
                    continue
                money = int(money)
                msg = bank.transfer_interface(from_username, to_username, money) #调用转账接口
                print(msg)
                break
            print("用户不存在")
    
    @common.login_auth
    #还款模块
    def repay():
        print("欢迎来到还款模块")
    
        msg = bank.repay_interface(user_info['user']) #调用还款接口
        print(msg)
    
    @common.login_auth
    #取现功能
    def withdraw(): 
        print("欢迎来到取现功能")
        while True:
            money = input("请输入取现金额:")
            if not money.isdigit():
                print("输入必须是数字")
                continue
            else:
                money = int(money)
                msg = bank.withdraw_interface(user_info['user'], money)#调用取现模块
                print(msg)
                break
    @common.login_auth
    #查看流水模块
    def history():
        print("欢迎来到查看流水模块")
    
        msg = bank.bank_flow_interface(user_info['user'])#调用查看流水模块
        print(msg)
    
    @common.login_auth
    #购物模块
    def shopping():
        print("欢迎来到购物模块")
        while True:
            for index, goods in enumerate(settings.SHOP_DIST): #用列表存储的商品输出,得到索引和有两个元素的商品小列表
                print(f'{index} {goods}')
            goods_n = input("请输入你要的商品编号,按q退出:")
            if goods_n == 'q':
                break
            if not goods_n.isdigit():
                print("输入有误")
                continue
            goods_n = int(goods_n)
            goods = settings.SHOP_DIST[goods_n] # 拿到的商品是一个有两个值(第一个是商品名,第二个是价格)的列表
            goods_name = goods[0] # 列表第一个元素是商品名
            user_dic = db_handler.read_json(user_info['user']) # 拿到当前用户的数据字典
            my_money = user_dic['extra'] # 把用户字典中的查看额度取出来
            if goods[-1] <= my_money: # 如果商品金额小于额度,可以买
                if goods_name in user_dic['shop_car']:
                    user_dic['shop_car'][goods_name] += goods[-1] # 如果我的字典里面的购物车字典有该商品,把价格加上去
                else:
                    user_dic['shop_car'][goods_name] = goods[-1] # 如果我的字典里面的购物车字典没有该商品,把商品名加上去,价格加上去
                db_handler.save_json(user_dic) # 做完修改要保存
                print(f'{goods_name}加入购物车成功')
            else:
                print("余额不足")
                break
        print(f"你的购物车是{user_dic['shop_car']}") # 买完之后要打印一下
    
    
    @common.login_auth
    # 购物车模块
    def shopping_car():
        print("欢迎来到购物车模块")
    
        while True:
            user_dic = db_handler.read_json(user_info['user']) #用户数据读取
            goods_dic = user_dic['shop_car'] # 拿到用户数据字典的购物车字典
            cost_choice = input(f"购物车是{goods_dic},是否选择购买y/n:") # 判断是否购买
            if cost_choice == 'n':
                break
            elif cost_choice == 'y':
                cost = sum(goods_dic.values()) # 把用户购物车字典中的值求和得到总价
                if cost > user_dic['extra']:
                    print('余额不足,支付失败')
                    break
                user_dic['extra'] -= cost # 支付就是把用户字典的额度减去总价
                db_handler.save_json(user_dic) # 操作完了保存
                print("支付成功")
                break
    
    
    
    
    def run():
    
        FUNC_DICT = {
            '0':logout,
            '1':login,
            '2':register,
            '3':check_extra,
            '4':transfer,
            '5':repay,
            '6':withdraw,
            '7':history,
            '8':shopping,
            '9':shopping_car,
        }
        from confs.settings import FUNC_MSG
        while True:
            for k, v in FUNC_MSG.items(): # 把功能列表打印出来展示给用户,包括序号和值
                print(f'{k}: {v}')
    
            func_choice = input("请输入你需要的功能,按q退出>>>>>").strip()
            if func_choice == 'q':
                break
    
            if not FUNC_DICT.get(func_choice):
                print('输入有误,请重新输入')
                continue
    
            func = FUNC_DICT.get(func_choice)
            func()
    
    if __name__ == '__main__':
        run()
    
    
    # db
    ## db_handler(数据处理模块,主要是用户存取数据,格式是json)
    
    import os
    import json
    from confs import settings
    import sys
    
    def save_json(user_dic): #存数据,记得存的是字典,所有拼接名字的时候要把字典里面的用户名取出来
        user_path = os.path.join(settings.DB_PATH,
                                 f'{user_dic.get("username")}.json') #拼接路径
        with open(user_path, 'w', encoding='utf8') as fw:
            json.dump(user_dic, fw) # 存进去,第一个参数是数据,第二个是文件,就是把第一个数据存到第二个文件中
    
    def read_json(username):# 读数据, 拼路径,读出来数据就可以了,记得返回
        user_path = os.path.join(settings.DB_PATH, f'{username}.json')
        if os.path.exists(user_path):
            with open(user_path, 'r', encoding='utf8') as fr:
                data = json.load(fr)
            return data
    
    #interface(主要就是银行和用户两个接口)
    ## bank.py
    from db import db_handler
    
    def transfer_interface(from_username, to_username, money):# 转账接口,
        from_user_dic = db_handler.read_json(from_username) # 读当前用户数据
        to_user_dict = db_handler.read_json(to_username) # 读要转账用户数据
        my_money = from_user_dic['extra'] # 把用户的钱单独拿出来
    
        if money > my_money:
            return  '钱不够'
    
        else:
            from_user_dic['extra'] -= money # 我减钱
            to_user_dict['extra'] += money # 对方加钱
            msg_f = f'已向{to_username}转账{money}元' #记录我的信息
            msg_t = f'已收到{from_username}转账{money}元' #记录对方信息
    
            from_user_dic['bank_flow'].append(msg_f) #加我流水
            to_user_dict['bank_flow'].append(msg_t) #加对方流水
    
            db_handler.save_json(from_user_dic) #存数据
            db_handler.save_json(to_user_dict) #存数据
            return msg_f #返回操作信息
    
    def repay_interface(username): #还款接口
        while True:
            money = input("请输入你的还款金额:").strip()
            if not money.isdigit():
                print('请输入数字')
            else:
                money = int(money)
                user_dic = db_handler.read_json(username) #拿用户数据
                user_dic['extra'] += money # 字典里面加钱
                db_handler.save_json(user_dic) #保存数据
                return f'{username}已成功还款{money}' #返回信息
    
    
    def withdraw_interface(username, money):# 取现接口
        user_dic = db_handler.read_json(username) #拿用户信息
    
        if money*1.005 > user_dic['extra']:
            return "钱不够"
        else:
            user_dic['extra'] -= money*1.05 # 减钱
            db_handler.save_json(user_dic) # 存数据 
            return f'{username}已成功取现{money}元'
    
    
    def bank_flow_interface(username): # 银行流水信息
        user_dic = db_handler.read_json(username) # 拿用户数据
        return user_dic['bank_flow'] #返回用户字典里的流水
    
    ## user.py(用户接口)
    from db import db_handler
    from confs import settings
    import os
    
    def register_interface(username, pwd): #注册接口
        #新生成的用户的信息字典
        user_dic = {
            'username': username,
            'pwd': pwd,
            'extra': 1500000,
            'bank_flow':[],
            'shop_car':{}
        }
        db_handler.save_json(user_dic) #保存数据
        return f'{username}注册成功'
    
    def login_interface(username, pwd): #登录模块
        user_data = db_handler.read_json(username) # 拿数据
    
        if user_data['pwd'] == pwd:
            return True, '登录成功'
        else:
            return False, '密码输入错误'
    
    def check_extra(username):# 查看余额接口
        user_data = db_handler.read_json(username) # 拿数据
        extra = user_data['extra']
        return f'{username}查看了余额,余额为{extra}元'
    
    # libs
    ## common.py(通用模块)
    import logging
    import os
    from db import db_handler
    from confs import settings
    import logging.config
    
    
    
    def input_username_pwd():# 用户输入的模块
        username = input('请输入用户名>>>>').strip()
        pwd = input("请输入密码>>>>").strip()
    
        return username, pwd
    
    def check_user(username): # 检查用户是否存在模块
        user_path = os.path.join(settings.DB_PATH, f'{username}.json') #拼接用户路径,判断是否有该路径
        if os.path.exists(user_path):
            return True
        else:
            return False
    
    
    def login_auth(func):  # 装饰函数,用于验证是否登录,套用装饰函数模板
        from core import src  
        def inner(*args, **kwargs):
            if src.user_info.get('user'):  
                res = func(*args, **kwargs)
                return res
            else:
                print('未登录,请去登录!')
                src.login()
    
        return inner
    
    #start.py (开始模块,项目的起始点)
    
    from core import src
    import os
    import sys
    
    sys.path.append(os.path.dirname(__file__)) #一定要把当前路径加入环境变量里
    if __name__ == '__main__':
        src.run()
    
    

    注意点

    
    1. 首先要把项目单独打开,即作为根目录。
    2. 记住写项目,尤其是需要导入模块时,一定要写开始的函数(start.py),可以避免出现循环导入问题,造成一些变量传入出错。
    3. 有些时候Pycharm不能识别数据类型,就没有提示,但不代表是错的,只要可以运行就可以。
    4. 保存的是字典,所以拼接路径时要注意名字,取字典里key = username对应的值作为名字
    5. 登录成功后把user_info['user']赋值为输入的用户名
    
  • 相关阅读:
    图像维纳滤波实现(2)
    C++之路 变量和基本类型(2)
    [C# 线程处理系列]专题四:线程同步
    [转]排列组合
    Bessie Come Home(!)先存着
    The ONE v1.4.1 Readme
    myeclipse字体修改
    vm 三种上网方式
    Cow Tours
    C++中, 构造函数和析构函数能不能被显示调用?
  • 原文地址:https://www.cnblogs.com/michealjy/p/11396060.html
Copyright © 2020-2023  润新知