作业需求
- 指定最大透支额度
- 可取款
- 定期还款(每月指定日期还款,如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 完整的路径是 ATMdbaccounts 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) # 这个数据的目录 ATMdbaccounts 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 [ 33[31;1m%s 33[0m] is not enough for this transaction [-%s], your current balance is [ 33[32;1m%s 33[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("