作业:ATM

作业题目: 模拟实现一个ATM + 购物商城程序
1、额度 15000或自定义 2、实现购物商城,买东西加入 购物车,调用信用卡接口结账 3、可以提现,手续费5% 4、支持多账户登录 5、支持账户间转账 6、记录每月日常消费流水 7、提供还款接口 8、ATM记录操作日志 9、提供管理接口,包括添加账户、用户额度,冻结账户等。。。 10、用户认证用装饰器
流程图:


代码目录结构图:

atm
│ ATM.pdf
│ main_server.py --  程序入口
│ README
│ __init__.py


├─config
│ │ setting.py ---- 配置文件
│ │ __init__.py
│ │
│ └─__pycache__
│ setting.cpython-36.pyc
│ __init__.cpython-36.pyc

├─core
│ │ admin.py -- 后台管理
│ │ ATM_operation.py --- ATM操作
│ │ auth.py --- 账户验证
│ │ db_handler.py --- 文件操作
│ │ loggers.py --- 日志
│ │ main.py ---主程序入口
│ │ make.py ---  交易中心
│ │ shopping.py --- 购物商城
│ │ __init__.py
│ │
│ └─__pycache__
│ admin.cpython-36.pyc
│ ATM_operation.cpython-36.pyc
│ auth.cpython-36.pyc
│ db_handler.cpython-36.pyc
│ loggers.cpython-36.pyc
│ main.cpython-36.pyc
│ make.cpython-36.pyc
│ shopping.cpython-36.pyc
│ __init__.cpython-36.pyc



├─db
│ │ __init__.py
│ │
│ └─accounts --- 账户文件
│ 12.json
│ 123.json
│ 1234.json
│ 14.json
│ admin.json
│ __init__.py

├─log
│ │ access.log --- 普通用户操作日志
│ │ admin.log --- 管理员操作日志
│ │ shopping.log ---- 消费日志
│ │ transaction.log ---- 交易日志
│ │ __init__.py
│ │
│ └─__pycache__
│ __init__.cpython-36.pyc

└─shopp
│ __init__.py

└─__pycache__
__init__.cpython-36.pyc

main_server.py --  程序入口

1 import os,sys
2 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
3 sys.path.append(BASE_DIR)
4 if __name__ == '__main__':
5     from core import main
6     main.entrance()

main.py ---主程序入口

 1 from .auth import authentication
 2 from .loggers import logger_log
 3 from.ATM_operation import with_draw
 4 from .ATM_operation import transfer
 5 from .ATM_operation import pay_back
 6 from .ATM_operation import view_account_info
 7 from .shopping import shoppings
 8 from .admin import admin_load
 9 from .db_handler import load_account
10 from .db_handler import save_db
11 
12 access_logger = logger_log('access')
13 transaction_logger = logger_log('transaction')
14 
15 
16 info = [
17         ('查看账户信息',view_account_info),
18         ('转账',transfer),
19         ('还款',pay_back),
20         ('取现',with_draw),
21         ('购物商城',shoppings),
22         ('后台管理',admin_load)
23     ]
24 
25 def conroller(use_boj):
26     '功能分发器'
27     while True:
28         for i,v in enumerate(info):
29             print(i,v[0])
30         choice = input('请输入您的选择:').strip()
31         if not choice:continue
32         if choice.isdigit():
33             choice = int(choice)
34             if choice < len(info) and choice >= 0:
35                 info[choice][1](use_boj,transaction_logger=transaction_logger,access_logger=access_logger)
36 def entrance():
37     '程序入口'
38     user_obj = {
39         'is_authentication':False,
40         'data':None
41     }
42     retry_count = 0
43     while user_obj['is_authentication'] is not True:
44         account = input('请输入账号:').strip()
45         password = input('请输入密码:').strip()
46         auth_data = authentication(account,password)
47         if  auth_data:
48             user_obj['is_authentication'] = True
49             user_obj['data'] = auth_data
50             print('欢迎登陆'.center(50,'*'))
51             access_logger.info('%s已登陆'%user_obj['data']['id'])
52             conroller(user_obj)
53         else:
54             print('账号密码错误!')
55         retry_count += 1
56         if retry_count == 3:
57             msg = '用户%s已登陆3失败'%account
58             access_logger.error(msg)
59 
60             break
View Code

