2.2

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

示例代码 https://github.com/triaquae/py3_training/tree/master/atm
简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329

---------------------------------------------------------------
做项目的步骤:
1.分析功能,需求
账户数据的增删改查 ,提现 转账 还款 --> 加钱 减钱
日志
模块间的互相调用
功能的重用
2.画流程图 https://www.processon.com/
https://www.processon.com/view/link/589eb841e4b0999184934329
3.搭框架

---------------------------------------------------------------
注意事项:
1.一个账户一个文件(.json),防止多个用户同时读数据,修改文件后,会覆盖别人已经修改好的文件!
2.num_func = {'1': view_account, '2': withdraw, '3': pay_back, '4': transfer, '5': quit}
choice_num = input('num>>>:').strip()
num_func[choice_num](choice_num)
字典 value 的值可以放 (地址)
3.settings文件要重视,防止以后修改需求,可自定义配置
4. json.dump(account_info['account_data'], f)
f.close()
os.replace(path_tmp, path)
防止断电 .json 数据修改后,还未保存到硬盘上,所以一般写到 新文件中 再替换
5.注意写的 模块公用,模块内的参数 一定不能写成死的!
6.注意写的 函数公用,函数内的参数 一定要注意公用!
7.公共的 函数,不要涉及到与用户交互!
8.imoprt ***.py 引入模块时,引入模块得顺序:内置模块,第三方模块,自定义模块
引入模块,一般到函数级别from *** import (***,***),为了可维护,程序可读性。无论加载一个模块还是加载一个函数,函数所在得模块都会被加载到内存中!
9.load(open('**.py','r')) 和 with open('**.py','r') as f: 建议用后者 不需要关闭文件 python会自动关 但是f.close()是个好习惯 f.close()
f.flush() 会触发磁盘写操作 增加io压力 增加系统负载 但是 特殊情况下 可以这么做
10.变量在哪里使用就在哪里定义,因为函数传参是有一定代价的!
11.密码md5加盐salt

用户注册时:
用户输入【账号】和【密码】(以及其他用户信息);
系统为用户生成【Salt值】;
系统将【Salt值】和【用户密码】连接到一起;
对连接后的值进行散列,得到【Hash值】;
将【Hash值1】和【Salt值】分别放到数据库中。

用户登录时:
用户输入【账号】和【密码】;
系统通过用户名找到与之对应的【Hash值】和【Salt值】;
系统将【Salt值】和【用户输入的密码】连接到一起;
对连接后的值进行散列,得到【Hash值2】(注意是即时运算出来的值);
比较【Hash值1】和【Hash值2】是否相等,相等则表示密码正确,否则表示密码错误。
----------------------------------------------------------------------------

README:

1.管理员的账号:999    密码:123
2.普通账号:1000 / 1001 / 1002   密码:123

atm.py

 1 # -*- coding:utf-8 -*-
 2 import os
 3 import sys
 4 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 5 
 6 from core import(
 7     main, manager, shopper
 8 )
 9 
10 
11 def main_run():
12     main.run()
13 
14 
15 def manager_run():
16     manager.run()
17 
18 
19 def shopper_run():
20     shopper.run()
21 
22 
23 def quit_func():
24     exit('bye bye ...')
25 
26 
27 def choice():
28     choice_msg = '''
29     -----start-----
30     1.普通账户
31     2.管理员
32     3.购物者
33     4.退出
34     ------end------
35     '''
36     dict_choice = {'1': main_run, '2': manager_run, '3': shopper_run, '4': quit_func}
37     while True:
38         print(choice_msg)
39         choice_num = input('num>>>:').strip()
40         if choice_num in dict_choice:
41             dict_choice[choice_num]()
42         else:
43             print('请输入正确的序号!')
44 
45 
46 if __name__ == '__main__':
47     choice()
atm

