每次作一点就发出来,大神不要嫌重复mysql
2016/11/4git
今天来搞ATM,反正逃不了的,说来惭愧,这个做业是我10/4号20天前拿到的,当时是万脸蒙比的,今天又作了一点,如今算是百脸蒙比吧。sql
额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结帐 实际上是两套单独程序
能够提现,手续费5% 提现不能超过总余额一半
每个月22号出帐单,每个月10号为还款日,过时未还,按欠款总额 万分之5 每日计息
支持多帐户登陆,每一个用户有单独信息
支持帐户间转帐,
记录每个月平常消费流水
提供还款接口
ATM记录操做日志
提供管理接口,包括添加帐户、用户额度,冻结帐户等。。。数据库
角色:json
管理员功能:
增删改查
记录日志
基本信息
额度 15000
普通用户功能:
能够提现,手续费5%
支持多帐户登陆
支持帐户间转帐
记录每个月平常消费流水
提供还款接口
ATM记录操做日志ide
刚开始的蒙比从不知道文件怎么建立开始?擦!怎么多需求,确定不止一两个文件的,那多个文件又是怎么建的?我还特的心血来潮花一个早上去图去馆研究一下,最后挺乱的,后来看了视频,才发现有文件建立上是有开发规范的!学习
bin 用于执行可执行文件测试
conf 配置文件字体
db 用于存放用户数据spa
log 日志,记录相关信息
这里我每次写一些,改一些,方便我这种小白看思路,想看最终版的直接拉到文章最后。
今天实现了检查账户是否存在,信用卡是否超期的功能。自我感受良好,哈哈~
1. 如何让字体打印出来有颜色??
print("\033[31;1mAccount[%s]doesnotexist!\033[0m" % account)
运行结果:Account [qee] does not exist! 打印出来是红色的
2.如何将一个文件内的字符串形式经过json转化为相应的字典格式??
用json.load()就好嘛,不过仍是遇到一点小问题。
#account_file是文件的绝对路径
with open(account_file, "r", encoding="utf-8") as f: #打开文件
file_data = json.load(account_file) print(file_data)
这样居然出错了!! 错误信息:AttributeError: 'str' object has no attribute 'read'
因而我去看了下json.load()的源码。
def load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing a JSON document) to a Python object. ``object_hook`` is an optional function that will be called with the result of any object literal decode (a ``dict``). The return value of ``object_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting). ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders that rely on the order that the key and value pairs are decoded (for example, collections.OrderedDict will remember the order of insertion). If ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. """ return loads(fp.read(), cls=cls, object_hook=object_hook, parse_float=parse_float, parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
注意这一句return loads(fp.read(),……),我觉得搞个文件的绝对路径就能够的,结果错误信息,固然是路径没有read()功能。
#改正: if os.path.isfile(account_file): #若是用户文件存在(即用户存在)
with open(account_file, "r", encoding="utf-8") as f: #打开文件
file_data = json.load(f) print(file_data)
运行正确,GOOD!
3.如何把时间字符串转化为时间戳(忘了的)
先经过time.strptime()将时间字符串转成struct_time格式,再经过time.mktime()将struct_time转成时间戳。
atm.py
""" ATM程序的执行文件 """
import os import sys dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路径
sys.path.insert(0, dir) #添加路径
print(dir) #将main.py里面全部代码封装成main变量
from core import main if __name__ == "__main__": #这里我刚开始用run()就爆错了
main.run()
settings.py
1 """ 2 初始化的配置 3 """ 4 5 import logging 6 import os 7 8 #到ATM目录,方便后面建立账户文件 9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 11 LOGIN_LEVEL = logging.INFO #初始化日志级别 12 13 14 DATABASE = { 15 "db_tool":"file_storage", #文件存储,这里可拓展成数据库形式的 16 "name":"accounts", #db下的文件名 17 "path":"%s/db" % BASE_DIR 18 }
auth.py
1 """
2 认证模块 3 """
4 print("BB") 5 import os 6 import json 7 import time 8
9 from core import db_handle 10 from conf import settings 11
12
13 def access_auth(account, password): 14 """
15 下面的access_login调用access_auth方法,用于登录 16 :param acount: 用户名 17 :param password: 密码 18 :return:若是未超期,返回字典,超期则打印相应提示 19 """
20 db_path = db_handle.handle(settings.DATABASE) #调用db_handle下的handle方法,返回路径/db/accounts
21 print(db_path) 22 account_file = "%s/%s.json" % (db_path, account) #用户文件
23 print(account_file) 24 if os.path.isfile(account_file): #若是用户文件存在(即用户存在)
25 with open(account_file, "r", encoding="utf-8") as f: #打开文件
26 account_data = json.load(f) #file_data为字典形式
27 print(account_data) 28 if account_data["password"] == password: 29 expire_time = time.mktime(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 30 print(expire_time) 31 print(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 32 if time.time() > expire_time: #若是信用卡已超期
33 print("\033[31;1mAccount %s had expired,Please contract the bank" % account) 34 else: #信用卡未超期,返回用户数据的字典
35 print("return") 36 return account_data 37 else: 38 print("\033[31;1mAccount or Passworddoes not correct!\033[0m") 39 else: #用户不存在
40 print("\033[31;1mAccount [%s] does not exist!\033[0m" % account) 41
42
43
44
45 def access_login(user_data): 46 """
47 用记登录,当登录失败超过三次?? 48 :param user_data: 49 :return: 50 """
51 retry = 0 52 while not user_data["is_authenticated"] and retry < 3: 53 account = input("Account:").strip() 54 password = input("Password:").strip() 55 access_auth(account, password)
db_handle.py
1 """
2 处理与数据库的交互,如果file_db_storage,返回路径 3 """
4
5 def file_db_handle(database): 6 """
7 数据存在文件 8 :param database: 9 :return: 返回路径 ATM/db/accounts 10 """
11 db_path = "%s/%s" % (database["path"], database["name"]) 12 print(db_path) 13 return db_path 14
15
16
17 def mysql_db_handle(database): 18 """
19 处理mysql数据库,这里用文件来存数据, 20 保留这个方法主要为了程序拓展性 21 :return: 22 """
23 pass
24
25
26 def handle(database): 27 """
28 对某种数据库形式处因而 29 本程序用的是文件处理file_storage 30 :param database: settings里面的DATABASE 31 :return: 返回路径 32 """
33 if database["db_tool"] == "file_storage": 34 return file_db_handle(database) 35 if database["db_tool"] == "mysql": 36 return mysql_db_handle(database)
main.py
1 """
2 主逻辑交互模块 3 """
4 from core import auth 5
6
7 #用户数据信息
8 user_data = { 9 'account_id':None, #账号ID
10 'is_authenticated':False, #是否定证
11 'account_data':None #账号数据
12
13 } 14
15
16 def account_info(): 17 """
18 用户账户信息 19 :return: 20 """
21 pass
22
23
24 def repay(): 25 """
26 还款 27 :return: 28 """
29 pass
30
31
32 def withdraw(): 33 """
34 退出 35 :return: 36 """
37 pass
38
39
40 def transfer(): 41 """
42 转账 43 :return: 44 """
45 pass
46
47
48 def paycheck(): 49 """
50 转账检查 51 :return: 52 """
53 pass
54
55
56 def logout(): 57 """
58 退出登录 59 :return: 60 """
61 pass
62
63
64 def interactive(): 65 """
66 交互 67 :return: 68 """
69 pass
70
71
72
73 def run(): 74 """
75 当程序启动时调用,用于实现主要交互逻辑 76 :return: 77 """
78 access_data = auth.access_login(user_data) #调用认证模块,返回用户文件json.load后的字典
79 print("AA")
zcl.json
{"status": 0, "expire_date": "2021-01-01", "credit": 15000, "pay_day": 22, "balance": 15000, "enroll_date": "2016-01-02", "id": 22, "password": "abc"}
测试结果1:
C:\Users\Administrator\PycharmProjects\laonanhai\ATM BB Account:zcl Password:abc C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json {'id': 22, 'credit': 15000, 'password': 'abc', 'status': 0, 'expire_date': '2012-01-01', 'enroll_date': '2016-01-02', 'pay_day': 22, 'balance': 15000} 1325347200.0 time.struct_time(tm_year=2012, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=1, tm_isdst=-1) Account zcl had expired,Please contract the bank Account:
测试结果2:
C:\Users\Administrator\PycharmProjects\laonanhai\ATM BB Account:zcl Password:abc C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json {'expire_date': '2021-01-01', 'status': 0, 'enroll_date': '2016-01-02', 'balance': 15000, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22} 1609430400.0 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) return Account:
OK, 今日退朝,明日继续!
1.amt.py运行时调用core目录下的main.py
2.main.py调用core目录下的auth.py进行登录和信用卡认证
3.auth.py调用db_handle.py,返回账号文件的路径,进行信用卡账户检查
4.auth.py进行登录认证,登录失败不能超过三次(未彻底实现)
今天完善了登录功能,实现了日志功能,写了一点点交互功能,好比查看账户信息,自我感受良好。
1.看下面这段代码
1 msg = ( 2 """ 3 -------------ZhangChengLiang Bank--------------- 4 \033[31;1m 1. 帐户信息 5 2. 还款 6 3. 取款 7 4. 转帐 8 5. 帐单 9 6. 退出 10 \033[0m""" 11 ) 12 menu_dic = { 13 "1":account_info, 14 "2":repay, 15 "3":withdraw, 16 "4":transfer, 17 "5":paycheck, 18 "6":logout 19 } 20 flag = False 21 while not flag: 22 print(msg) 23 choice = input("<<<:").strip() 24 if choice in menu_dic: 25 #很重要!!省了不少代码,不用像以前一个一个判断! 26 menu_dic[choice](acc_data) 27 28 else: 29 print("\033[31;1mYou choice doesn't exist!\033[0m")
固然,在面向对象能够用反射(我尚未过),但这里我感受用得至关巧!!不用像我以前一个一个用if...else..来判断。
2.掌握日志的用法
以前只是知道,写单独的一个文件,此次综合的运用,感受我对日志的用法已经至关有信心了。
16/11/5 文件目录
与昨天的基本没有什么变化,只是运行时在log包下多了个access.log文件还有在core包下多了log.py文件
atm.py 不变
settings.py
只多了个LOGIN_TYPE字典,用于后面生成access.log日志文件
1 """
2 初始化的配置 3 """
4
5 import logging 6 import os 7
8 #到ATM目录,方便后面建立账户文件
9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10
11 LOGIN_LEVEL = logging.INFO #初始化日志级别
12
13 LOGIN_TYPE = { 14 "access":"access.log"
15 } 16
17
18 DATABASE = { 19 "db_tool":"file_storage", #文件存储,这里可拓展成数据库形式的
20 "name":"accounts", #db下的文件名
21 "path":"%s/db" % BASE_DIR 22 }
auth.py
完善了登录功能,日志功能
1 """
2 认证模块 3 """
4 print("BB") 5 import os 6 import json 7 import time 8
9 from core import db_handle 10 from conf import settings 11
12
13 def access_auth(account, password, log_obj): 14 """
15 下面的access_login调用access_auth方法,用于登录 16 :param acount: 用户名 17 :param password: 密码 18 :return:若是未超期,返回字典,超期则打印相应提示 19 """
20 db_path = db_handle.handle(settings.DATABASE) #调用db_handle下的handle方法,返回路径/db/accounts
21 print(db_path) 22 account_file = "%s/%s.json" % (db_path, account) #用户文件
23 print(account_file) 24 if os.path.isfile(account_file): #若是用户文件存在(即用户存在)
25 with open(account_file, "r", encoding="utf-8") as f: #打开文件
26 account_data = json.load(f) #file_data为字典形式
27 print(account_data) 28 if account_data["password"] == password: 29 expire_time = time.mktime(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 30 print(expire_time) 31 print(time.strptime(account_data["expire_date"], "%Y-%m-%d")) 32 if time.time() > expire_time: #若是信用卡已超期
33 log_obj.error("Account [%s] had expired,Please contract the bank" % account) 34 print("\033[31;1mAccount [%s] had expired,Please contract the bank" % account) 35 else: #信用卡未超期,返回用户数据的字典
36 print("return") 37 log_obj.info("Account [%s] logging success" % account) 38 return account_data 39 else: 40 log_obj.error("Account or Passworddoes not correct!") 41 print("\033[31;1mAccount or Passworddoes not correct!\033[0m") 42 else: #用户不存在
43 log_obj.error("Account [%s] does not exist!" % account) 44 print("\033[31;1mAccount [%s] does not exist!\033[0m" % account) 45
46
47
48
49 def access_login(user_data, log_obj): 50 """
51 用记登录,当登录失败超过三次则退出 52 :param user_data: main.py里面的字典 53 :return:若用户账号密码正确且信用卡未超期,返回用户数据的字典 54 """
55 retry = 0 56 while not user_data["is_authenticated"] and retry < 3: 57 account = input("Account:").strip() 58 password = input("Password:").strip() 59 #用户账号密码正确且信用卡未超期,返回用户数据的字典
60 user_auth_data = access_auth(account, password, log_obj) 61 if user_auth_data: 62 user_data["is_authenticated"] = True #用户认证为True
63 user_data["account_id"] = account #用户账号ID为账号名
64 print("welcome") 65 return user_auth_data 66 retry += 1 #登录和信用卡认证出错,则次数加1
67
68 else: #若次数超过三次,打印相关信息并退出
69 print("Account [%s] try logging too many times..." % account) 70 log_obj.error("Account [%s] try logging too many times..." % account) 71 exit()
db_handle.py不变
log.py
实现日志功能,我里我先文件和屏幕都有输出。
1 import logging 2 from conf import settings 3
4
5 def log(logging_type): 6 """
7 main模块调用access_logger = log.log("access") 8 :param logging_type: "access" 9 :return: 返回logger日志对象 10 """
11 logger = logging.getLogger(logging_type) #传日志用例,生成日志对象
12 logger.setLevel(settings.LOGIN_LEVEL) #设置日志级别
13
14 ch = logging.StreamHandler() #日志打印到屏幕,获取对象
15 ch.setLevel(settings.LOGIN_LEVEL) 16
17 # 获取文件日志对象及日志文件
18 log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOGIN_TYPE[logging_type]) 19 fh = logging.FileHandler(log_file) 20 fh.setLevel(settings.LOGIN_LEVEL) 21
22 #日志格式
23 formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s-%(message)s") 24
25 #输出格式
26 ch.setFormatter(formatter) 27 fh.setFormatter(formatter) 28
29 #把日志打印到指定的handler
30 logger.addHandler(ch) 31 logger.addHandler(fh) 32
33 return logger #log方法返回logger对象
34
35 # logger.debug('debugmessage')
36 # logger.info('infomessage')
37 # logger.warn('warnmessage')
38 # logger.error('errormessage')
39 # logger.critical('criticalmessage')
main.py
增长了一点用交互功能(未完成)
1 """
2 主逻辑交互模块 3 """
4 from core import auth 5 from core import log 6
7
8 #用户数据信息
9 user_data = { 10 'account_id':None, #账号ID
11 'is_authenticated':False, #是否定证
12 'account_data':None #账号数据
13
14 } 15
16 #调用log文件下的log方法,返回日志对象
17 access_logger = log.log("access") 18
19
20 def account_info(acc_data): 21 """
22 查看用户账户信息 23 :return: 24 """
25 print(acc_data) 26
27
28 def repay(acc_data): 29 """
30 还款 31 :return: 32 """
33 pass
34
35
36 def withdraw(): 37 """
38 退出 39 :return: 40 """
41 pass
42
43
44 def transfer(): 45 """
46 转账 47 :return: 48 """
49 pass
50
51
52 def paycheck(): 53 """
54 转账检查 55 :return: 56 """
57 pass
58
59
60 def logout(): 61 """
62 退出登录 63 :return: 64 """
65 pass
66
67
68 def interactive(acc_data): 69 """
70 用户交互 71 :return: 72 """
73 msg = ( 74 """
75 -------------ZhangChengLiang Bank--------------- 76 \033[31;1m 1. 帐户信息 77 2. 还款 78 3. 取款 79 4. 转帐 80 5. 帐单 81 6. 退出 82 \033[0m"""
83 ) 84 menu_dic = { 85 "1":account_info, 86 "2":repay, 87 "3":withdraw, 88 "4":transfer, 89 "5":paycheck, 90 "6":logout 91 } 92 flag = False 93 while not flag: 94 print(msg) 95 choice = input("<<<:").strip() 96 if choice in menu_dic: 97 #很重要!!省了不少代码,不用像以前一个一个判断!
98 menu_dic[choice](acc_data) 99
100 else: 101 print("\033[31;1mYou choice doesn't exist!\033[0m") 102
103
104
105 def run(): 106 """
107 当程序启动时调用,用于实现主要交互逻辑 108 :return: 109 """
110 # 调用认证模块,返回用户文件json.load后的字典,传入access_logger日志对象
111 access_data = auth.access_login(user_data, access_logger) 112 print("AA") 113 if user_data["is_authenticated"]: #若是用户认证成功
114 print("has authenticated") 115 #将用户文件的字典赋给user_data["account_data"]
116 user_data["account_data"] = access_data 117 interactive(user_data) #用户交互开始
1 C:\Users\Administrator\PycharmProjects\laonanhai\ATM 2 BB 3 Account:123 4 Password:333 5 2016-11-05 23:03:55,210-access-ERROR-Account [123] does not exist! 6 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 7 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 8 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/123.json 9 Account [123] does not exist! 10 Account:zcl 11 Password:abc 12 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 13 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 14 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json 15 {'balance': 15000, 'enroll_date': '2016-01-02', 'expire_date': '2021-01-01', 'status': 0, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22} 16 2016-11-05 23:04:08,977-access-INFO-Account [zcl] logging success 17 1609430400.0 18 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) 19 return 20 welcome 21 AA 22 has authenticated 23 24 -------------ZhangChengLiang Bank--------------- 25 1. 帐户信息 26 2. 还款 27 3. 取款 28 4. 转帐 29 5. 帐单 30 6. 退出 31 32 <<<:1 33 {'account_data': {'balance': 15000, 'enroll_date': '2016-01-02', 'expire_date': '2021-01-01', 'status': 0, 'id': 22, 'password': 'abc', 'credit': 15000, 'pay_day': 22}, 'is_authenticated': True, 'account_id': 'zcl'} 34 35 -------------ZhangChengLiang Bank--------------- 36 1. 帐户信息 37 2. 还款 38 3. 取款 39 4. 转帐 40 5. 帐单 41 6. 退出
1.log.py设置日志级别、生成日志对象,返回logger日志对象
2.main.py在调用auth.py认证模块时,传logger对象
3.经过logger对象进行一系列操做
4.main.py中run()方法调用interactive交互接口
5.interactive()方法经过用户选择进行交互(大部分还未实现)
11/5 OK,明日继续!
今天都在实现用户的交互功能,我只实现了存款功能repay,别看只实现了一个,我拓展性搞得还能够的!其余未实现,但感受套路都是差很少的。
在实现用户交互功能之一(存款)时,个人思考以下:
6. 到这里我大悟,每次用户调用ATM交互功能,应先将用户信息读出来,每个功能结束后都应将信息更新到数据库中去
1.用户交易模块的拓展性惊人
def make_transaction(account_data, transaction_type, amount): 这里的transaction_type交易类型(存,取,转…)
在settings.py定义好交易的类型,拓展性很好!
1 #用户交易类型,每一个类型对应一个字典,包括账户金额变更方式,利息
2 TRANSACTION_TYPE = { 3 "repay":{"action":"plus", "interest":0}, #存款
4 "withdraw":{"action":"minus", "interest": 0.05} #取款(提现)
5 }
2. if num == "b" or "back"
这里我SB了,哈哈~
1 num = input(">>>>:") 2 if num == "b" or "back": 3 print("OK") 4 else: 5 print("ERROR")
这里我测试时,明明输入的不是"b" 或者"back", 但结果倒是“OK", 一度让我怀疑人生,因而我作了上面的测试。
仔细一想, or "back",“back” 不为0,因此这个判断为True, 必定输出的是"OK". .......之后不再敢了~
与11/5多了transaction.py模块,account.py模块,test.py是我本身测试用的,能够忽略~
main.py
实现了还款功能
1 """ 2 主逻辑交互模块 3 """ 4 from core import auth 5 from core import log 6 from core import transaction 7 from core import account 8 9 10 #用户数据信息 11 user_data = { 12 'account_id':None, #账号ID 13 'is_authenticated':False, #是否定证 14 'account_data':None #账号数据 15 16 } 17 18 #调用log文件下的log方法,返回日志对象 19 access_logger = log.log("access") 20 21 22 def account_info(acc_data): 23 """ 24 acc_data:包括ID,is_authenticaed,用户账号信息 25 查看用户账户信息 26 :return: 27 """ 28 print(acc_data) 29 30 31 def repay(acc_data): 32 """ 33 acc_data:包括ID,is_authenticaed,用户账号信息 34 还款 35 :return: 36 """ 37 print(acc_data) 38 print("??") 39 #调用account模块的load_account方法,从数据库从load出用户信息 40 account_data = account.load_account(acc_data["id"]) 41 print(account_data) 42 current_balance = """ 43 -------------BALANCE INFO-------------- 44 Credit:%s 45 Balance:%s 46 """ % (account_data["credit"], account_data["balance"]) 47 back_flag = False 48 while not back_flag: 49 print(current_balance) 50 repay_amount = input("\033[31;1mInput repay amount(b=back):\033[0m").strip() 51 #若是用户输入整型数字 52 if len(repay_amount) > 0 and repay_amount.isdigit(): 53 #调用transaction模块的方法,参数分别是用户账户信息,交易类型,交易金额 54 new_account_data = transaction.make_transaction(account_data, "repay", repay_amount) 55 if new_account_data: 56 print("\033[42;1mNew Balance:%s\033[0m" % new_account_data["balance"]) 57 58 else: 59 print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % repay_amount) 60 61 if repay_amount =="b" or repay_amount == "back": 62 back_flag = True 63 64 def withdraw(): 65 """ 66 取款 67 :return: 68 """ 69 pass 70 71 72 def transfer(): 73 """ 74 转账 75 :return: 76 """ 77 pass 78 79 80 def paycheck(): 81 """ 82 转账检查 83 :return: 84 """ 85 pass 86 87 88 def logout(): 89 """ 90 退出登录 91 :return: 92 """ 93 pass 94 95 96 def interactive(acc_data): 97 """ 98 用户交互 99 :return: 100 """ 101 msg = ( 102 """ 103 -------------ZhangChengLiang Bank--------------- 104 \033[31;1m 1. 帐户信息 105 2. 存款 106 3. 取款 107 4. 转帐 108 5. 帐单 109 6. 退出 110 \033[0m""" 111 ) 112 menu_dic = { 113 "1":account_info, 114 "2":repay, 115 "3":withdraw, 116 "4":transfer, 117 "5":paycheck, 118 "6":logout 119 } 120 flag = False 121 while not flag: 122 print(msg) 123 choice = input("<<<:").strip() 124 if choice in menu_dic: 125 #很重要!!省了不少代码,不用像以前一个一个判断! 126 menu_dic[choice](acc_data) 127 128 else: 129 print("\033[31;1mYou choice doesn't exist!\033[0m") 130 131 132 133 def run(): 134 """ 135 当程序启动时调用,用于实现主要交互逻辑 136 :return: 137 """ 138 # 调用认证模块,返回用户文件json.load后的字典,传入access_logger日志对象 139 access_data = auth.access_login(user_data, access_logger) 140 print("AA") 141 if user_data["is_authenticated"]: #若是用户认证成功 142 print("has authenticated") 143 #将用户文件的字典赋给user_data["account_data"] 144 user_data["account_data"] = access_data 145 interactive(user_data) #用户交互开始
settings.py
增长了用户交易类型TRANSACTION_TYPE{}
1 """ 2 初始化的配置 3 """ 4 5 import logging 6 import os 7 8 #到ATM目录,方便后面建立账户文件 9 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 11 LOGIN_LEVEL = logging.INFO #初始化日志级别 12 13 LOGIN_TYPE = { 14 "access":"access.log" 15 } 16 17 18 DATABASE = { 19 "db_tool":"file_storage", #文件存储,这里可拓展成数据库形式的 20 "name":"accounts", #db下的文件名 21 "path":"%s/db" % BASE_DIR 22 } 23 24 #用户交易类型,每一个类型对应一个字典,包括账户金额变更方式,利息 25 TRANSACTION_TYPE = { 26 "repay":{"action":"plus", "interest":0}, #存款 27 "withdraw":{"action":"minus", "interest": 0.05} #取款(提现) 28 }
transaction.py
处理用户交易的模块
1 """ 2 交易模块,处理用户金额移动 3 """ 4 import json 5 from conf import settings 6 from core import account 7 8 9 def make_transaction(account_data, transaction_type, amount): 10 """ 11 处理用户的交易 12 :param account_data:字典,用户的账户信息 13 :param transaction_type:用户交易类型,repay or withdraw... 14 :param amount:交易金额 15 :return:用户交易后账户的信息 16 """ 17 #将字符串类型转换为float类型 18 amount = float(amount) 19 #若是交易类型存在 20 if transaction_type in settings.TRANSACTION_TYPE: 21 #利息金额 22 interest = amount * settings.TRANSACTION_TYPE[transaction_type]["interest"] 23 #用户原金额 24 old_balace = account_data["balance"] 25 print(interest,old_balace) 26 #若是账户金额变化方式是"plus",加钱 27 if settings.TRANSACTION_TYPE[transaction_type]["action"] == "plus": 28 new_balance = old_balace + amount + interest 29 #若是账户金额变化方式是"minus",减钱 30 elif settings.TRANSACTION_TYPE[transaction_type]["action"] == "minus": 31 new_balance = old_balace - amount - interest 32 #减钱时对账户金额进行检查,防止超额 33 if new_balance < 0: 34 print("\033[31;1mYour Credit [%s] is not enough for transaction [-%s], and Now your" 35 " current balance is [%s]" % (account_data["credit"], (amount+interest), old_balace)) 36 return 37 38 account_data["balance"] = new_balance 39 #调用core下account模块将已更改的用户信息更新到用户文件 40 account.dump_account(account_data) 41 return account_data 42 43 else: 44 print("\033[31;1mTransaction is not exist!033[0m")
account.py
将用户信息读出或写入的模块
1 """ 2 用于处理用户信息的load or dump 3 每进行一个操做就将信息更新到数据库 4 """ 5 from core import db_handle 6 from conf import settings 7 import json 8 9 def load_account(account_id): 10 """ 11 将用户信息从文件中load出来 12 :return: 用户信息的字典 13 """ 14 #返回路径 ATM/db/accounts 15 db_path = db_handle.handle(settings.DATABASE) 16 account_file = "%s/%s.json" % (db_path, account_id) 17 with open(account_file, "r", encoding="utf-8") as f: 18 account_data = json.load(f) 19 return account_data 20 21 22 def dump_account(account_data): 23 """ 24 将已更改的用户信息更新到用户文件 25 :param account_data: 每操做后用户的信息 26 :return: 27 """ 28 db_path = db_handle.handle(settings.DATABASE) 29 account_file = "%s/%s.json" % (db_path, account_data["id"]) 30 with open(account_file, "w", encoding="utf-8") as f: 31 json.dump(account_data, f) 32 33 print("dump success")
1 C:\Users\Administrator\PycharmProjects\laonanhai\ATM 2 BB 3 Account:zcl 4 Password:abc 5 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 6 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 7 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts/zcl.json 8 {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 9 1609430400.0 10 time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=-1) 11 return 12 2016-11-07 13:42:24,678-access-INFO-Account [zcl] logging success 13 welcome 14 AA 15 has authenticated 16 17 -------------ZhangChengLiang Bank--------------- 18 1. 帐户信息 19 2. 存款 20 3. 取款 21 4. 转帐 22 5. 帐单 23 6. 退出 24 25 <<<:2 26 {'is_authenticated': True, 'account_data': {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'}, 'account_id': None, 'id': 'zcl'} 27 ?? 28 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 29 {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 30 31 -------------BALANCE INFO-------------- 32 Credit:15000 33 Balance:26000.0 34 35 Input repay amount(b=back):4500 36 0.0 26000.0 37 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 38 dump success 39 New Balance:30500.0 40 41 -------------BALANCE INFO-------------- 42 Credit:15000 43 Balance:26000.0 44 45 Input repay amount(b=back):back 46 back is not valid amount,Only accept interger! 47 48 -------------ZhangChengLiang Bank--------------- 49 1. 帐户信息 50 2. 存款 51 3. 取款 52 4. 转帐 53 5. 帐单 54 6. 退出 55 56 <<<:2 57 {'is_authenticated': True, 'account_data': {'balance': 26000.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'}, 'account_id': None, 'id': 'zcl'} 58 ?? 59 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 60 {'balance': 30500.0, 'expire_date': '2021-01-01', 'credit': 15000, 'status': 0, 'enroll_date': '2016-01-02', 'password': 'abc', 'pay_day': 22, 'id': 'zcl'} 61 62 -------------BALANCE INFO-------------- 63 Credit:15000 64 Balance:30500.0 65 66 Input repay amount(b=back):10000 67 0.0 30500.0 68 C:\Users\Administrator\PycharmProjects\laonanhai\ATM/db/accounts 69 dump success 70 New Balance:40500.0 71 72 -------------BALANCE INFO-------------- 73 Credit:15000 74 Balance:30500.0 75 76 Input repay amount(b=back):
1.repay还款功能调用account.py经过ID读出用户信息
2.repay还款功能调用transaction.py交易模块
3.transaction.py交易模块调用account.py更新用户数据到数据库
4.settings.py里的TRANSACTION_TYPE字典传入交易方法,实现拓展性
今日超神,明日继续实现交互功能或体息一天!
作了还款,取款,转账功能,都是套路了,难度不大。
咋晚给舍友看了我作了东西,居然被舍友说,亮点在哪里。时间有限,生命有限,继续学习之路,这个小项目就到此为止了。
ATM压缩包:http://pan.baidu.com/s/1hrNF5TM