auth.py  --- 账户验证

 1 from .db_handler import load_account
 2 
 3 def authentication(account,password):
 4     '验证账户'
 5     account_data = load_account(account)
 6     # print(account_data)
 7     if account_data['status'] == 0:
 8         account_data = account_data['data']
 9         if password == account_data['password']:
10             # print(account_data)
11             return account_data
12         else:
13             return None
14     else:
15         return '账户已被锁定!'
16 def auth(fun):
17     def wrapper(*args,**kwargs):
18         if args[0].get('is_authentication'):
19             return fun(*args,**kwargs)
20         else:
21             print('用户不能登陆!')
22     return wrapper
View Code

 db_handler.py --- 文件操作

 1 import json,os
 2 from config import setting
 3 
 4 def load_account(account):
 5     '读取文件'
 6     account_file = os.path.join(setting.BASE_DB,'%s.json'%account)
 7     # print(account_file)
 8     if os.path.isfile(account_file):
 9         f = open(account_file)
10         data = json.load(f)
11         f.close()
12         return {'status':0,'data':data}
13     else:
14         return {'status':-1,'error':'文件不存在'}
15 
16 def save_db(account_data):
17     '保存文件'
18     account_file = os.path.join(setting.BASE_DB,'%s.json'%account_data)
19     print(account_file)
20     if os.path.isfile(account_file):
21         f = open('%s.new'%account_file,'w')
22         data = json.dump(account_data,f)
23         f.close()
24         os.remove(account_file)
25         os.rename('%s.new'%account_file,account_file)
26         return {'status':0,'data':data}
27     else:
28         return {'status':-1,'error':'文件不存在'}
View Code

ATM_operation.py --- ATM操作

 1 from .loggers import logger_log
 2 from .make import make_transfer
 3 from .auth import auth
 4 
 5 def view_account_info(account_data,*args,**kwargs):
 6     '查询账户信息'
 7     # print(account_data)
 8     trans_logger = kwargs.get('transaction_logger')
 9     print('账户个人信息'.center(50,'*'))
10     for k,v in account_data['data'].items():
11         if k not in ('password'):
12             print('%15s:%s'%(k,v))
13     print('END'.center(50,'*'))
14     trans_logger.info('%s查询了账户信息'%account_data['data']['id'])
15 @auth
16 def transfer(account_data,*args,**kwargs):
17     '账户转账'
18     trans_logger = kwargs.get('transaction_logger')
19     print('账户余额'.center(50,'*'))
20     print('credit:%s
'
21           'blance:%s'%(account_data['data']['credit'],account_data['data']['balance']))
22     flag_exit = False
23     while not flag_exit:
24         receiving_account = input('请输入接收账号或按B返回:').strip()
25         transfer_amount = input('请输入转账金额按B返回:').strip()
26         if len(transfer_amount) > 0 and transfer_amount.isdigit():
27             transfer_amount = int(transfer_amount)
28             if (account_data['data']['balance'] / 2) >= transfer_amount:
29                 transaction_result = make_transfer(trans_logger,account_data,'transfer',transfer_amount,
30                                                    receiving_account=receiving_account)
31                 if transaction_result['status'] == 0:
32                     print('成功转账%s元,余额还有%s'%(transfer_amount,account_data['data']['balance']))
33                 else:
34                     print(transaction_result)
35             else:
36                 print('余额不足,可转账%s元'%int(account_data['data']['balance']/2))
37         if receiving_account == 'b'.lower():
38             flag_exit = True
39 @auth
40 def with_draw(account_data,*args,**kwargs):
41     '取现'
42     trans_logger = kwargs.get('transaction_logger')
43     print('账户余额'.center(50,'*'))
44     print('credit:%s
'
45           'blance:%s'%(account_data['data']['credit'],account_data['data']['balance']))
46     flag_exit = False
47     while not flag_exit:
48         withdraw_amount = input('请输入提现的金额或按按B返回:').strip()
49         if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
50             withdraw_amount = int(withdraw_amount)
51             if (account_data['data']['balance'] / 2) >= withdraw_amount:
52                 transaction_result = make_transfer(trans_logger,account_data,'withdraw',withdraw_amount)
53                 if transaction_result['status'] == 0:
54                     print('成功提现%s元,余额还有%s'%(withdraw_amount,account_data['data']['balance']))
55                 else:
56                     print(transaction_result)
57             else:
58                 print('余额不足,可提取%s元'%int(account_data['data']['balance']/2))
59         if withdraw_amount == 'b'.lower():
60             flag_exit = True
61 @auth
62 def pay_back(account_data,*args,**kwargs):
63     '还款'
64     trans_logger = kwargs.get('transaction_logger')
65     print('账户余额'.center(50, '*'))
66     print('credit:%s
'
67           'blance:%s' % (account_data['data']['credit'], account_data['data']['balance']))
68     flag_exit = False
69     while not flag_exit:
70         payback_amount = input('请输入还款的金额按B返回:').strip()
71         if len(payback_amount) > 0 and payback_amount.isdigit():
72             payback_amount = int(payback_amount)
73             transaction_result = make_transfer(trans_logger, account_data, 'repay', payback_amount)
74             if transaction_result['status'] == 0:
75                 print('成功还款%s元,当前余额还有%s' % (payback_amount, account_data['data']['balance']))
76             else:
77                 print(transaction_result)
78         else:
79             print('输入错误,请重新输入!')
80         if payback_amount == 'b'.lower():
81             flag_exit = True
View Code

