• Python学习--------------Atm+购物车系统


    一、程序需求

    模拟实现一个ATM + 购物商城程序:
    1.额度 15000或自定义
    2.实现购物商城,买东西加入 购物车,调用信用卡接口结账
    3.可以提现,手续费5%
    4.每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息(没写)
    5.支持多账户登录
    6.支持账户间转账
    7.记录每月日常消费流水
    8.提供还款接口
    9.ATM记录操作日志
    10.提供管理接口,包括添加账户、用户额度,冻结账户等。。。
    11.用户认证用装饰器

     脑图:

    二、目录

     1 ├── ATM #ATM主程目录
     2 │   ├── __init__.py
     3 │   ├── bin                    #ATM 执行文件 目录
     4 │   │   ├── __init__.py
     5 │   │   ├── atm.py                 #ATM 执行程序
     6 │   │   ├── manage.py              #信用卡管理 
     7 │   ├── conf                   #配置文件
     8 │   │   ├── __init__.py
     9 │   │   └── Settings.py            #配置参数
    10 │   ├── core                   #主要程序逻辑都 在这个目录 里
    11 │   │   ├── __init__.py
    12 │   │   ├── accounts.py            #用于从文件里加载和存储账户数据
    13 │   │   ├── auth.py                #用户认证模块及主要功能函数
    14 │   │   ├── db_handler.py          #数据库连接引擎
    15 │   │   ├── logger.py              #日志记录模块
    16 │   │   ├── main.py                #主逻辑交互程序
    17 │   │   ├── transaction.py         #记账还钱取钱与账户金额相关的操作,冻结或者锁定用户
    18 │   ├── db                     #用户数据存储的地方
    19 │   │   ├── __init__.py
    20 │   │   ├── account_sample.py   #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
    21 │   │   └── accounts            #存各个用户的账户数据 ,一个用户一个文件
    22 │   │       └── 123.json           #新创建的用户账户示例文件
    23 │   │       └── 1234.json          #一个用户账户示例文件
    24 │   │       └── 123456.json        #一个用户账户示例文件
    25 │   │       └── 6230001.json       #管理用户账户示例文件
    26 │   └── log                    #日志目录
    27 │        ├── access.log              #用户访问和操作的相关日志
    28 │        └── login_in.log            #登陆日志
    29 └── shopping_mall               #电子商城程序,需单独实现,主要实现购物的功能。
    30 │        └── __init__.py
    31 │        └── product.txt             #存放商品的txt文件
    32 │        └── shopping_list.txt       #存放购物清单的txt.文件
    33 │        └── shopping_mall.py        #购物商城程序
    34 ├── README
    目录

    三、简要说明

    1.程序从/bin/atm.py开始执行if __name__ == '__main__':
                                                    main.run()
    2.程序转到/core/main.py下的run()函数,登陆时调用/core/auth的acc_login()进行登陆验证:用到了/core/auth下的acc_auth2()方法进行验证(此时传入的参数时用户输入的账户和密码)
    acc_auth2中有调用了/core/db_handler下的db_handler()方法(参数是输入的账户名)在db_handler中只是进行判断是什么引擎,return file_db_handle(数据库引擎)解析文件,返回文件执行加载输入的用户的账户的所有数据
    接下来判断是否为管理者账户,或者是否被冻结,若都不是,则判断输入的密码是否与数据库中的密码一样,在判断到期时间是否过期
    所有都通过的话就返回这个账户的数据,之前已经创建了一个空字典,里面有是否验证:用户数据:用户账户:,判断是否被验证过,然后把用户数据临时的传递到里面,执行主循环函数
    可以选择进入到购物商城,或者信用卡操作或者退出
    1)购物商城
      调用/shopping_mall/shopping_mall.py文件执行,主循环函数,选择你是商家还是用户,
      ①如果选择商家,商家有增加商品修改商品的功能
      ②如果选择用户,用户则有购物,刷信用卡消费的功能,当退出时打印消费清单
    2)信用卡操作
       调用/core/main.py下interactive(用户的所有数据)调用主循环函数,可以打印账户信息、还款、取款、转账、账单、退出等操作
      ①账户信息
      ②还款
      ③取款
      ④转账
      ⑤账单
      ⑥退出
    3)若在账户登陆的时候进行输入的时管理员账户调用/bin/manage.py则可以对用户进行管理,解冻    用户、冻结用户、申领新卡
      ①添加账户
      ②冻结账户
      ③解冻账户
      ④退出

    四、主程序

    1.bin目录下代码

      1 '''/bin/atm.py'''
      2 
      3 
      4 #!/usr/bin/env python
      5 #-*- Coding:utf-8 -*-
      6 # Author:Eric.Shen
      7 import os,sys
      8 base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
      9 #print(base_dir)
     10 sys.path.append(base_dir)
     11 from core import main
     12 
     13 
     14 if __name__ == '__main__':
     15     main.run()
     16 
     17 
     18 
     19 
     20 
     21 
     22 
     23 '''/bin/manage.py'''
     24 
     25 
     26 
     27 #!/usr/bin/env python
     28 #-*- Coding:utf-8 -*-
     29 # Author:Eric.Shen
     30 #管理端(提供管理接口,包括添加账户、用户额度,冻结账户)
     31 #解冻账户
     32 #from core.auth import login_required
     33 from core import accounts
     34 from core import transaction
     35 #解冻账户
     36 def unblock_account(acc_data):
     37     user_input = input("请输入你要解冻的用户:")
     38     flag = 0
     39     #锁定用户
     40     val = transaction.lock_or_not(user_input,flag)
     41     if val == 0:
     42         print("解冻成功!")
     43         return
     44 #冻结账户
     45 def block_account(acc_data):
     46     '''
     47     冻结账户初步构想是,在linux里把他的权限改掉;
     48     或者将其文件改名
     49     :param acc_data: 
     50     :return: 
     51     '''
     52     user_input = input("请输入你要冻结的用户:")
     53     flag = 1
     54     #锁定用户
     55     val = transaction.lock_or_not(user_input,flag)
     56     if val == 0:
     57         print("冻结成功!")
     58         return
     59 
     60 #添加账户、用户额度
     61 def add_account(acc_data):
     62     account = {
     63         "id": None,
     64         "balance": None,
     65         "expire_date": None,
     66         "enroll_date": None,
     67         "credit": None,
     68         "pay_day": None,
     69         "password": None,
     70         "status": None
     71     }
     72     menu = {
     73         0: "账户(数字):",
     74         1: "余额:",
     75         2: "到期时间:",
     76         3: "办卡时间:",
     77         4: "信用额度:",
     78         5: "还款日期:",
     79         6: "密码:",
     80         7: "默认:"}
     81     menu_user = {
     82         0: "id",
     83         1: "balance",
     84         2: "expire_date",
     85         3: "enroll_date",
     86         4: "credit",
     87         5: "pay_day",
     88         6: "password",
     89         7: "status"
     90     }
     91     for i in range(8):
     92         data = input("%s" % menu[i]).strip()
     93         account['%s' % menu_user[i]] = data
     94     accounts.dump_account(account)#写入文件
     95     print("创建成功!")
     96     return
     97 
     98 
     99 
    100 def logout(acc_data):
    101     exit("程序退出!")
    102 #管理界面主程序
    103 def manage_main(acc_data):
    104 
    105     menu = u'''
    106     ---------管理界面---------
    107     1.添加账户
    108     2.冻结账户
    109     3.解冻账户
    110     4.退出'''
    111     menu_dic = {
    112         '1': add_account,
    113         '2': block_account,
    114         '3': unblock_account,
    115         '4': logout
    116     }
    117     exit_flag = False
    118     while not exit_flag:
    119         print(menu)
    120         user_option = input("请输入你的选择:")
    121         if user_option in menu_dic:
    122             menu_dic[user_option](acc_data)
    123         else:
    124             print("33[31;1m选择不存在!33[0m")
    125 
    126 
    127 
    128 
    129 .
    View Code

    2.conf目录下代码

     1 '''/conf/Settings.py'''
     2 
     3 
     4 #!/usr/bin/env python
     5 #-*- Coding:utf-8 -*-
     6 # Author:Eric.Shen
     7 #参数配置文件
     8 import os,sys,logging
     9 
    10 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#/Atm
    11 
    12 DATABASE = {
    13     'engine': 'file_storage',
    14     'name': 'accounts',
    15     'path': "%s/db" % BASE_DIR#../Atm
    16 }
    17 
    18 LOG_LEVEL = logging.INFO
    19 LOG_TYPES = {
    20     'transaction': 'transaction.log',
    21     'access': 'access.log',
    22 }
    23 
    24 #发生交易的配置类型
    25 TRANSACTION_TYPE = {
    26     'repay':{'action':'plus','interest':0},#还款
    27     'withdraw':{'action':'minus','interest':0.05},#取现是降低可用余额
    28     'transfer':{'action':'minus','interest':0.05},#转账是降低可用余额
    29     'consume':{'action':'minus','interest':0},
    30 }
    View Code

    3.core目录下代码

     1 '''/core/accounts.py'''
     2 
     3 
     4 #!/usr/bin/env python
     5 #-*- Coding:utf-8 -*-
     6 # Author:Eric.Shen
     7 #用于从文件里加载和存储账户数据
     8 import json,time
     9 from core import db_handler
    10 from conf import Settings
    11 
    12 #返回账户余额和其他基础信息(返回最新的数据)
    13 def load_current_balance(account_id):
    14     '''
    15     返回账户余额和其他基础信息
    16     :param account_id: 用户账户的名字
    17     :return: 返回最新读到的数据文件中的最新数据
    18     '''
    19     # db_path = db_handler.db_handler(settings.DATABASE)
    20     # account_file = "%s/%s.json" %(db_path,account_id)
    21     #
    22     db_api = db_handler.db_handler()
    23     data = db_api("select * from accounts where account=%s" % account_id)#在进行操作的时候在读取一遍数据中的数据(保证数据的最新)
    24     return data#返回读取到的数据
    25 
    26     # with open(account_file) as f:
    27     #     acc_data = json.load(f)
    28     #     return  acc_data
    29 
    30 #写入文件数据
    31 def dump_account(account_data):
    32     '''
    33     
    34     :param account_data: 
    35     :return: 
    36     '''
    37     db_api = db_handler.db_handler()
    38     data = db_api("update accounts where account=%s" % account_data['id'],account_data = account_data)
    39 
    40     # db_path = db_handler.db_handler(settings.DATABASE)
    41     # account_file = "%s/%s.json" %(db_path,account_data['id'])
    42     # with open(account_file, 'w') as f:
    43     #     acc_data = json.dump(account_data,f)
    44     return True
    accounts.py
      1 '''/core/auth.py'''
      2 
      3 
      4 #!/usr/bin/env python
      5 #-*- Coding:utf-8 -*-
      6 # Author:Eric.Shen
      7 #用户认证模块
      8 import json,time,os
      9 from core import db_handler
     10 from bin import manage
     11 from conf import Settings
     12 from core import logger
     13 #装饰器(用于验证账户是否登陆过)
     14 def login_required(func):
     15     '''
     16     验证用户是否登陆
     17     :return: 
     18     '''
     19     def wrapper(*args,**kwargs):
     20         if args[0].get('is_authenticated'):
     21             return func(*args,**kwargs)
     22         else:
     23             exit("用户不能认证")
     24     return wrapper
     25 
     26 def acc_auth(account,password):
     27     '''
     28     账户验证函数
     29     :return: 
     30     '''
     31     db_path = db_handler.db_handler()
     32     account_file = "%s/%s.json" %(db_path,account)
     33     print(account_file)
     34     if os.path.isfile(account_file):
     35         with open(account_file,'r') as f:
     36             account_data = json.load(f)
     37             if account_data['password'] == password:
     38                 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))
     39                 if time.time() >exp_time_stamp:
     40                     print("33[31;1m[%s]账户已经注销,请重新申领账户!33[0m" % account)
     41                 else: #passed the authentication
     42                     return  account_data
     43             else:
     44                 print("33[31;1m账号或密码错误,请重新输入!33[0m")
     45     else:
     46         print("33[31;1m[%s]账户不存在!33[0m" % account)
     47 
     48 def acc_auth2(account,password):
     49     '''
     50     优化版认证接口
     51     :param
     52         account:信用卡账户
     53         password:信用卡密码
     54     :return: 返回读取到的数据文件的所有账户数据
     55     '''
     56     db_api = db_handler.db_handler()
     57     data = db_api("select * from accounts where account=%s" %account)#此处返回值为db_handler.py中的
     58     # 得到的所有数据(读取到的这个账户的所有数据)赋值给data
     59     if data["status"] == 2:#判断是否为管理者
     60         manage.manage_main(data)
     61     if data['status'] == 1:
     62         print("你的账户已经被冻结,请联系管理员!
    ")
     63         option = input("请按b退出!")
     64         if option == "b":
     65             exit("程序已经退出!")
     66     if data['password'] == password:#判断data中的password数据是否恒等于输入的password(此处如果继续执行,则账户密码完全正确)
     67         #time.mktime 返回用秒数来表示时间的浮点数。
     68         #实例结果:time.mktime(t) : 1234915418.000000
     69         #time.strptime 根据指定的格式把一个时间字符串解析为时间元组
     70         #实例结果:time.strptime(string[, format])
     71         exp_time_stamp = time.mktime(time.strptime(data['expire_date'],"%Y-%m-%d"))#将数据文件中的expire_data时间
     72         # 转为以秒计数的时间赋值给exp_time_stamp
     73         if time.time() > exp_time_stamp:#判断当前以秒计算的数据是否大于数据文件中的数据
     74             print("33[31;1m[%s]账户以及过期,请重新激活!33[0m" % account)
     75         else:
     76             return data#没有超时,则返回读取到的数据文件的所有内容
     77     else:
     78         print("33[31;1m帐户名或者密码错误!33[0m")
     79 
     80 
     81 def acc_login(user_data,log_obj):
     82     '''
     83     账户登陆函数
     84     :param
     85         user_data:用户信息数据,只存在内存中
     86     :return: 账户密码都对的情况下,返回所有账户数据
     87     '''
     88     retry_count = 0#初始化重试次数
     89     while user_data['is_authenticated'] is not True and retry_count < 3:#如果没有验证过,或循环此时没超过三次就执行下面的
     90         account = input("33[32;1m账户:33[0m").strip()#输入账户
     91         password = input("33[32;1m密码:33[0m").strip()#输入密码
     92         auth = acc_auth2(account,password)#解耦,将输入的账户和密码传入到acc_auth2函数中,进行验证
     93         # (最后返回的是读取到的输入正确账户的所有数据)赋值给auth
     94         if auth:
     95             user_data['is_authenticated'] = True#登陆成功,将只存在与内存中的数据中的是否验证改为True
     96             user_data['account_id'] = account#将只存在与内存中的数据中的账户id改为账户名字(开始输入的帐户名)
     97             return auth#这一步操作就是验证此账户是否登陆,然后返回账户的所有数据(数据文件中的所有数据)
     98         retry_count += 1
     99     else:
    100         log_obj.error("[%s]账户太多次尝试" % account)
    101         exit()
    auth.py
     1 '''/core/db_handler.py'''
     2 
     3 
     4 
     5 #!/usr/bin/env python
     6 #-*- Coding:utf-8 -*-
     7 # Author:Eric.Shen
     8 #数据库连接引擎
     9 #处理所有数据库交互
    10 import json,time,os
    11 from conf import Settings
    12 
    13 #解析文件数据路径
    14 def file_db_handle(conn_params):
    15     '''
    16     解析数据库文件路径
    17     :return: 
    18     '''
    19     #print('file db:',conn_params)
    20     return file_execute
    21 
    22 #数据库句柄
    23 def db_handler():
    24     '''
    25     连接数据库
    26     :return: 
    27     '''
    28     conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params
    29     if conn_params['engine'] == 'file_storage':#判断Settings下的DABASE是什么引擎,这里只用文件文件引擎
    30         return file_db_handle(conn_params)#则把Settings下的DABASE的数据传给file_db_handle并返回
    31     elif conn_params['engine'] == 'mysql':
    32         pass#支持扩展,此次只作为一个说明
    33 
    34 #文件执行
    35 def file_execute(sql,**kwargs):
    36     '''
    37     传入sql语句,及其他变量,
    38     :param sql: sql语句操作得到结果
    39     :param kwargs: 其他得变量
    40     :return: 
    41     '''
    42     conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params,再一次赋值意味着得到最新得数据
    43     db_path = '%s/%s' % (conn_params['path'],conn_params['name'])#数据库的文件路径 ../db/accounts
    44     #print(sql,db_path)#sql = select * from accounts where account=%s %account(此时这个account等于程序开始时要求哟用户输入得数据)
    45     sql_list = sql.split('where')#将上面得sql语句以where分开,(sql_list列表内容:'select * from accounts' ,"account='account' ")
    46     #print(sql_list)
    47     #startswith() 方法用于检查字符串是否是以指定子字符串开头,
    48     # 如果是则返回 True,否则返回False。如果参数 beg 和 end 指定值,
    49     # 则在指定范围内检查。
    50     if sql_list[0].startswith('select') and len(sql_list) > 1:#判断sql_list列表中得第一个字符是select并且列表的长度是大于1的
    51         column,val = sql_list[1].strip().split('=')#将sql_list列表第二个数据先去掉默认空格,并且以‘=’为界分开放入--》
    52         #-->column = account , val = '此处为开始程序输入的账户'
    53         #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
    54         if column == 'account':#判断是否为account,然后做指定的操作(这里使用的是account)
    55             account_file = '%s/%s.json' % (db_path,val)#这一步得到数据文件路径的文件绝对路径
    56             #print(account_file)
    57             if os.path.isfile(account_file):#使用绝对路径判断是否为文件,返回True
    58                 with open(account_file,'r') as f:#以只对的方式打开文件并把文件句柄赋值给f(用with方法打开不用自己写关闭文件的方法)
    59                     account_data = json.load(f)#json加载文件赋值给account_data
    60                     return account_data#返回account_data数据(将.json文件中的数据都都出来返回)
    61             else:
    62                 exit("33[31;1m[%s]账户不存在!33[0m" % val)#若判断不是,则返回没有此用户
    63     #写入数据
    64     elif sql_list[0].startswith('update') and len(sql_list) > 1:
    65         column, val = sql_list[1].strip().split('=')#将帐户名写入到val中
    66         if column == 'account':
    67             account_file = "%s/%s.json" % (db_path,val)
    68 #            if os.path.isfile(account_file):
    69             account_data = kwargs.get("account_data")#得到账户数据
    70             with open(account_file,'w') as f:
    71                 acc_data = json.dump(account_data,f)
    72                 #print(acc_data)
    73                 return True
    db_handler.py
     1 '''/core/logger.py'''
     2 
     3 #!/usr/bin/env python
     4 #-*- Coding:utf-8 -*-
     5 # Author:Eric.Shen
     6 #日志记录模块,处理所有日志工作
     7 
     8 import logging
     9 from conf import Settings
    10 
    11 def logger(log_type):
    12     #创建日志
    13     logger = logging.getLogger(log_type)
    14     logger.setLevel(Settings.LOG_LEVEL)
    15 
    16     #创建控制台处理程序并将级别设置为调试
    17     ch = logging.StreamHandler()
    18     ch.setLevel(Settings.LOG_LEVEL)
    19     #创建文件处理程序并设置级别为警告
    20     log_file = "%s/logs/%s" %(Settings.BASE_DIR,Settings.LOG_TYPES[log_type])
    21     fh = logging.FileHandler(log_file)
    22     fh.setLevel(Settings.LOG_LEVEL)
    23     #创建格式化程序
    24     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levename)s- %(message)s')
    25 
    26     #添加格式化的CH和FH
    27     ch.setFormatter(formatter)
    28     fh.setFormatter(formatter)
    29 
    30     #添加CH和FH到loggerh
    31     logger.addHandler(ch)
    32     logger.addHandler(fh)
    33 
    34     return logger
    35 
    36     #应用程序代码
    37     '''logger.debug('debug message')
    38     '''
    logger.py
     1 #!/usr/bin/env python
     2 #-*- Coding:utf-8 -*-
     3 # Author:Eric.Shen
     4 #记账还钱取钱与账户金额相关的操作,冻结或者锁定用户
     5 from conf import Settings
     6 from core import accounts
     7 from core import logger
     8 
     9 def make_transaction(log_obj,account_data,tran_type,amount,**kwargs):
    10     '''
    11     处理所有用户的所有交易
    12     :param log_obj: 
    13     :param account_data: 用户最新的数据
    14     :param tran_type: 交易类型
    15     :param amount: 交易数量
    16     :param other: 主要用于日志使用
    17     :return: 返回最新的账户数据
    18     '''
    19     amount = float(amount)#转换为浮点型
    20     if tran_type in Settings.TRANSACTION_TYPE:#判断传入的类型是否在配置参数里面
    21         interest = amount * Settings.TRANSACTION_TYPE[tran_type]["interest"]#根据交易类型计算利息赋值给interest
    22         old_balance = account_data['balance']#读取数据中账户余额
    23         #还款操作
    24         if Settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':#因为是信用卡,所以还款时提升可使用余额的操作,故计为加plus
    25             new_balance = old_balance + amount + interest#执行的是信用卡的还款操作,计算方法是,旧余额+还款的钱和利息=最后的账户可用余额
    26         #取现转账操作
    27         elif Settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':#因为是信用卡,所以取现都是降低可用余额的操作
    28             new_balance = old_balance - amount - interest
    29             #只属于转账的
    30             if kwargs.get('re_account'):
    31                 #print(kwargs[0],kwargs[1])
    32                 re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据
    33                 re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值
    34                 re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中
    35                 print(re_account_data)
    36                 accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中
    37             if new_balance < 0:
    38                 print("33[31;1m[%s]账户的信用余额不足以支付此次交易[-%s],你当前的余额是[%s]33[0m"
    39                       % (account_data['creat'], (amount + interest), old_balance))
    40                 return
    41         #转账
    42         '''
    43         elif Settings.TRANSACTION_TYPE[tran_type] == 'transfer' :
    44             new_balance = old_balance - amount - interest#自己账户的最新余额
    45             #读取转入的账户,写入转入金额
    46             print(kwargs[0],kwargs[1])
    47             re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据
    48             re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值
    49             re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中
    50             print(re_account_data)
    51             accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中
    52         '''
    53 
    54         account_data['balance'] = new_balance#将最新的余额写入到账户数据中
    55         print(account_data)
    56         accounts.dump_account(account_data)#将最新的账户余额写回文件
    57         #写入日志
    58         #log_obj.info('账户:%s,操作:%s,数量:%s,利息:%s' %(account_data['id'],tran_type,amount,interest))
    59         return account_data
    60     else:
    61         print("33[31;1m%s交易类型不存在33[0m" % tran_type)
    62 #冻结或者锁定用户
    63 def lock_or_not(account,flag):
    64     data = accounts.load_current_balance(account)
    65 
    66     if data["status"] == 1:
    67         print("该账户已经锁定!")
    68     if data['status']:
    69         data["status"] = flag
    70         accounts.dump_account(data)
    71         return 0
    transaction.py
      1 #!/usr/bin/env python
      2 #-*- Coding:utf-8 -*-
      3 # Author:Eric.Shen
      4 #主程序句柄模块,处理所有用户交互内容
      5 from core import auth
      6 from core import accounts
      7 from core import logger
      8 from core import transaction
      9 from  core.auth import login_required
     10 from shopping_mall import shopping_mall
     11 from bin import manage
     12 import time
     13 
     14 
     15 #交易日志
     16 trans_logger = logger.logger('transaction')
     17 #访问日志
     18 access_logger = logger.logger('access')
     19 
     20 #临时账户数据,仅存在于内存中
     21 user_data = {
     22     'account_id':None,
     23     'is_authenticated':False,
     24     'account_data':None
     25 }
     26 
     27 #账户信息
     28 def account_info(acc_data):
     29     print(user_data)
     30 #还款
     31 @login_required#装饰器,判断用户是否登陆
     32 def repay(acc_data):
     33     '''
     34     打印当前余额,让用户偿还账单
     35     :param acc_data: 
     36     :return: 
     37     '''
     38     account_data = accounts.load_current_balance(acc_data['account_id'])#将用户账户名字传入到load_current_balance中
     39     #返回最新的用户数据赋值给 account_data
     40     current_balance = '''
     41     ---------银行信息----------
     42     信用额度: %s
     43     可用余额: %s
     44     ''' %(account_data['credit'],account_data['balance'])
     45     print(current_balance)
     46     back_flag = False
     47     while not back_flag:
     48         repay_amount = input("33[33;1m输入你要还款的金额:33[0m").strip()#还款金额
     49         if len(repay_amount) > 0 and repay_amount.isdigit():
     50             #print('ddd 00')
     51             #将数据传入make_transaction中(交易日志,用户数据,交易类型,还款金额)进行操作,最后返回的是最新操作之后的账户数据
     52             new_balance = transaction.make_transaction(trans_logger,account_data,'repay',repay_amount)
     53             if new_balance:
     54                 print('''33[42;1m最新的余额:%s33[0m''' %(new_balance['balance']))
     55             else:
     56                 print('33[31;1m[%s]是无效的账户!33[0m' % repay_amount)
     57             if repay_amount == 'b':
     58                 back_flag =True
     59 #取款
     60 @login_required
     61 def withdraw(acc_data):
     62     '''
     63     打印当前余额,让用户执行取款操作
     64     :param acc_data: 
     65     :return: 
     66     '''
     67     account_data = accounts.load_current_balance(acc_data['account_id'])
     68     # 将用户账户名字传入到load_current_balance中
     69     # 返回最新的用户数据赋值给 account_data
     70     current_balance = ''' --------- 银行信息 --------
     71     信用额度: %s
     72     账户余额: %s''' % (account_data['credit'], account_data['balance'])
     73     print(current_balance)
     74     back_flag = False
     75     while not back_flag:
     76         withdraw_amount = input("33[33;1m输入取款金额:33[0m").strip()
     77         if withdraw_amount == 'b':
     78             return
     79         if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
     80             new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount)
     81             if new_balance:
     82                 print('''33[42;1m最新余额:%s33[0m''' %(new_balance['balance']))
     83         else:
     84             print('33[31;1m[%s]是无效的账户!33[0m' % withdraw_amount)
     85 
     86 
     87 #转账
     88 @login_required
     89 def transfer(acc_data):
     90     '''
     91     打印当前余额,转账操作函数
     92     :param acc_data:用户数据 
     93     :return: 
     94     '''
     95     account_data = accounts.load_current_balance(acc_data['account_id'])
     96     # 将用户账户名字传入到load_current_balance中
     97     # 返回最新的用户数据赋值给 account_data
     98     current_balance = ''' --------- 银行信息 --------
     99     信用额度: %s
    100     账户余额: %s''' % (account_data['credit'], account_data['balance'])
    101     print(current_balance)
    102     back_flag = False
    103     while not back_flag:
    104         reciprocal_account = input("33[31;1m请输入对方帐户名:33[0m").strip()#输入对方账户信息
    105         transfer_amount = input("33[31;1m转账金额:33[0m").strip()#转账金额
    106         if reciprocal_account or transfer_amount  == 'b' :
    107             return
    108         if len(transfer_amount) > 0 and transfer_amount.isdigit():
    109             new_balance = transaction.make_transaction(trans_logger,account_data,'transfer',
    110                                                        transfer_amount,re_account = reciprocal_account)
    111             if new_balance:
    112                 print("33[41;1m转账成功!33[0m")
    113                 print("33[42;1m您当前的余额为:%s33[0m" %(new_balance["balance"]))
    114         else:
    115             print('33[31;1m[%s] 33[0m')
    116 
    117 
    118 #账单
    119 @login_required
    120 def pay_check(acc_data):
    121     pass
    122 #退出
    123 def logout(acc_data):
    124     exit("程序已经退出!")
    125 #购物商城
    126 def shopping_mall_this(acc_data):
    127     shopping_mall.main_menu(acc_data)
    128 #管理窗口
    129 def goto_manage():
    130    manage.manage_main(user_data)
    131 #菜单
    132 def interactive(acc_data):
    133     '''
    134     与用户交互
    135     :param acc_data: 验证过的用户的所用数据
    136     :return: 
    137     '''
    138     menu = u'''
    139     -----------银行----------
    140     33[32;1m
    141     1.账户信息
    142     2.还款
    143     3.取款
    144     4.转账
    145     5.账单
    146     6.退出
    147     33[0m
    148     '''
    149     menu_dic = {
    150         '1': account_info,
    151         '2': repay,
    152         '3': withdraw,
    153         '4': transfer,
    154         '5': pay_check,
    155         '6': logout,
    156     }
    157     exit_flag = False
    158     while not exit_flag:
    159         print(menu)#打印出菜单,供用户选择
    160         user_option = input("请输入你的选择:").strip()#输入用户的选择,过滤掉空格
    161         if user_option == 'b':
    162             return
    163         if user_option in menu_dic:#用户的选择如果在这个菜单里
    164             #print('accdata',acc_data)
    165             menu_dic[user_option](acc_data)#用户选择执行的功能,把acc_data验证过的用户的所有数据(数据文件中的数据)
    166         else:
    167             print("33[31;1m选择不存在!33[0m")
    168 #带有购物商场的主菜单
    169 def main_menu(acc_data):
    170     main_menu = u'''
    171     ----------主菜单---------
    172     33[32;1m
    173     1.购物商城
    174     2.银行卡操作
    175     3.退出
    176     33[0m
    177     '''
    178     main_menu_dic = {
    179         '1':shopping_mall_this,
    180         '2':interactive,
    181         '3':logout,
    182     }
    183     exit_flag = False
    184     while not exit_flag:
    185         print(main_menu)
    186         user_option = input("请输入你的选择:").strip()
    187         if user_option == 'b':
    188             return
    189         if user_option in main_menu_dic:
    190             main_menu_dic[user_option](acc_data)
    191         else:
    192             print("33[31;1m选择不存在!33[0m")
    193 def run():
    194     '''
    195     当程序启动时,这个程序开始运行,处理关于用户的所有交互的内容
    196     '''
    197     acc_data = auth.acc_login(user_data,access_logger)#程序从这里开始,执行auth下的acc_login函数
    198     # (返回的是验证过的正确的账户数据)赋值给acc_data(此时这里的数据为输入账户名字的数据文件的数据)
    199     if user_data['is_authenticated']:
    200         user_data['account_data'] = acc_data#把账户所有信息传给账户开始时的临时的账户数据空字典,
    201         # 把所有的数据文件传给账户的账户数据里面,
    202         #interactive(user_data)#把user_data里的所有数据传入菜单函数,进行下一步操作
    203         main_menu(user_data)
    main.py

    4.db下目录下代码

    /db/accounts/123.json

    1 {"pay_day": "22", "enroll_date": "2018-02-19", "credit": "15000", "balance": "123", "id": "123", "expire_date": "2032-01-01", "password": "123", "status": 0}
    123.json

    5.logs目录下代码

    /logs/access.log&transaction.log

    6.shopping_mall下代码

    /shopping_mall/product.txt&shopping_list.txt

      1 #!/usr/bin/env python
      2 #-*- Coding:utf-8 -*-
      3 # Author:Eric.Shen
      4 # !/usr/bin/env python
      5 # -*- Coding:utf-8 -*-
      6 # Author:Eric.Shen
      7 # 2018.02.06
      8 # path python3.5
      9 # 优化版的购物车
     10 # 用户入口:
     11 # 1.商品的信息存到文件里
     12 # 2.已购商品,余额记录
     13 # 商家入口:
     14 # 1.可以添加商品 2.修改商品价格
     15 # 存储商品列表
     16 import fileinput
     17 from core import accounts
     18 
     19 product_list = []
     20 f = open("D:\Python_train\day4\Atm\shopping_mall\product.txt", "r")  # 打开文件
     21 for line in f.readlines():
     22     line = line.strip()  # 去掉最后一个换行符
     23     index, item = line.split(":")  # 以冒号分割得到前后两个数据
     24     product_list.append((index, item))  # 添加的数据
     25 f.close()
     26 
     27 
     28 def print_product_list():
     29     for index, item in enumerate(product_list):
     30         print(index, item)
     31 
     32 
     33 # 用户入口
     34 # 用户购物
     35 def user_shopping(account_data):
     36     #salary = input("请输入你的薪水:")
     37     salary = account_data['account_data']['balance']
     38     print_product_list()
     39     if salary > 0:
     40         shopping_list = []  # 存放用户购物车清单
     41         while True:
     42             option = input("喜欢那个就买哪个(对应的标号):")
     43             if option.isdigit():
     44                 option = int(option)
     45                 if option >= 0 and option <= len(product_list):
     46                     p_item = product_list[option]  # 用户选择的商品
     47                     # print(product_list)
     48                     # print(p_item[1])
     49                     c_num = int(p_item[1])
     50                     if salary >= c_num:
     51                         shopping_list.append(p_item)
     52                         salary -= c_num
     53                         print("添加购物车成功,你的余额还有%s" % (salary))
     54                     else:
     55                         print("你的余额不足,只剩%s元" % (salary))
     56                 else:
     57                     print("输入错误,请重新输入!")
     58             elif option == "q":
     59                 print("----------------购物清单---------------")
     60                 for s_list in shopping_list:
     61                     print(s_list)
     62                 print("你的余额为%s" % (salary))
     63                 account_data['account_data']['balance'] = salary
     64                 #print(account_data)
     65                 accounts.dump_account(account_data['account_data'])#写入文件
     66                 print("..........exit.........")
     67                 exit()
     68             else:
     69                 print("无效的输入")
     70     else:
     71         exit("余额不足!")
     72 
     73 
     74 # 商家入口
     75 # 商家添加商品
     76 def add_product():
     77     name_of_product = input("请输入你要添加的商品名字:")
     78     price_of_product = input("请输入你要添加商品的价格:")
     79     f = open("product.txt", "a")
     80     f.write(str("
    " + name_of_product) + ": %s" % (price_of_product))
     81     f.close()
     82     print("添加成功!
    exit----------")
     83 
     84 
     85 # 修改商品价格
     86 def change_price():
     87     print_product_list()  # 打印商品列表
     88     choice = input("请输入你的选择:")
     89     # name_of_change = input("请输入你要改变的商品名字")
     90     price_of_change = input("请输入你要改变商品的价格:")
     91     if choice.isdigit():
     92         choice = int(choice)
     93         if choice >= 0 and choice <= len(product_list):
     94             p_item = product_list[choice]  # 选择的商品
     95             # c_num = int(p_item[1])#转换成int类型
     96             for line in fileinput.input("product.txt", inplace="%s" % (choice)):  # 对输入的选择行进行修改
     97                 line = line.replace("%s" % (p_item[1]), "%s" % (price_of_change)).strip()
     98                 print(line)
     99             exit("修改成功!")
    100         else:
    101             print("输入无效")
    102     else:
    103         if choice == "q":
    104             exit("退出")
    105 
    106 
    107 def main_menu(account_data):
    108     print("--------------------------"
    109           "--------------------------"
    110           "
    "
    111           "                  欢迎进入购物菜单      "
    112           "
    "
    113           "
    "
    114           "商家请按b,用户请按c
    "
    115           "--------------------------"
    116           "--------------------------")
    117     c_num = input("请输入你的选择:")  # 使用者选择
    118     if c_num == "b":
    119         print("--------------------------"
    120               "--------------------------"
    121               "
    "
    122               "                  欢迎进入商家界面      "
    123               "
    "
    124               "
    "
    125               "添加商品请按a,修改价格请按c
    "
    126               "--------------------------"
    127               "--------------------------")
    128         c_num2 = input("请输入你的选择:")
    129         if c_num2 == "a":
    130             # 实现添加商品功能
    131             add_product()
    132         if c_num2 == "c":
    133             # 实现商品价格修改功能
    134             change_price()
    135         else:
    136             print("输入有误!")
    137     if c_num == "c":
    138         print("--------------------------"
    139               "--------------------------"
    140               "
    "
    141               "                  欢迎进入用户界面      "
    142               "
    "
    143               "
    "
    144 
    145               "--------------------------"
    146               "--------------------------")
    147         # 购物功能
    148         print(account_data)
    149         user_shopping(account_data)
    150     else:
    151         print("输入有误程序退出!")
    shopping_mall

    五、README

     1 作者:Eric.shen
     2 此次系统的设计仅用来学习python,开始于2018.2.13-19完(此系统,日志部分没有完善留着日后补充现在还没学到)
     3 作业需求:
     4 
     5 模拟实现一个ATM + 购物商城程序:
     6     1.额度 15000或自定义
     7     2.实现购物商城,买东西加入 购物车,调用信用卡接口结账
     8     3.可以提现,手续费5%
     9     4.每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息(没写)
    10     5.支持多账户登录
    11     6.支持账户间转账
    12     7.记录每月日常消费流水
    13     8.提供还款接口
    14     9.ATM记录操作日志
    15     10.提供管理接口,包括添加账户、用户额度,冻结账户等。。。
    16     11.用户认证用装饰器
    17 
    18 一、软件定位,软件的基本功能。
    19     实现一个简单的atm与购物车程序,
    20 二、运行代码的方法: 安装环境、启动命令等。
    21     用Python3.5写的,语法就是至此之前所学的,直接打开运行即可
    22 三、目录结构。
    23 
    24 ├── ATM #ATM主程目录
    25 │   ├── __init__.py
    26 │   ├── bin                    #ATM 执行文件 目录
    27 │   │   ├── __init__.py
    28 │   │   ├── atm.py                 #ATM 执行程序
    29 │   │   ├── manage.py              #信用卡管理 
    30 │   ├── conf                   #配置文件
    31 │   │   ├── __init__.py
    32 │   │   └── Settings.py            #配置参数
    33 │   ├── core                   #主要程序逻辑都 在这个目录 里
    34 │   │   ├── __init__.py
    35 │   │   ├── accounts.py            #用于从文件里加载和存储账户数据
    36 │   │   ├── auth.py                #用户认证模块及主要功能函数
    37 │   │   ├── db_handler.py          #数据库连接引擎
    38 │   │   ├── logger.py              #日志记录模块
    39 │   │   ├── main.py                #主逻辑交互程序
    40 │   │   ├── transaction.py         #记账还钱取钱与账户金额相关的操作,冻结或者锁定用户
    41 │   ├── db                     #用户数据存储的地方
    42 │   │   ├── __init__.py
    43 │   │   ├── account_sample.py   #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
    44 │   │   └── accounts            #存各个用户的账户数据 ,一个用户一个文件
    45 │   │       └── 123.json           #新创建的用户账户示例文件
    46 │   │       └── 1234.json          #一个用户账户示例文件
    47 │   │       └── 123456.json        #一个用户账户示例文件
    48 │   │       └── 6230001.json       #管理用户账户示例文件
    49 │   └── log                    #日志目录
    50 │        ├── access.log              #用户访问和操作的相关日志
    51 │        └── login_in.log            #登陆日志
    52 └── shopping_mall               #电子商城程序,需单独实现,主要实现购物的功能。
    53 │        └── __init__.py
    54 │        └── product.txt             #存放商品的txt文件
    55 │        └── shopping_list.txt       #存放购物清单的txt.文件
    56 │        └── shopping_mall.py        #购物商城程序
    57 ├── README
    58 四、简要说明,更详细点可以说明软件的基本原理。
    59     1.程序从/bin/atm.py开始执行if __name__ == '__main__':
    60                              main.run()
    61     2.程序转到/core/main.py下的run()函数,登陆时调用/core/auth的acc_login()进行登陆验证:用到了/core/auth下的acc_auth2()方法进行验证(此时传入的参数时用户输入的账户和密码)
    62 acc_auth2中有调用了/core/db_handler下的db_handler()方法(参数是输入的账户名)在db_handler中只是进行判断是什么引擎,return file_db_handle(数据库引擎)解析文件,返回文件执行加载输入的用户的账户的所有数据
    63 接下来判断是否为管理者账户,或者是否被冻结,若都不是,则判断输入的密码是否与数据库中的密码一样,在判断到期时间是否过期
    64 所有都通过的话就返回这个账户的数据,之前已经创建了一个空字典,里面有是否验证:用户数据:用户账户:,判断是否被验证过,然后把用户数据临时的传递到里面,执行主循环函数
    65 可以选择进入到购物商城,或者信用卡操作或者退出
    66     1)购物商城
    67     调用/shopping_mall/shopping_mall.py文件执行,主循环函数,选择你是商家还是用户,
    68         ①如果选择商家,商家有增加商品修改商品的功能
    69         ②如果选择用户,用户则有购物,刷信用卡消费的功能,当退出时打印消费清单
    70     2)信用卡操作
    71     调用/core/main.py下interactive(用户的所有数据)调用主循环函数,可以打印账户信息、还款、取款、转账、账单、退出等操作
    72         ①账户信息
    73         ②还款
    74         ③取款
    75         ④转账
    76         ⑤账单
    77         ⑥退出
    78     3)若在账户登陆的时候进行输入的时管理员账户调用/bin/manage.py则可以对用户进行管理,解冻用户、冻结用户、申领新卡
    79         ①添加账户
    80         ②冻结账户
    81         ③解冻账户
    82         ④退出
    83 五、常见问题说明。
    84 日志没有实现,账单没有实现
    View Code

     ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    product.txt

    iphone: 5288
    Mac pro: 12000
    Bike: 800
    Watch: 36000
    Coffe: 39
    Python book: 120
    Book: 100

    shopping_list.txt

    ('Coffe', 39)
    ('Pychon book', 120)

    长风破浪会有时,直挂云帆济沧海。

    欢迎多多提提意见

  • 相关阅读:
    String前后去掉空格、option只能定义value值吗?还能添加什么值。dom和Jquery对象转换。
    JsonObject没有fromObject、idea引入maven有红线没依赖、JsonObject maven 依赖包
    json几个小例子
    [极客大挑战 2019]PHP1
    栈溢出原理笔记(一)
    CentOS7怎么安装图形界面
    快速搭建WordPress博客
    Mac 安装Mysql 之 Sqlservice 区别
    Metasploit-初篇
    Windows To Go 制作详解
  • 原文地址:https://www.cnblogs.com/zhengyuan/p/8454216.html
Copyright © 2020-2023  润新知