python day4 作业 ATM
作业需求
- 指定最大透支额度
- 可取款
- 定期还款(每月指定日期还款,如15号)
- 可存款
- 定期出账单
- 支持多用户登陆,用户间转帐
- 支持多用户
- 管理员可添加账户、指定用户额度、冻结用户等
目录结构如下:
ATM2/
├── bin
│ ├── admin_user.py ##管理员进入界面
│ ├── atm_user.py # 普通用户进入界面
│ └── __init__.py
├── conf
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ └── settings.cpython-36.pyc
│ └── settings.py # 主配置文件 (首先看这个)
├── core
│ ├── accounts.py # 用户数据json 文件
│ ├── auth.py # 用户认证
│ ├── bill_date.py # 时间格式
│ ├── db_handler.py # 数据库
│ ├── __init__.py
│ ├── logger.py #log 文件
│ ├── main.py # 主函数
│ ├── __pycache__
│ │ ├── accounts.cpython-36.pyc
│ │ ├── auth.cpython-36.pyc
│ │ ├── bill_date.cpython-36.pyc
│ │ ├── db_handler.cpython-36.pyc
│ │ ├── __init__.cpython-36.pyc
│ │ ├── logger.cpython-36.pyc
│ │ ├── main.cpython-36.pyc
│ │ └── transaction.cpython-36.pyc
│ └── transaction.py
├── db
│ ├── accounts
│ │ ├── admin.json
│ │ ├── liang2.json
│ │ └── liang.json
│ └── __init__.py
├── __init__.py
└── log
├── access.log
├── accounts
├── __init__.py
└── transactions.log
说下心得哈。首先我。我也是第一次写这种代码 最开始的时候一个文件相互调来调去的确实繁琐,
后面看ygqygq2 老哥写的,豁然开朗。第一步就是看代码。先把代码一行行去读起来。因为我也没
学多久。久久看了两天才把老哥的代码看懂。实在没办法。 还有就是看代码的顺序。第一看的是配置
文件,后面你文件头里面的import 是那个文件,这样以此类推的看下去。
我的代码还是有点问题,没有老哥的代码写的完美。那么上代码把
settings.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import sys,os,logging BASE_DIR= os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) BILL_DAY=25 DATABASE={ 'engine':'file_storage', 'name':'accounts', 'path':'%s/db' %BASE_DIR } LOG_LEVEL=logging.INFO LOG_TYPES={ 'transaction':'transactions.log', 'access':'access.log', } LOG_DATABASE={ 'engine': 'file_storage', 'name': 'accounts', 'path': '%s/log' %BASE_DIR } TRANSACTION_TYPE={ 'repay':{'action':'plus','interest':0}, # 还款 'receive':{'action':'plus','interest':0}, #接受 'withdraw':{'action':'munus','interest':0.05}, #提款 'transfer':{'action':'minus','interest':0.05}, # 转出 'pay':{'action':'minus','interest':0}, #支付 'sava':{'action':'plus','interest':0}, #存钱 } ACCOUNT_FORMAT={ ''' 用户数据格式 {"enroll_date": "2016-01-02", "password": "abc", "id": 1000, "credit": 15000, "status": 0, "balance": 1000.0, "expire_date": "2021-01-01", "pay_day": 22} ''' }
db_handler.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang def file_db_handle(conn_params): ''' 存放数据的文件路径 :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: :return: ''' if conn_parms['engine']=='file_storage': return file_db_handle(conn_parms) elif conn_parms['engine']=='mysql': pass
auth.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import os,sys BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) import os from core import db_handler from core import accounts from conf import settings import json import datetime def acc_auth(account,password): ''' 用户验证函数 :param account: :param password: :return: ''' db_path=db_handler.db_handler(settings.DATABASE) account_file="%s/%s.json" %(db_path,account) if os.path.isfile(account_file): with open(account_file) as f: account_data=json.load(f) if account_data["password"] == password: exp_time_stamp=datetime.datetime.strptime(account_data['expire_date'], "%Y-%m-%d") status=account_data['status'] if datetime.datetime.now() > exp_time_stamp: print("%s账户已近过期了.请联系管理员"%account) elif status == 0 or status == 8: return account_data else: print("账户已经过期了。或者不是管理员!!") else: print("密码错误") else: print("文件不存在") def acc_login(user_data,log_obj): ''' 用户登录 的函数 :param user_data: :param log_obj: :return: ''' exit_count=3 #登录次数 retry_connt=0 # 初始化重试数据 same_account=0 #输入时。相同数据计数 last_account="" # 初始化上一次输入的用户 while user_data['is_authenticated'] is not True and retry_connt<exit_count: account=input("请输入用户名:").strip() password=input("请输入密码").strip() if account==last_account: same_account+=1 auth=acc_auth(account,password) last_account=account if auth: user_data['is_authenticated']=True user_data['account_id']=account return auth retry_connt+=1 else: if same_account==exit_count -1: log_obj.error("account [%s] too many login attempts" % account) exit() def acc_check(account): ''' 查询账户是否存在 :param account: :return: ''' db_path=db_handler.db_handler(settings.DATABASE) account_file="%s/%s.json" %(db_path,account) if os.path.isfile(account_file): with open(account_file,'r') as f: account_data=json.load(f) status=account_data["status"] exp_time_stamp=datetime.datetime.strptime(account_data['expire_date'],"%Y-%m-%d") if datetime.datetime.now()>exp_time_stamp: print("此%s账户已经过期。请联系管理员"%account) else: return account_data else: return False def sign_up(): ''' 用户注册和admin 管理员用户 :return: ''' pay_dat=22 exit_flag=True while exit_flag is True: account=input("请输入你的用户名:").strip() password=input("请输入你的密码:").strip() exit_flag=acc_check(account) if exit_flag: print("次用户已经存在。请选择其他用户名") else: # 现在的时间格式 today=datetime.datetime.now().strftime("%Y-%m-%d") # 默认五年后过期 after_5_years=int(datetime.datetime.now().strftime('%Y')) +5 #五年后的今天 after_5_years_today=datetime.datetime.now().replace(year=after_5_years) #五年后的昨天 expire_day=(after_5_years_today + datetime.timedelta(-1)).strftime('%Y-%m-%d') """用户数据库格式 {"enroll_date": "2016-01-02", "password": "abc", "id": 1000, "credit": 15000,"balance":0, "status": 0, "balance": 1000.0, "expire_date": "2021-01-01", "pay_day": 22} """ account_data={"enroll_date":today,"password":password,"id":account,"credit":15000,"balance":0, "status":0,"expire_date":expire_day,"pay_day":pay_dat} print(account_data) accounts.dump_account(account_data) print("添加成功 用户ID:[%s]!!!" %account) return True def modify(): ''' 修改用户信息 :return: ''' items=["password","credit","status","expire_day","pay_day"] acc_data=False contine_flag=False while acc_data is False: account=input("请输入你要修改的用户名:").strip() # 丢到验证函数中 account_data=acc_check(account) if account_data is False: print("你输入的用户不存在") else: while contine_flag is not True: #判断输入json 格式 print('''请你输入json 格式 { "password": "abc", "credit": 15000, "status": 0, "expire_date": "2021-01-01", "pay_day": 22 }''') modify_items=input("请你输入json格式").strip() try: modify_items=json.loads(modify_items) except Exception as e: print("输入错误!!!") continue error_flag=False # 初始化错误标记 for index in modify_items: if index in items: # 修改用户数据 就是字典修改方式 account_data[index]=modify_items[index] else: print("输入有错误!!!") continue if error_flag: continue #再写到文件中 accounts.dump_account(account_data) print("修改成功!!!") contine_flag=True acc_data = True return True
accounts.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import json import time from core import db_handler from conf import settings def load_current_balance(account_id): ''' json load 用户文件 :param account_id: :return: ''' db_path=db_handler.db_handler(settings.DATABASE) # db_path 调用的是配置文件的DATABASE路径 # db_path 完整的路径是 ATM\db\accounts account_file="%s/%s.json" %(db_path,account_id) with open(account_file,'r') as f: acc_data=json.load(f) return acc_data def dump_account(account_data): ''' 写到文件当中 :param account_data: :return: ''' db_path=db_handler.db_handler(settings.DATABASE) # 这个数据的目录 ATM\db\accounts account_file="%s/%s.json" %(db_path,account_data['id']) with open(account_file,'w') as f: acc_data=json.dump(account_data,f) return True
bill_date.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang from conf import settings import datetime def get_bill_time(year_month): ''' 获取给出的年-月的信用卡账单 月份起止时间 :param year_month: 年-月 :return: 返回时间 ''' the_bill_day="%s-%s" %(year_month,settings.BILL_DAY) bill_begin_time=datetime.datetime.strptime(the_bill_day,"%Y-%m-%d") year=bill_begin_time.year month=bill_begin_time.month if month ==12: month=1 year +=1 else: month+=1 bill_end_time=datetime.datetime(year,month,settings.BILL_DAY) return bill_begin_time,bill_end_time
transaction.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang # from conf import settings from core import accounts from core import logger # transaction logger def make_transaction(log_obj, account_data, tran_type, amount, **others): ''' deal all the user transactions :param account_data: user account data :param tran_type: transaction type :param amount: transaction amount :param others: mainly for logging usage :return: ''' # 交易金额 为浮点型 amount = float(amount) # 判断交易类型是否在存在里面 if tran_type in settings.TRANSACTION_TYPE: # 利息的计算 interest = amount * settings.TRANSACTION_TYPE[tran_type]['interest'] # 我现有的金额 old_balance = account_data['balance'] #判断是否是加金额 if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus': # 金额的加 是 本金+交易金额+ 利息 new_balance = old_balance + amount + interest # 如果为减 elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus': # 那就是 本金 减 交易金额 减 利息 new_balance = old_balance - amount - interest # check credit #减去了 所有的 如果大于0 if new_balance < 0: # 输出用户的额度 、 减少了多少金额 、剩下了多少额度 print('''Your credit [\033[31;1m%s\033[0m] is not enough for this transaction [-%s], your current balance is [\033[32;1m%s\033[0m]''' % (account_data['credit'], (amount + interest), old_balance)) return #把用户剩余的额度 写入到文件中 account_data['balance'] = new_balance # json 序列化到文件中 accounts.dump_account(account_data) # save the new balance back to file #输出用户的用户名、交易类型、交易金额、利息 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) # from conf import settings # from core import accounts # from core import logger # # # # # # def make_transaction(log_obj,account_data,tran_type,amount,**kwargs): # ''' # 交易函数 # :param log_obj: log # :param account_data: 用户数据 # :param tran_type: 交易类型 # :param amount: 金额action # :param kwargs: 主要用于日志 # :return: # ''' # #交易金额 为浮点型 # amount=float(amount) # # if tran_type in settings.TRANSACTION_TYPE: # # #利息的计算 # interest=amount *settings.TRANSACTION_TYPE[tran_type]['interest'] # print(interest) # # 现有的余额 # old_balance= account_data['balance'] # # #判断是否加金额 # if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus': # # 金额 就是本金+交易金额+利息 # new_balance=old_balance+amount+interest # print(new_balance) # #如果是减去 # elif settings.TRANSACTION_TYPE[tran_type]['action']=='minus': # new_balance=old_balance-amount-interest # if new_balance<0: # print("你的额度为%s .你本次交易的金额(+利息的)%s 你的余额为%s"%(account_data['credit'],(amount+interest),account_data['old_balance'])) # return None # #把用户更新的额度写入到文件中 # account_data['balance']= new_balance # # # json 序列化到文件中 # xx=accounts.dump_account(account_data) # # 输出用户的用户名、交易类型、交易金额、利息 # log_obj.info("account:%s action:%s amount:%s interest:%s" % # (account_data["id"],tran_type,amount,interest)) # # return xx # # else: # print("错误类型") # # money=input("输入需要存款的数量:>>>") # # account_data={'enroll_date': '2018-01-31', 'password': '123456', 'id': 'liang', 'credit': 15000, 'balance': 0, 'status': 0, 'expire_date': '2023-01-30', 'pay_day': 22} # # # # x=make_transaction(trans_logger,account_data,'sava',money) # # print(x)
logger.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import logging import datetime from conf import settings from core import bill_date def logger(log_type): # 创建loggin logger = logging.getLogger(log_type) logger.setLevel(settings.LOG_LEVEL) # create console handler and set level to debug ch = logging.StreamHandler() ch.setLevel(settings.LOG_LEVEL) # create file handler and set level to warning # 创建 log 文件的一个级别 log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOG_TYPES[log_type]) fh = logging.FileHandler(log_file) fh.setLevel(settings.LOG_LEVEL) # create formatter # log的输入格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # add formatter to ch and fh ch.setFormatter(formatter) fh.setFormatter(formatter) # add ch and fh to logger logger.addHandler(ch) logger.addHandler(fh) return logger # 'application' code '''logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')''' def show_log(account, log_type, year_month): """ 显示日志内容 :param user_name: 用户名 :param log_type: 日志类型 :return: """ #给出的账单时间 结束的账单时间 begin_time, end_time = bill_date.get_bill_time(year_month) # log文件的所在路径 log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOG_TYPES[log_type]) # 打开log文件 file = open(log_file) print("-".center(50, "-")) for line in file: #log 时间 log_time = datetime.datetime.strptime(line.split(",")[0], "%Y-%m-%d %H:%M:%S") # 记录的用户 user_name = line.split()[7].split(":")[1] # 帐单生成日是25号,则每月帐单是从上月25日到本月24日之间 if account == user_name and begin_time <= log_time < end_time: print(line.strip()) print("-".center(50, "-")) file.close() # import os,sys # BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # sys.path.append(BASE_DIR) # import logging # import datetime # from conf import settings # from core import bill_date # # # def logger(log_type): # # #创建loggin # logger=logging.getLogger(log_type) # logger.setLevel(settings.LOG_LEVEL) # # ch=logging.StreamHandler() # ch.setLevel(settings.LOG_LEVEL) # # # 创建log 文件 级别 # log_file="%s/log/%s" %(settings.BASE_DIR,settings.LOG_TYPES[log_type]) # fh =logging.StreamHandler(log_file) # fh.setLevel(settings.LOG_LEVEL) # # #log 的输入格式 # formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # # ch.setFormatter(formatter) # fh.setFormatter(formatter) # # return logger # # def show_log(account,log_type,year_month): # ''' # 显示 日志内容 # :param account: 用户 名 # :param log_type: 日志类型 # :param year_month: # :return: # ''' # # 给出账单 时间 结束时间 # begin_time,end_time=bill_date.get_bill_time(year_month) # # log 文件路径 # log_file="%s/log/%s" %(settings.BASE_DIR,settings.LOG_TYPES[log_type]) # # # 打开log文件 # file=open(log_file,'r') # print("-".center(50,"-")) # for line in file: # # log 时间 # log_time=datetime.datetime.strptime(line.split(",")[0],"%Y-%m-%d %H:%M:%S") # # 记录用户 # user_name=line.split()[7].split(":")[1] # #账单生成日是25 号 则每月账单是从上月25到本月24之间 # if account==user_name and begin_time<=log_time<end_time: # print(line.strip()) # print("-".center(50,"-")) # file.close() # # # # # x=logger('transaction') # x.info("account:%s action:%s amount:%s interest:%s" %('liang','tran_type','amount','interest'))
main.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import os,sys BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from core import auth from core import logger from core import accounts from core import transaction from core import db_handler from conf import settings import datetime import time import os # 建立transaction.log 文件 trans_logger=logger.logger('transaction') #建立 access.log 文件 access_logger=logger.logger('access') # 临时账户数据、仅保存在内存中 user_data={ 'account_id':None, 'is_authenticated':False, 'account_data':None } def disp_account_info(account_data): ''' 格式化输出账户信息(管理员可直接使用) #去除 password 字段显示 :param account_data: 账户信息 :return: ''' ignore_display=["password"] for k in account_data: if k in ignore_display: continue else: print("{:<20}:\033[32;1m{:<20}\033[0m".format(k, account_data[k])) def admin_account_info(acc_data): ''' 管理员查看其它用户 :param acc_data: :return: ''' user_id=acc_data["account_id"] account_data=acc_data["account_data"] status=account_data["status"] if status ==8: admin_input_id=input("请输入你需要查询的ID").strip() new_user_info=auth.acc_check(admin_input_id) new_user_status=new_user_info["status"] if new_user_status ==8: if user_id==admin_input_id: disp_account_info(new_user_info) return True else: print("你能查询其它管理员【%s】的信息"%(admin_input_id)) elif new_user_info !=8: disp_account_info(new_user_info) else: exit("非法操作") def account_info(acc_data): ''' 普通用户打印登录用户信息 :param acc_data: 登录信息 :return: ''' # 用户ID account_id=acc_data["account_id"] # account_data=acc_data["account_data"] # status=account_data["status"] # if status !=8: disp_account_info(account_data) return True else: exit("谢谢!!!!!") def get_user_data(): ''' 登录并获取新的user-data :return: ''' account_data=auth.acc_login(user_data,access_logger) if user_data["is_authenticated"]: #此刻就是有数据了 user_data["account_data"]=account_data # 返回最新用户数据 return user_data else: return None def pay(amount): ''' 消费付款 :param amount: 付款金额 :return: ''' #用户数据 acc_data=get_user_data() account_data=accounts.load_current_balance(acc_data['account_id']) if amount>0: # new_balance 是用户的最新数据。有两个结果 。一个是None 一个是用户数据 new_balance=transaction.make_transaction(trans_logger,account_data,'pay',amount) if new_balance: return True # 小于0 else: print("你输入的金额需要大于0%s"%amount) return None def repay(acc_data): ''' 还款 :param acc_data: :return: ''' print(acc_data) account_data = accounts.load_current_balance(acc_data['account_id']) current_blance=''' -------- balance info --------- Credit : %s Balance: %s '''%(account_data['credit'],account_data['balance']) print(current_blance) back_flag=False while not back_flag: print("按b退出") # 还款金额 reap_amount=input("请输入你还款的金额:>>").strip() if len(reap_amount) >0 and reap_amount.isdigit(): # new_balance = 用户最新数据 new_balance=transaction.make_transaction(trans_logger,account_data,'repay',reap_amount) time.sleep(0.1) if new_balance: print("你的余额为%s"%(new_balance['balance'])) elif reap_amount =='b': back_flag=True else: print("输入错误。请从新输入!!!!%s"%(reap_amount)) def withdraw2(acc_data): ''' 提款 :param acc_data: :return: ''' # 用户最新数据 account_data=accounts.load_current_balance(acc_data['account_id']) current_blance=''' -------- balance info --------- Credit : %s Balance: %s '''%(account_data['credit'],account_data['balance']) print(current_blance) back_flag=False while not back_flag: print("输入b 跳出") withdrwa_amount=input("请输入提款金额:>>>").strip() if len(withdrwa_amount)>0 and withdrwa_amount.isdigit(): new_balance2=transaction.make_transaction(transaction,account_data,'withdraw',withdrwa_amount) time.sleep(0.1) if new_balance2: print("你剩余的余额%s" %new_balance2['balance']) elif withdrwa_amount=='b': back_flag=True else: print("你输入错误!!!%s"%withdrwa_amount) def withdraw(acc_data): ''' 提款 print current balance and let user do the withdraw action :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: print("Tip: [b] to back") # 输入还款金额 withdraw_amount = input("\033[33;1mInput withdraw amount:\033[0m").strip() # 长度大于0 并且是数字 if len(withdraw_amount) > 0 and withdraw_amount.isdigit(): #返回用户最新的数据 new_balance = transaction.make_transaction(trans_logger, account_data, 'withdraw', withdraw_amount) time.sleep(0.1) # 处理显示问题 # 如果有数据, 就显示现有的账目 if new_balance: print('''\033[42;1mNew Balance:%s\033[0m''' % (new_balance['balance'])) elif withdraw_amount == 'b': back_flag = True elif withdraw_amount == 'q' and withdraw_amount == 'exit': exit("谢谢下次再来") break else: print('[\033[31;1m%s\033[0m] is not a valid amount, only accept integer!' % withdraw_amount) def transfer(acc_data): ''' 打印出当前余额 并转钱 :param acc_data: :return: ''' # 用户最近数据 account_data=accounts.load_current_balance(acc_data['account_id']) #显示用户的额度 current_blance=''' -------- balance info --------- Credit : %s Balance: %s '''%(account_data['credit'],account_data['balance']) print(current_blance) back_flag=False while not back_flag: #输入转给谁 .不能转给自己 recevier=input("输入你需要转钱的用户:>>>>").strip() if str(recevier)==str(account_data["id"]): print("不能转给自己") continue elif recevier=='b': back_flag=True else: #检查是否有这个ID receiver_account_data=auth.acc_check(recevier) #判断这个Id 是否过期和是不是普通用户 status=receiver_account_data["status"] print(status) if status ==0: # 如果等于0就让他输入金额 transfer_amount=input("输入你需要转的金额:>>") if len(transfer_amount) >0 and transfer_amount.isdigit(): new_blance=transaction.make_transaction(trans_logger,account_data,'transfer',transfer_amount) transaction.make_transaction(trans_logger,receiver_account_data,'receive',transfer_amount) if new_blance: time.sleep(0.2) print("转钱成功!!!") else: print("请输入大于0的金额!!!!") if transfer_amount=='b': back_flag=True else: print("不能转为其他人") def pay_check(acc_data): ''' 查询账单详情 :param acc_data: :return: ''' bill_data=input("请输入你需要查询的年月份 例如[2018-01]:>>>>").strip() log_path=db_handler.db_handler(settings.DATABASE) bill_log="%s/%s.bills" %(log_path,acc_data["account_id"]) if not os.path.exists(bill_log): print("没有记录用户[%s]"%acc_data["account_id"]) return print("请输入你需要查询的ID %s"%acc_data["account_id"]) print("-".center(50,'#')) with open(bill_data,'r') as f: for bill in f: print(bill) b_data=bill.split(" ")[0] if bill_data==b_data: print("%s"%bill.strip()) log_type="transactions" print("%s" %acc_data["account_id"]) logger.show_log(acc_data["account_id"],log_type,bill_data) def save(acc_data): ''' 存钱 :param acc_data: :return: ''' account_data=accounts.load_current_balance(acc_data["account_id"]) print(account_data) current_balance = ''' --------- BALANCE INFO -------- Credit : %s Balance: %s (Tip: input [b] to back)''' % (account_data['credit'], account_data['balance']) print(current_balance) back_flag=False while not back_flag: # 输入存款金额 save_amount=input("输入你需要存款的金额:>>>").strip() if save_amount == 'b': back_flag = True elif len(save_amount) > 0 and save_amount.isdigit(): new_balance = transaction.make_transaction(trans_logger, account_data, 'save', save_amount) time.sleep(0.1) # 解决日志显示问题 if new_balance: print('''\033[42;1mNew Balance:%s\033[0m''' % (new_balance['balance'])) back_flag = True else: print('[\033[31;1m%s\033[0m] is not a valid amount, only accept integer!' % save_amount) def logout(acc_data): ''' 清除认证信息、退出 :param acc_data: :return: ''' exit("谢谢!!!!".center(50,'#')) def interactive(acc_data): ''' 普通用户界面 :param acc_data: :return: ''' status=acc_data["account_data"]["status"] if status==8: print("管理员不能查看!!%s"%acc_data["account_id"]) menu=u''' ----------- user bank ------------ 1. 账户信息 2. 还款 3. 取款 4. 转账 5. 存款 6. 账单 7. 退出 ''' menu_dic={ '1':account_info, '2':repay, '3':withdraw, '4':transfer, '5':save, '6':pay_check, '7':logout, } exit_flag=False while not exit_flag: print(menu) user_option=input(":>>>").strip() if user_option in menu_dic: #print(acc_data) menu_dic[user_option](acc_data) else: print("输入错误!!! ") def get_bill(account_id): ''' 生成账单 、定义每月25 日 :param account_id: :return: ''' #当前时间 i = datetime.datetime.now() year_month="%s-%s" %(i.year,i.month) account_data=accounts.load_current_balance(account_id) balance=account_data["balance"]# 可用额度 credit=account_data["credit"] if i.day !=settings.BILL_DAY: print("\033[31;1mToday is not the bill generation day!\033[0m") if balance>=credit: repay_amount=0 bill_info="Account [\033[32;1m%s\033[0m] needn't to repay." %account_id else: repay_amount=credit-balance bill_info="Account [\033[32;1m%s\033[0m] need to repay [\033[33;1m%s\033[0m]" \ % (account_id, repay_amount) print(bill_info) log_path=db_handler.db_handler(settings.LOG_DATABASE) bill_log="%s/%s.bills" %(log_path,account_data["account_id"]) with open(bill_log,'a+') as f: f.write("bill_date: %s account_id: %s need_repay: %d\n" % (year_month, account_id, repay_amount)) def get_all_bill(): db_path=db_handler.db_handler(settings.DATABASE) for root, dirs , files in os.walk(db_path): for file in files: #分割出来结尾的文件 if os.path.splitext(file)[1] =='json': account_id=os.path.splitext(file)[0] # 账户id #检查这个账户 account_data=auth.acc_check(account_id) status=account_data['status'] print("Account bill:".center(50,'=')) #除了管理员其他人都应该出账单 if status !=8: disp_account_info(account_data)#显示账户详情 get_bill(account_id) print("End".center(50,'-')) return True def chenk_admin(func): ''' 检查是否是管理员 :param func: :return: ''' def inner(*args,**kwargs): if user_data['account_data'].get('status',None)==8: ret=func(*args,**kwargs) return ret else: print("不是管理员") return inner def manage_func(acc_data): ''' 管理员功能 :param acc_data: :return: ''' menu = u''' ------- Admin erea ---------\033[32;1m 1. 添加账户 2. 查询用户信息 3. 用户信息修改(冻结帐户、用户信用卡额度等) 4. 生成全部用户帐单 5. 退出 \033[0m''' menu_dic={ '1':'auth.sign_up()', '2':'account_info(acc_data)', '3':'auth.modify()', '4':'get_all_bill()', '5':'logout(acc_data)', } go_flag=True while go_flag: print(menu) user_option=input(":>>").strip() if user_option in menu_dic.keys(): go_flag=eval(menu_dic[user_option]) else: print("\033[31;1mOption does not exist!\033[0m") def run(): ''' 这个是普通用户运行的界面 :return: ''' print("Welocome to ATM ".center(50,'#')) user_data=get_user_data() interactive(user_data) def admin_run(): print(" ATM admin manager".center(50,'#')) user_data=get_user_data() manage_func(user_data)
admin_user.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import os import sys base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(base_dir) from core import main if __name__ == '__main__': main.admin_run() # 管理员账户 admin 密码 abc
atm_user.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author: liang import os import sys base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(base_dir) from core import main if __name__ == '__main__': main.run() # 普通用户 liang 密码 123456
文件的存储位置如以下图片:
测试如下:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python36.exe G:/python/ATM2/bin/atm_user.py
#################Welocome to ATM #################
请输入用户名:liang
请输入密码123456
----------- user bank ------------
1. 账户信息
2. 还款
3. 取款
4. 转账
5. 存款
6. 账单
7. 退出
:>>>1
enroll_date :2018-01-31
id :liang
credit :15000
balance :1888888888737010.2
status :0
expire_date :2023-01-30
pay_day :22
----------- user bank ------------
1. 账户信息
2. 还款
3. 取款
4. 转账
5. 存款
6. 账单
7. 退出
:>>>2
{'account_id': 'liang', 'is_authenticated': True, 'account_data': {'enroll_date': '2018-01-31', 'password': '123456', 'id': 'liang', 'credit': 15000, 'balance': 1888888888737010.2, 'status': 0, 'expire_date': '2023-01-30', 'pay_day': 22}}
-------- balance info ---------
Credit : 15000
Balance: 1888888888737010.2
按b退出
请输入你还款的金额:>>10
2018-01-31 15:41:35,310 - transaction - INFO - account:liang action:repay amount:10.0 interest:0.0
你的余额为1888888888737020.2
按b退出
请输入你还款的金额:>>b
----------- user bank ------------
1. 账户信息
2. 还款
3. 取款
4. 转账
5. 存款
6. 账单
7. 退出
:>>>4
-------- balance info ---------
Credit : 15000
Balance: 1888888888737020.2
输入你需要转钱的用户:>>>>admin
8
不能转为其他人
输入你需要转钱的用户:>>>>liang
不能转给自己
输入你需要转钱的用户:>>>>liang2
0
输入你需要转的金额:>>1000
2018-01-31 15:42:21,639 - transaction - INFO - account:liang action:transfer amount:1000.0 interest:50.0
2018-01-31 15:42:21,639 - transaction - INFO - account:liang2 action:receive amount:1000.0 interest:0.0
转钱成功!!!
输入你需要转钱的用户:>>>>