make.py ---  交易中心

 1 from config import setting
 2 from .db_handler import save_db
 3 from .db_handler import load_account
 4 
 5 
 6 def make_transfer(logger,user_obj,trans_type,amount,**kwargs):
 7     '交易中心,进行账户间的加减'
 8     amount = float(amount)
 9     if trans_type in setting.TRANSACTION_TYPE:
10         interest = amount * setting.TRANSACTION_TYPE[trans_type]['interest']
11         old_balance = user_obj['data']['balance']
12         if setting.TRANSACTION_TYPE[trans_type]['action'] == 'transfer':
13             re_account = load_account(kwargs.get('receiving_account'))
14             re_account_data = re_account['data']['balance']
15             re_account_data_balance = amount + re_account_data + interest
16             new_balance = old_balance - amount - interest
17             re_account['data']['balance'] = re_account_data_balance
18             user_obj['data']['balance'] = new_balance
19             save_db(re_account['data'])
20             save_db(user_obj['data'])
21         elif setting.TRANSACTION_TYPE[trans_type]['action'] == 'plus':
22             new_balance = amount + old_balance + interest
23         elif setting.TRANSACTION_TYPE[trans_type]['action'] == 'minus':
24             new_balance = old_balance - amount - interest
25             if new_balance < 0:
26                 print('对不起,您的信用额度%s对当前的交易是不够的-%s,你当前的信用额度是%s元'%(user_obj['credit'],(amount+interest)
27                                                             ,old_balance))
28                 return {'status':-1,'error':'交易失败,余额不足'}
29         user_obj['data']['balance'] = new_balance
30         save_db(user_obj['data'])
31 
32         logger.info('account:%s action:%s amount:%s interest:%s balance:%s'%
33                     (user_obj['data']['id'],trans_type,amount,interest,new_balance))
34         return {'status':0,'msg':'交易成功'}
35     else:
36         print('对不起,%s交易类型不支持'%trans_type)
37         return {'status':1,'error':'交易失败,不支持的类型%s'%trans_type}
View Code

loggers.py --- 日志

 1 from config import setting
 2 import logging
 3 import os
 4 from logging import handlers
 5 def logger_log(log_type):
 6     log = logging.getLogger(log_type)
 7     log.setLevel(setting.LOG_LEVE)
 8 
 9     file_log = os.path.join(setting.LOG_PATH,setting.LOG_TYPE[log_type])
10     fh = handlers.TimedRotatingFileHandler(file_log,when='D',interval=3,encoding='utf-8')
11     log.addHandler(fh)
12 
13     file = setting.LOG_FORMATTER
14     fh.setFormatter(file)
15     return log
View Code

 shopping.py --- 购物商城

 1 from  .make import make_transfer
 2 from .db_handler import save_db
 3 from .loggers import logger_log
 4 from.auth import auth
 5 
 6 
 7 shopping_logger = logger_log('shopping')
 8 def shoppings(account_data,*args,**kwargs):
 9     trans_logger = kwargs.get('transaction_logger')
