作业需求及初步思路

  需求  思路 
1 自定义信用卡额度 e.g 15000   见下数据存储模式
 2  实现购物商城,买东西加入购物车,调用信用卡结构结账  改下购物车的扣款接口 
3 可以提现,手续费5%   【提现】注意有利息,同时打印日志 
4 支持多账户登陆(admin, client)

【信用卡中心】for client

【管理员中心】for admin

5  支持账户间转账  【转账】打印日志 
 6 记录每月日常消费流水  【消费流水】transaction.log; 呈现购物车消费,提现,转账,还款的日志 
 7 提供还款结构  【还款】 
 8 ATM记录操作日志 access.log; 呈现账户操作日志 
 9 提供管理接口(admin),包括添加账户、用户额度、冻结账户等  【管理员中心】
10 用户认证用装饰器  登陆之后,在其他接口时,用于验证登陆状态

知识点

1. 程序的解耦:以下引用知乎的一个解释

解耦即增加正交性,通俗的讲就是减少模块间的互相干扰,让各个模块的修改变化尽可能小的影响其它模块

完全不耦合是不可能的,完全不耦合的程序不可能进行数据和指令的传递与交换。

解耦的基本方法是面向接口进行开发,也就是说各个模块只和接口发生耦合,要么调用接口要么实现接口,因此接口本身的设计是程序模块化的重中之重,大型程序中接口设计的优劣常常直接决定整个系统的优劣。

一个常见且基本的例子是图形处理。在正交的程序中,当你得到一个shape对象,可以通过该对象的draw方法直接把它画出来,而不必关心它实际上是一个 circle,rectangle,还是triangle。而在一个非正交的程序中,你必须分别知道它们的圆心位置和半径,长和宽,各顶点位置等信息再进行具体的绘制。简单说,前一种情况只依赖了draw方法,而后一种情况需要依赖各个图形的具体参数。

在ATM作业中,比较典型的解耦例子:auth 和 transaction 

2. 多线程操作下的文件存储方式:每个client account 建立一个 json文件。 目的是,当某个用户在操作账户时,另一个客户也可以同时操作更改账户信息。

3. 数据类型接口: 为了能够对接不同的数据库,一般设置鉴别数据存贮的方式。 具体操作是,在conf/settings中,设置以下database的字典。这种操作和Django里一样。 这样操作主要是为了任意更换数据库类型, 可以是file, mysql, postegresal等。

DATABASE = dict(engine="file_storage",                              # engine为数据库类型;可扩张成不同数据源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"database"),   # 数据库路径name="accounts")                                    # 数据库名称,每个数据库一个json文件,为了支持多线程操作。

数据库接口代码如下:

但是,写数据库接口 db api 中,要注意统一不同数据库的解析语言(mysql)。接口对象有:

4. logging 模块: 写入不同的文件(handler); 读取日志,有条件地读取日志信息(show_logger)

MY WORK

#!usr/bin/env python
#-*- coding:utf-8 -*-import os
import sysBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)from core import mainif __name__ == '__main__':main.sys_run()

bin\atm.py