settings.py

 1 # -*- coding:utf-8 -*-
 2 import os
 3 import logging
 4 import time
 5 import datetime
 6 
 7 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 8 
 9 DATABASE = {
10     'engine:': 'file_storage',
11     'path': os.path.join(BASE_DIR, 'db/accounts')
12 }
13 
14 LOG_LEVEL = logging.INFO
15 LOG_FORMATTER = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %I:%M:%S %p')
16 
17 TRANSACTION_TYPE = {
18     'withdraw': {'action': 'minus', 'interest': 0.05},
19     'pay_back': {'action': 'plus', 'interest': 0},
20     'transfer': {'action': 'minus', 'interest': 0.05},
21     'consume': {'action': 'minus', 'interest': 0}
22 }
23 
24 GOODS = [
25     {"name": "电脑", "price": 1999},
26     {"name": "鼠标", "price": 10},
27     {"name": "游艇", "price": 20},
28     {"name": "美女", "price": 998}
29 ]
30 
31 MANAGER_ID = '999'
32 
33 datetime_tmp = datetime.datetime.now().replace(year=2050, month=1, day=1)
34 DEFAULT_ACCOUNT = {
35     'id': 0,
36     'password': '',
37     'salt': '',
38     'balance': 15000,
39     'credit': 15000,
40     'enroll_date': time.strftime('%Y-%m-%d', time.localtime()),
41     'expire_date': '%s-%s-%s' % (datetime_tmp.year, datetime_tmp.month, datetime_tmp.day),
42     'pay_day': 22,
43     'status': 0
44 }
settings

auth.py

 1 # -*- coding:utf-8 -*-
 2 import os
 3 import json
 4 from hashlib import md5
 5 
 6 from conf.settings import DATABASE
 7 
 8 
 9 def auth_login(func):
10     # 装饰器
11     def inner(*args, **kwargs):
12         if args[0]['is_auth']:
13             return func(*args, **kwargs)
14         else:
15             exit('您还未登录!')
16     return inner
17 
18 
19 def hash_password(password, salt):
20     # 用户输入的密码 + salt 得到hash值
21     hash_value = md5()
22     hash_value.update((password+salt).encode('utf-8'))
23     return hash_value.hexdigest()
24 
25 
26 def judge_account(account):
27     # 判断用户是否存在 存在返回json数据
28     path_json = DATABASE['path']
29     file_path = os.path.join(path_json, account+'.json')
30     if os.path.isfile(file_path):
31         with open(file_path, 'r', encoding='utf-8') as f:
32             account_data = json.load(f)
33             f.close()
34             return account_data
35 
36 
37 def login(logger, *args):
38     # 判断账号密码是否正确
39     account_info = {
40         'is_auth': False,
41         'account': None,
42         'account_data': None
43     }
44     login_count = 0
45     while login_count < 3:
46         account = input('33[1;32maccount>>>:33[0m').strip()
47         password = input('33[1;32mpassword>>>:33[0m').strip()
48         account_data = judge_account(account)
49         if account_data:
50             if account_data.get('password') == hash_password(password, account_data['salt']):
51                 # print('33[1;33m登录成功!33[0m'.center(25, '-'))
52                 account_info['is_auth'] = True
53                 account_info['account'] = account
54                 account_info['account_data'] = account_data
55                 if account_data['status'] == 1:  # 表示账号 被冻结
56                     print('33[1;31m账号:%s 被冻结!33[0m'.center(30, '-') % account)
57                 else:
58                     if len(args) != 0:  # 管理员
59                         if args[0] == account:
60                             logger.info('管理员account: %s - 登录成功' % account)
61                             return account_info
62                         else:
63                             print('33[1;31m您不是管理员!33[0m'.center(25, '-'))
64                     else:  # 普通账号
65                         logger.info('account: %s - 登录成功' % account)
66                         return account_info
67             else:
68                 print('33[1;31m密码错误!33[0m'.center(25, '-'))
69         else:
70             print('33[1;31m账号:%s 不存在33[0m' % account)
71         login_count += 1
72     else:
73         logger.critical('account: %s - 登录失败次数超过3次' % account)
74         exit()
auth

db_handler.py

 1 # -*- coding:utf-8 -*-
 2 import os
 3 import json
 4 
 5 from .logger import set_logger
 6 from .auth import judge_account
 7 from conf.settings import(
 8     DATABASE, TRANSACTION_TYPE
 9 )