10     exit_flag = False
11     goods = [
12         ["电脑",1999],
13         ["鼠标",10],
14         ["游艇", 20],
15         ["美女",  998],
16     ]
17 
18     shopping_list = {}
19     while not exit_flag:
20         print('-----------商品列表-------')
21         for i, v in enumerate(goods):
22             print(i, v)
23 
24         choice = input('请输入商品的编号|q退出|y结账:').strip()
25 
26         if choice.isdigit():
27             choice = int(choice)
28             if choice >= 0 and choice < len(goods):
29                 product = goods[choice]
30 
31                 if product[0] in shopping_list:
32                     shopping_list[product[0]][1] += 1
33                 else:
34                     shopping_list[ product[0] ] =[ product[1],1]
35                     print('%s已成功加入购物车'%product[0])
36 
37         elif choice == 'y'.lower():
38             print('购物车'.center(50,'*'))
39             id_cat = 1
40             total = 0
41             print('id	商品	数量	单价	总价')
42             for key in shopping_list:
43                 print('%s	%s	%s	%s	%s'%(id_cat,
44                       key,
45                       shopping_list[key][1],
46                       shopping_list[key][0],
47                       shopping_list[key][1]*shopping_list[key][0]))
48                 id_cat += 1
49                 total += shopping_list[key][1]*shopping_list[key][0]
50                 buckles_money(account_data, total)
51         elif choice == 'q'.lower():
52             break
53 @auth
54 def buckles_money(account_data,total,*args,**kwargs):
55     settle_acount = input('是否买单|y是|q退出:').strip()
56     if settle_acount == 'y':
57         shopping_data = float(total)
58         print('账户余额'.center(50, '*'))
59         print('credit:%s
'
60               'blance:%s' % (account_data['data']['credit'], account_data['data']['balance']))
61         old_balance = account_data['data']['balance']
62         if shopping_data <= old_balance:
63             new_balance = old_balance - shopping_data
64             print('已购买成功,您总共花了%s元,现在余额是%s元'%(shopping_data,new_balance))
65             exit()
66         else:
67             print('余额不足,您现在的余额是%s元'%new_balance)
68         account_data['data']['balance'] = new_balance
69         save_db(account_data['data'])
70         shopping_logger.info('account:%s consume:%s  balance:%s' %
71                          (account_data['data']['id'], shopping_data, new_balance))
72     elif settle_acount == 'q':
73             exit()
View Code

setting.py ---- 配置文件

 1 import  os,sys
 2 import logging
 3 
 4 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 5 
 6 BASE_DB = "%sdb\accounts"%BASE_DIR
 7 
 8 
 9 LOG_LEVE = logging.INFO
10 
11 LOG_TYPE = {
12     'access':'access.log',
13     'transaction':'transaction.log',
14     'shopping':'shopping.log',
15     'admin':'admin.log'
16 }
17 
18 LOG_FORMATTER =logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
19 LOG_PATH = os.path.join(BASE_DIR,'log')
20 
21 TRANSACTION_TYPE = {
22     'repay':{'action':'plus', 'interest':0},
23     'withdraw':{'action':'minus', 'interest':0.05},
24     'transfer':{'action':'transfer', 'interest':0.05},
25 }
View Code

