先说最重要的地方,怕忘记在把各个模块做完后记得在最外面的文件夹下,鼠标点击右键找到以下图片上的东西点击,不然程序不能运行
day6 #ATM主程目录
├── __init__.py
├── acc_operation #用户选择命令操作
│ ├── __init__.py
│ ├── main_interface.py #主要的操作执行程序
├── atm #ATM 执行文件 目录
│ ├── __init__.py
│ ├── atm.py #ATM 执行程序
│
├── conf #配置文件
│ ├── __init__.py
│ └── settings.py
├── core #主要程序逻辑都 在这个目录 里
│ ├── __init__.py
│ ├── account.py #用于从文件里加载和存储账户数据
│ ├── auth.py #用户认证模块
│ ├── db_handler.py #数据库连接引擎
│ ├── logger.py #日志记录模块
│ ├── main.py #主逻辑交互程序
│ └── transaction.py #记账\还钱\取钱等所有的与账户金额相关的操作都 在这
├── db #用户数据存储的地方
│ ├── __init__.py
│ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
│ └── accounts #存各个用户的账户数据 ,一个用户一个文件
│ └── zhou.json #一个用户账户示例文件
└── log #日志目录
├── __init__.py
├── access.log #用户访问和操作的相关日志
└── transactions.log #所有的交易日志
main_interface
from core import account
from core import logger
from core import transaction
from conf import settings
user_data = {
'account_id': None,
'is_authenticated': False,
'account_data': None
}
trans_logger = logger.logger('transaction')
access_logger = logger.logger('access')
def account_info(acc_data):
print(acc_data)
def repay(acc_data):
account_data = account.load_current_balance(acc_data['id'])
current_balace = '''
----------INFO----------
Credit : %s
Balance : %s
''' % (account_data['credit'], account_data['balance'])
print(current_balace)
back_flag = False
while not back_flag:
repay_amount = input("\033[033;1mInput repay amount(b = break):\033[0m").strip()
if len(repay_amount) > 0 and repay_amount.isdigit():
print(repay_amount)
new_balance = transaction.make_transaction(trans_logger, account_data, 'repay', repay_amount)
if new_balance:
print('''\033[42;1mNew Balance:%s\033[0m''' % (new_balance['balance']))
else:
print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % repay_amount)
if repay_amount == 'b':
back_flag = True
def withdraw(acc_data):
account_data = account.load_current_balance(acc_data['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 amount(b = break):\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[42;1mNew Balance:%s\033[0m''' % (new_balance['balance']))
else:
print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % withdraw_amount)
if withdraw_amount == 'b':
back_flag = True
def transfer(acc_data):
'''
转账
:param acc_data:
:return:
'''
account_data = account.load_current_balance(acc_data['id'])
current_balance = '''
---------------INFO----------------
Credit :%s
Balance :%s
''' % (account_data['credit'], account_data['balance'])
back_flag = False
transfer_ccount = input("\033[31;1mInput transfer account").strip()
transfer_amount_info = account.load_current_balance(transfer_ccount)
while not back_flag:
print(current_balance)
transfer_amount = input("\033[31;1mInput transfer amount (b = break)").strip()
if len(transfer_amount) > 0 and transfer_amount.isdigit():
# transfer_account_data = new_account_data
new_account_data = transaction.make_transaction(trans_logger, account_data, 'transfer', transfer_amount)
if new_account_data:
print("\033[42;1mNew Balance:%s\033[0m" % new_account_data['balance'])
new_account_data2 = transaction.make_transaction(trans_logger, transfer_amount_info, 'repay', transfer_amount)
if new_account_data2:
print("\033[42;1mNew Balance2:%s\033[0m" % new_account_data2["balance"])
else:
print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % transfer_amount)
if transfer_amount == "b" or transfer_amount == "back":
back_flag = True
def paycheck(acc_data):
time = input('Please input time (Y-M-D) : ').strip()
log_file = "%s/log%s" % (settings.BASE_DIR, settings.LOG_TYPES['transaction'])
print(log_file)
with open(log_file, 'r', encoding='utf-8')as f:
for count in f.readlines():
if time == count[0:10]:
print(count)
elif time == count[0:7]:
print(count)
elif time == count[0:4]:
print(count)
def logout(acc_data):
q = input("if you want to quit, please input q")
if q == 'q':
exit()
def shopping(acc_data):
product_list ={
('Iphone', 60000),
('Watch', 4600),
('Books', 200),
('Bike', 50),
('Banana', 1),
('GaoDaModel', 150)
}
shopping_list = []
salary = acc_data['balance']
while not False:
for index, item in enumerate(product_list):
print(index, item)
user_choice = input('Enter the serial number(b=break)').strip()
if user_choice.isdigit():
user_choice = int(user_choice)
if user_choice = 0:
p_item = product_list[user_choice]
if p_item[1] <= salary:
shopping_list.append(p_item)
salary -= p_item[1]
transaction.make_transaction(access_logger, 'consume', acc_data, p_item[1])
else:
print("You balance is not enough")
else:
print("The goods you entered do not exit")
elif user_choice == 'b':
print("-------shopping list---------")
for goods in shopping_list:
print(goods)
print("Your current balance is %s" % salary)
exit()
else:
print("Invalid option")
def interactive(acc_data):
menu = u'''
\033[32;1m
1. 账户信息
2. 还款
3. 取款
4. 转账
5. 账单
6. 进入商城
7. 退出
\033[0m
'''
menu_dic = {
'1': account_info,
'2': repay,
'3': withdraw,
'4': transfer,
'5': paycheck,
'6': shopping,
'7': logout,
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input("please elect number:").strip()
if user_option in menu_dic:
print('acc_data', acc_data)
menu_dic[user_option](acc_data)
atm函数入口
import os
import sys
from core import main
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
if __name__ == '__main__':
main.run()
conf配置模块
import os
import logging
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATABASE = {
'engine': 'file_storage', #support mysql,postgresql in the future
'name': 'accounts',
'path': "%s/db" % BASE_DIR
}
LOG_LEVEL = logging.INFO
LOG_TYPES = {
'transaction': 'transactions.log',
'access': 'access.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各个模块
account
import json
import time
from core import db_handler
from conf import settings
def load_current_balance(account_id):
db_api = db_handler.db_handler()
data = db_api("select * from accounts where account=%s" % account_id)
return data
def dump_account(account_data):
db_api = db_handler.db_handler()
data = db_api("update accounts where account=%s" % account_data['id'], account_data=account_data)
return True
auth
import os
from core import db_handler
from conf import settings
from core import logger
import json
import time
acc_dic = {
'id': 1234,
'password': 'abc',
'credit': 15000,
'balance': 15000,
'enroll_date': '2016-01-02',
'expire_date': '2021-01-01',
'pay_day': 22,
'status': 0 # 0 = normal, 1 = locked, 2 = disabled
}
def user_login(name, password, log):
acc_dic['id'] = name
acc_dic['password'] = password
value = settings.DATABASE
db_path = '%s/%s' % (value['path'], value['name'])
# print(db_path)
account_file = '%s/%s.json' % (db_path, name)
# content = "%s.json" % name
print(account_file)
if os.path.isdir(db_path):
if os.path.isfile(account_file):
print("\033[31;lm Account is exist!\033[0m")
else:
with open(account_file, 'w', encoding='utf-8')as f:
acc_data = json.dump(acc_dic, f)
log.info("%s registration is successful " % acc_dic['id'])
return acc_data
else:
os.mkdir(db_path)
with open(account_file, 'w', encoding='utf-8')as f:
acc_data = json.dump(acc_dic, f)
log.info("%s registration is successful " % acc_dic['id'])
return acc_data
def acc_auth2(account, password):
'''
优化版认证接口
:param account: credit account number
:param password: credit card password
:return: if passed the authentication , retun the account object, otherwise ,return None
'''
db_api = db_handler.db_handler()
data = db_api("select * from accounts where account=%s" % account)
if data['password'] == password:
exp_time_stamp = time.mktime(time.strptime(data['expire_date'], "%Y-%m-%d"))
if time.time() > exp_time_stamp:
print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account)
else: # passed the authentication
return data
else:
print("\033[31;1mAccount ID or password is incorrect!\033[0m")
def acc_login(user_data, log_obj):
retry_count = 0
while user_data['is_authenticated'] is not True and retry_count < 3:
account = input("\033[32;1maccount:\033[0m").strip()
password = input("\033[32;1mpassword:\033[0m").strip()
auth = acc_auth2(account, password)
if auth: # not None means passed the authentication
user_data['is_authenticated'] = True
user_data['account_id'] = account
# user_data['account_data'] = auth
print("welcome")
return auth
retry_count += 1
print("Wrong username or password")
else:
log_obj.error("account [%s] too many login attempts" % account)
exit()
db_handler
import json
import time
import os
from conf import settings
def file_db_handle(conn_params):
'''
parse the db file path
:param conn_params: the db connection params set in settings
:return:
'''
print('file db:', conn_params)
return file_execute
def db_handler():
'''
connect to db
:param conn_parms: the db connection params set in settings
:return:a
'''
conn_params = settings.DATABASE
if conn_params['engine'] == 'file_storage':
return file_db_handle(conn_params)
elif conn_params['engine'] == 'mysql':
pass
def file_execute(sql, **kwargs):
conn_params = settings.DATABASE
db_path = '%s/%s' % (conn_params['path'], conn_params['name'])
sql_list = sql.split("where")
if sql_list[0].startswith("select") and len(sql_list) > 1: # has where clause
column, val = sql_list[1].strip().split("=")
if column == 'account':
account_file = "%s/%s.json" % (db_path, val)
if os.path.isfile(account_file):
with open(account_file, 'r') as f:
account_data = json.load(f)
return account_data
else:
exit("\033[31;1mAccount [%s] does not exist!\033[0m" % val)
elif sql_list[0].startswith("update") and len(sql_list) > 1: # has where clause
column, val = sql_list[1].strip().split("=")
if column == 'account':
account_file = "%s/%s.json" % (db_path, val)
if os.path.isfile(account_file):
account_data = kwargs.get("account_data")
with open(account_file, 'w') as f:
acc_data = json.dump(account_data, f)
return True
logger
import logging
from conf import settings
def logger(log_type):
#create logger
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_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOG_TYPES[log_type])
print(log_file)
fh = logging.FileHandler(log_file)
fh.setLevel(settings.LOG_LEVEL)
# create formatter
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')'''
main
from core import auth
from core import logger
from acc_operation import main_interface
trans_logger = logger.logger('transaction')
access_logger = logger.logger('access')
user_data = {
'account_id': None,
'is_authenticated': False,
'account_data': None
}
def account_info(acc_data):
print(acc_data)
def run():
while True:
msg = u'''
--------------INFO--------------
\033[31;1m1.registered\033[0m
\033[31;1m2.login\033[0m
'''
print(msg)
user_choose = input("请输入:").strip()
if user_choose == '1':
name = input("\033[31;1m请输入姓名\033[0m").strip()
pwd = input("\033[31;1m请输入密码\033[0m").strip()
auth.user_login(name, pwd, access_logger)
print("success")
elif user_choose == '2':
acc_data = auth.acc_login(user_data, access_logger)
print("\033[31;1mvaregaergg\033[0m")
if user_data['is_authenticated']:
user_data['account_data'] = acc_data
account_info(acc_data)
main_interface.interactive(acc_data)
transaction
from conf import settings
from core import account
from core import logger
def make_transaction(log_obj, account_data, tran_type, amount):
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
if new_balance < 0:
print('''\033[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is
[%s]''' % (account_data['credit'], (amount + interest), old_balance))
return
account_data['balance'] = new_balance
account.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
记录用户信息
log
存储日志