10 
11 trans_logger = set_logger('transactions')
12 
13 
14 def account_data_save(account, account_data):
15     # 修改文件的 公共方法
16     path = os.path.join(DATABASE['path'], account + '.json')
17     path_tmp = os.path.join(DATABASE['path'], account + '_tmp' + '.json')
18     if os.path.isfile(path):
19         with open(path_tmp, 'w', encoding='utf-8') as f:
20             json.dump(account_data, f)
21         os.replace(path_tmp, path)
22         return account_data
23 
24 
25 def save_json_common(account, new_balance, account_data):
26     # 内存中 替换余额
27     account_data['balance'] = round(new_balance, 2)
28     return account_data_save(account, account_data)
29 
30 
31 def transaction_logger(account, new_balance, account_data, arguments):
32     # 记录 日志的 公共方法
33     account_data_new = save_json_common(account, new_balance, account_data)
34     if account_data_new:
35         trans_logger.info('account: %s - account_type: %s - action: %s - interest: %s' % (account, arguments[0], arguments[1]['action'], arguments[1]['interest']))
36         return account_data_new
37 
38 
39 def split_account(new_balance, account_info, *args, **kwargs):
40     # 区分开 是两个账号间的操作 还是一个账号
41     account = account_info['account']
42     if len(kwargs) != 0:  # 转账 两个账号 间的操作
43         transfer_data = save_json_common(kwargs['transfer_account'], kwargs['transfer_new_balance'], kwargs['transfer_data'])
44         if transfer_data:
45             return transaction_logger(account, new_balance, account_info['account_data'], args)
46     else:  # 一个 账号 的操作
47         return transaction_logger(account, new_balance, account_info['account_data'], args)
48 
49 
50 def make_transaction(money, account_info, account_type, *args):
51     # 提现 还款 转账 公共方法
52     if account_type in TRANSACTION_TYPE:
53         transaction_type = TRANSACTION_TYPE[account_type]
54         interest = money * transaction_type['interest']
55         old_balance = account_info['account_data']['balance']
56         # 减钱的 操作
57         if transaction_type['action'] == 'minus':
58             if len(args) == 0:  # 提现 或者 消费 没有附加的参数
59                 new_balance = old_balance - money - interest
60                 if new_balance < 0:
61                     print('33[1;31m交易失败,余额不足33[0m')
62                 else:
63                     return split_account(new_balance, account_info, account_type, transaction_type)
64             else:  # 转账
65                 if args[0] == account_info['account']:
66                     print('33[1;31m注:同一账号,不允许转账33[0m')
67                 else:
68                     transfer_data = judge_account(args[0])
69                     if transfer_data:
70                         if transfer_data['status'] == 1:
71                             print('33[1;31m账号:%s 被冻结!33[0m'.center(30, '-') % args[0])
72                         else:
73                             new_balance = old_balance - money - interest
74                             if new_balance < 0:
75                                 print('33[1;31m交易失败,余额不足33[0m')
76                             else:
77                                 transfer_new_balance = transfer_data['balance'] + money
78                                 return split_account(new_balance, account_info, account_type, transaction_type, transfer_account = args[0], transfer_new_balance = transfer_new_balance, transfer_data = transfer_data)
79                     else:
80                         print('33[1;31m账号:%s 不存在33[0m' % args[0])
81         # 加钱的 操作
82         elif transaction_type['action'] == 'plus':
83             new_balance = old_balance + money + interest
84             return split_account(new_balance, account_info, account_type, transaction_type)
85 
86     else:
87         print('33[1;31m%s 交易类型不存在!33[0m' % account_type)
db_handler

logger.py

 1 # -*- coding:utf-8 -*-
 2 import os
 3 import logging
 4 from logging import handlers
 5 
 6 from conf.settings import(
 7     LOG_LEVEL, BASE_DIR, LOG_FORMATTER
 8 )
 9 
10 
11 def set_logger(name):
12     # 配置logger对象
13     logger = logging.getLogger(name)
14     logger.setLevel(LOG_LEVEL)
15 
16     # fh = logging.FileHandler(os.path.join(BASE_DIR, 'log/'+name+'.log'), encoding='utf-8')
17     # fh = handlers.RotatingFileHandler(filename = os.path.join(BASE_DIR, 'log/'+name+'.log'), maxBytes=10, backupCount=2, encoding='utf-8')
18     fh = handlers.TimedRotatingFileHandler(filename = os.path.join(BASE_DIR, 'log/'+name+'.log'), when='S', interval=2, backupCount=2, encoding='utf-8')
19     logger.addHandler(fh)
20 
21     fh_formatter = LOG_FORMATTER
22     fh.setFormatter(fh_formatter)
23 
24     return logger
logger

