天天看點

模拟實作一個ATM + 購物商城程式

           記得上次小編上傳了一個購物車程式,這次呢稍微複雜一點,還是那句話,上傳在這裡不是為了炫耀什麼,隻是督促小編學習,如果大神有什麼意見和建議,歡迎指導。

  于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  日志,記錄相關資訊
      

四,思路流程圖

模拟實作一個ATM + 購物商城程式
模拟實作一個ATM + 購物商城程式
模拟實作一個ATM + 購物商城程式

 五,簡要說明

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()
      

不經一番徹骨寒 怎得梅花撲鼻香

繼續閱讀