ATM
2018-05-02 17:23 钱先生 阅读(293) 评论(0) 编辑 收藏 举报ATM 要求
示例代码: https://github.com/triaquae/py_training/tree/master/sample_code/day5-atm
=================================================================================================================================
作业代码: https://github.com/cheese320/atm
bin
- main.py 主程序
#!/usr/bin/python # -*- coding: utf-8 -*- import os import sys path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(path) # 这样这个路径会在最后面,每次都要遍历到最后才能找到(如果中途没有同名文件的话) sys.path.insert(0, path) # 将该路径插到前面去 from core import tools def run(): exit_flag = False # 普通用户 if tools.username != "admin": # 能打印帐户信息的都是正常状态的帐户, 所以这里不显示帐户状态 initial = ''' ---------- {_name}帐户信息 --------- credit: {_credit} balance: {_balance} enroll-date: {_enroll} expire_date: {_expire} pay_day: {_payday} ------------ The End ----------- '''.format(_name=tools.username, _credit=tools.info[tools.username]["credit"], _balance=tools.info[tools.username]["balance"], _enroll=tools.info[tools.username]["enroll_date"], _expire=tools.info[tools.username]["expire_date"], _payday=tools.info[tools.username]["pay_day"]) print(initial) while not exit_flag: msg = ''' 1. 商城 2. 还款 3. 取款 4. 转帐 5. 帐单 6. 退出 ''' print("功能列表".center(20, "*")) print(msg) print("The end".center(23, "*")) user_choice = input("请选择功能数字代码: ") if user_choice == "quit": exit_flag = True elif not user_choice.isdigit(): print("输入有误, 请重输") break else: seq = int(user_choice) if seq <= 0 or seq > 6: print("输入有误, 请重输") elif seq == 1: tools.shopping_mall() elif seq == 2: tools.repay() elif seq == 3: tools.withdraw() elif seq == 4: tools.transfer() elif seq == 5: tools.bill() elif seq == 6: exit() else: while not exit_flag: msg2 = ''' 1. 添加帐户 2. 解锁帐户 3. 修改用户额度 4. 冻结帐户 5. 解冻帐户 6. 退出 ''' print("功能列表".center(20, "*")) print(msg2) print("The end".center(23, "*")) print("\r\n") user_choice2 = input("请选择功能数字代码: ") if user_choice2 == "quit": exit_flag = True elif not user_choice2.isdigit(): print("输入有误, 请重输") break else: seq2 = int(user_choice2) if seq2 <= 0 or seq2 > 6: print("输入有误, 请重输") elif seq2 == 1: tools.new_account() elif seq2 == 2: tools.unlock() elif seq2 == 3: tools.adjustment() elif seq2 == 4: tools.freeze() elif seq2 == 5: tools.unfreeze() elif seq2 == 6: exit() run()
- path_define.py 执行主程序
#!/usr/bin/python # -*- coding: utf-8 -*- import os import sys base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, base_dir) from bin import main if __name__ == '__main__': main.run()
conf
- settings.py 数据库,log,路径等
#!/usr/bin/python # -*- coding: utf-8 -*- import logging import os BASE_DIR =os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DATABASE = { 'engine': 'file_storage', # support mysql, postgresql in the future 'name': 'account', 'path': "%s\db" % BASE_DIR } LOG_LEVEL = logging.INFO LOG_TYPES = { 'transaction': 'transactions.log', 'access': 'access.log' } TRANSACTION_TYPE = { 'repay': {'action': 'plus', 'interest': 0}, 'withdraw': {'action': 'minus', 'interest': 0.05}, 'transfer': {'action': 'minus', 'interest': 0.05}, 'consume': {'action': 'minus', 'interest': 0}, }
core
- db_handle.py 处理json文件(读, 写)
#!/usr/bin/python # -*- coding: utf-8 -*- def file_db_handle(database): """ 数据存于文件 :param database: :return: 文件存储路径 """ db_path = "%s" % (database['path']) return db_path def sql_db_handle(database): """ 数据存于数据库 :param database: :return: """ pass def handle(database): """ 根据数据存储方式判断如何获取数据 :param database: :return: """ if database['engine'] == 'file_storage': return file_db_handle(database) elif database['engine'] == 'sql': return sql_db_handle(database) else: pass
db
- account.json 帐户信息
- repository.json 商品信息
- shopping_list.json 已购买清单
{"Alex": {"password": "aaa", "credit": 78000, "balance": 15000.0, "enroll_date": "2017-01-01", "expire_date": "2021-01-01", "pay_day": 22, "status": 0}, "Lucy": {"password": "bbb", "credit": 15000, "balance": 15000, "enroll_date": "2017-02-02", "expire_date": "2022-02-02", "pay_day": 22, "status": 0}, "Jack": {"password": "ccc", "credit": 15000, "balance": 15000, "enroll_date": "2017-03-03", "expire_date": "2023-03-03", "pay_day": 22, "status": 2}, "admin": {"password": "root", "status": 0}, "David,999": {"password": "999", "credit": 150000, "balance": 15000, "enroll_date": "2017-01-01", "expire_date": "2021-01-01", "pay_day": 22, "status": 0}}
{"iphone": {"inventory": 20, "price": 9000}, "book": {"inventory": 3, "price": 50}, "bike": {"inventory": 90, "price": 600}, "cd": {"inventory": 100, "price": 83}, "fish": {"inventory": 90, "price": 40}}
{"Alex": {"cd": {"buy_qty": 5, "spent": 249}, "book": {"buy_qty": 8, "spent": 100}, "iphone": {"buy_qty": 1, "spent": 9000}}, "Lucy": {"book": {"buy_qty": 3, "spent": 150}, "iphone": {"buy_qty": 1, "spent": 9000}}, "Jack": {}}
doc
- flowchart
- idea.txt 设计思路
1. 主程序 /* 错误提示字体颜色: 34 成功提示字体颜色: 31 帐户状态: 0 - normal 1 - locked 2 - frozen 退出 : 1. 在任一子程序, 输入quit返回上一级. 2. 在功能列表层级, 输入quit结束程序. */ 1.1, 判断用户是否登录, 并返回用户信息. def login() A. 普通用户 (进入循环菜单) 1.1.1, 打印功能列表 1). 商城 def shopping_mall() 2). 还款 def repay() 3). 取款 def "withdraw() 4). 转帐 def transfer() 5). 帐单 def bill() 6). 退出 B. 管理帐户 (进入循环菜单) 1.1.2, 打印功能列表 1). 添加帐户 def new_account() 2). 解锁帐户 def unlock() 3). 修改用户额度 def adjustment() 4). 冻结帐户 def freeze() 5). 解冻帐户 def unfreeze() 6). 退出 2. 登录 def login() 2.1, 用户输入用户名密码 1). 对用户输入进行处理strip() 2). 判断 A). 用户输入是否是quit? -- 是: 退出程序 -- 不是: 进入下一步 ==>2.1.2.c B). 用户输入用户名是否存在? a). 不存在: 需重输. b). 存在: 判断密码是否正确 -- 不正确: 需重输, 重输超过三次, 锁定帐户 (提示联系管理员解锁并退出程序) -- 正确: 判断用户是普通用户还是管理帐户, 返回相应帐户信息 -- 若帐户已冻结, 提示联系管理员解冻并退出程序 3. 商城 def shopping_mall() 3.1, 打印商品列表 3.2, 用户输入商品编号和购买数量 1). 判断输入的商品是否存在, 及购买数量是否合适 -- 商品存在且购买数量<=库存 : 下一步 ==> 3.3 -- else: 请用户输入商品编号及购买数量 2). 用户输入quit退出 3.3, 判断帐户余额是否足够支付 -- 不足够支付: 重输商品编号和购买数量 (重复3.2判断) -- 足够支付: 下一步 ==> 3.4 3.4, 打印用户购买商品清单 3.5, 购买成功 1). 扣减帐户余额, 并打印更新的帐户信息; 同时, 更新帐户信息写回account.py @ATM LOG 2). 扣减库存, 并写回repository.py 4. 还款 def repay() 4.1, 打印当前欠款金额 4.2, 用户输入还款金额 1). 判断输入是否是quit -- 是: 退出 -- 不是: 下一步 ==> 4.2.2 2). 判断输入的金额是否是数字 -- 是: 下一步 ==> 4.3 -- 不是: 重输 4.3, 还款成功 1). 更新帐户余额, 并打印更新的帐户信息; 更新的帐户信息写回account.py @ATM LOG 5. 取款 def withdraw() 5.1, 用户输入取款金额 5.2, 对用户输入进行处理strip() 5.3, 判断输入是否是quit -- 是: 退出 -- 不是: 下一步 ==> 5.4 5.4, 判断输入是否是数字 -- 是: 下一步 ==> 5.4 -- 不是: 重输 5.5, 判断输入的数字是否<当前帐户余额 -- 是: 下一步 ==> 5.5 -- 不是: 重输 5.6, 借钱成功 1). 扣减帐户余额, 并打印更新的帐户信息; 更新的帐户信息写回account.py @ATM LOG 6. 转帐 def transfer() 6.1, 用户输入收款用户名和转帐金额 6.2, 判断输入是否是quit -- 是: 退出 -- 不是: 下一步 ==> 6.3 6.3, 判断用户名是否存在 -- 存在: 判断转帐金额是否是数字 -- 是数字且金额小于帐户余额: 下一步 ==> 6.3 -- else: 重输 -- 不存在: 重输 6.4, 转帐成功 1). 扣减帐户余额, 并打印更新的帐户信息; 更新的帐户信息写回account.py @ATM LOG 7. 帐单 def bill() 7.1, 用户输入年,月 7.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 7.3 7.3, 判断用户输入是否有效 -- 有效: 下一步 ==> 7.4 -- 无效: 重输 7.4, 打印帐单明细 8. 添加帐户 def new_account() 8.1, 用户输入用户名和密码及帐户信息 8.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 8.3 8.3, 判断用户名是否存在 -- 是: 重输 -- 不是: 下一步 ==> 8.4 8.4, 添加成功 1). 将用户信息添加到account.py 9. 解锁帐户 def unlock() 9.1, 用户输入需要解锁的用户名 9.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 9.3 9.3, 判断帐户是否已被锁定 -- 是: 下一步 -- 不是: 重输 9.4, 解锁成功 1). 将用户信息更新到account.py 10. 修改用户额度 def adjustment() 10.1, 用户输入用户名 10.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 10.3 10.3, 修改成功 1). 将用户信息更新到account.py 11. 冻结帐户 def freeze() 11.1, 用户输入用户名 11.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 11.3 11.3, 冻结成功 1). 将用户信息更新到account.py 12. 解冻帐户 def unfreeze() 12.1, 用户输入用户名 12.2, 判断输入是否是quit -- 是: 退出程序 -- 不是: 下一步 ==> 12.3 12.3, 解冻成功 1). 将用户信息更新到account.py common: a. 判断输入是否是quit b. 判断用户名是否存在 c. 更新account.py
log
- log.py 记录access和transactions的日志
#!/usr/bin/python # -*- coding: utf-8 -*- import os import sys import json import logging path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(path) # 这样这个路径会在最后面,每次都要遍历到最后才能找到(如果中途没有同名文件的话) sys.path.insert(0, path) # 将该路径插到前面去 from conf import settings def log(logging_type): """ 去掉打印在屏幕上的功能 :param logging_type: :return: """ # 传日志用例, 生成日志对象 logger = logging.getLogger(logging_type) # 设置日志级别 logger.setLevel(settings.LOG_LEVEL) # # 日志打印到屏幕上 # ch = logging.StreamHandler() # ch.setLevel(settings.LOG_LEVEL) # 获取文件日志对象及日志文件 log_file = "%s\log\%s" % (settings.BASE_DIR, settings.LOG_TYPES[logging_type]) # 默认log文件编译用GBK, 这里指定编码utf-8 fh = logging.FileHandler(log_file, "a", encoding="UTF-8") fh.setLevel(settings.LOG_LEVEL) # 日志格式 formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s-%(message)s") # 输出格式 # ch.setFormatter(formatter) fh.setFormatter(formatter) # 把日志打印到指定的handler # logger.addHandler(ch) logger.addHandler(fh) return logger
readme.txt
Module2-atm/
├── README
├── atm #ATM主程目录
│ ├── __init__.py
│ ├── bin #ATM 执行文件 目录
│ │ ├── __init__.py
│ │ ├── main.py # 主程序
│ │ └── path_define.py # 执行程序
│ ├── conf #配置文件
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── core #主要程序逻辑都在这个目录 里
│ │ ├── __init__.py
│ │ ├── db_handle.py #数据库连接引擎
│ │ └── tools.py #所有子程序都在这儿,a包括商城程序.
│ ├── db #用户数据存储的地方
│ │ ├── __init__.py
│ │ ├── account.py #便于迅速恢复同名json文件数据初始化状态.
│ │ ├── account.json #用户帐户信息.
│ │ ├── repository.py #便于迅速恢复同名json文件数据初始化状态.
│ │ ├── repository.json #商品库存信息
│ │ └── shopping_list.json #存各个用户的商城购买清单
│ │
│ │── doc #文档
│ │ ├── __init__.py
│ │ ├── idea.txt #代码思路
│ │ └── flowchart.jpg #流程图
│ └── log #日志目录
│ ├── __init__.py
│ ├── access.log #用户访问和操作的相关日志
└── └── transactions.log #所有的交易日志