main.py

  1 # -*- coding:utf-8 -*-
  2 import re
  3 
  4 from .logger import set_logger
  5 from .db_handler import make_transaction
  6 from .auth import (
  7     login, auth_login
  8 )
  9 
 10 access_logger = set_logger('access')
 11 
 12 
 13 @auth_login
 14 def checkout(account_info, money):
 15     # 购买商品之后 结账
 16     account_data = make_transaction(money, account_info, 'consume')
 17     if account_data:
 18         print('账户:%s ->> 消费 33[1;34m%s33[0m -> 余额 33[1;31m%s33[0m' % (account_info['account'], money, account_data['balance']))
 19         exit()
 20     else:
 21         print('33[1;31m结账失败!33[0m')
 22 
 23 
 24 def judge_num(num):
 25     # 判断 int float
 26     str_num = re.sub('.', '', num, count=1)
 27     if str_num.isdigit():
 28         return float(num)
 29 
 30 
 31 @auth_login
 32 def view_account(account_info):
 33     # 查看账户信息
 34     msg_info = '''33[1;34m
 35     -----账户:%s 的信息:-----
 36     balance: %10s
 37     credit:  %10s
 38     pay_day: %10s33[0m
 39     ''' % (account_info.get('account'), account_info['account_data']['balance'], account_info['account_data']['credit'], account_info['account_data']['pay_day'])
 40     print(msg_info)
 41 
 42 
 43 @auth_login
 44 def withdraw(account_info):
 45     # 提现
 46     while True:
 47         money = input('withdraw_money(q表示退出)>>>:').strip()
 48         if not money:
 49             continue
 50         if money == 'q':
 51             break
 52         float_money = judge_num(money)
 53         if float_money:
 54             account_data = make_transaction(float_money, account_info, 'withdraw')
 55             if account_data:
 56                 print('账户:%s -> 提现成功 -> 提现 33[1;34m%s33[0m -> 余额 33[1;31m%s33[0m' % (account_info['account'], money, account_data['balance']))
 57             else:
 58                 print('33[1;31m提现失败!33[0m')
 59         else:
 60             print('请输入33[1;34m正确的33[0m并33[1;31m大于033[0m的金额'.center(45, '-'))
 61 
 62 
 63 @auth_login
 64 def pay_back(account_info):
 65     # 还款
 66     while True:
 67         money = input('pay_back_money(q表示退出)>>>:').strip()
 68         if not money:
 69             continue
 70         if money == 'q':
 71             break
 72         float_money = judge_num(money)
 73         if float_money:
 74             account_data = make_transaction(float_money, account_info, 'pay_back')
 75             if account_data:
 76                 print('账户:%s -> 还款成功 -> 还款 33[1;34m%s33[0m -> 余额 33[1;31m%s33[0m' % (account_info['account'], money, account_data['balance']))
 77             else:
 78                 print('33[1;31m还款失败!33[0m')
 79         else:
 80             print('请输入33[1;34m正确的33[0m并33[1;31m大于033[0m的金额'.center(45, '-'))
 81 
 82 
 83 @auth_login
 84 def transfer(account_info):
 85     # 转账
 86     while True:
 87         transfer_account = input('transfer_account(q表示退出)>>>:').strip()
 88         if not transfer_account:
 89             continue
 90         if transfer_account == 'q':
 91             break
 92         while True:
 93             money = input('transfer_money(q表示退出)>>>:').strip()
 94             if not money:
 95                 continue
 96             if money == 'q':
 97                 return
 98             float_money = judge_num(money)
 99             if float_money:
100                 account_data = make_transaction(float_money, account_info, 'transfer', transfer_account)
101                 if account_data:
102                     print('账户:%s -> 转账成功 -> 转账 33[1;34m%s33[0m -> 余额 33[1;31m%s33[0m' % (account_info['account'], money, account_data['balance']))
103                 else:  # 交易失败余额不足的 或者 账号不存在的 或者 同一账号的 会直接退出
104                     print('33[1;31m转账失败!33[0m')
105                     return
106             else:
107                 print('请输入33[1;34m正确的33[0m并33[1;31m大于033[0m的金额'.center(45, '-'))
108 
109 
110 def quit_func(account_info):
111     # 退出
112     exit('bye bye ...')
113 
114 
115 def controller(account_info):
116     # 功能分发器
117     print('账户33[0;34m%s33[0m登录成功'.center(35, '*') % account_info.get('account'))
118     msg_num = '''33[1;33m
119     --------start--------
120     1. 账户信息
121     2. 提现
122     3. 还款
123     4. 转账
124     5. 退出
125     ---------end---------
126     33[0m
127     '''
128     num_func = {'1': view_account, '2': withdraw, '3': pay_back, '4': transfer, '5': quit_func}  # 字典的值可存放 地址
129     while True:
130         print(msg_num)
131         choice_num = input('num>>>:').strip()
132         if not choice_num:
133             continue
134         if choice_num in num_func:
135             num_func[choice_num](account_info)
136         else:
137             print('33[1;31m请输入正确的序号33[0m')
138 
139 
140 def run():
141     account_info = login(access_logger)
142     if access_logger:
143         controller(account_info)
main

