python项目练习之ATM

程序框图 (消费模块暂未写入)

 bin:程序执行


 1 import os
 2 import sys
 3 base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 4 print(base_dir)
 5 sys.path.append(base_dir)
 6 
 7 from core import main
 8 
 9 
10 if __name__ == '__main__':   #当作为脚本直接运行的时候,此时__name__等于__main__,当作为模块导入的时候,__name__为文件名但不带.py,故不运行if后语句。
11     main.run()
atm.py

config:配置文件


 1 import os
 2 import sys
 3 import logging
 4 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 5 
 6 
 7 DATABASE = {
 8     'engine': 'file_storage', #support mysql,postgresql in the future
 9     'name':'accounts',
10     'path': "%s/db" % BASE_DIR
11 }
12 
13 
14 LOG_LEVEL = logging.INFO
15 LOG_TYPES = {
16     'transaction': 'transactions.log',
17     'access': 'access.log',
18     '11111':'11111.log'
19 }
20 
21 TRANSACTION_TYPE = {
22     'repay':{'action':'plus', 'interest':0},
23     'withdraw':{'action':'minus', 'interest':0.05},
24     'transfer':{'action':'minus', 'interest':0.05},
25     'consume':{'action':'minus', 'interest':0},
26 }
settings

core:程序主要代码


 1 import json
 2 import time
 3 from core import db_handler
 4 from conf import settings
 5 
 6 
 7 def load_current_balance(account_id):
 8     '''
 9     return account balance and other basic info
10     :param account_id:
11     :return:
12     '''
13     db_path = db_handler.db_handler(settings.DATABASE)
14     account_file = "%s/%s.json" %(db_path,account_id)
15     with open(account_file) as f:
16         acc_data = json.load(f)
17         return  acc_data
18 def dump_account(account_data):
19     '''
20     after updated transaction or account data , dump it back to file db
21     :param account_data:
22     :return:
23     '''
24     db_path = db_handler.db_handler(settings.DATABASE)
25     account_file = "%s/%s.json" %(db_path,account_data['id'])
26     with open(account_file, 'w') as f:
27         acc_data = json.dump(account_data,f)
28 
29     return True
accounts
 1 import os
 2 from core import db_handler
 3 from conf import settings
 4 from core import logger
 5 import json
 6 import time
 7 
 8 def acc_auth(account,password):
 9     '''
10     account auth func
11     :param account: credit account number
12     :param password: credit card password
13     :return: if passed the authentication , retun the account object, otherwise ,return None
14     '''
15     db_path = db_handler.db_handler(settings.DATABASE)
16     account_file = "%s/%s.json" %(db_path,account)
17     print(account_file)  #base_dir + accounts + account.json
18     if os.path.isfile(account_file):   #判断文件名是否存在,存在执行下面语句
19         with open(account_file,'r') as f:
20             account_data = json.load(f)
21             if account_data['password'] == password:
22                 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))
23                 if time.time() >exp_time_stamp:
24                     print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account)
25                 else: #passed the authentication
26                     return  account_data
27             else:
28                 print("\033[31;1mAccount ID or password is incorrect!\033[0m")
29     else:
30         print("\033[31;1mAccount [%s] does not exist!\033[0m" % account)
31 
32 def acc_login(user_data,log_obj):
33     '''
34     account login func
35     :user_data: user info data , only saves in memory
36     :return:
37     '''
38     retry_count = 0
39     while user_data['is_authenticated'] is not True and retry_count < 3 :
40         account = input("\033[32;1maccount:\033[0m").strip()
41         password = input("\033[32;1mpassword:\033[0m").strip()
42         auth = acc_auth(account, password)
43         if auth: #not None means passed the authentication
44             user_data['is_authenticated'] = True
45             user_data['account_id'] = account
46             #print("welcome")
47             return auth
48         retry_count +=1
49     else:
50         log_obj.error("account [%s] too many login attempts" % account)
51         exit()
登陆认证
 1 def file_db_handle(conn_params):
 2     '''
 3     parse the db file path
 4     :param conn_params: the db connection params set in settings
 5     :return:
 6     '''
 7     print('file db:',conn_params)
 8     db_path ='%s/%s' %(conn_params['path'],conn_params['name'])
 9     return db_path
10 
11 def mysql_db_handle(conn_parms):
12     pass
13 def db_handler(conn_parms):
14     '''
15     connect to db
16     :param conn_parms: the db connection params set in settings
17     :return:a
18     '''
19 
20     if conn_parms['engine'] == 'file_storage':
21         return file_db_handle(conn_parms)
22 
23     if conn_parms['engine'] == 'mysql':
24         return mysql_db_handle(conn_parms)
数据存储路径
 1 import logging
 2 from conf import settings
 3 
 4 def logger(log_type):
 5 
 6     #create logger
 7     logger = logging.getLogger(log_type)
 8     logger.setLevel(settings.LOG_LEVEL)
 9 