#!usr/bin/env python
#-*- coding:utf-8 -*-import os, sys, logging# 主程序目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 数据库
DATABASE = dict(engine="file",          # engine为数据库类型;可扩张成不同数据源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"database"),name="accounts")        # 数据库名称,每个数据库一个json文件,为了支持多线程操作。# 日志
LOG_LEVEL = logging.INFO
LOG_TYPES = dict(transactions="transactions.log",access="access.log")LOG_DATABASE = dict(engine="file",           # 可扩张成不同数据源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"log"),name="accounts")# 参数
BILL_DAY = 22TRANSACTION_TYPE = {'repay': {'action': 'plus', 'interest': 0},          # 还款'receive': {'action': "plus", 'interest': 0},        # 接收'withdraw': {'action': 'minus', 'interest':0.05},    # 提款'transfer': {'action': 'minus', 'interest':0.05},    # 转出'pay': {'action': 'minus', 'interest': 0},           # 支付
}SHOPPING_MENU = {'海鲜水产':{'竹节虾': {'单价': 68, '数量': 5},'面包蟹': {'单价': 75, '数量': 5},'石斑鱼': {'单价': 50, '数量': 5},'活蛏子': {'单价': 20, '数量': 10}},'新鲜水果':{'阳山水蜜桃': {'单价': 33, '数量': 5},'8424西瓜': {'单价': 60, '数量': 5},'巨峰葡萄': {'单价': 21, '数量': 5},'仙居杨梅': {'单价': 40, '数量': 5},'小台农芒果': {'单价': 13, '数量': 20}},'肉禽蛋品': {'土鸡蛋': {'单价': 9, '数量': 4},'澳洲上脑牛排': {'单价': 30, '数量': 5},'黑毛猪小排': {'单价': 28, '数量': 5},'澳洲冰鲜牛腩': {'单价': 45, '数量': 5},'帝王鸡': {'单价': 100, '数量': 5}},'乳制品': {'低脂鲜牛奶': {'单价': 17, '数量': 5},'全脂牛奶': {'单价': 20, '数量': 4},'酸奶': {'单价': 21, '数量': 2}}}

conf\settings

#!usr/bin/env python
#-*- coding:utf-8 -*-
OPEN_WIN = '''
|------------------------------------MyBank\'s ATM SYSTEM--------------------------------------|
|                                                                                              |
|                                       1. Admin                                               |
|                                       2. Existing Client                                     |
|                                                                                              |
| Please contact our local service counter for a new credit card application.                  |
|----------------------------------------------------------------------------------------------|
'''CLIENT_WIN = '''
|------------------------------------MyBank\'s ATM SYSTEM--------------------------------------|
| Dear {},                                                                                     |
|             1. Online Shopping        2. My Account            3. Repayment                  |
|             4. Withdrawal             5. Transfer              6. Account Statement          |
|                                       7. Log Out                                             |
|                                                                                              |
|----------------------------------------------------------------------------------------------|
'''ADMIN_WIN = '''
|------------------------------------MyBank\'s ATM SYSTEM--------------------------------------|
| Dear {},                                                                                     |
|             1. Create                 2. Reactivate             3. Freeze                    |
|             4. Credit update          5. Log Out                                             |
|                                                                                              |
|                                                                                              |
|----------------------------------------------------------------------------------------------|
'''STATEMENT_TEMP = '''
|---------------------------------------------------STATEMENT REPORT----------------------------------------------------|Dear {},Your desired reporting period: \033[31;1m{}\033[0m  to  \033[31;1m{}\033[0m
|-----------------------------------------------------------------------------------------------------------------------|
'''SHOPPING_WIN = '''
|--------------------------MyBank\'s Online Shopping Mall--------------------------------------|
| Dear {},                                                                                     |
|             1. Shopping               2. Historical shopping log                             |
|                                                                                              |
|                                                                                              |
|----------------------------------------------------------------------------------------------|
'''

conf\templates

 1 #!usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3
 4 import os,json,datetime
 5 from conf import settings
 6 from core import db_handler
 7 from core import update_acc_info
 8 from core import logger
 9
10 def login(user_data, log_type):
11     '''
12     系统登录,将读取的json信息作为account_data 更新到user_data 字典中去
13     :param user_data: from main
14     :return:
15     '''
16     login_count = 0
17     max_count = 3
18     account_id = input("Accout ID: ").strip()
19     while user_data["is_authenticated"] is not True:
20         if login_count < max_count:
21             password = input("Password: ").strip()
22             acc_file = "%s.json" % account_id
23             db_file_path = db_handler.db_handler(settings.DATABASE)
24             acc_path = os.path.join(db_file_path, acc_file)  # 获取单个acc 路径,支持多线程操作
25             if os.path.isfile(acc_path):
26                 with open(acc_path, "r+", encoding="utf-8") as f:
27                     account_data = json.load(f)
28                 if account_data["password"] == password:
29                     exp_date_stamp = datetime.datetime.strptime(account_data["expire_date"], "%Y-%m-%d")
30                     acc_status = account_data["status"]
31                     if acc_status == 0 or acc_status == 8:
32                         if exp_date_stamp < datetime.datetime.today():
33                             print("Your account is expired. please contact admin for renew.")
34                         else:
35                             return account_data
36                     else:
37                         exit("Your account is frozen. Please contact admin for updates")
38                 else:
39                     print("Incorrect password ")
40                     login_count +=1
41                     continue
42             else:
43                 exit("Account does not exit! Please contact admin")
44         else:
45             log_type.error("account is frozen for trying too many times")
46             account_data = update_acc_info.load_account(account_id)
47             account_data["status"] = 2
48             update_acc_info.dump_account(account_data)
49             exit()

core\auth

 1 #!usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3
 4 import datetime
 5 from conf import settings
 6
 7 def get_bill_date(year_month):
 8     '''
 9     获取账单时间内的账单。每月账单日22日
10     :param year_month_date:
11     :return:
12     '''
13     bill_day = "%s-%s" % (year_month, settings.BILL_DAY)
14     bill_bday = datetime.datetime.strptime(bill_day, "%Y-%m-%d")
15     year = bill_bday.year
16     month = bill_bday.month
17     if month == 12:
18         year +=1
19         month =1
20     else:
21         month +=1
22     bill_eday = datetime.datetime(year, month, settings.BILL_DAY)
23     return bill_bday,bill_eday

core\billdate

 1 #!usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3
 4
 5 def db_handler(conn_params):
 6     '''
 7     数据库接口解析。可扩展到mysql, postgresql等其他数据库方式。现在只用file 存储
 8     :param conn_params: settings.DATABASE
 9     :return: file读取,返回数据库路径
10     '''
11     if conn_params["engine"] == "file":
12         return conn_params["database_path"]
13     else:
14         print('Current system does not support other databases')

core\db_handler

 1 #!usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3
 4 import logging
 5 import os
 6 import datetime
 7 from conf import settings
 8 from conf import templates
 9 from core import billdate
10
11 def logger(log_type):
12     '''
13     写日志到屏幕和不同文件
14     :param log_type: transaction 或 access
15     :return:
16     '''
17     # 创建logger
18     logger = logging.getLogger(log_type)
19     logger.setLevel(settings.LOG_LEVEL)
20
21     # 屏幕handler
22     ch = logging.StreamHandler()
23     ch.setLevel(settings.LOG_LEVEL)
24
25     # 文件handler
26     log_file = os.path.join(os.path.join(settings.BASE_DIR,"log"),settings.LOG_TYPES[log_type])
27     fh = logging.FileHandler(log_file)
28     fh.setLevel(settings.LOG_LEVEL)
29
30     # handler输出的格式设置
31     formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelno)s-%(message)s")
32
33     # 关联handler和formatter
34     ch.setFormatter(formatter)
35     fh.setFormatter(formatter)
36
37     # 告诉logger输出不同的handler
38     logger.addHandler(ch)
39     logger.addHandler(fh)
40
41     return logger
42
43
44 def show_logger(acc_id, log_obj, year_month):
45     '''
46
47     :param acc_id:
48     :param log_obj:
49     :param year_month:
50     :return:
51     '''
52
53     bill_bday, bill_eday = billdate.get_bill_date(year_month)
54     print(templates.STATEMENT_TEMP.format(acc_id, bill_bday, bill_eday))
55     log_path = os.path.join(settings.LOG_DATABASE["database_path"], settings.LOG_TYPES[log_obj])
56     with open(log_path,"r+", encoding="utf-8") as file:
57         for i in file:
58             log_time = datetime.datetime.strptime(i.split(",")[0], "%Y-%m-%d %H:%M:%S")
59             account_id = i.split("-")[5].split(":")[1]
60             if acc_id == account_id and bill_bday <= log_time < bill_eday:
61                 print(i)
62     print("")

core\logger

  1 #!usr/bin/env python
  2 #-*- coding:utf-8 -*-
  3
  4 import os, sys, json
  5 from prettytable import PrettyTable
  6 from conf import settings
  7 from conf import templates
  8 from core import auth
  9 from core import shopping
 10 from core import logger
 11 from core import transaction
 12 from core import update_acc_info
 13
 14
 15 TRANSACTION_LOGGER = logger.logger("transactions")
 16 ACCESS_LOGGER = logger.logger("access")
 17
 18 # 登陆成功后,将信息更新入tmp USER_DATA
 19 USER_DATA = {
 20     "account_id": None,
 21     "is_authenticated": False,    # 在客户进行不同操作时,都需要验证是否登陆
 22     "account_data": None          # json文件信息
 23 }
 24
 25 def verify(func):
 26     '''
 27     装饰器,每次在客户转账,还款,取现等现金操作时,验证是已经登陆。
 28     :param func:
 29     :return:
 30     '''
 31     def wrapper(*args,**kwargs):
 32         if USER_DATA["is_authenticated"]:
 33             res = func(*args,**kwargs)
 34         else:
 35             print("please log in again!")
 36     return wrapper
 37
 38 @verify
 39 def shopping_menu(acc_data):
 40     '''
 41     购物车
 42     :param acc_data:
 43     :return:
 44     '''
 45     shopping.shopping(acc_data)
 46
 47
 48 # 写日志
 49 def get_acc_info(acc_data):
 50     '''
 51     client function 2: 获取账户信息
 52     :param acc_data:
 53     :return:
 54     '''
 55     print("2.account information")
 56     table = PrettyTable(["Account Id", "Credit", "Current Balance", "Expired Date"])
 57     table.add_row(
 58         [acc_data["id"], acc_data["credit"], acc_data["balance"], acc_data["expire_date"]])
 59     print(table)
 60     client_portal()
 61
 62
 63 @verify
 64 def repayment(acc_data):
 65     '''
 66     打印current balance, 并且还款
 67     :param acc_data:
 68     :return:
 69     '''
 70     table = PrettyTable(["Account Id", "Credit", "Current Balance"])
 71     table.add_row([acc_data["id"],acc_data["credit"], acc_data["balance"]])
 72     print(table)
 73     back_flag = False
 74     while not back_flag:
 75         repay_amount = input("\033[33;1mPlease input repay amount\033[0m or press [b] for back").strip()
 76         if len(repay_amount) > 0 and repay_amount.isdigit():
 77             n_acc_data = transaction.transaction(acc_data, TRANSACTION_LOGGER, "repay", repay_amount)
 78             new_balance = n_acc_data["balance"]
 79             if new_balance:
 80                 print("Your credit card has been repaid. Current balance is %s" % acc_data["balance"])
 81                 client_portal()
 82         elif repay_amount == "b":
 83             back_flag = True
 84         else:
 85             print("Please input a valid number")
 86             back_flag = True
 87
 88 @verify
 89 def withdrawal(acc_data):
 90     '''
 91     取款
 92     :param acc_data:
 93     :return:
 94     '''
 95     print("Current balance: %s" % acc_data["balance"])
 96     back_flag = False
 97     while not back_flag:
 98         withdraw_amount = input("\033[33;1mPlease input amount for withdrawal\033[0m or press [b] for back>>>").strip()
 99         if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
100             n_acc_data= transaction.transaction(acc_data, TRANSACTION_LOGGER, "withdraw", withdraw_amount)
101             new_balance = n_acc_data["balance"]
102             print("You have withdrawn %s and your current balance is %s" %(withdraw_amount, new_balance))
103             client_portal()
104         elif withdraw_amount == "b":
105             back_flag = True
106         else:
107             print("Please input a valid number")
108             back_flag = True
109
110
111 @verify
112 def transfer(acc_data):
113     '''
114     转账
115     :param acc_data:
116     :return:
117     '''
118     print("Current balance: %s" % acc_data["balance"])
119     back_flag = False
120     while not back_flag:
121         transferee_acc_id = input('press [b] for back or please input transferee\'s account id:').strip()
122         transfer_amount = input("\033[33;1mPlease input amount for transfer(extra 5% transaction fee)\033[0m>>>").strip()
123         if len(transfer_amount) > 0 and transfer_amount.isdigit():
124             transferee_acc_data = update_acc_info.load_account(transferee_acc_id)
125             transaction.transaction(acc_data, TRANSACTION_LOGGER, "transfer", transfer_amount)
126             transaction.transaction(transferee_acc_data,TRANSACTION_LOGGER,"receive", transfer_amount)
127             print("Successfully transferred. ")
128             client_portal()
129         elif transferee_acc_data == "b":
130             back_flag = True
131         else:
132             print("Please input a valid number")
133             continue
134
135
136 def statement(acc_data):
137     '''
138     查询账单
139     :param acc_data:
140     :return:
141     '''
142
143     back_flag = False
144     while not back_flag:
145         bill_month = input("Please input your desired year-month (e.g. 2001-02) or press [b] for back >>>").strip()
146         if len(bill_month) > 6:
147             acc_id = acc_data["id"]
148             logger.show_logger(acc_id, "transactions", bill_month)
149         elif bill_month == "b":
150             back_flag = True
151         else:
152             print("Please input a valid year and month")
153             back_flag
154
155 def logout(acc_id):
156     exit("Thank you for your trust to MyBank!")
157
158
159 def get_user_data():
160     account_data = auth.login(USER_DATA, ACCESS_LOGGER)               # 登陆验证func
161     if account_data["status"] == 8:
162         exit("Please choose Admin portal!")
163     else:
164         USER_DATA["account_id"] = account_data["id"]
165         USER_DATA["account_data"] = account_data
166         USER_DATA["is_authenticated"] = True
167         return USER_DATA
168
169
170 def client_portal():
171     '''
172     客户接口, 登陆后更新USER_DATA。
173     :return:
174     '''
175     if USER_DATA["is_authenticated"] == False:
176         get_user_data()
177         account_data = USER_DATA["account_data"]
178     else:
179         account_data = USER_DATA["account_data"]
180
181     client_menu = {
182         "1": shopping_menu,
183         "2": get_acc_info,
184         "3": repayment,
185         "4": withdrawal,
186         "5": transfer,
187         "6": statement,
188         "7": logout
189     }
190     print(templates.CLIENT_WIN.format(USER_DATA["account_id"]))
191     exit_flag = False
192     while not exit_flag:
193         client_option = input("Please select your action >>>").strip()
194         if client_option in client_menu:
195             client_menu[client_option](account_data)
196         else:
197             print("Invalid option. please try again.")
198             exit_flag = True
199
200
201 def admin_create():
202     '''
203     管理员新创建账户
204     :return:
205     '''
206     print(" -------------Admin to creat a new account--------------")
207     acc_id = input("New Account ID >>>").strip()
208     acc_psd = input("Initial passward >>>").strip()
209     acc_cc = str(input("New credit card # >>>").strip())
210     acc_credit = input ("Initial credit >>>").strip()
211     enroll_date = str(input("Enroll date (e.g. 2000-01-01)>>>").strip())
212     expire_date = str(input("Expired date (e.g. 2005-01-01) >>>").strip())
213     account_dict = {
214         "id": acc_id,
215         "password": acc_psd,
216         "credit_card": acc_cc,
217         "credit": acc_credit,
218         "balance": 0,
219         "enroll_date": enroll_date,
220         "expire_date": expire_date,
221         "billing_day": 22,
222         "status": "0"  # 0 = normal, 1 = locked, 2 = disabled, 8 = admin
223     }
224     acc_file = "%s.json" %acc_id
225     acc_path = os.path.join(settings.DATABASE["database_path"], acc_file)
226     with open(acc_path, "w", encoding="utf-8") as f:
227         json.dump(account_dict,f)
228
229
230 def admin_reactivate():
231     """
232     激活
233     :return:
234     """
235     back_flag = False
236     while not back_flag:
237         acc_id = input("please input the account id you want to reactivate>>>")
238         acc_data = update_acc_info.load_account(acc_id)
239         reconfirm_msg = input("please reconfirm you want to reactivate the account (Y/N) or press [b] for back >>>").strip()
240         if reconfirm_msg == "Y":
241             acc_data["status"] = "0"
242             update_acc_info.dump_account(acc_data)
243             print("The account has been unlocked")
244         elif reconfirm_msg == "b":
245             back_flag = True
246         else:
247             print("Reactivation failed")
248             back_flag = True
249
250
251 def admin_freeze():
252     '''
253     冻结
254     :return:
255     '''
256     back_flag = False
257     while not back_flag:
258         acc_id = input("please input the account id you want to freeze>>>")
259         acc_data = update_acc_info.load_account(acc_id)
260         reconfirm_msg = input("please reconfirm you want to freeze the account (Y/N) or press [b] for back>>>").strip()
261         if reconfirm_msg == "Y":
262             acc_data["status"] = "2"
263             update_acc_info.dump_account(acc_data)
264         elif reconfirm_msg == "b":
265             back_flag = False
266         else:
267             print("Freeze failed")
268             back_flag = True
269
270
271 def admin_credit_update():
272     '''
273     更新信用额度
274     :return:
275     '''
276     back_flag = False
277     while not back_flag:
278         acc_id = input("please input the account id you want to update the credit >>>")
279         acc_data = update_acc_info.load_account(acc_id)
280         new_credit = input("please input the new credit for {}".format(acc_id)).strip()
281         if len(new_credit)> 0 and new_credit.isdigit():
282             acc_data["credit"] = new_credit
283             update_acc_info.dump_account(acc_data)
284         else:
285             print("Invalid input")
286             back_flag = True
287
288
289 def admin_portal():
290     '''
291     管理员入口
292     :return:
293     '''
294     account_data = auth.login(USER_DATA, ACCESS_LOGGER)
295     admin_menu = {
296         "1": admin_create,
297         "2": admin_reactivate,
298         "3": admin_freeze,
299         "4": admin_credit_update,
300         "5": exit
301     }
302     exit_flag = False
303     while not exit_flag:
304         if account_data["status"] == 8:
305             print(templates.ADMIN_WIN.format(account_data["id"]))
306             admin_option = input("Your action >>>").strip()
307             if admin_option in admin_menu:
308                 admin_menu[admin_option]()
309             else:
310                 print("Invalid option. please try again.")
311                 continue
312         else:
313             exit("Permission denied")
314
315
316 def sys_run():
317     '''
318     主程序窗口
319     :return:
320     '''
321     print(templates.OPEN_WIN)
322     open_input = input('\033[31;1mYour choice >>>\033[0m ')
323     open_dic = {
324         "1": admin_portal,
325         "2": client_portal
326     }
327     if open_input in open_dic:
328         open_dic[open_input]()
329     else:
330         print("Invalid option. please try again.")
331
332
333 sys_run()

core\main

#!usr/bin/env python
# -*- coding:utf-8 -*-import sys
import json
from conf import templates
from conf import settings
from core import update_acc_info
from core import maindef shopping(acc_data):# 购物acc_id = acc_data["id"]print(templates.SHOPPING_WIN.format(acc_id))menu_dict = settings.SHOPPING_MENUwhile True:for i in sorted(menu_dict):print(i)option1 = input('请选择\033[001m产品分类\033[0m 【b】返回 【任意键】退出').strip()            # 001加粗if option1 in menu_dict:print('{}清单如下:'.format(option1).rjust(25, '-'))for k in menu_dict[option1]:print(k, menu_dict[option1][k])while True:option2 = input('请选择 \033[001m商品\033[0m 加入购物车【b】返回 【q键】退出 ').strip()if option2 in menu_dict[option1]:option3_num = input('请输入购买数量').strip()if option3_num.isdigit() and int(option3_num) <= menu_dict[option1][option2]['数量']:num = int(option3_num)price = menu_dict[option1][option2]['单价']cost = num*pricebalance = acc_data["balance"]if cost <= balance:acc_data["balance"] = balance - costupdate_acc_info.dump_account(acc_data)menu_dict[option1][option2]['数量'] -= numprint("商品已购,您的最新余额为\033[34m%d\033[0m" % (acc_data["balance"]))breakelse:print('账户余额不足,请还款')main.client_portal()else:print("抱歉,商品数目不足")continueelif option2 == 'b':breakelif option2 == 'q':sys.exit()else:print('错误信息,请重新选择')continueelif option1 == 'b':main.client_portal()else:sys.exit()

core\shopping

#!usr/bin/env python
# -*- coding:utf-8 -*-from conf import settings
from core import update_acc_infoTRANSACTION_TYPE = {'repay': {'action': 'plus', 'interest': 0},          # 还款'receive': {'action': "plus", 'interest': 0},        # 接收'withdraw': {'action': 'minus', 'interest':0.05},    # 提款'transfer': {'action': 'minus', 'interest':0.05},    # 转出'pay': {'action': 'minus', 'interest': 0},           # 支付
}def transaction(acc_data, log_obj, tran_type, amount, **other):'''cover all money transactions listed in settings.TRANSACTION_TYPE:param acc_data::param log_obj::param tran_type::param amount::param other::return:'''amount = float(amount)transaction_type = settings.TRANSACTION_TYPEinterest = amount * transaction_type[tran_type]["interest"]if transaction_type[tran_type]["action"] == "plus":new_balance = acc_data["balance"] + amountelif transaction_type[tran_type]["action"] == "minus":new_balance = acc_data["balance"] - amount - interestif new_balance < 0:print('Your current balance is %s, which may not be enough for this transaction'% acc_data["balance"])acc_data["balance"] = new_balanceupdate_acc_info.dump_account(acc_data)log_obj.info("ID:{}-Action:{}-Amount:{}-Interest:{}".format(acc_data["id"],tran_type,amount,interest))return acc_data

core\transaction

 1 #!usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # function: update any modifies or transaction into json file
 4 \
 5
 6 import os
 7 import json
 8 from conf import settings
 9 from core import db_handler
10
11 def dump_account(acc_data):
12     '''
13     存入文件
14     :param acc_data:
15     :return:
16     '''
17     acc_file = "%s.json" % acc_data["id"]
18     db_file_path = db_handler.db_handler(settings.DATABASE)
19     acc_path = os.path.join(db_file_path, acc_file)
20     #print(acc_path)
21     with open(acc_path,"w+", encoding="utf-8") as f:
22         json.dump(acc_data,f)
23     return True
24
25
26 def load_account(acc_id):
27     '''
28     读取文件,用于transfer
29     :param acc_id:
30     :return:
31     '''
32     acc_file = "%s.json" % acc_id
33     db_file_path = db_handler.db_handler(settings.DATABASE)
34     acc_path = os.path.join(db_file_path, acc_file)
35     with open(acc_path, "r+", encoding="utf-8") as f:
36         acc_data = json.load(f)
37     return acc_data

update_acc_info

#!usr/bin/env python
#-*- coding:utf-8 -*-import jsonaccount_dict = {"id": "admin001","password": "admin1","credit_card": None,"credit": None,"balance": None,"enroll_date": "2000-01-01","expire_date": "2999-12-31","billing_day": 22,"status": "8"   # 0 = normal, 1 = locked, 2 = disabled, 8 = admin
}account_file = "%s.json" % account_dict["id"]with open(account_file, "w+") as f:json.dump(account_dict,f)