manager.py

  1 # -*- coding:utf-8 -*-
  2 import os
  3 import json
  4 import string
  5 import random
  6 from hashlib import md5
  7 
  8 from .logger import set_logger
  9 from .main import judge_num
 10 from .db_handler import account_data_save
 11 from .auth import(
 12     login, judge_account, auth_login
 13 )
 14 from conf.settings import(
 15     MANAGER_ID, DATABASE, DEFAULT_ACCOUNT
 16 )
 17 
 18 manager_logger = set_logger('manager')
 19 
 20 
 21 def set_salt():
 22     # 每个用户的salt值不一样 库中的password就不一样
 23     salt = ''.join(random.sample(string.digits + string.ascii_letters + string.punctuation, 8))  # 随机的8位盐 使得相同的密码 也有不同md5()值
 24     md5_value = md5()
 25     md5_value.update(b'123' + salt.encode('utf-8'))
 26     return salt, md5_value.hexdigest()
 27 
 28 
 29 def get_account():
 30     # 输入 id 得到账户信息
 31     while True:
 32         id_account = input('id>>>:').strip()
 33         if id_account.isdigit():
 34             account_date = judge_account(id_account)
 35             if account_date:
 36                 return account_date, id_account
 37             else:
 38                 print('33[1;31m账号:%s 不存在33[0m' % id_account)
 39         else:
 40             print('33[1;31m请输入整数的 id 账户33[0m')
 41 
 42 
 43 @auth_login
 44 def add_acount(m_account_info):
 45     # 添加账户
 46     print('33[1;34m管理员 %s 开始添加账户33[0m'.center(30, '-') % m_account_info['account'])
 47     while True:
 48         id_account = input('id>>>:').strip()
 49         if id_account.isdigit():
 50             account_date = judge_account(id_account)
 51             if account_date:
 52                 print('33[1;31m账号:%s 已存在33[0m' % id_account)
 53             else:
 54                 salt_pass = set_salt()
 55                 DEFAULT_ACCOUNT['id'] = int(id_account)
 56                 DEFAULT_ACCOUNT['password'] = salt_pass[1]
 57                 DEFAULT_ACCOUNT['salt'] = salt_pass[0]
 58                 with open(os.path.join(DATABASE['path'], id_account + '.json'), 'w', encoding='utf-8') as f:
 59                     json.dump(DEFAULT_ACCOUNT, f)
 60                 print('33[1;32m账号:%s 添加成功33[0m' % id_account)
 61                 manager_logger.info('管理员account:%s - 添加账户account:%s' % (m_account_info['account'], id_account))
 62                 break
 63         else:
 64             print('33[1;31m请输入整数的 id 账户33[0m')
 65 
 66 
 67 @auth_login
 68 def credit_account(m_account_info):
 69     # 设定用户 额度
 70     account_tuple = get_account()
 71     if account_tuple:
 72         credit = input('new_credit>>>:').strip()
 73         float_credit = judge_num(credit)
 74         if float_credit:
 75             account_tuple[0]['credit'] = round(float_credit, 2)
 76             account_data = account_data_save(account_tuple[1], account_tuple[0])
 77             if account_data:
 78                 print('修改账号: 33[1;33m%s33[0m 额度成功,现在额度为:33[1;34m%s33[0m' % (account_tuple[1], account_data['credit']))
 79                 manager_logger.info('管理员account:%s - 修改账号account:%s - 修改额度credit:%s' % (m_account_info['account'], account_tuple[1], float_credit))
 80             else:
 81                 print('账号:%s 文件修改失败!' % account_tuple[1])
 82         else:
 83             print('33[1;31m注意:用户额度须为整数或小数33[0m')
 84 
 85 
 86 @auth_login
 87 def freeze_account(m_account_info):
 88     # 冻结账户
 89     account_tuple = get_account()
 90     if account_tuple:
 91         if account_tuple[1] == m_account_info['account']:  # 是管理员 本人
 92             print('33[1;31m您是管理员,不能冻结自己!33[0m')
 93         else:
 94             if account_tuple[0]['status'] == 1:
 95                 print('账号是 33[1;32m冻结33[0m 状态,将 33[1;34m解冻33[0m')
 96                 account_tuple[0]['status'] = 0
 97             else:
 98                 print('账号是 33[1;32m解冻33[0m 状态,将 33[1;34m冻结33[0m')
 99                 account_tuple[0]['status'] = 1