10 
11     # create console handler and set level to debug
12     ch = logging.StreamHandler()
13     ch.setLevel(settings.LOG_LEVEL)
14 
15     # create file handler and set level to warning
16     log_file = "%s/log/%s" %(settings.BASE_DIR, settings.LOG_TYPES[log_type])
17     fh = logging.FileHandler(log_file)
18     fh.setLevel(settings.LOG_LEVEL)
19     # create formatter
20     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
21 
22     # add formatter to ch and fh
23     ch.setFormatter(formatter)
24     fh.setFormatter(formatter)
25 
26     # add ch and fh to logger
27     logger.addHandler(ch)
28     logger.addHandler(fh)
29 
30     return logger
日志
  1 from core import auth
  2 from core import accounts
  3 from core import logger
  4 from core import accounts
  5 from core import transaction
  6 import time
  7 
  8 #transaction logger
  9 trans_logger = logger.logger('transaction')
 10 #access logger
 11 access_logger = logger.logger('access')
 12 
 13 
 14 #temp account data ,only saves the data in memory
 15 user_data = {
 16     'account_id':None,
 17     'is_authenticated':False,
 18     'account_data':None
 19 
 20 }
 21 
 22 def account_info(acc_data):
 23     print(user_data)
 24 def repay(acc_data):
 25     '''
 26     print current balance and let user repay the bill
 27     :return:
 28     '''
 29     account_data = accounts.load_current_balance(acc_data['account_id'])  #获取用户id,就是要用实时的最新数据,为了安全
 30     #for k,v in account_data.items():
 31     #    print(k,v )
 32     current_balance= ''' --------- BALANCE INFO --------
 33         Credit :    %s
 34         Balance:    %s''' %(account_data['credit'],account_data['balance'])
 35     print(current_balance)
 36     back_flag = False
 37     while not back_flag:
 38         repay_amount = input("\033[33;1mInput repay amount:\033[0m").strip()
 39         if len(repay_amount) >0 and repay_amount.isdigit():
 40             #print('ddd 00')
 41             new_balance = transaction.make_transaction(trans_logger,account_data,'repay', repay_amount)
 42             if new_balance:
 43                 print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
 44 
 45         else:
 46             print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % repay_amount)
 47 
 48         if repay_amount == 'b':
 49             back_flag = True
 50 def withdraw(acc_data):
 51     '''
 52     print current balance and let user do the withdraw action
 53     :param acc_data:
 54     :return:
 55     '''
 56     account_data = accounts.load_current_balance(acc_data['account_id'])
 57     current_balance= ''' --------- BALANCE INFO --------
 58         Credit :    %s
 59         Balance:    %s''' %(account_data['credit'],account_data['balance'])
 60     print(current_balance)
 61     back_flag = False
 62     while not back_flag:
 63         withdraw_amount = input("\033[33;1mInput withdraw amount:\033[0m").strip()
 64         if len(withdraw_amount) >0 and withdraw_amount.isdigit():
 65             new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount)  # new_balance就是 函数返回值 acount_data
 66             if new_balance:
 67                 print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
 68 
 69         else:
 70             print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % withdraw_amount)
 71 
 72         if withdraw_amount == 'b':
 73             back_flag = True
 74 
 75 def transfer(acc_data):
 76     pass
 77 def pay_check(acc_data):
 78     pass
 79 def logout(acc_data):
 80     pass
 81 def interactive(acc_data):
 82     '''
 83     interact with user
 84     :return:
 85     '''
 86     menu = u'''
 87     ------- Oldboy Bank ---------
 88     \033[32;1m1.  账户信息
 89     2.  还款(功能已实现)
 90     3.  取款(功能已实现)
 91     4.  转账
 92     5.  账单
 93     6.  退出
 94     \033[0m'''
 95     menu_dic = {
 96         '1': account_info,
 97         '2': repay,
 98         '3': withdraw,
 99         '4': transfer,
100         '5': pay_check,
101         '6': logout,
102     }
103     exit_flag = False
104     while not exit_flag:
105         print(menu)
106         user_option = input(">>:").strip()
107         if user_option in menu_dic:
108             menu_dic[user_option](acc_data)  #比如选择了2 ,则运行 repay(acc_data),调用repay函数
109 
110         else:
111             print("\033[31;1mOption does not exist!\033[0m")
112 def run():
113     '''
114     this function will be called right a way when the program started, here handles the user interaction stuff
115     :return:
116     '''
117     acc_data = auth.acc_login(user_data,access_logger)   #userdata作为条件,access_logger作为日志信息传入
118     if user_data['is_authenticated']:
119         user_data['account_data'] = acc_data  #acc_data 即是用户信息 1234.json
120         interactive(user_data) #交互
主程序
 1 from conf import settings
 2 from core import accounts
 3 from core import logger
 4 #transaction logger
 5 
 6 
 7 def make_transaction(log_obj,account_data,tran_type,amount,**others):
 8     '''
 9     deal all the user transactions
10     :param account_data: user account data
11     :param tran_type: transaction type
12     :param amount: transaction amount
13     :param others: mainly for logging usage
14     :return:
15     '''
16     amount = float(amount)
17     if tran_type in  settings.TRANSACTION_TYPE:
18 
19         interest =  amount * settings.TRANSACTION_TYPE[tran_type]['interest']
20         old_balance = account_data['balance']
21         if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':
22             new_balance = old_balance + amount + interest
23         elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':
24             new_balance = old_balance - amount - interest
25             #check credit
26             if  new_balance <0:
27                 print('''\033[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is
28                 [%s]''' %(account_data['credit'],(amount + interest), old_balance ))
29                 return
30         account_data['balance'] = new_balance
31         accounts.dump_account(account_data) #save the new balance back to file
32         log_obj.info("account:%s   action:%s    amount:%s   interest:%s" %
33                           (account_data['id'], tran_type, amount,interest) )
34         return account_data
35     else:
36         print("\033[31;1mTransaction type [%s] is not exist!\033[0m" % tran_type)
交易种类

db:用户信息存储


1 {"id": "gkx", "password": "123", "credit": 15000, "balance": 15000, "enroll_date": "2016-01-02", "expire_date": "2021-01-01", "pay_day": 22, "status": 0}
View Code

猜你喜欢

转载自www.cnblogs.com/gkx0731/p/9496301.html
今日推荐