database\test_accounts_dump

log\access.log

log\transaction.log

示例

sample 1:  alex的列子

sample 2:大牛的例子(涉及类)

转载于:https://www.cnblogs.com/lg100lg100/p/7527057.html

Python 基础 - Day 5 Assignment - ATM相关推荐

  1. Python 基础 - Day 2 Assignment - ShoppingCart 购物车程序

    作业要求 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 4.可随 ...

  2. Python 基础 - Day 1 Assignment - Login 模拟登陆

    作业要求: 1. 用户输入帐号密码进行登陆 2. 用户信息保存在文件内 3. 用户密码输入错误三次后锁定用户 知识点总结: 1. file的操作: with open 2. 读取file信息, 从st ...

  3. Python 基础 - Day 1 Assignment - Three tier menu 三级菜单

    作业要求 1. 运行程序输出第一级菜单 2. 选择一级菜单某项,输出二级菜单,同理输出三级菜单 3. 菜单数据保存在文件中 4. 让用户选择是否要退出 5. 有返回上一级菜单的功能 评分标准: 用多层 ...

  4. 万字长文爆肝Python基础入门【巨详细,一学就会】

    目录 数据的名字和种类--变量和类型 初探数据种类 数据类型 数值运算 比较运算 变量和赋值 变量的好处 用赋值更新变量 变量和数据类型的关系 总结 数据类型 数值运算 数值比较 变量和赋值 一串数据 ...

  5. 九. Python基础(9)--命名空间, 作用域

    九. Python基础(9)--命名空间, 作用域 1 ● !a 与 not a 注意, C/C++可以用if !a表示if a == 0, 但是Python中只能用if not a来表示同样的意义. ...

  6. Python基础类型之元组

    Python基础类型之元组 一.元组的介绍 二.元组的使用 三.元组不可变特性 1.不可修改 2.元组的第一层不可变 四.单独元素的使用 一.元组的介绍 1.Python的元组与列表类似,不同之处在于 ...

  7. python sorted下标_全!Python基础之原生数据类型、判断和循环、函数和文件操作合集...

    长文预警! Python基础系列会将基础内容大致分为三到五个板块,每块着重讲一方面,知识不会很难,主要是以小例子的形式解读,如果你已经入门Python,希望可以帮你温习一下:如果你想入门Python, ...

  8. Python基础概念_14_常见术语

    常见术语 15 常见术语 15.1 简介 Python里有一些常见的专业名词.用语,我们一般统称为术语.为了更方便的学习python我们通过表格的方式列举了常用的术语和单词以及工具. 15.2 常见术 ...

  9. python中遍历结构可以是哪些数据类型_全!Python基础之原生数据类型、判断和循环、函数和文件操作合集...

    长文预警! Python基础系列会将基础内容大致分为三到五个板块,每块着重讲一方面,知识不会很难,主要是以小例子的形式解读,如果你已经入门Python,希望可以帮你温习一下:如果你想入门Python, ...