100             account_data = account_data_save(account_tuple[1], account_tuple[0])
101             if account_data:
102                 print('33[1;33m修改账号的 冻结状态:%s 成功!33[0m' % (account_tuple[1]))
103                 manager_logger.info('管理员account:%s - 修改账号account:%s - 修改冻结状态成功' % (m_account_info['account'], account_tuple[1]))
104             else:
105                 print('账号:%s 文件修改失败!' % account_tuple[1])
106 
107 
108 def quit_func(m_account_info):
109     # 退出
110     exit('bye bye ...')
111 
112 
113 def controller(m_account_info):
114     # 功能分发器
115     print('33[1;33m欢迎管理员 %s 登录33[0m'.center(35, '-') % m_account_info.get('account'))
116     manager_choice = '''
117     ------start------
118     1. 添加账户
119     2. 用户额度
120     3. 冻结账户
121     4. 退出
122     ------end------
123     '''
124     dict_manager_info = {'1': add_acount, '2': credit_account, '3': freeze_account, '4': quit_func}
125     while True:
126         print(manager_choice)
127         num = input('num>>>:').strip()
128         if not num:
129             continue
130         if num in dict_manager_info:
131             dict_manager_info[num](m_account_info)
132         else:
133             print('33[1;31m请重新选择33[0m')
134 
135 
136 def run():
137     manager_account_info = login(manager_logger, MANAGER_ID)
138     if manager_account_info:
139         controller(manager_account_info)
manager

shopper.py

 1 # -*- coding:utf-8 -*-
 2 from conf.settings import GOODS
 3 from .auth import login
 4 from .main import (
 5     access_logger, checkout
 6 )
 7 
 8 
 9 def show_buy_goods(goods_buyed):
10     # 展示购买的商品
11     all_money = 0
12     if len(goods_buyed) == 0:
13         return all_money
14     else:
15         print('您已购买以下商品:'.center(20, '-'))
16         for index, i in enumerate(goods_buyed, 1):
17             print('%s. %s  %s' % (index, i['name'], i['price']))
18             all_money += int(i['price'])
19         return all_money
20 
21 
22 def buy_goods(dict_goods):
23     # 购买商品
24     goods_buyed = []
25     while True:
26         choice = input('num(q退出并结算)>>>:').strip()
27         if not choice:
28             continue
29         if choice == 'q':
30             return show_buy_goods(goods_buyed)
31         if choice in dict_goods:
32             goods_buyed.append(dict_goods[choice])
33             print('33[1;34m%s33[0m 加入购物车' % dict_goods[choice]['name'])
34         else:
35             print('33[1;31m重新选择33[0m')
36 
37 
38 def show_goods():
39     # 展示商品列表
40     dict_goods = {}
41     print('展示商品列表'.center(20,'-'))
42     for index, i in enumerate(GOODS):
43         dict_goods[str(index)] = i
44         print('%d. %s   %d' % (index, i['name'], i['price']))
45     return dict_goods
46 
47 
48 def run():
49     account_info = login(access_logger)
50     if account_info['is_auth'] is True:
51         all_money = buy_goods(show_goods())
52         checkout(account_info, all_money)
shopper

***.json

1 {"id": 999, "password": "4940e231b912f39abd7d98c81bed7053", "salt": "}fH>@&0o", "balance": 15000, "credit": 15000, "enroll_date": "2016-01-01", "expire_date": "2021-01-01", "pay_day": 22, "status": 0}
***.json

