记得上次小编上传了一个购物车程序,这次呢稍微复杂一点,还是那句话,上传在这里不是为了炫耀什么,只是督促小编学习,如果大神有什么意见和建议,欢迎指导。
于2018.3.11开始动笔,继续完成这个项目。
一,需求:模拟实现一个ATM + 购物商城程序
要求如下: 1.额度15000或者自定义 2.实现购物商城,买东西加入购物车,调用信用卡接口结账 3.可以提现,手续费5% 4.支持多账户登陆 5.支持账户间转账 6.记录每月日常消费流水 7.提供还款接口 8.ATM记录操作日志 9.提供管理接口,包括添加账户,用户额度,冻结账户等 10.用户认证用装饰器
二,分析功能需求
ATM的角色: 管理员功能: 1,增删改查,加钱,减钱 2,记录日志 3,基本信息 4,额度 15000 普通用户功能: 1,可以提现,手续费5% 2,支持多账户登录 3,支持账户间转账 4,记录每月日常消费流水 5,提供还款接口 6,ATM记录操作日志 购物车程序: 1,可以进入程序购买商品 2,支持多账户登录 3,购完东西显示余额和购买的东西
三,文件创建
文件的创建是有开发规范的,比如下面:
bin 用于执行可执行文件 conf 配置文件 core 用于存放核心代码 db 用于存放用户数据 log 日志,记录相关信息
四,思路流程图
五,简要说明
1,本程序思路是写了一个ATM和购物商城的程序 其中购物商场简单的实现了功能,并没有调用ATM中的信用卡结账 ATM写了信用卡操作和管理员操作,没有实现记录每月日常消费流水 2,对于购物商城: 调用/shopping_mall/shopping_run.py文件执行 简单的实现了用户进入商城,选择购物,则对账户余额进行扣款,推出时打印购买商品和余额 3,对于ATM有两个入口: (1):普通用户对信用卡操作 调用/atm-learn/bin/atm.py文件执行,可以打印账户信息、还款、取款、转账、账单、退出等操作 ①账户信息 ②还款 ③取款 ④转账 ⑤账单 ⑥退出 (2):管理用户对信用卡操作 调用/atm-learn/bin/atm_manage.py文件执行则可以对用户进行管理,解冻用户、冻结用户、申领新卡等操作 ①添加账户 ②冻结账户 ③解冻账户 ④退出
概述 本次作业文件夹一共包含了以下6个文件: 流程图一:ATM用户登录思路流程图 流程图二:ATM管理登陆思路流程图 流程图三:购物车思路流程图 程序结构图:整个ATM+shopping的程序文件结构 程序文件: ATM + shopping 程序说明文件:README.md 程序介绍 本程序思路是写了一个ATM和购物商城的程序 ATM写了信用卡操作和管理员操作,没有实现记录每月日常消费流水 购物商场简单的实现了功能,并没有调用ATM中的信用卡结账 1,对于ATM有两个入口: (1):普通用户对信用卡操作 调用/atm/bin/atm.py文件执行,可以打印账户信息、还款、取款、转账、账单、退出等操作 (2):管理用户对信用卡操作 调用/atm-learn/bin/atm_manage.py文件执行则可以对用户进行管理,解冻用户、冻结用户、申领新卡等操作 2,对于购物商城: 调用/shopping/shopping_run.py文件执行 简单的实现了用户进入商城,选择购物,则对账户余额进行扣款,推出时打印购买商品和余额 程序结构 备注 目前还不会在windows中用树的结构,所以做出程序结构的txt版本,放在文件外面 对几个实例json文件的说明 0000.json 一个用户账户示例文件(这个是账号正常,但是账号过期,不在使用范围内) 123.json 一个用户账户示例文件(这个是账号正常) 1234.json 一个用户账户示例文件(这个是账号被锁定,除非登陆管理端修改被冻结的状态,才能正常使用) admin.json 一个管理账户示例文件(如果不知道管理者的账户和密码,可以查看) 不足及其改进的方面 1,未实现购物商城调用信用卡接口结账 2,账户之间的转账 3,ATM中查看账单,未能实现调用每个月的流水帐单,只是简单的查看信用额度和账户余额 4,购物商场比较简单,每次买一个东西就自己结账退出
六,程序结构
atm+shopping`` ├── README ├── atm #ATM主程序目录 │ ├── __init__.py │ ├── bin #ATM 执行文件 目录 │ │ ├── __init__.py │ │ ├── atm.py #ATM 执行程序 │ │ └── manage.py #ATM 管理端 执行程序 │ ├── conf #配置文件 │ │ ├── __init__.py │ │ └── settings.py │ ├── core #主要程序逻辑都 在这个目录 里 │ │ ├── __init__.py │ │ ├── accounts.py #用于从文件里加载和存储账户数据 │ │ ├── atm_main.py #atm 主逻辑交互程序 │ │ ├── auth.py #用户认证模块 │ │ ├── db_handler.py #数据库连接引擎 │ │ ├── logger.py #日志记录模块 │ │ ├── manage_main.py #atm管理端主逻辑交互程序 │ │ └── transaction.py #记账\还钱\取钱等所有的与账户金额相关的操作都 在这 │ ├── db #用户数据存储的地方 │ │ ├── __init__.py │ │ ├── account_sample.py #一个存用户的账户数据的例子 │ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件 │ │ └── 0000.json #一个用户账户示例文件(这个是账号正常,但是账号过期,不在使用范围内) │ │ └── 123.json #一个用户账户示例文件(这个是账号正常) │ │ └── 1234.json #一个用户账户示例文件(这个是账号被锁定,除非登陆管理端修改被冻结的状态,才能正常使用) │ │ └── admin.json #一个管理账户示例文件(如果不知道管理者的账户和密码,可以查看) │ └── log #日志目录 │ ├── __init__.py │ ├── access.log #用户访问和操作的相关日志 │ └── transactions.log #所有的交易日志 └── shopping #购物车目录 └── __init__.py └── 123.json #一个购物用户账户示例文件(包括用户id,密码,余额) └── shopping_main.py #主逻辑交互程序 └── shopping_run.py #购物车 执行程序
七,程序代码
7.1 ATM代码
bin下atm.py
# _*_ coding: utf-8 _*_ import os import sys #添加环境变量 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路径 sys.path.append(BASE_DIR) #添加路径 #将main.py里面所有代码封装成main变量 from core import atm_main '''ATM程序的执行文件''' if __name__ == '__main__': atm_main.run_atm()
bin下atm_manage.py
# _*_ coding: utf-8 _*_ import os import sys #添加环境变量 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路径 sys.path.append(BASE_DIR) #添加路径 from core import manage_main '''管理程序的执行文件''' if __name__ == '__main__': manage_main.run_manage()
conf/setting.py
# _*_ coding: utf-8 _*_ '''初始化的配置''' import logging import os import sys #到ATM目录,方便后面创建账户文件 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) DATABASE = { 'engine':'file_storage', #文件存储,这里可扩展成数据库形式的 'name':'accounts', #db下的文件名 'path':'%s/db' %BASE_DIR } LOGIN_LEVEL = logging.INFO #初始化日志记录级别为INFO,INFO以下的可以直接打印 #日志类型 LOGIN_TYPE = { 'access':'access.log', 'transaction':'transaction.log' } TRANSACTION_TYPE = { 'repay':{'action':'plus','interest':0}, 'withdraw':{'action':'minus','interest':0.05}, 'transfer':{'action':'minus','interest':0.05}, 'consume':{'action':'minus','interest':0}, }
core/accounts.py
# _*_ coding: utf-8 _*_ import os import sys import json import logging import time import datetime BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) #添加环境变量 from core import auth from core import db_handler from conf import settings def load_current_balance(account_id): ''' # 把数据load下,返回账户余额和其他基础信息 :param account_id: 用户账户的名字 :return: 返回最新读到的数据文件中的最新数据 ''' db_path = db_handler.db_handler(settings.DATABASE) account_file = "%s/%s.json"%(db_path,account_id) with open(account_file,'r',encoding='utf-8') as f: acc_data = json.load(f) return acc_data def dump_account(account_dic): ''' 在更新完后,把数据dump到文件中,文件地址为\atm-learn/db/accounts :param account_data: :return: ''' db_path =db_handler.db_handler(settings.DATABASE) account_file = "%s/%s.json" %(db_path,account_dic['id']) with open(account_file,'w',encoding='utf-8') as f: acc_data = json.dump(account_dic,f)
core/atm_main.py
# _*_ coding: utf-8 _*_ '''主逻辑交互模块''' import logging import sys from core import auth from core import logger from core import accounts from core import transaction from core import db_handler #用户数据信息 user_data = { 'account_id':None , #账户ID 'is_authenticated':False, #是否认证 'account_data':None #账户数据 } #调用log文件下的log方法,返回日志对象 access_logger = logger.logger('access') trans_logger = logger.logger('transaction') def account_info(func): ''' 用户账号信息,acc_data:包括ID,is_authenticaed,用户帐号信息,主要看是否被锁住 :return: ''' def wrapper(acc_data): account_id=acc_data["account_id"] account_data=acc_data["account_data"] status=acc_data['account_data']["status"] if int(status) ==0: func(acc_data) return True else: print("\033[32;1msorry your account was locked\033[0m") exit() return wrapper @account_info def disp_account_info(acc_data): ''' 展示账户信息 #去除 password 字段显示 :param account_data: 账户信息 :return: ''' print("--------------ACCOUNT INFO---------------") for i in acc_data['account_data']: print("{:^20}:\033[32;1m{:^20}\033[0m".format(i, acc_data['account_data'][i])) @account_info def repay(acc_data): ''' 存款 acc_data:包括ID,is_authenticaed,用户帐号信息 :return: ''' account_data = accounts.load_current_balance(acc_data['account_id']) current_balance = '''---------------------BALANCE INFO----------------- Credit : %s Balance: %s'''%(account_data['credit'],account_data['balance']) print(current_balance) back_flag = False while not back_flag: repay_amount = input("\033[32;1mInput repay amout(input 'b' is back):\033[0m").strip() if len(repay_amount) >0 and repay_amount.isdigit(): new_balance = transaction.make_transaction( trans_logger,account_data,'repay',repay_amount) if new_balance: print('''\033[34;1mNEW Balance:%s\033[0m'''%(new_balance['balance'])) elif repay_amount == 'b': back_flag = True else: print("\033[31;1m%s is not valid amount ,Only accept interger!\033[0m"%repay_amount) @account_info def withdraw(acc_data): ''' 打印当前余下的钱,并且让用户做取钱的功能 :param acc_data: :return: ''' account_data = accounts.load_current_balance(acc_data['account_id']) current_balance ='''---------------------BALANCE INFO----------------- Credit : %s Balance: %s'''%(account_data['credit'],account_data['balance']) print(current_balance) back_flag = False while not back_flag: withdraw_amount = input("\033[33;1mInput withdraw amout(input 'b' is back):\033[0m").strip() if len(withdraw_amount) > 0 and withdraw_amount.isdigit(): new_balance = transaction.make_transaction( trans_logger, account_data, 'withdraw', withdraw_amount) if new_balance: print('''\033[32;1mNEW Balance:%s\033[0m''' % (new_balance['balance'])) elif withdraw_amount == 'b': back_flag = True else: print('\033[31;1m[%s] is not a valid amount , only accept integer\033[0m'%withdraw_amount) @account_info def transfer(acc_data): ''' 转账 :return: ''' account_data = accounts.load_current_balance(acc_data['account_id']) current_balance = '''---------------------BALANCE INFO----------------- Credit : %s Balance: %s''' % (account_data['credit'], account_data['balance']) print(current_balance) back_flag = False while not back_flag: transfer_amount = input("\033[33;1mInput transfer amount(input 'b' is back):\033[0m").strip() if len( transfer_amount) > 0 and transfer_amount.isdigit(): new_balance = transaction.make_transaction( trans_logger, account_data, 'transfer', transfer_amount) if new_balance: print('''\033[32;1mNEW Balance:%s\033[0m''' % (new_balance['balance'])) elif transfer_amount == 'b': back_flag = True else: print('\033[31;1m[%s] is not a valid amount , only accept integer\033[0m' % transfer_amount) @account_info def paycheck(acc_data): ''' 账单检查,记录每月日常消费流水 :return: ''' account_data = accounts.load_current_balance(acc_data['account_id']) current_balance = '''---------------------BALANCE INFO----------------- Credit : %s Balance: %s''' % (account_data['credit'], account_data['balance']) print(current_balance) @account_info def logout(acc_data): ''' 退出登陆 :return: ''' print("\033[32;1m-------Looking forward to your next visit-------\033[0m") exit() def interactive(acc_data): ''' 用户交互 :return: ''' msg = ( ''' ------------------CHINA BANK -------------- \033[31;1m1.账户信息 2.存款 3.取款 4.转账 5.账单 6.退出 \033[0m''' ) menu_dic = { "1":disp_account_info, "2":repay, "3":withdraw, "4":transfer, "5":paycheck, "6":logout, } exit_flag = False while not exit_flag: print(msg) user_choice = input(">>>>").strip() if user_choice in menu_dic: menu_dic[user_choice](acc_data) else: print("\033[31;1mYou choice doesn't exist!\033[0m") def run_atm(): ''' 当程序启动时候,调用,主要用于实现主要交互逻辑 :return: ''' # 调用认证模块,返回用户文件json.load后的字典,传入access_logger日志对象 access_data = auth.access_login(user_data,access_logger) if user_data['is_authenticated']: #如果用户认证成功 user_data["account_data"] = access_data interactive(user_data) #用户交互开始
core/auth.py
# _*_ coding: utf-8 _*_ import os import json import time from core import accounts from core import db_handler from conf import settings from bin import atm_manage from core import atm_main def access_auth(account,password,log_obj): ''' 下面access_login调用access_auth方法,用于登陆 :param account: 用户名 :param password: 密码 :return: 如果为超期,返回字典,超期则打印相应提示 ''' db_path = db_handler.db_handler(settings.DATABASE) #调用db_handle下的handle方法,返回路径/db/accounts account_file = '%s/%s.json'%(db_path, account) #用户文件 #判断文件和i否存在,如果存在的话 则执行下面的 if os.path.isfile(account_file): #如果用户文件存在(即用户存在) with open(account_file,'r',encoding='utf-8') as f: #打开文件 account_data = json.load(f) #file_data为字典形式 if account_data['password'] == password: expire_time = time.mktime(time.strptime(account_data['expire_date'],'%Y-%m-%d')) if time.time() > expire_time: #如果信用卡已经过期,当前时间戳大于国企的时间戳 log_obj.error("Account [%s] had expired,Please contract the bank" % account) print("\033[31;1mAccount %s had expired,Please contract the bank"%account) else: #信用卡未过期,返回用户数据的字典 log_obj.info("Account [%s] logging success" % account) return account_data else: log_obj.error("Account or Password does not correct!") print("\033[31;1mAccount or Passwordoes not correct!\033[0m") else: #用户不存在 log_obj.error("Account [%s] does not exist!" % account) print("\033[31;1mAccount [%s] does not exist!\033[0m"%account) def access_login(user_data,log_obj): ''' 用户登陆,当登陆失败超过三次 :param user_date:main.py里面的字典,用户信息数据,只存在内存中 :return:若用户账号密码正确,且信用卡未过期,则返回用户数据的字典 ''' retry_count = 0 while user_data['is_authenticated'] is not True and retry_count < 3: account = input('\033[32;1mplease input Acount:\033[0m').strip() password = input('\033[32;1mplease input Password:\033[0m').strip() #用户账号密码正确而且信用卡未过期,返回用户数据的字典 auth = access_auth(account, password,log_obj) if auth: user_data['is_authenticated'] = True #用户认证为True user_data['account_id'] = account #用户账号ID为账号名 # print("welcome") return auth retry_count += 1 else: print("Account [%s] try logging too many times..."%account) log_obj.error("Account [%s] try logging too many times..." % account) exit()
core/db_handler.py
# _*_ coding: utf-8 _*_ '''处理与数据之间的交互,如果file_db_storage,返回路径''' import json import time from conf import settings def file_db_handle(conn_params): ''' parse the db file path 对文件路径做语法分析 :param conn_params: :return: ''' db_path = '%s/%s' %(conn_params['path'],conn_params['name']) return db_path def db_handler(conn_parms): ''' :param conn_parms: the db connection params set in settings :return: a DATABASE = { 'engine':'file_storage', #文件存储,这里可扩展成数据库形式的 'name':'accounts', #db下的文件名 'path':'%s/db' %BASE_DIR } ''' if conn_parms['engine'] == 'file_storage': return file_db_handle(conn_parms)
core/logger.py
# _*_ coding: utf-8 _*_ '''操作所有的日志工作''' import logging from conf import settings def logger(log_type): logger = logging.getLogger(log_type) logger.setLevel(settings.LOGIN_LEVEL) #创建屏幕对象和设置等级debug # ch = logging.StreamHandler() # ch.setLevel(settings.LOGIN_LEVEL) #创建文件对象,给文件对象设置等级 log_file = "%s/log/%s"%(settings.BASE_DIR,settings.LOGIN_TYPE[log_type]) fh = logging.FileHandler(log_file) fh.setLevel(settings.LOGIN_LEVEL) # 设置输出对象格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #把格式添加到配置中 # ch.setFormatter(formatter) fh.setFormatter(formatter) #把日志打印到指定的handler # logger.addHandler(ch) logger.addHandler(fh) return logger
core/manage_main.py
# _*_ coding: utf-8 _*_ '''管理端,提供管理接口,包括添加账户,用户额度,冻结账户,解冻账户''' import os import sys import json from core import auth from core import accounts from core import transaction from core import db_handler from conf import settings # 解冻账户 def unlock_account(): '''解冻账户的初步思路是读取用户文件,把status的状态一更改就ok ''' account = input("\033[34;1mPlease input the account that you want to unlock:\033[0m") read_data = unlock_accountcore(account) return read_data def unlock_accountcore(account): ''' 解冻账户,读取用户文件,读到status,把状态更改为0 #0 = naormal,1 = locked , :param account: :return: ''' # 调用db_handle下的handle方法,返回路径/db/accounts db_path = db_handler.db_handler(settings.DATABASE) account_file = '%s/%s.json' % (db_path, account) account_new = '%s/%s.json' % (db_path, account) if os.path.isfile(account_file): with open(account_file, 'r', encoding='utf-8') as f: account_data = json.load(f) account_data['status'] = 0 with open(account_new, 'w', encoding='utf-8') as fnew: new_data = json.dump(account_data, fnew) # 冻结账户 def lock_account(): ''' 冻结账户,思路与解冻刚好相反 :param acc_data: :return: ''' account = input("\033[34;1mPlease input the account that you want to lock:\033[0m") read_data = lock_accountcore(account) return read_data def lock_accountcore(account): ''' 冻结账户,读取用户文件,读到status,把状态更改为1 #0 = naormal,1 = locked , :param account: :return: ''' # 调用db_handle下的handle方法,返回路径/db/accounts db_path = db_handler.db_handler(settings.DATABASE) account_file = '%s/%s.json' % (db_path, account) account_new = '%s/%s.json' % (db_path, account) if os.path.isfile(account_file): with open(account_file, 'r', encoding='utf-8') as f: account_data = json.load(f) account_data['status'] = 1 with open(account_new, 'w', encoding='utf-8') as fnew: new_data = json.dump(account_data, fnew) # 添加账户 def add_account(): ''' 添加账户,是admin添加的用户,下次就可以登陆添加的账户了 :return: ''' acc_dic = { 'id':None, 'balance':None, 'password': None, 'credit': None, 'enroll_date': None, 'expire_date': None, 'status': None # 0 = naormal,1 = locked , 2 = disabled } menu = { 0:"请输入要添加的账户:", 1:"请输入要添加的余额:", 2:"请输入要添加的密码:", 3:"请输入要添加的信用额度(only more than 0)", 4:"请输入要添加的办卡日期(such as 2018-8-8)", 5:"请输入要添加的卡到期时间(such as 2018-8-8)", 6:"请输入是否锁定添加账号的状态(only input 0 or 1)", } menu_user = { 0: "id", 1: "balance", 2: "password", 3: "credit", 4: "enroll_date", 5: "expire_date", 6: "status", } print("\033[31;1m\t\twelcome to add account\033[0m") print('*'.center(40,'*')) for i in range(7): data = input('%s'%menu[i]).strip() acc_dic["%s" % menu_user[i]] = data accounts.dump_account(acc_dic) print("\033[32;1mcongratulations you account was created successfully\033[0m") return True # 退出程序 def logout(): ''' 退出登陆 :return: ''' print("\033[32;1m-------Looking forward to your next visit-------\033[0m") exit() def auth_login(): ''' 登陆管理员密码账号 :return: ''' print("\033[34;1m-------Welcome into the management interface--------\033[0m") managename = input("\033[34;1mplease input Username:\033[0m") password = input("\033[34;1mplease input Password:\033[0m") account = account_auth(managename,password) return account def account_auth(managename,password): ''' 管理员认证信息 {"id": admin,"password": "root" } :return: ''' db_path = db_handler.db_handler(settings.DATABASE) # 调用db_handle下的handle方法,返回路径/db/accounts managename_file = '%s/%s.json'%(db_path,managename) if os.path.isfile(managename_file): with open(managename_file,'r',encoding='utf-8') as f: manage_data = json.load(f) # print(manage_data) if manage_data['password'] == password: print("\033[31;1m-------Welcome to the administrator--------\033[0m") return manage_interactive(managename) else: print("\033[31;1mAccount or Passwordoes not correct!\033[0m") # 管理界面主程序 def manage_interactive(managename): menu = ''' \033[31;1m-----------management console----------- 1,add_account 2,lock_account 3,unblock_account 4, exit\033[0m''' menu_dic = { '1':add_account, '2':lock_account, '3':unlock_account, '4': logout } exit_flag = False while not exit_flag: print(menu) user_option = input('please input your choice>>>').strip() if user_option in menu_dic: print(menu_dic[user_option]()) else: print("\033[31;1mYou choice doesn't exist!\033[0m") def run_manage(): ''' 当程序启动的时候调用,主要用于实现主要交互逻辑,客户认证登陆 :return: ''' auth_login()
core/tranction.py
# _*_ coding: utf-8 _*_ import json from conf import settings from core import accounts def make_transaction(log_obj,account_data,tran_type,amount,**others): ''' 处理所有的用户的交易 :param log_obj: :param amount_data: user account data :param tran_type: transaction type :param amount: transaction amount :param other: mainly for logging usage :return: ''' # 将字符串类型转换为float类型 amount = float(amount) # tran_type 交易类型 if tran_type in settings.TRANSACTION_TYPE: # 利息金额 interest =amount * settings.TRANSACTION_TYPE[tran_type]['interest'] old_balance = account_data['balance'] if tran_type in settings.TRANSACTION_TYPE: # 利息金额 interest = amount * settings.TRANSACTION_TYPE[tran_type]["interest"] # 用户原金额 old_balace = account_data["balance"] if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus': new_balance = float(old_balance) + amount + float(interest) elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus': new_balance = float(old_balance) - amount - float(interest) # 做一个判断小于0的操作,减钱时对帐户金额进行检查,防止超额 if new_balance <0: print('\033[31;1mYour credit [%s] is not enough for this transaction' '[%s]'%(account_data['credit'],(amount + interest),old_balance)) return account_data['balance'] = new_balance # 保存新的余额返回到文件中 accounts.dump_account(account_data) log_obj.info("account:%s action:%s amount:%s interest:%s " %(account_data['id'],tran_type,amount,interest)) return account_data else: print("\033[31;1mTransaction type [%s] is not exist\033[0m"%tran_type)
db/account_sample/py(此处只举一个例子)
# _*_ coding: utf-8 _*_ import json acc_dic = { 'id':1234, 'password':'abc', 'credit':15000, 'balance':15000, 'enroll_date':'2018-01-01', 'expire_date':'2023-01-01', # 'pay_day':22, #支付日期(但是现在没有要求,可以不考虑) 'status':0 #0 = naormal,1 = locked , 2 = disabled } print(acc_dic,type(acc_dic)) a = json.dumps(acc_dic) print(a,type(a))
7.2 shopping代码
shopping_main.py
# _*_ coding: utf-8 _*_ import datetime import os import json def auth_login(): ''' 登陆密码账号 :return: ''' print("-------welcome to shopping_mall--------") username = input("\033[32;1mplease input Username:\033[0m") password = input("\033[32;1mplease input Password:\033[0m") account = account_auth(username,password) return account def account_auth(username,password): ''' 用户认证账户信息格式化读取模块,并验证账号密码是否正确 :return: ''' username_file = '%s.json'%username if os.path.isfile(username_file): with open(username_file,'r',encoding='utf-8') as f: username_data = json.load(f) if username_data['password'] == password: balance = username_data['balance'] print("\033[32;1myou balance is %s\033[0m"% balance) return account_shopping(username,balance) else: print("\033[31;1mAccount or Passwordoes not correct!\033[0m") def account_shopping(username,balance): '''用户购物操作 这次只能买一件东西,不能重复买 ''' goods = [ {"name": "电脑", "price": 6999}, {"name": "鼠标", "price": 300}, {"name": "游艇", "price": 2000}, {"name": "美女", "price": 9980}, ] print("*".center(40, '*')) print("goods".center(40, '-')) for index,item in enumerate(goods): print(index,item) print('end'.center(40,'-')) while True: choice = input("请输入要想购买的商品编号(或者按q直接退出):") if choice.isdigit(): #判断是否为数字 choice = int(choice) if choice>=0 and choicegoods[choice].get('price'): new_balance = balance - goods[choice].get('price') print("now your balance is \033[32;1m%s\033[0m"% new_balance) else: print("sorry your balance is \033[32;1m%s\033[0m,unable to purchase" %balance) continue else: print("\033[31;1mplease input the correct goods number\033[0m") elif choice == 'q': exit() return write_data(username,new_balance) def write_data(username, new_balance): ''' 买了东西之后,余额信息更新一下 :param username: 用户姓名 :param new_balance: 余额信息 :return: ''' username_file = '%s.json' % username usernew_file = '%s.json' % username f = open(username_file, 'r', encoding='utf-8') username_data = json.load(f) username_data['balance'] = new_balance f.close() fnew = open(usernew_file, 'w', encoding='utf-8') new_data = json.dump(username_data,fnew) fnew.close() def run_shopping(): ''' 当程序启动的时候,调用,主要用于实现主要交互逻辑,客户认证登陆函数 :return: ''' userdata = auth_login() def account_recharge(balance): '''用户充值操作,此思路是接ATM''' recharge_money = input("please input recharge money: ") recharge_money =int(recharge_money) balance = balance + recharge_money print("Congratulations. Recharge success. balance is \033[32;1m%s\033[0m" %balance) return balance def legout(): ''' 退出程序 :return: ''' print("\033[32;1m-------Looking forward to your next visit-------\033[0m") exit() def interactive(acc_data): ''' 用户交互 :param acc_data: :return: ''' msg = ( ''' ------------------SHOPPING INFO -------------- \033[31;1m1.购物 2.充值 3.退回 \033[0m''' ) menu_dic = { "1": account_shopping, "2": account_recharge, "3": legout, } exit_flag = False while not exit_flag: print(msg) user_choice = input(">>>>").strip() if user_choice in menu_dic: menu_dic[user_choice]() else: print("\033[31;1mYou choice doesn't exist!\033[0m") def manage_accountauth(): ''' 管理员账户认证函数, :return: ''' manage_account = [] with open('manageinfo.txt', 'r', encoding='utf-8') as f: for i in f.readlines(): i_space = i.replace('\n', '') manage_account.append(i_space) return manage_account def account_balance(): ''' 账户余额信息格式化读取模块 :return: ''' balance = [] with open('account_balance.txt', 'r', encoding='utf-8') as f: for i in f.readlines(): i_space = i.replace('\n', '') balance.append(i_space) return balance def account_save(account,cash): ''' 把账户及其余额信息持久化到本地,以消除文件内容,然后以读写的方式打开文件 :param account: 用户信息 :return: ''' save_info = open('account_balance.txt','w+',encoding='utf-8') save_info.write(account) save_info.write('\n') save_info.write(str(cash)) save_info.close() def account_auth_changshi(username,password): ''' 用户认证账户信息格式化读取模块,尝试登陆三次, {"id": 123,"password": "123", "balance": 20000 } :return: ''' retry_count = 0 while username_data['password'] is not True and retry_count <3: username_file = '%s.json'%username if os.path.isfile(username_file): with open(username_file,'r',encoding='utf-8') as f: username_data = json.load(f) print(username_data['password']) print(password) if username_data['password'] == password: return account_shopping else: print("\033[31;1mAccount or Passwordoes not correct!\033[0m") retry_count += 1 else: print("Account [%s] try logging too many times..." % username) exit()
shopping_run.py
# _*_ coding: utf-8 _*_ import os import sys #添加环境变量 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路径 sys.path.append(BASE_DIR) #添加路径 from shopping import shopping_main '''购物车程序的执行文件''' if __name__ == '__main__': shopping_main.run_shopping()