一、程序需求
模拟实现一个ATM + 购物商城程序:
1.额度 15000或自定义
2.实现购物商城,买东西加入 购物车,调用信用卡接口结账
3.可以提现,手续费5%
4.每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息(没写)
5.支持多账户登录
6.支持账户间转账
7.记录每月日常消费流水
8.提供还款接口
9.ATM记录操作日志
10.提供管理接口,包括添加账户、用户额度,冻结账户等。。。
11.用户认证用装饰器
脑图:
二、目录
1 ├── ATM #ATM主程目录2 │ ├── __init__.py3 │ ├── bin #ATM 执行文件 目录4 │ │ ├── __init__.py5 │ │ ├── atm.py #ATM 执行程序6 │ │ ├── manage.py #信用卡管理7 │ ├── conf #配置文件8 │ │ ├── __init__.py9 │ │ └── Settings.py #配置参数10 │ ├── core #主要程序逻辑都 在这个目录 里11 │ │ ├── __init__.py12 │ │ ├── accounts.py #用于从文件里加载和存储账户数据13 │ │ ├── auth.py #用户认证模块及主要功能函数14 │ │ ├── db_handler.py #数据库连接引擎15 │ │ ├── logger.py #日志记录模块16 │ │ ├── main.py #主逻辑交互程序17 │ │ ├── transaction.py #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户18 │ ├── db #用户数据存储的地方19 │ │ ├── __init__.py20 │ │ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找21 │ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件22 │ │ └── 123.json #新创建的用户账户示例文件23 │ │ └── 1234.json #一个用户账户示例文件24 │ │ └── 123456.json #一个用户账户示例文件25 │ │ └── 6230001.json #管理用户账户示例文件26 │ └── log #日志目录27 │ ├── access.log #用户访问和操作的相关日志28 │ └── login_in.log #登陆日志29 └── shopping_mall #电子商城程序,需单独实现,主要实现购物的功能。30 │ └── __init__.py31 │ └── product.txt #存放商品的txt文件32 │ └── shopping_list.txt #存放购物清单的txt.文件33 │ └── shopping_mall.py #购物商城程序34 ├── README
目录
三、简要说明
1.程序从/bin/atm.py开始执行if __name__ == '__main__':
main.run()
2.程序转到/core/main.py下的run()函数,登陆时调用/core/auth的acc_login()进行登陆验证:用到了/core/auth下的acc_auth2()方法进行验证(此时传入的参数时用户输入的账户和密码)
acc_auth2中有调用了/core/db_handler下的db_handler()方法(参数是输入的账户名)在db_handler中只是进行判断是什么引擎,return file_db_handle(数据库引擎)解析文件,返回文件执行加载输入的用户的账户的所有数据
接下来判断是否为管理者账户,或者是否被冻结,若都不是,则判断输入的密码是否与数据库中的密码一样,在判断到期时间是否过期
所有都通过的话就返回这个账户的数据,之前已经创建了一个空字典,里面有是否验证:用户数据:用户账户:,判断是否被验证过,然后把用户数据临时的传递到里面,执行主循环函数
可以选择进入到购物商城,或者信用卡操作或者退出
1)购物商城
调用/shopping_mall/shopping_mall.py文件执行,主循环函数,选择你是商家还是用户,
①如果选择商家,商家有增加商品修改商品的功能
②如果选择用户,用户则有购物,刷信用卡消费的功能,当退出时打印消费清单
2)信用卡操作
调用/core/main.py下interactive(用户的所有数据)调用主循环函数,可以打印账户信息、还款、取款、转账、账单、退出等操作
①账户信息
②还款
③取款
④转账
⑤账单
⑥退出
3)若在账户登陆的时候进行输入的时管理员账户调用/bin/manage.py则可以对用户进行管理,解冻 用户、冻结用户、申领新卡
①添加账户
②冻结账户
③解冻账户
④退出
四、主程序
1.bin目录下代码
1 '''/bin/atm.py'''
2
3
4 #!/usr/bin/env python
5 #-*- Coding:utf-8 -*-
6 #Author:Eric.Shen
7 importos,sys8 base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))9 #print(base_dir)
10 sys.path.append(base_dir)11 from core importmain12
13
14 if __name__ == '__main__':15 main.run()16
17
18
19
20
21
22
23 '''/bin/manage.py'''
24
25
26
27 #!/usr/bin/env python
28 #-*- Coding:utf-8 -*-
29 #Author:Eric.Shen
30 #管理端(提供管理接口,包括添加账户、用户额度,冻结账户)
31 #解冻账户
32 #from core.auth import login_required
33 from core importaccounts34 from core importtransaction35 #解冻账户
36 defunblock_account(acc_data):37 user_input = input("请输入你要解冻的用户:")38 flag =039 #锁定用户
40 val =transaction.lock_or_not(user_input,flag)41 if val ==0:42 print("解冻成功!")43 return
44 #冻结账户
45 defblock_account(acc_data):46 '''
47 冻结账户初步构想是,在linux里把他的权限改掉;48 或者将其文件改名49 :param acc_data:50 :return:51 '''
52 user_input = input("请输入你要冻结的用户:")53 flag = 1
54 #锁定用户
55 val =transaction.lock_or_not(user_input,flag)56 if val ==0:57 print("冻结成功!")58 return
59
60 #添加账户、用户额度
61 defadd_account(acc_data):62 account ={63 "id": None,64 "balance": None,65 "expire_date": None,66 "enroll_date": None,67 "credit": None,68 "pay_day": None,69 "password": None,70 "status": None71 }72 menu ={73 0: "账户(数字):",74 1: "余额:",75 2: "到期时间:",76 3: "办卡时间:",77 4: "信用额度:",78 5: "还款日期:",79 6: "密码:",80 7: "默认:"}81 menu_user ={82 0: "id",83 1: "balance",84 2: "expire_date",85 3: "enroll_date",86 4: "credit",87 5: "pay_day",88 6: "password",89 7: "status"
90 }91 for i in range(8):92 data = input("%s" %menu[i]).strip()93 account['%s' % menu_user[i]] =data94 accounts.dump_account(account)#写入文件
95 print("创建成功!")96 return
97
98
99
100 deflogout(acc_data):101 exit("程序退出!")102 #管理界面主程序
103 defmanage_main(acc_data):104
105 menu = u'''
106 ---------管理界面---------107 1.添加账户108 2.冻结账户109 3.解冻账户110 4.退出'''
111 menu_dic ={112 '1': add_account,113 '2': block_account,114 '3': unblock_account,115 '4': logout116 }117 exit_flag =False118 while notexit_flag:119 print(menu)120 user_option = input("请输入你的选择:")121 if user_option inmenu_dic:122 menu_dic[user_option](acc_data)123 else:124 print("\033[31;1m选择不存在!\033[0m")125
126
127
128
129 .
View Code
2.conf目录下代码
1 '''/conf/Settings.py'''
2
3
4 #!/usr/bin/env python
5 #-*- Coding:utf-8 -*-
6 #Author:Eric.Shen
7 #参数配置文件
8 importos,sys,logging9
10 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#/Atm
11
12 DATABASE ={13 'engine': 'file_storage',14 'name': 'accounts',15 'path': "%s/db" % BASE_DIR#../Atm
16 }17
18 LOG_LEVEL =logging.INFO19 LOG_TYPES ={20 'transaction': 'transaction.log',21 'access': 'access.log',22 }23
24 #发生交易的配置类型
25 TRANSACTION_TYPE ={26 'repay':{'action':'plus','interest':0},#还款
27 'withdraw':{'action':'minus','interest':0.05},#取现是降低可用余额
28 'transfer':{'action':'minus','interest':0.05},#转账是降低可用余额
29 'consume':{'action':'minus','interest':0},30 }
View Code
3.core目录下代码
1 '''/core/accounts.py'''
2
3
4 #!/usr/bin/env python
5 #-*- Coding:utf-8 -*-
6 #Author:Eric.Shen
7 #用于从文件里加载和存储账户数据
8 importjson,time9 from core importdb_handler10 from conf importSettings11
12 #返回账户余额和其他基础信息(返回最新的数据)
13 defload_current_balance(account_id):14 '''
15 返回账户余额和其他基础信息16 :param account_id: 用户账户的名字17 :return: 返回最新读到的数据文件中的最新数据18 '''
19 #db_path = db_handler.db_handler(settings.DATABASE)
20 #account_file = "%s/%s.json" %(db_path,account_id)
21 #22 db_api =db_handler.db_handler()23 data = db_api("select * from accounts where account=%s" % account_id)#在进行操作的时候在读取一遍数据中的数据(保证数据的最新)
24 return data#返回读取到的数据
25
26 #with open(account_file) as f:
27 #acc_data = json.load(f)
28 #return acc_data
29
30 #写入文件数据
31 defdump_account(account_data):32 '''
33
34 :param account_data:35 :return:36 '''
37 db_api =db_handler.db_handler()38 data = db_api("update accounts where account=%s" % account_data['id'],account_data =account_data)39
40 #db_path = db_handler.db_handler(settings.DATABASE)
41 #account_file = "%s/%s.json" %(db_path,account_data['id'])
42 #with open(account_file, 'w') as f:
43 #acc_data = json.dump(account_data,f)
44 return True
accounts.py
1 '''/core/auth.py'''
2
3
4 #!/usr/bin/env python
5 #-*- Coding:utf-8 -*-
6 #Author:Eric.Shen
7 #用户认证模块
8 importjson,time,os9 from core importdb_handler10 from bin importmanage11 from conf importSettings12 from core importlogger13 #装饰器(用于验证账户是否登陆过)
14 deflogin_required(func):15 '''
16 验证用户是否登陆17 :return:18 '''
19 def wrapper(*args,**kwargs):20 if args[0].get('is_authenticated'):21 return func(*args,**kwargs)22 else:23 exit("用户不能认证")24 returnwrapper25
26 defacc_auth(account,password):27 '''
28 账户验证函数29 :return:30 '''
31 db_path =db_handler.db_handler()32 account_file = "%s/%s.json" %(db_path,account)33 print(account_file)34 ifos.path.isfile(account_file):35 with open(account_file,'r') as f:36 account_data =json.load(f)37 if account_data['password'] ==password:38 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))39 if time.time() >exp_time_stamp:40 print("\033[31;1m[%s]账户已经注销,请重新申领账户!\033[0m" %account)41 else: #passed the authentication
42 returnaccount_data43 else:44 print("\033[31;1m账号或密码错误,请重新输入!\033[0m")45 else:46 print("\033[31;1m[%s]账户不存在!\033[0m" %account)47
48 defacc_auth2(account,password):49 '''
50 优化版认证接口51 :param52 account:信用卡账户53 password:信用卡密码54 :return: 返回读取到的数据文件的所有账户数据55 '''
56 db_api =db_handler.db_handler()57 data = db_api("select * from accounts where account=%s" %account)#此处返回值为db_handler.py中的
58 #得到的所有数据(读取到的这个账户的所有数据)赋值给data
59 if data["status"] == 2:#判断是否为管理者
60 manage.manage_main(data)61 if data['status'] == 1:62 print("你的账户已经被冻结,请联系管理员!\n")63 option = input("请按b退出!")64 if option == "b":65 exit("程序已经退出!")66 if data['password'] == password:#判断data中的password数据是否恒等于输入的password(此处如果继续执行,则账户密码完全正确)
67 #time.mktime 返回用秒数来表示时间的浮点数。
68 #实例结果:time.mktime(t) : 1234915418.000000
69 #time.strptime 根据指定的格式把一个时间字符串解析为时间元组
70 #实例结果:time.strptime(string[, format])
71 exp_time_stamp = time.mktime(time.strptime(data['expire_date'],"%Y-%m-%d"))#将数据文件中的expire_data时间
72 #转为以秒计数的时间赋值给exp_time_stamp
73 if time.time() > exp_time_stamp:#判断当前以秒计算的数据是否大于数据文件中的数据
74 print("\033[31;1m[%s]账户以及过期,请重新激活!\033[0m" %account)75 else:76 return data#没有超时,则返回读取到的数据文件的所有内容
77 else:78 print("\033[31;1m帐户名或者密码错误!\033[0m")79
80
81 defacc_login(user_data,log_obj):82 '''
83 账户登陆函数84 :param85 user_data:用户信息数据,只存在内存中86 :return: 账户密码都对的情况下,返回所有账户数据87 '''
88 retry_count = 0#初始化重试次数
89 while user_data['is_authenticated'] is not True and retry_count < 3:#如果没有验证过,或循环此时没超过三次就执行下面的
90 account = input("\033[32;1m账户:\033[0m").strip()#输入账户
91 password = input("\033[32;1m密码:\033[0m").strip()#输入密码
92 auth = acc_auth2(account,password)#解耦,将输入的账户和密码传入到acc_auth2函数中,进行验证
93 #(最后返回的是读取到的输入正确账户的所有数据)赋值给auth
94 ifauth:95 user_data['is_authenticated'] = True#登陆成功,将只存在与内存中的数据中的是否验证改为True
96 user_data['account_id'] = account#将只存在与内存中的数据中的账户id改为账户名字(开始输入的帐户名)
97 return auth#这一步操作就是验证此账户是否登陆,然后返回账户的所有数据(数据文件中的所有数据)
98 retry_count += 1
99 else:100 log_obj.error("[%s]账户太多次尝试" %account)101 exit()
auth.py
1 '''/core/db_handler.py'''
2
3
4
5 #!/usr/bin/env python
6 #-*- Coding:utf-8 -*-
7 #Author:Eric.Shen
8 #数据库连接引擎
9 #处理所有数据库交互
10 importjson,time,os11 from conf importSettings12
13 #解析文件数据路径
14 deffile_db_handle(conn_params):15 '''
16 解析数据库文件路径17 :return:18 '''
19 #print('file db:',conn_params)
20 returnfile_execute21
22 #数据库句柄
23 defdb_handler():24 '''
25 连接数据库26 :return:27 '''
28 conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params
29 if conn_params['engine'] == 'file_storage':#判断Settings下的DABASE是什么引擎,这里只用文件文件引擎
30 return file_db_handle(conn_params)#则把Settings下的DABASE的数据传给file_db_handle并返回
31 elif conn_params['engine'] == 'mysql':32 pass#支持扩展,此次只作为一个说明
33
34 #文件执行
35 def file_execute(sql,**kwargs):36 '''
37 传入sql语句,及其他变量,38 :param sql: sql语句操作得到结果39 :param kwargs: 其他得变量40 :return:41 '''
42 conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params,再一次赋值意味着得到最新得数据
43 db_path = '%s/%s' % (conn_params['path'],conn_params['name'])#数据库的文件路径 ../db/accounts
44 #print(sql,db_path)#sql = select * from accounts where account=%s %account(此时这个account等于程序开始时要求哟用户输入得数据)
45 sql_list = sql.split('where')#将上面得sql语句以where分开,(sql_list列表内容:'select * from accounts' ,"account='account' ")
46 #print(sql_list)
47 #startswith() 方法用于检查字符串是否是以指定子字符串开头,
48 #如果是则返回 True,否则返回False。如果参数 beg 和 end 指定值,
49 #则在指定范围内检查。
50 if sql_list[0].startswith('select') and len(sql_list) > 1:#判断sql_list列表中得第一个字符是select并且列表的长度是大于1的
51 column,val = sql_list[1].strip().split('=')#将sql_list列表第二个数据先去掉默认空格,并且以‘=’为界分开放入--》
52 #-->column = account , val = '此处为开始程序输入的账户'
53 #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
54 if column == 'account':#判断是否为account,然后做指定的操作(这里使用的是account)
55 account_file = '%s/%s.json' % (db_path,val)#这一步得到数据文件路径的文件绝对路径
56 #print(account_file)
57 if os.path.isfile(account_file):#使用绝对路径判断是否为文件,返回True
58 with open(account_file,'r') as f:#以只对的方式打开文件并把文件句柄赋值给f(用with方法打开不用自己写关闭文件的方法)
59 account_data = json.load(f)#json加载文件赋值给account_data
60 return account_data#返回account_data数据(将.json文件中的数据都都出来返回)
61 else:62 exit("\033[31;1m[%s]账户不存在!\033[0m" % val)#若判断不是,则返回没有此用户
63 #写入数据
64 elif sql_list[0].startswith('update') and len(sql_list) > 1:65 column, val = sql_list[1].strip().split('=')#将帐户名写入到val中
66 if column == 'account':67 account_file = "%s/%s.json" %(db_path,val)68 #if os.path.isfile(account_file):
69 account_data = kwargs.get("account_data")#得到账户数据
70 with open(account_file,'w') as f:71 acc_data =json.dump(account_data,f)72 #print(acc_data)
73 return True
db_handler.py
1 '''/core/logger.py'''
2
3 #!/usr/bin/env python
4 #-*- Coding:utf-8 -*-
5 #Author:Eric.Shen
6 #日志记录模块,处理所有日志工作
7
8 importlogging9 from conf importSettings10
11 deflogger(log_type):12 #创建日志
13 logger =logging.getLogger(log_type)14 logger.setLevel(Settings.LOG_LEVEL)15
16 #创建控制台处理程序并将级别设置为调试
17 ch =logging.StreamHandler()18 ch.setLevel(Settings.LOG_LEVEL)19 #创建文件处理程序并设置级别为警告
20 log_file = "%s/logs/%s" %(Settings.BASE_DIR,Settings.LOG_TYPES[log_type])21 fh =logging.FileHandler(log_file)22 fh.setLevel(Settings.LOG_LEVEL)23 #创建格式化程序
24 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levename)s- %(message)s')25
26 #添加格式化的CH和FH
27 ch.setFormatter(formatter)28 fh.setFormatter(formatter)29
30 #添加CH和FH到loggerh
31 logger.addHandler(ch)32 logger.addHandler(fh)33
34 returnlogger35
36 #应用程序代码
37 '''logger.debug('debug message')38 '''
logger.py
1 #!/usr/bin/env python
2 #-*- Coding:utf-8 -*-
3 #Author:Eric.Shen
4 #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户
5 from conf importSettings6 from core importaccounts7 from core importlogger8
9 def make_transaction(log_obj,account_data,tran_type,amount,**kwargs):10 '''
11 处理所有用户的所有交易12 :param log_obj:13 :param account_data: 用户最新的数据14 :param tran_type: 交易类型15 :param amount: 交易数量16 :param other: 主要用于日志使用17 :return: 返回最新的账户数据18 '''
19 amount = float(amount)#转换为浮点型
20 if tran_type in Settings.TRANSACTION_TYPE:#判断传入的类型是否在配置参数里面
21 interest = amount * Settings.TRANSACTION_TYPE[tran_type]["interest"]#根据交易类型计算利息赋值给interest
22 old_balance = account_data['balance']#读取数据中账户余额
23 #还款操作
24 if Settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':#因为是信用卡,所以还款时提升可使用余额的操作,故计为加plus
25 new_balance = old_balance + amount + interest#执行的是信用卡的还款操作,计算方法是,旧余额+还款的钱和利息=最后的账户可用余额
26 #取现\转账操作
27 elif Settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':#因为是信用卡,所以取现都是降低可用余额的操作
28 new_balance = old_balance - amount -interest29 #只属于转账的
30 if kwargs.get('re_account'):31 #print(kwargs[0],kwargs[1])
32 re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据
33 re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值
34 re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中
35 print(re_account_data)36 accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中
37 if new_balance <0:38 print("\033[31;1m[%s]账户的信用余额不足以支付此次交易[-%s],你当前的余额是[%s]\033[0m"
39 % (account_data['creat'], (amount +interest), old_balance))40 return
41 #转账
42 '''
43 elif Settings.TRANSACTION_TYPE[tran_type] == 'transfer' :44 new_balance = old_balance - amount - interest#自己账户的最新余额45 #读取转入的账户,写入转入金额46 print(kwargs[0],kwargs[1])47 re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据48 re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值49 re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中50 print(re_account_data)51 accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中52 '''
53
54 account_data['balance'] = new_balance#将最新的余额写入到账户数据中
55 print(account_data)56 accounts.dump_account(account_data)#将最新的账户余额写回文件
57 #写入日志
58 #log_obj.info('账户:%s,操作:%s,数量:%s,利息:%s' %(account_data['id'],tran_type,amount,interest))
59 returnaccount_data60 else:61 print("\033[31;1m%s交易类型不存在\033[0m" %tran_type)62 #冻结或者锁定用户
63 deflock_or_not(account,flag):64 data =accounts.load_current_balance(account)65
66 if data["status"] == 1:67 print("该账户已经锁定!")68 if data['status']:69 data["status"] =flag70 accounts.dump_account(data)71 return 0
transaction.py
1 #!/usr/bin/env python
2 #-*- Coding:utf-8 -*-
3 #Author:Eric.Shen
4 #主程序句柄模块,处理所有用户交互内容
5 from core importauth6 from core importaccounts7 from core importlogger8 from core importtransaction9 from core.auth importlogin_required10 from shopping_mall importshopping_mall11 from bin importmanage12 importtime13
14
15 #交易日志
16 trans_logger = logger.logger('transaction')17 #访问日志
18 access_logger = logger.logger('access')19
20 #临时账户数据,仅存在于内存中
21 user_data ={22 'account_id':None,23 'is_authenticated':False,24 'account_data':None25 }26
27 #账户信息
28 defaccount_info(acc_data):29 print(user_data)30 #还款
31 @login_required#装饰器,判断用户是否登陆
32 defrepay(acc_data):33 '''
34 打印当前余额,让用户偿还账单35 :param acc_data:36 :return:37 '''
38 account_data = accounts.load_current_balance(acc_data['account_id'])#将用户账户名字传入到load_current_balance中
39 #返回最新的用户数据赋值给 account_data
40 current_balance = '''
41 ---------银行信息----------42 信用额度: %s43 可用余额: %s44 ''' %(account_data['credit'],account_data['balance'])45 print(current_balance)46 back_flag =False47 while notback_flag:48 repay_amount = input("\033[33;1m输入你要还款的金额:\033[0m").strip()#还款金额
49 if len(repay_amount) > 0 andrepay_amount.isdigit():50 #print('ddd 00')
51 #将数据传入make_transaction中(交易日志,用户数据,交易类型,还款金额)进行操作,最后返回的是最新操作之后的账户数据
52 new_balance = transaction.make_transaction(trans_logger,account_data,'repay',repay_amount)53 ifnew_balance:54 print('''\033[42;1m最新的余额:%s\033[0m''' %(new_balance['balance']))55 else:56 print('\033[31;1m[%s]是无效的账户!\033[0m' %repay_amount)57 if repay_amount == 'b':58 back_flag =True59 #取款
60 @login_required61 defwithdraw(acc_data):62 '''
63 打印当前余额,让用户执行取款操作64 :param acc_data:65 :return:66 '''
67 account_data = accounts.load_current_balance(acc_data['account_id'])68 #将用户账户名字传入到load_current_balance中
69 #返回最新的用户数据赋值给 account_data
70 current_balance = '''--------- 银行信息 --------71 信用额度: %s72 账户余额: %s''' % (account_data['credit'], account_data['balance'])73 print(current_balance)74 back_flag =False75 while notback_flag:76 withdraw_amount = input("\033[33;1m输入取款金额:\033[0m").strip()77 if withdraw_amount == 'b':78 return
79 if len(withdraw_amount) > 0 andwithdraw_amount.isdigit():80 new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount)81 ifnew_balance:82 print('''\033[42;1m最新余额:%s\033[0m''' %(new_balance['balance']))83 else:84 print('\033[31;1m[%s]是无效的账户!\033[0m' %withdraw_amount)85
86
87 #转账
88 @login_required89 deftransfer(acc_data):90 '''
91 打印当前余额,转账操作函数92 :param acc_data:用户数据93 :return:94 '''
95 account_data = accounts.load_current_balance(acc_data['account_id'])96 #将用户账户名字传入到load_current_balance中
97 #返回最新的用户数据赋值给 account_data
98 current_balance = '''--------- 银行信息 --------99 信用额度: %s100 账户余额: %s''' % (account_data['credit'], account_data['balance'])101 print(current_balance)102 back_flag =False103 while notback_flag:104 reciprocal_account = input("\033[31;1m请输入对方帐户名:\033[0m").strip()#输入对方账户信息
105 transfer_amount = input("\033[31;1m转账金额:\033[0m").strip()#转账金额
106 if reciprocal_account or transfer_amount == 'b':107 return
108 if len(transfer_amount) > 0 andtransfer_amount.isdigit():109 new_balance = transaction.make_transaction(trans_logger,account_data,'transfer',110 transfer_amount,re_account =reciprocal_account)111 ifnew_balance:112 print("\033[41;1m转账成功!\033[0m")113 print("\033[42;1m您当前的余额为:%s\033[0m" %(new_balance["balance"]))114 else:115 print('\033[31;1m[%s] \033[0m')116
117
118 #账单
119 @login_required120 defpay_check(acc_data):121 pass
122 #退出
123 deflogout(acc_data):124 exit("程序已经退出!")125 #购物商城
126 defshopping_mall_this(acc_data):127 shopping_mall.main_menu(acc_data)128 #管理窗口
129 defgoto_manage():130 manage.manage_main(user_data)131 #菜单
132 definteractive(acc_data):133 '''
134 与用户交互135 :param acc_data: 验证过的用户的所用数据136 :return:137 '''
138 menu = u'''
139 -----------银行----------140 \033[32;1m141 1.账户信息142 2.还款143 3.取款144 4.转账145 5.账单146 6.退出147 \033[0m148 '''
149 menu_dic ={150 '1': account_info,151 '2': repay,152 '3': withdraw,153 '4': transfer,154 '5': pay_check,155 '6': logout,156 }157 exit_flag =False158 while notexit_flag:159 print(menu)#打印出菜单,供用户选择
160 user_option = input("请输入你的选择:").strip()#输入用户的选择,过滤掉空格
161 if user_option == 'b':162 return
163 if user_option in menu_dic:#用户的选择如果在这个菜单里
164 #print('accdata',acc_data)
165 menu_dic[user_option](acc_data)#用户选择执行的功能,把acc_data验证过的用户的所有数据(数据文件中的数据)
166 else:167 print("\033[31;1m选择不存在!\033[0m")168 #带有购物商场的主菜单
169 defmain_menu(acc_data):170 main_menu = u'''
171 ----------主菜单---------172 \033[32;1m173 1.购物商城174 2.银行卡操作175 3.退出176 \033[0m177 '''
178 main_menu_dic ={179 '1':shopping_mall_this,180 '2':interactive,181 '3':logout,182 }183 exit_flag =False184 while notexit_flag:185 print(main_menu)186 user_option = input("请输入你的选择:").strip()187 if user_option == 'b':188 return
189 if user_option inmain_menu_dic:190 main_menu_dic[user_option](acc_data)191 else:192 print("\033[31;1m选择不存在!\033[0m")193 defrun():194 '''
195 当程序启动时,这个程序开始运行,处理关于用户的所有交互的内容196 '''
197 acc_data = auth.acc_login(user_data,access_logger)#程序从这里开始,执行auth下的acc_login函数
198 #(返回的是验证过的正确的账户数据)赋值给acc_data(此时这里的数据为输入账户名字的数据文件的数据)
199 if user_data['is_authenticated']:200 user_data['account_data'] = acc_data#把账户所有信息传给账户开始时的临时的账户数据空字典,
201 #把所有的数据文件传给账户的账户数据里面,
202 #interactive(user_data)#把user_data里的所有数据传入菜单函数,进行下一步操作
203 main_menu(user_data)
main.py
4.db下目录下代码
/db/accounts/123.json
1 {"pay_day": "22", "enroll_date": "2018-02-19", "credit": "15000", "balance": "123", "id": "123", "expire_date": "2032-01-01", "password": "123", "status": 0}
123.json
5.logs目录下代码
/logs/access.log&transaction.log
6.shopping_mall下代码
/shopping_mall/product.txt&shopping_list.txt
1 #!/usr/bin/env python
2 #-*- Coding:utf-8 -*-
3 #Author:Eric.Shen
4 #!/usr/bin/env python
5 #-*- Coding:utf-8 -*-
6 #Author:Eric.Shen
7 #2018.02.06
8 #path python3.5
9 #优化版的购物车
10 #用户入口:
11 #1.商品的信息存到文件里
12 #2.已购商品,余额记录
13 #商家入口:
14 #1.可以添加商品 2.修改商品价格
15 #存储商品列表
16 importfileinput17 from core importaccounts18
19 product_list =[]20 f = open("D:\\Python_train\\day4\\Atm\\shopping_mall\\product.txt", "r") #打开文件
21 for line inf.readlines():22 line = line.strip() #去掉最后一个换行符
23 index, item = line.split(":") #以冒号分割得到前后两个数据
24 product_list.append((index, item)) #添加的数据
25 f.close()26
27
28 defprint_product_list():29 for index, item inenumerate(product_list):30 print(index, item)31
32
33 #用户入口
34 #用户购物
35 defuser_shopping(account_data):36 #salary = input("请输入你的薪水:")
37 salary = account_data['account_data']['balance']38 print_product_list()39 if salary >0:40 shopping_list = [] #存放用户购物车清单
41 whileTrue:42 option = input("喜欢那个就买哪个(对应的标号):")43 ifoption.isdigit():44 option =int(option)45 if option >= 0 and option <=len(product_list):46 p_item = product_list[option] #用户选择的商品
47 #print(product_list)
48 #print(p_item[1])
49 c_num = int(p_item[1])50 if salary >=c_num:51 shopping_list.append(p_item)52 salary -=c_num53 print("添加购物车成功,你的余额还有%s" %(salary))54 else:55 print("你的余额不足,只剩%s元" %(salary))56 else:57 print("输入错误,请重新输入!")58 elif option == "q":59 print("----------------购物清单---------------")60 for s_list inshopping_list:61 print(s_list)62 print("你的余额为%s" %(salary))63 account_data['account_data']['balance'] =salary64 #print(account_data)
65 accounts.dump_account(account_data['account_data'])#写入文件
66 print("..........exit.........")67 exit()68 else:69 print("无效的输入")70 else:71 exit("余额不足!")72
73
74 #商家入口
75 #商家添加商品
76 defadd_product():77 name_of_product = input("请输入你要添加的商品名字:")78 price_of_product = input("请输入你要添加商品的价格:")79 f = open("product.txt", "a")80 f.write(str("\n" + name_of_product) + ": %s" %(price_of_product))81 f.close()82 print("添加成功!\nexit----------")83
84
85 #修改商品价格
86 defchange_price():87 print_product_list() #打印商品列表
88 choice = input("请输入你的选择:")89 #name_of_change = input("请输入你要改变的商品名字")
90 price_of_change = input("请输入你要改变商品的价格:")91 ifchoice.isdigit():92 choice =int(choice)93 if choice >= 0 and choice <=len(product_list):94 p_item = product_list[choice] #选择的商品
95 #c_num = int(p_item[1])#转换成int类型
96 for line in fileinput.input("product.txt", inplace="%s" % (choice)): #对输入的选择行进行修改
97 line = line.replace("%s" % (p_item[1]), "%s" %(price_of_change)).strip()98 print(line)99 exit("修改成功!")100 else:101 print("输入无效")102 else:103 if choice == "q":104 exit("退出")105
106
107 defmain_menu(account_data):108 print("--------------------------"
109 "--------------------------"
110 "\n"
111 "欢迎进入购物菜单"
112 "\n"
113 "\n"
114 "商家请按b,用户请按c\n"
115 "--------------------------"
116 "--------------------------")117 c_num = input("请输入你的选择:") #使用者选择
118 if c_num == "b":119 print("--------------------------"
120 "--------------------------"
121 "\n"
122 "欢迎进入商家界面"
123 "\n"
124 "\n"
125 "添加商品请按a,修改价格请按c\n"
126 "--------------------------"
127 "--------------------------")128 c_num2 = input("请输入你的选择:")129 if c_num2 == "a":130 #实现添加商品功能
131 add_product()132 if c_num2 == "c":133 #实现商品价格修改功能
134 change_price()135 else:136 print("输入有误!")137 if c_num == "c":138 print("--------------------------"
139 "--------------------------"
140 "\n"
141 "欢迎进入用户界面"
142 "\n"
143 "\n"
144
145 "--------------------------"
146 "--------------------------")147 #购物功能
148 print(account_data)149 user_shopping(account_data)150 else:151 print("输入有误程序退出!")
shopping_mall
五、README
1 作者:Eric.shen2 此次系统的设计仅用来学习python,开始于2018.2.13-19完(此系统,日志部分没有完善留着日后补充现在还没学到)3 作业需求:4
5 模拟实现一个ATM +购物商城程序:6 1.额度 15000或自定义7 2.实现购物商城,买东西加入 购物车,调用信用卡接口结账8 3.可以提现,手续费5%
9 4.每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息(没写)10 5.支持多账户登录11 6.支持账户间转账12 7.记录每月日常消费流水13 8.提供还款接口14 9.ATM记录操作日志15 10.提供管理接口,包括添加账户、用户额度,冻结账户等。。。16 11.用户认证用装饰器17
18 一、软件定位,软件的基本功能。19 实现一个简单的atm与购物车程序,20 二、运行代码的方法: 安装环境、启动命令等。21 用Python3.5写的,语法就是至此之前所学的,直接打开运行即可22 三、目录结构。23
24 ├── ATM #ATM主程目录
25 │ ├── __init__.py26 │ ├── bin #ATM 执行文件 目录
27 │ │ ├── __init__.py28 │ │ ├── atm.py #ATM 执行程序
29 │ │ ├── manage.py #信用卡管理
30 │ ├── conf #配置文件
31 │ │ ├── __init__.py32 │ │ └── Settings.py #配置参数
33 │ ├── core #主要程序逻辑都 在这个目录 里
34 │ │ ├── __init__.py35 │ │ ├── accounts.py #用于从文件里加载和存储账户数据
36 │ │ ├── auth.py #用户认证模块及主要功能函数
37 │ │ ├── db_handler.py #数据库连接引擎
38 │ │ ├── logger.py #日志记录模块
39 │ │ ├── main.py #主逻辑交互程序
40 │ │ ├── transaction.py #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户
41 │ ├── db #用户数据存储的地方
42 │ │ ├── __init__.py43 │ │ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
44 │ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件
45 │ │ └── 123.json #新创建的用户账户示例文件
46 │ │ └── 1234.json #一个用户账户示例文件
47 │ │ └── 123456.json #一个用户账户示例文件
48 │ │ └── 6230001.json #管理用户账户示例文件
49 │ └── log #日志目录
50 │ ├── access.log #用户访问和操作的相关日志
51 │ └── login_in.log #登陆日志
52 └── shopping_mall #电子商城程序,需单独实现,主要实现购物的功能。
53 │ └── __init__.py54 │ └── product.txt #存放商品的txt文件
55 │ └── shopping_list.txt #存放购物清单的txt.文件
56 │ └── shopping_mall.py #购物商城程序
57 ├── README58 四、简要说明,更详细点可以说明软件的基本原理。59 1.程序从/bin/atm.py开始执行if __name__ == '__main__':60 main.run()61 2.程序转到/core/main.py下的run()函数,登陆时调用/core/auth的acc_login()进行登陆验证:用到了/core/auth下的acc_auth2()方法进行验证(此时传入的参数时用户输入的账户和密码)62 acc_auth2中有调用了/core/db_handler下的db_handler()方法(参数是输入的账户名)在db_handler中只是进行判断是什么引擎,returnfile_db_handle(数据库引擎)解析文件,返回文件执行加载输入的用户的账户的所有数据63 接下来判断是否为管理者账户,或者是否被冻结,若都不是,则判断输入的密码是否与数据库中的密码一样,在判断到期时间是否过期64 所有都通过的话就返回这个账户的数据,之前已经创建了一个空字典,里面有是否验证:用户数据:用户账户:,判断是否被验证过,然后把用户数据临时的传递到里面,执行主循环函数65 可以选择进入到购物商城,或者信用卡操作或者退出66 1)购物商城67 调用/shopping_mall/shopping_mall.py文件执行,主循环函数,选择你是商家还是用户,68 ①如果选择商家,商家有增加商品修改商品的功能69 ②如果选择用户,用户则有购物,刷信用卡消费的功能,当退出时打印消费清单70 2)信用卡操作71 调用/core/main.py下interactive(用户的所有数据)调用主循环函数,可以打印账户信息、还款、取款、转账、账单、退出等操作72 ①账户信息73 ②还款74 ③取款75 ④转账76 ⑤账单77 ⑥退出78 3)若在账户登陆的时候进行输入的时管理员账户调用/bin/manage.py则可以对用户进行管理,解冻用户、冻结用户、申领新卡79 ①添加账户80 ②冻结账户81 ③解冻账户82 ④退出83 五、常见问题说明。84 日志没有实现,账单没有实现
View Code
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
product.txt
iphone: 5288Mac pro:12000Bike:800Watch:36000Coffe:39Python book:120Book:100
shopping_list.txt
('Coffe', 39)
('Pychon book', 120)
长风破浪会有时,直挂云帆济沧海。
欢迎多多提提意见