account_sample.py

 1 # -*- coding:utf-8 -*-
 2 import json
 3 import random
 4 import string
 5 from hashlib import md5
 6 
 7 salt = ''.join(random.sample(string.digits + string.ascii_letters + string.punctuation, 8))
 8 md5_value = md5()
 9 md5_value.update(b'123'+salt.encode('utf-8'))
10 
11 account_dic = {
12     'id': 999,
13     'password': md5_value.hexdigest(),
14     'salt': salt,
15     'balance': 15000,  # 账户余额
16     'credit': 15000,  # 信用额度
17     'enroll_date': '2016-01-01',
18     'expire_date': '2021-01-01',
19     'pay_day': 22,
20     'status': 0  # 0 = normal, 1 = locked, 2 = disabled
21 }
22 
23 print(json.dumps(account_dic))
24 # json.dump(account_dic, open('./accounts/999.json', 'w', encoding='utf-8'))
account_sample

access.log

 1 2018-03-04 11:33:52 AM - access - CRITICAL - account:  - 登录失败次数超过3次
 2 2018-03-04 11:34:03 AM - access - INFO - account: 1000 - 登录成功
 3 2018-03-04 11:34:50 AM - access - INFO - account: 999 - 登录成功
 4 2018-03-04 11:35:57 AM - access - INFO - account: 1000 - 登录成功
 5 2018-03-04 11:38:23 AM - access - INFO - account: 1008 - 登录成功
 6 2018-03-04 11:39:29 AM - access - INFO - account: 1008 - 登录成功
 7 2018-03-04 11:40:17 AM - access - INFO - account: 1008 - 登录成功
 8 2018-03-04 11:41:40 AM - access - INFO - account: 1008 - 登录成功
 9 2018-03-04 11:43:41 AM - access - INFO - account: 1008 - 登录成功
10 2018-03-04 11:46:12 AM - access - CRITICAL - account:  - 登录失败次数超过3次
11 2018-03-04 11:46:19 AM - access - INFO - account: 1000 - 登录成功
12 2018-03-04 11:50:57 AM - access - CRITICAL - account: 1010 - 登录失败次数超过3次
13 2018-03-04 11:51:03 AM - access - INFO - account: 999 - 登录成功
14 2018-03-04 11:51:08 AM - access - INFO - account: 1010 - 登录成功
15 2018-03-04 11:51:49 AM - access - INFO - account: 999 - 登录成功
16 2018-03-04 11:52:00 AM - access - INFO - account: 1010 - 登录成功
17 2018-03-04 11:54:02 AM - access - INFO - account: 1000 - 登录成功
18 2018-03-04 11:54:56 AM - access - INFO - account: 1000 - 登录成功
19 2018-03-04 11:55:38 AM - access - INFO - account: 1000 - 登录成功
20 2018-03-04 11:57:30 AM - access - INFO - account: 1000 - 登录成功
21 2018-03-04 12:02:44 PM - access - INFO - account: 999 - 登录成功
22 2018-03-04 12:02:57 PM - access - CRITICAL - account: 1000 - 登录失败次数超过3次
23 2018-03-04 12:03:04 PM - access - INFO - account: 1000 - 登录成功
24 2018-03-04 12:03:14 PM - access - INFO - account: 999 - 登录成功
25 2018-03-04 12:05:04 PM - access - INFO - account: 999 - 登录成功
access

manager.log

 1 2018-03-04 11:34:18 AM - manager - CRITICAL - account: 123 - 登录失败次数超过3次
 2 2018-03-04 11:34:24 AM - manager - INFO - 管理员account: 999 - 登录成功
 3 2018-03-04 11:34:37 AM - manager - INFO - 管理员account:999 - 修改账号account:1000 - 修改冻结状态成功
 4 2018-03-04 11:35:25 AM - manager - INFO - 管理员account:999 - 添加账户account:900
 5 2018-03-04 11:35:38 AM - manager - INFO - 管理员account: 999 - 登录成功
 6 2018-03-04 11:35:52 AM - manager - INFO - 管理员account:999 - 修改账号account:1000 - 修改冻结状态成功
 7 2018-03-04 11:37:39 AM - manager - INFO - 管理员account:999 - 添加账户account:1008
 8 2018-03-04 11:38:03 AM - manager - INFO - 管理员account:999 - 修改账号account:1008 - 修改额度credit:1200.0
 9 2018-03-04 11:38:37 AM - manager - INFO - 管理员account:999 - 修改账号account:1008 - 修改冻结状态成功
