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("\033[31;1m选择不存在!\033[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("\033[31;1m[%s]账户已经注销,请重新申领账户!\033[0m" % account)
 41                 else: #passed the authentication
 42                     return  account_data
 43             else:
 44                 print("\033[31;1m账号或密码错误,请重新输入!\033[0m")
 45     else:
 46         print("\033[31;1m[%s]账户不存在!\033[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("你的账户已经被冻结,请联系管理员!\n")
 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("\033[31;1m[%s]账户以及过期,请重新激活!\033[0m" % account)
 75         else:
 76             return data#没有超时,则返回读取到的数据文件的所有内容
 77     else:
 78         print("\033[31;1m帐户名或者密码错误!\033[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("\033[32;1m账户:\033[0m").strip()#输入账户
 91         password = input("\033[32;1m密码:\033[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("\033[31;1m[%s]账户不存在!\033[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("\033[31;1m[%s]账户的信用余额不足以支付此次交易[-%s],你当前的余额是[%s]\033[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("\033[31;1m%s交易类型不存在\033[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("\033[33;1m输入你要还款的金额:\033[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('''\033[42;1m最新的余额:%s\033[0m''' %(new_balance['balance']))
 55             else:
 56                 print('\033[31;1m[%s]是无效的账户!\033[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("\033[33;1m输入取款金额:\033[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('''\033[42;1m最新余额:%s\033[0m''' %(new_balance['balance']))
 83         else:
 84             print('\033[31;1m[%s]是无效的账户!\033[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("\033[31;1m请输入对方帐户名:\033[0m").strip()#输入对方账户信息
105         transfer_amount = input("\033[31;1m转账金额:\033[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("\033[41;1m转账成功!\033[0m")
113                 print("\033[42;1m您当前的余额为:%s\033[0m" %(new_balance["balance"]))
114         else:
115             print('\033[31;1m[%s] \033[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     \033[32;1m
141     1.账户信息
142     2.还款
143     3.取款
144     4.转账
145     5.账单
146     6.退出
147     \033[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("\033[31;1m选择不存在!\033[0m")
168 #带有购物商场的主菜单
169 def main_menu(acc_data):
170     main_menu = u'''
171     ----------主菜单---------
172     \033[32;1m
173     1.购物商城
174     2.银行卡操作
175     3.退出
176     \033[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("\033[31;1m选择不存在!\033[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("\n" + name_of_product) + ": %s" % (price_of_product))
 81     f.close()
 82     print("添加成功!\nexit----------")
 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           "\n"
111           "                  欢迎进入购物菜单      "
112           "\n"
113           "\n"
114           "商家请按b,用户请按c\n"
115           "--------------------------"
116           "--------------------------")
117     c_num = input("请输入你的选择:")  # 使用者选择
118     if c_num == "b":
119         print("--------------------------"
120               "--------------------------"
121               "\n"
122               "                  欢迎进入商家界面      "
123               "\n"
124               "\n"
125               "添加商品请按a,修改价格请按c\n"
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               "\n"
141               "                  欢迎进入用户界面      "
142               "\n"
143               "\n"
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)

 

 

 

 

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

欢迎多多提提意见

posted @ 2018-02-19 18:42  ankuo  阅读(2230)  评论(10编辑  收藏  举报