最新文章

  1. Linux下批量重命名文件名为数字索引编号(0~N.xxx)的方法
  2. 我身边那些逃离深圳的朋友们
  3. dockerfile各种命令解析
  4. 创建字符串枚举的最好方法
  5. rabbitmq详细入门文档+springboot结合使用
  6. spring.mvc.static-path-pattern、spring.resources.static-locations
  7. JavaScript中循环遍历JSON响应
  8. 高级参数绑定(数组和List绑定)
  9. 华为最新人事调整:余承东任智能汽车解决方案 BU CEO;美团悄悄更换抽佣规则,佣金不降反升;Scala 3 正式发布|极客头条...
  10. 【NOI2014】魔法森林
  11. php 父子id,父子关系PHP / MYSQL
  12. [c++11]我理解的右值引用、移动语义和完美转发
  13. 服务器进销财务管理系统,进销存财务管理系统
  14. Android 11 存储权限适配指南
  15. 【activiti6】设计器的前后端集成与汉化
  16. imp导入dmp文件,过滤不想导入的表
  17. 两台电脑如何共享文件
  18. 玩家密无忧 v7.0.7 绿色
  19. 声纹识别概述(3)声纹识别系统
  20. 前端中DOM是什么,怎样理解dom

热门文章

  1. rabbitmq安装完整版
  2. 用系统某一用户的的身份运行某一命令
  3. Spring MVC 教程,快速入门,深入分析——多视图控制器
  4. oracle 11g EM停止后无法启动
  5. linux共享库位置配置(LD_LIBRARY_PATH环境变量 或者 更改/etc/ld.so.conf)
  6. 企业真的要培养员工?
  7. linux自学视频资料第四讲:目录
  8. react 拖拽生成html,[React] 基于react 拖拽时间选择器
  9. Win7 Tensorflow 安装
  10. Linux下调试python