10 2018-03-04 11:41:48 AM - manager - INFO - 管理员account: 999 - 登录成功
11 2018-03-04 11:41:52 AM - manager - INFO - 管理员account:999 - 修改账号account:1008 - 修改冻结状态成功
12 2018-03-04 11:43:50 AM - manager - INFO - 管理员account:999 - 修改账号account:1008 - 修改冻结状态成功
13 2018-03-04 11:48:13 AM - manager - CRITICAL - account: 1000 - 登录失败次数超过3次
14 2018-03-04 11:48:19 AM - manager - INFO - 管理员account: 999 - 登录成功
15 2018-03-04 11:48:26 AM - manager - INFO - 管理员account:999 - 添加账户account:1009
16 2018-03-04 11:48:32 AM - manager - INFO - 管理员account:999 - 添加账户account:23
17 2018-03-04 11:48:45 AM - manager - INFO - 管理员account:999 - 添加账户account:1010
18 2018-03-04 11:49:36 AM - manager - INFO - 管理员account:999 - 修改账号account:1009 - 修改额度credit:1000.0
19 2018-03-04 11:49:52 AM - manager - INFO - 管理员account:999 - 修改账号account:1009 - 修改冻结状态成功
20 2018-03-04 11:50:31 AM - manager - INFO - 管理员account: 999 - 登录成功
21 2018-03-04 11:50:38 AM - manager - INFO - 管理员account:999 - 添加账户account:123
22 2018-03-04 11:56:32 AM - manager - INFO - 管理员account: 999 - 登录成功
23 2018-03-04 11:56:38 AM - manager - INFO - 管理员account:999 - 修改账号account:1003 - 修改冻结状态成功
24 2018-03-04 11:56:53 AM - manager - INFO - 管理员account:999 - 修改账号account:1003 - 修改冻结状态成功
25 2018-03-04 12:03:37 PM - manager - INFO - 管理员account: 999 - 登录成功
26 2018-03-04 12:03:45 PM - manager - INFO - 管理员account:999 - 修改账号account:999 - 修改额度credit:123.0
27 2018-03-04 12:04:48 PM - manager - INFO - 管理员account:999 - 修改账号account:999 - 修改额度credit:15000.0
manager

transactions.log

 1 2018-03-04 11:36:10 AM - transactions - INFO - account: 1000 - account_type: withdraw - action: minus - interest: 0.05
 2 2018-03-04 11:36:31 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
 3 2018-03-04 11:36:34 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
 4 2018-03-04 11:37:02 AM - transactions - INFO - account: 1000 - account_type: transfer - action: minus - interest: 0.05
 5 2018-03-04 11:38:58 AM - transactions - INFO - account: 1008 - account_type: pay_back - action: plus - interest: 0
 6 2018-03-04 11:42:17 AM - transactions - INFO - account: 1008 - account_type: withdraw - action: minus - interest: 0.05
 7 2018-03-04 11:46:34 AM - transactions - INFO - account: 1000 - account_type: withdraw - action: minus - interest: 0.05
 8 2018-03-04 11:46:42 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
 9 2018-03-04 11:46:45 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
10 2018-03-04 11:47:48 AM - transactions - INFO - account: 1000 - account_type: transfer - action: minus - interest: 0.05
11 2018-03-04 11:51:15 AM - transactions - INFO - account: 1010 - account_type: consume - action: minus - interest: 0
12 2018-03-04 11:52:08 AM - transactions - INFO - account: 1010 - account_type: withdraw - action: minus - interest: 0.05
13 2018-03-04 11:55:22 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
14 2018-03-04 11:55:41 AM - transactions - INFO - account: 1000 - account_type: withdraw - action: minus - interest: 0.05
15 2018-03-04 11:55:47 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
16 2018-03-04 11:56:04 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
17 2018-03-04 11:56:06 AM - transactions - INFO - account: 1000 - account_type: pay_back - action: plus - interest: 0
18 2018-03-04 11:57:35 AM - transactions - INFO - account: 1000 - account_type: consume - action: minus - interest: 0
transactions

github:https://github.com/alice-bj/atm


原文地址:https://www.cnblogs.com/alice-bj/p/8504381.html