記得上次小編上傳了一個購物車程序,這次呢稍微復雜一點,還是那句話,上傳在這里不是為了炫耀什么,只是督促小編學習,如果大神有什么意見和建議,歡迎指導。
於2018.3.11開始動筆,繼續完成這個項目。
一,需求:模擬實現一個ATM + 購物商城程序
要求如下:
1.額度15000或者自定義
2.實現購物商城,買東西加入購物車,調用信用卡接口結賬
3.可以提現,手續費5%
4.支持多賬戶登陸
5.支持賬戶間轉賬
6.記錄每月日常消費流水
7.提供還款接口
8.ATM記錄操作日志
9.提供管理接口,包括添加賬戶,用戶額度,凍結賬戶等
10.用戶認證用裝飾器
二,分析功能需求
ATM的角色:
管理員功能:
1,增刪改查,加錢,減錢
2,記錄日志
3,基本信息
4,額度 15000
普通用戶功能:
1,可以提現,手續費5%
2,支持多賬戶登錄
3,支持賬戶間轉賬
4,記錄每月日常消費流水
5,提供還款接口
6,ATM記錄操作日志
購物車程序:
1,可以進入程序購買商品
2,支持多賬戶登錄
3,購完東西顯示余額和購買的東西
三,文件創建
文件的創建是有開發規范的,比如下面:
bin 用於執行可執行文件
conf 配置文件
core 用於存放核心代碼
db 用於存放用戶數據
log 日志,記錄相關信息
四,思路流程圖