admin.py -- 后台管理

  1 from config import setting
  2 import os
  3 import json
  4 from .db_handler import save_db
  5 from .loggers import logger_log
  6 
  7 admin_logger = logger_log('admin')
  8 
  9 def add_account(account):
 10     '增加账户'
 11     dic = {
 12         'id':None,
 13         'password':None,
 14         "credit":None,
 15         "balance": None,
 16         "enroll_date":None,
 17         "expire_date": None,
 18         "pay_day": None,
 19         "status": 0
 20     }
 21     account_file = os.path.join(setting.BASE_DB, '%s.json' %account)
 22     print(account_file)
 23     if os.path.isfile(account_file):
 24         print('账户已存在!')
 25     else:
 26         add_id = input('id:').strip()
 27         if add_id.isdigit():
 28             add_id = int(add_id)
 29         add_passwd = input('passwd:').strip()
 30         add_credit = input('credit:').strip()
 31         if add_credit.isdigit():
 32             add_credit = int(add_credit)
 33         balance = input('balance:').strip()
 34         if balance.isdigit():
 35             balance = int(balance)
 36         enroll_date = input('enroll_date:').strip()
 37         expire_date = input('expire_date:').strip()
 38         pay_day = input('pay_day:').strip()
 39         if pay_day.isdigit():
 40             pay_day = int(pay_day)
 41         dic['id'] = add_id
 42         dic['password'] = add_passwd
 43         dic['credit'] = add_credit
 44         dic['balance'] = balance
 45         dic['enroll_date'] = enroll_date
 46         dic['expire_date'] = expire_date
 47         dic['pay_day'] = pay_day
 48         f = open(os.path.join(setting.BASE_DB,'%s.json'%dic['id']),'w')
 49         json.dump(dic,f)
 50         f.close()
 51         print('账户已添加成功!')
 52         admin_logger.info('账户:%s已成功添加,信用额为%s元'%(dic['id'],dic['credit']))
 53 
 54 
 55 def modify_line(account):
 56     '修改信用额度'
 57     account_file = os.listdir(setting.BASE_DB)
 58     modify_file = input('请输入要修改的账号:').strip()
 59     modify_file = '%s.json'%modify_file
 60     for i,v in enumerate(account_file):
 61         if modify_file == v:
 62             f = open(os.path.join(setting.BASE_DB,v),'r')
 63             data = json.load(f)
 64             f.close()
 65             print('当前额度%s元'%data['credit'])
 66             modifyline = input('请输入修改的额度:').strip()
 67             if modifyline.isdigit():
 68                 modifyline = int(modifyline)
 69             data['credit'] = modifyline
 70             save_db(data)
 71             print('已成功修改%s额度,目前信用额度为%s元'%(modify_file,data['credit']))
 72             admin_logger.info('已成功修改账户:%s额度,目前信用额度为%s元'%(modify_file,data['credit']))
 73 
 74 def unfreeze_account(account):
 75     '账户解锁'
 76     unfreeze_file = os.listdir(setting.BASE_DB)
 77     unfreeze = input('请输入要修改的账号:').strip()
 78     unfreeze = '%s.json'%unfreeze
 79     for i,v in enumerate(unfreeze_file):
 80         if unfreeze == v:
 81             f = open(os.path.join(setting.BASE_DB,v),'r')
 82             data = json.load(f)
 83             f.close()
 84             unfreeze_acc = input('是否解冻账号:').strip()
 85             if unfreeze_acc == 'y'.lower():
 86                 data['status'] = 0
 87                 print('账户:%s已解冻'%unfreeze)
 88             else:
 89                 print('输入错误!')
 90             save_db(data)
 91             admin_logger.info('账户:%s已解冻'%unfreeze)
 92 admin_msg = [
 93     ('账户添加',add_account),
 94     ('修改额度',modify_line),
 95     ('解冻账户',unfreeze_account)
 96 ]
 97 def admin_load(account,*args,**kwargs):
 98     admin_id = account['data']['id']
 99     if admin_id == 8888:
100         for i, v in enumerate(admin_msg):
101             print(i, v[0])
102         choice = input('请选择|q退出:').strip()
103         if choice.isdigit():
104             choice = int(choice)
105             if choice < len(admin_msg) and choice >= 0:
106                 admin_msg[choice][1](account)
107         elif choice == 'q'.lower():
108               exit()
109     else:
110         print('不是管理员!')
111         exit()
View Code

账户文件

 1 import json
 2 acc_dic = {
 3     'id': 1234,
 4     'password': 'abc',
 5     'credit': 15000,
 6     'balance': 15000,
 7     'enroll_date': '2016-01-02',
 8     'expire_date': '2021-01-01',
 9     'pay_day': 22,
10     'status': 0 # 0 = normal, 1 = locked, 2 = disabled
11 }
12 
13 print(json.dumps(acc_dic))
View Code
原文地址:https://www.cnblogs.com/yjiu1990/p/9096566.html