五,簡要說明
1,本程序思路是寫了一個ATM和購物商城的程序
其中購物商場簡單的實現了功能,並沒有調用ATM中的信用卡結賬
ATM寫了信用卡操作和管理員操作,沒有實現記錄每月日常消費流水
2,對於購物商城:
調用/shopping_mall/shopping_run.py文件執行
簡單的實現了用戶進入商城,選擇購物,則對賬戶余額進行扣款,推出時打印購買商品和余額
3,對於ATM有兩個入口:
(1):普通用戶對信用卡操作
調用/atm-learn/bin/atm.py文件執行,可以打印賬戶信息、還款、取款、轉賬、賬單、退出等操作
①賬戶信息
②還款
③取款
④轉賬
⑤賬單
⑥退出
(2):管理用戶對信用卡操作
調用/atm-learn/bin/atm_manage.py文件執行則可以對用戶進行管理,解凍用戶、凍結用戶、申領新卡等操作
①添加賬戶
②凍結賬戶
③解凍賬戶
④退出
概述 本次作業文件夾一共包含了以下6個文件: 流程圖一:ATM用戶登錄思路流程圖 流程圖二:ATM管理登陸思路流程圖 流程圖三:購物車思路流程圖 程序結構圖:整個ATM+shopping的程序文件結構 程序文件: ATM + shopping 程序說明文件:README.md 程序介紹 本程序思路是寫了一個ATM和購物商城的程序 ATM寫了信用卡操作和管理員操作,沒有實現記錄每月日常消費流水 購物商場簡單的實現了功能,並沒有調用ATM中的信用卡結賬 1,對於ATM有兩個入口: (1):普通用戶對信用卡操作 調用/atm/bin/atm.py文件執行,可以打印賬戶信息、還款、取款、轉賬、賬單、退出等操作 (2):管理用戶對信用卡操作 調用/atm-learn/bin/atm_manage.py文件執行則可以對用戶進行管理,解凍用戶、凍結用戶、申領新卡等操作 2,對於購物商城: 調用/shopping/shopping_run.py文件執行 簡單的實現了用戶進入商城,選擇購物,則對賬戶余額進行扣款,推出時打印購買商品和余額 程序結構 備注 目前還不會在windows中用樹的結構,所以做出程序結構的txt版本,放在文件外面 對幾個實例json文件的說明 0000.json 一個用戶賬戶示例文件(這個是賬號正常,但是賬號過期,不在使用范圍內) 123.json 一個用戶賬戶示例文件(這個是賬號正常) 1234.json 一個用戶賬戶示例文件(這個是賬號被鎖定,除非登陸管理端修改被凍結的狀態,才能正常使用) admin.json 一個管理賬戶示例文件(如果不知道管理者的賬戶和密碼,可以查看) 不足及其改進的方面 1,未實現購物商城調用信用卡接口結賬 2,賬戶之間的轉賬 3,ATM中查看賬單,未能實現調用每個月的流水帳單,只是簡單的查看信用額度和賬戶余額 4,購物商場比較簡單,每次買一個東西就自己結賬退出
六,程序結構
atm+shopping``
├── README
├── atm #ATM主程序目錄
│ ├── __init__.py
│ ├── bin #ATM 執行文件 目錄
│ │ ├── __init__.py
│ │ ├── atm.py #ATM 執行程序
│ │ └── manage.py #ATM 管理端 執行程序
│ ├── conf #配置文件
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── core #主要程序邏輯都 在這個目錄 里
│ │ ├── __init__.py
│ │ ├── accounts.py #用於從文件里加載和存儲賬戶數據
│ │ ├── atm_main.py #atm 主邏輯交互程序
│ │ ├── auth.py #用戶認證模塊
│ │ ├── db_handler.py #數據庫連接引擎
│ │ ├── logger.py #日志記錄模塊
│ │ ├── manage_main.py #atm管理端主邏輯交互程序
│ │ └── transaction.py #記賬\還錢\取錢等所有的與賬戶金額相關的操作都 在這
│ ├── db #用戶數據存儲的地方
│ │ ├── __init__.py
│ │ ├── account_sample.py #一個存用戶的賬戶數據的例子
│ │ └── accounts #存各個用戶的賬戶數據 ,一個用戶一個文件
│ │ └── 0000.json #一個用戶賬戶示例文件(這個是賬號正常,但是賬號過期,不在使用范圍內)
│ │ └── 123.json #一個用戶賬戶示例文件(這個是賬號正常)
│ │ └── 1234.json #一個用戶賬戶示例文件(這個是賬號被鎖定,除非登陸管理端修改被凍結的狀態,才能正常使用)
│ │ └── admin.json #一個管理賬戶示例文件(如果不知道管理者的賬戶和密碼,可以查看)
│ └── log #日志目錄
│ ├── __init__.py
│ ├── access.log #用戶訪問和操作的相關日志
│ └── transactions.log #所有的交易日志
└── shopping #購物車目錄
└── __init__.py
└── 123.json #一個購物用戶賬戶示例文件(包括用戶id,密碼,余額)
└── shopping_main.py #主邏輯交互程序
└── shopping_run.py #購物車 執行程序
七,程序代碼
7.1 ATM代碼
bin下atm.py
# _*_ coding: utf-8 _*_
import os
import sys
#添加環境變量
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路徑
sys.path.append(BASE_DIR) #添加路徑
#將main.py里面所有代碼封裝成main變量
from core import atm_main
'''ATM程序的執行文件'''
if __name__ == '__main__':
atm_main.run_atm()
bin下atm_manage.py
# _*_ coding: utf-8 _*_
import os
import sys
#添加環境變量
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路徑
sys.path.append(BASE_DIR) #添加路徑
from core import manage_main
'''管理程序的執行文件'''
if __name__ == '__main__':
manage_main.run_manage()
conf/setting.py
# _*_ coding: utf-8 _*_
'''初始化的配置'''
import logging
import os
import sys
#到ATM目錄,方便后面創建賬戶文件
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
DATABASE = {
'engine':'file_storage', #文件存儲,這里可擴展成數據庫形式的
'name':'accounts', #db下的文件名
'path':'%s/db' %BASE_DIR
}
LOGIN_LEVEL = logging.INFO #初始化日志記錄級別為INFO,INFO以下的可以直接打印
#日志類型
LOGIN_TYPE = {
'access':'access.log',
'transaction':'transaction.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/accounts.py
# _*_ coding: utf-8 _*_
import os
import sys
import json
import logging
import time
import datetime
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR) #添加環境變量
from core import auth
from core import db_handler
from conf import settings
def load_current_balance(account_id):
'''
# 把數據load下,返回賬戶余額和其他基礎信息
:param account_id: 用戶賬戶的名字
:return: 返回最新讀到的數據文件中的最新數據
'''
db_path = db_handler.db_handler(settings.DATABASE)
account_file = "%s/%s.json"%(db_path,account_id)
with open(account_file,'r',encoding='utf-8') as f:
acc_data = json.load(f)
return acc_data
def dump_account(account_dic):
'''
在更新完后,把數據dump到文件中,文件地址為\atm-learn/db/accounts
:param account_data:
:return:
'''
db_path =db_handler.db_handler(settings.DATABASE)
account_file = "%s/%s.json" %(db_path,account_dic['id'])
with open(account_file,'w',encoding='utf-8') as f:
acc_data = json.dump(account_dic,f)
core/atm_main.py
# _*_ coding: utf-8 _*_
'''主邏輯交互模塊'''
import logging
import sys
from core import auth
from core import logger
from core import accounts
from core import transaction
from core import db_handler
#用戶數據信息
user_data = {
'account_id':None , #賬戶ID
'is_authenticated':False, #是否認證
'account_data':None #賬戶數據
}
#調用log文件下的log方法,返回日志對象
access_logger = logger.logger('access')
trans_logger = logger.logger('transaction')
def account_info(func):
'''
用戶賬號信息,acc_data:包括ID,is_authenticaed,用戶帳號信息,主要看是否被鎖住
:return:
'''
def wrapper(acc_data):
account_id=acc_data["account_id"]
account_data=acc_data["account_data"]
status=acc_data['account_data']["status"]
if int(status) ==0:
func(acc_data)
return True
else:
print("\033[32;1msorry your account was locked\033[0m")
exit()
return wrapper
@account_info
def disp_account_info(acc_data):
'''
展示賬戶信息
#去除 password 字段顯示
:param account_data: 賬戶信息
:return:
'''
print("--------------ACCOUNT INFO---------------")
for i in acc_data['account_data']:
print("{:^20}:\033[32;1m{:^20}\033[0m".format(i, acc_data['account_data'][i]))
@account_info
def repay(acc_data):
'''
存款
acc_data:包括ID,is_authenticaed,用戶帳號信息
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
current_balance = '''---------------------BALANCE INFO-----------------
Credit : %s
Balance: %s'''%(account_data['credit'],account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
repay_amount = input("\033[32;1mInput repay amout(input 'b' is back):\033[0m").strip()
if len(repay_amount) >0 and repay_amount.isdigit():
new_balance = transaction.make_transaction(
trans_logger,account_data,'repay',repay_amount)
if new_balance:
print('''\033[34;1mNEW Balance:%s\033[0m'''%(new_balance['balance']))
elif repay_amount == 'b':
back_flag = True
else:
print("\033[31;1m%s is not valid amount ,Only accept interger!\033[0m"%repay_amount)
@account_info
def withdraw(acc_data):
'''
打印當前余下的錢,並且讓用戶做取錢的功能
:param acc_data:
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
current_balance ='''---------------------BALANCE INFO-----------------
Credit : %s
Balance: %s'''%(account_data['credit'],account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
withdraw_amount = input("\033[33;1mInput withdraw amout(input 'b' is back):\033[0m").strip()
if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
new_balance = transaction.make_transaction(
trans_logger, account_data, 'withdraw', withdraw_amount)
if new_balance:
print('''\033[32;1mNEW Balance:%s\033[0m''' % (new_balance['balance']))
elif withdraw_amount == 'b':
back_flag = True
else:
print('\033[31;1m[%s] is not a valid amount , only accept integer\033[0m'%withdraw_amount)
@account_info
def transfer(acc_data):
'''
轉賬
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
current_balance = '''---------------------BALANCE INFO-----------------
Credit : %s
Balance: %s''' % (account_data['credit'], account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
transfer_amount = input("\033[33;1mInput transfer amount(input 'b' is back):\033[0m").strip()
if len( transfer_amount) > 0 and transfer_amount.isdigit():
new_balance = transaction.make_transaction(
trans_logger, account_data, 'transfer', transfer_amount)
if new_balance:
print('''\033[32;1mNEW Balance:%s\033[0m''' % (new_balance['balance']))
elif transfer_amount == 'b':
back_flag = True
else:
print('\033[31;1m[%s] is not a valid amount , only accept integer\033[0m' % transfer_amount)
@account_info
def paycheck(acc_data):
'''
賬單檢查,記錄每月日常消費流水
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
current_balance = '''---------------------BALANCE INFO-----------------
Credit : %s
Balance: %s''' % (account_data['credit'], account_data['balance'])
print(current_balance)
@account_info
def logout(acc_data):
'''
退出登陸
:return:
'''
print("\033[32;1m-------Looking forward to your next visit-------\033[0m")
exit()
def interactive(acc_data):
'''
用戶交互
:return:
'''
msg = (
'''
------------------CHINA BANK --------------
\033[31;1m1.賬戶信息
2.存款
3.取款
4.轉賬
5.賬單
6.退出
\033[0m'''
)
menu_dic = {
"1":disp_account_info,
"2":repay,
"3":withdraw,
"4":transfer,
"5":paycheck,
"6":logout,
}
exit_flag = False
while not exit_flag:
print(msg)
user_choice = input(">>>>").strip()
if user_choice in menu_dic:
menu_dic[user_choice](acc_data)
else:
print("\033[31;1mYou choice doesn't exist!\033[0m")
def run_atm():
'''
當程序啟動時候,調用,主要用於實現主要交互邏輯
:return:
'''
# 調用認證模塊,返回用戶文件json.load后的字典,傳入access_logger日志對象
access_data = auth.access_login(user_data,access_logger)
if user_data['is_authenticated']: #如果用戶認證成功
user_data["account_data"] = access_data
interactive(user_data) #用戶交互開始
core/auth.py
# _*_ coding: utf-8 _*_
import os
import json
import time
from core import accounts
from core import db_handler
from conf import settings
from bin import atm_manage
from core import atm_main
def access_auth(account,password,log_obj):
'''
下面access_login調用access_auth方法,用於登陸
:param account: 用戶名
:param password: 密碼
:return: 如果為超期,返回字典,超期則打印相應提示
'''
db_path = db_handler.db_handler(settings.DATABASE) #調用db_handle下的handle方法,返回路徑/db/accounts
account_file = '%s/%s.json'%(db_path, account) #用戶文件
#判斷文件和i否存在,如果存在的話 則執行下面的
if os.path.isfile(account_file): #如果用戶文件存在(即用戶存在)
with open(account_file,'r',encoding='utf-8') as f: #打開文件
account_data = json.load(f) #file_data為字典形式
if account_data['password'] == password:
expire_time = time.mktime(time.strptime(account_data['expire_date'],'%Y-%m-%d'))
if time.time() > expire_time: #如果信用卡已經過期,當前時間戳大於國企的時間戳
log_obj.error("Account [%s] had expired,Please contract the bank" % account)
print("\033[31;1mAccount %s had expired,Please contract the bank"%account)
else: #信用卡未過期,返回用戶數據的字典
log_obj.info("Account [%s] logging success" % account)
return account_data
else:
log_obj.error("Account or Password does not correct!")
print("\033[31;1mAccount or Passwordoes not correct!\033[0m")
else: #用戶不存在
log_obj.error("Account [%s] does not exist!" % account)
print("\033[31;1mAccount [%s] does not exist!\033[0m"%account)
def access_login(user_data,log_obj):
'''
用戶登陸,當登陸失敗超過三次
:param user_date:main.py里面的字典,用戶信息數據,只存在內存中
:return:若用戶賬號密碼正確,且信用卡未過期,則返回用戶數據的字典
'''
retry_count = 0
while user_data['is_authenticated'] is not True and retry_count < 3:
account = input('\033[32;1mplease input Acount:\033[0m').strip()
password = input('\033[32;1mplease input Password:\033[0m').strip()
#用戶賬號密碼正確而且信用卡未過期,返回用戶數據的字典
auth = access_auth(account, password,log_obj)
if auth:
user_data['is_authenticated'] = True #用戶認證為True
user_data['account_id'] = account #用戶賬號ID為賬號名
# print("welcome")
return auth
retry_count += 1
else:
print("Account [%s] try logging too many times..."%account)
log_obj.error("Account [%s] try logging too many times..." % account)
exit()
core/db_handler.py
# _*_ coding: utf-8 _*_
'''處理與數據之間的交互,如果file_db_storage,返回路徑'''
import json
import time
from conf import settings
def file_db_handle(conn_params):
'''
parse the db file path 對文件路徑做語法分析
:param conn_params:
:return:
'''
db_path = '%s/%s' %(conn_params['path'],conn_params['name'])
return db_path
def db_handler(conn_parms):
'''
:param conn_parms: the db connection params set in settings
:return: a
DATABASE = {
'engine':'file_storage', #文件存儲,這里可擴展成數據庫形式的
'name':'accounts', #db下的文件名
'path':'%s/db' %BASE_DIR
}
'''
if conn_parms['engine'] == 'file_storage':
return file_db_handle(conn_parms)
core/logger.py
# _*_ coding: utf-8 _*_
'''操作所有的日志工作'''
import logging
from conf import settings
def logger(log_type):
logger = logging.getLogger(log_type)
logger.setLevel(settings.LOGIN_LEVEL)
#創建屏幕對象和設置等級debug
# ch = logging.StreamHandler()
# ch.setLevel(settings.LOGIN_LEVEL)
#創建文件對象,給文件對象設置等級
log_file = "%s/log/%s"%(settings.BASE_DIR,settings.LOGIN_TYPE[log_type])
fh = logging.FileHandler(log_file)
fh.setLevel(settings.LOGIN_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
core/manage_main.py
# _*_ coding: utf-8 _*_
'''管理端,提供管理接口,包括添加賬戶,用戶額度,凍結賬戶,解凍賬戶'''
import os
import sys
import json
from core import auth
from core import accounts
from core import transaction
from core import db_handler
from conf import settings
# 解凍賬戶
def unlock_account():
'''解凍賬戶的初步思路是讀取用戶文件,把status的狀態一更改就ok '''
account = input("\033[34;1mPlease input the account that you want to unlock:\033[0m")
read_data = unlock_accountcore(account)
return read_data
def unlock_accountcore(account):
'''
解凍賬戶,讀取用戶文件,讀到status,把狀態更改為0
#0 = naormal,1 = locked ,
:param account:
:return:
'''
# 調用db_handle下的handle方法,返回路徑/db/accounts
db_path = db_handler.db_handler(settings.DATABASE)
account_file = '%s/%s.json' % (db_path, account)
account_new = '%s/%s.json' % (db_path, account)
if os.path.isfile(account_file):
with open(account_file, 'r', encoding='utf-8') as f:
account_data = json.load(f)
account_data['status'] = 0
with open(account_new, 'w', encoding='utf-8') as fnew:
new_data = json.dump(account_data, fnew)
# 凍結賬戶
def lock_account():
'''
凍結賬戶,思路與解凍剛好相反
:param acc_data:
:return:
'''
account = input("\033[34;1mPlease input the account that you want to lock:\033[0m")
read_data = lock_accountcore(account)
return read_data
def lock_accountcore(account):
'''
凍結賬戶,讀取用戶文件,讀到status,把狀態更改為1
#0 = naormal,1 = locked ,
:param account:
:return:
'''
# 調用db_handle下的handle方法,返回路徑/db/accounts
db_path = db_handler.db_handler(settings.DATABASE)
account_file = '%s/%s.json' % (db_path, account)
account_new = '%s/%s.json' % (db_path, account)
if os.path.isfile(account_file):
with open(account_file, 'r', encoding='utf-8') as f:
account_data = json.load(f)
account_data['status'] = 1
with open(account_new, 'w', encoding='utf-8') as fnew:
new_data = json.dump(account_data, fnew)
# 添加賬戶
def add_account():
'''
添加賬戶,是admin添加的用戶,下次就可以登陸添加的賬戶了
:return:
'''
acc_dic = {
'id':None,
'balance':None,
'password': None,
'credit': None,
'enroll_date': None,
'expire_date': None,
'status': None # 0 = naormal,1 = locked , 2 = disabled
}
menu = {
0:"請輸入要添加的賬戶:",
1:"請輸入要添加的余額:",
2:"請輸入要添加的密碼:",
3:"請輸入要添加的信用額度(only more than 0)",
4:"請輸入要添加的辦卡日期(such as 2018-8-8)",
5:"請輸入要添加的卡到期時間(such as 2018-8-8)",
6:"請輸入是否鎖定添加賬號的狀態(only input 0 or 1)",
}
menu_user = {
0: "id",
1: "balance",
2: "password",
3: "credit",
4: "enroll_date",
5: "expire_date",
6: "status",
}
print("\033[31;1m\t\twelcome to add account\033[0m")
print('*'.center(40,'*'))
for i in range(7):
data = input('%s'%menu[i]).strip()
acc_dic["%s" % menu_user[i]] = data
accounts.dump_account(acc_dic)
print("\033[32;1mcongratulations you account was created successfully\033[0m")
return True
# 退出程序
def logout():
'''
退出登陸
:return:
'''
print("\033[32;1m-------Looking forward to your next visit-------\033[0m")
exit()
def auth_login():
'''
登陸管理員密碼賬號
:return:
'''
print("\033[34;1m-------Welcome into the management interface--------\033[0m")
managename = input("\033[34;1mplease input Username:\033[0m")
password = input("\033[34;1mplease input Password:\033[0m")
account = account_auth(managename,password)
return account
def account_auth(managename,password):
'''
管理員認證信息
{"id": admin,"password": "root" }
:return:
'''
db_path = db_handler.db_handler(settings.DATABASE) # 調用db_handle下的handle方法,返回路徑/db/accounts
managename_file = '%s/%s.json'%(db_path,managename)
if os.path.isfile(managename_file):
with open(managename_file,'r',encoding='utf-8') as f:
manage_data = json.load(f)
# print(manage_data)
if manage_data['password'] == password:
print("\033[31;1m-------Welcome to the administrator--------\033[0m")
return manage_interactive(managename)
else:
print("\033[31;1mAccount or Passwordoes not correct!\033[0m")
# 管理界面主程序
def manage_interactive(managename):
menu = '''
\033[31;1m-----------management console-----------
1,add_account
2,lock_account
3,unblock_account
4, exit\033[0m'''
menu_dic = {
'1':add_account,
'2':lock_account,
'3':unlock_account,
'4': logout
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input('please input your choice>>>').strip()
if user_option in menu_dic:
print(menu_dic[user_option]())
else:
print("\033[31;1mYou choice doesn't exist!\033[0m")
def run_manage():
'''
當程序啟動的時候調用,主要用於實現主要交互邏輯,客戶認證登陸
:return:
'''
auth_login()
core/tranction.py
# _*_ coding: utf-8 _*_
import json
from conf import settings
from core import accounts
def make_transaction(log_obj,account_data,tran_type,amount,**others):
'''
處理所有的用戶的交易
:param log_obj:
:param amount_data: user account data
:param tran_type: transaction type
:param amount: transaction amount
:param other: mainly for logging usage
:return:
'''
# 將字符串類型轉換為float類型
amount = float(amount)
# tran_type 交易類型
if tran_type in settings.TRANSACTION_TYPE:
# 利息金額
interest =amount * settings.TRANSACTION_TYPE[tran_type]['interest']
old_balance = account_data['balance']
if tran_type in settings.TRANSACTION_TYPE:
# 利息金額
interest = amount * settings.TRANSACTION_TYPE[tran_type]["interest"]
# 用戶原金額
old_balace = account_data["balance"]
if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':
new_balance = float(old_balance) + amount + float(interest)
elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':
new_balance = float(old_balance) - amount - float(interest)
# 做一個判斷小於0的操作,減錢時對帳戶金額進行檢查,防止超額
if new_balance <0:
print('\033[31;1mYour credit [%s] is not enough for this transaction'
'[%s]'%(account_data['credit'],(amount + interest),old_balance))
return
account_data['balance'] = new_balance
# 保存新的余額返回到文件中
accounts.dump_account(account_data)
log_obj.info("account:%s action:%s amount:%s interest:%s "
%(account_data['id'],tran_type,amount,interest))
return account_data
else:
print("\033[31;1mTransaction type [%s] is not exist\033[0m"%tran_type)
db/account_sample/py(此處只舉一個例子)
# _*_ coding: utf-8 _*_
import json
acc_dic = {
'id':1234,
'password':'abc',
'credit':15000,
'balance':15000,
'enroll_date':'2018-01-01',
'expire_date':'2023-01-01',
# 'pay_day':22, #支付日期(但是現在沒有要求,可以不考慮)
'status':0 #0 = naormal,1 = locked , 2 = disabled
}
print(acc_dic,type(acc_dic))
a = json.dumps(acc_dic)
print(a,type(a))
7.2 shopping代碼
shopping_main.py
# _*_ coding: utf-8 _*_
import datetime
import os
import json
def auth_login():
'''
登陸密碼賬號
:return:
'''
print("-------welcome to shopping_mall--------")
username = input("\033[32;1mplease input Username:\033[0m")
password = input("\033[32;1mplease input Password:\033[0m")
account = account_auth(username,password)
return account
def account_auth(username,password):
'''
用戶認證賬戶信息格式化讀取模塊,並驗證賬號密碼是否正確
:return:
'''
username_file = '%s.json'%username
if os.path.isfile(username_file):
with open(username_file,'r',encoding='utf-8') as f:
username_data = json.load(f)
if username_data['password'] == password:
balance = username_data['balance']
print("\033[32;1myou balance is %s\033[0m"% balance)
return account_shopping(username,balance)
else:
print("\033[31;1mAccount or Passwordoes not correct!\033[0m")
def account_shopping(username,balance):
'''用戶購物操作
這次只能買一件東西,不能重復買
'''
goods = [
{"name": "電腦", "price": 6999},
{"name": "鼠標", "price": 300},
{"name": "游艇", "price": 2000},
{"name": "美女", "price": 9980},
]
print("*".center(40, '*'))
print("goods".center(40, '-'))
for index,item in enumerate(goods):
print(index,item)
print('end'.center(40,'-'))
while True:
choice = input("請輸入要想購買的商品編號(或者按q直接退出):")
if choice.isdigit(): #判斷是否為數字
choice = int(choice)
if choice>=0 and choice<len(goods): #判斷是否在商品范圍里面
choice_goods = goods[choice].get('name')
print("you will buy \033[32;1m%s\033[0m"%choice_goods)
if balance > goods[choice].get('price'):
new_balance = balance - goods[choice].get('price')
print("now your balance is \033[32;1m%s\033[0m"% new_balance)
else:
print("sorry your balance is \033[32;1m%s\033[0m,unable to purchase" %balance)
continue
else:
print("\033[31;1mplease input the correct goods number\033[0m")
elif choice == 'q':
exit()
return write_data(username,new_balance)
def write_data(username, new_balance):
'''
買了東西之后,余額信息更新一下
:param username: 用戶姓名
:param new_balance: 余額信息
:return:
'''
username_file = '%s.json' % username
usernew_file = '%s.json' % username
f = open(username_file, 'r', encoding='utf-8')
username_data = json.load(f)
username_data['balance'] = new_balance
f.close()
fnew = open(usernew_file, 'w', encoding='utf-8')
new_data = json.dump(username_data,fnew)
fnew.close()
def run_shopping():
'''
當程序啟動的時候,調用,主要用於實現主要交互邏輯,客戶認證登陸函數
:return:
'''
userdata = auth_login()
def account_recharge(balance):
'''用戶充值操作,此思路是接ATM'''
recharge_money = input("please input recharge money: ")
recharge_money =int(recharge_money)
balance = balance + recharge_money
print("Congratulations. Recharge success. balance is \033[32;1m%s\033[0m" %balance)
return balance
def legout():
'''
退出程序
:return:
'''
print("\033[32;1m-------Looking forward to your next visit-------\033[0m")
exit()
def interactive(acc_data):
'''
用戶交互
:param acc_data:
:return:
'''
msg = (
'''
------------------SHOPPING INFO --------------
\033[31;1m1.購物
2.充值
3.退回
\033[0m'''
)
menu_dic = {
"1": account_shopping,
"2": account_recharge,
"3": legout,
}
exit_flag = False
while not exit_flag:
print(msg)
user_choice = input(">>>>").strip()
if user_choice in menu_dic:
menu_dic[user_choice]()
else:
print("\033[31;1mYou choice doesn't exist!\033[0m")
def manage_accountauth():
'''
管理員賬戶認證函數,
:return:
'''
manage_account = []
with open('manageinfo.txt', 'r', encoding='utf-8') as f:
for i in f.readlines():
i_space = i.replace('\n', '')
manage_account.append(i_space)
return manage_account
def account_balance():
'''
賬戶余額信息格式化讀取模塊
:return:
'''
balance = []
with open('account_balance.txt', 'r', encoding='utf-8') as f:
for i in f.readlines():
i_space = i.replace('\n', '')
balance.append(i_space)
return balance
def account_save(account,cash):
'''
把賬戶及其余額信息持久化到本地,以消除文件內容,然后以讀寫的方式打開文件
:param account: 用戶信息
:return:
'''
save_info = open('account_balance.txt','w+',encoding='utf-8')
save_info.write(account)
save_info.write('\n')
save_info.write(str(cash))
save_info.close()
def account_auth_changshi(username,password):
'''
用戶認證賬戶信息格式化讀取模塊,嘗試登陸三次,
{"id": 123,"password": "123", "balance": 20000 }
:return:
'''
retry_count = 0
while username_data['password'] is not True and retry_count <3:
username_file = '%s.json'%username
if os.path.isfile(username_file):
with open(username_file,'r',encoding='utf-8') as f:
username_data = json.load(f)
print(username_data['password'])
print(password)
if username_data['password'] == password:
return account_shopping
else:
print("\033[31;1mAccount or Passwordoes not correct!\033[0m")
retry_count += 1
else:
print("Account [%s] try logging too many times..." % username)
exit()
shopping_run.py
# _*_ coding: utf-8 _*_
import os
import sys
#添加環境變量
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到路徑
sys.path.append(BASE_DIR) #添加路徑
from shopping import shopping_main
'''購物車程序的執行文件'''
if __name__ == '__main__':
shopping_main.run_shopping()
