一、程序需求

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

脑图:

二、目录

 ├── ATM #ATM主程目录
│ ├── __init__.py
│ ├── bin #ATM 执行文件 目录
│ │ ├── __init__.py
│ │ ├── atm.py #ATM 执行程序
│ │ ├── manage.py #信用卡管理
│ ├── conf #配置文件
│ │ ├── __init__.py
│ │ └── Settings.py #配置参数
│ ├── core #主要程序逻辑都 在这个目录 里
│ │ ├── __init__.py
│ │ ├── accounts.py #用于从文件里加载和存储账户数据
│ │ ├── auth.py #用户认证模块及主要功能函数
│ │ ├── db_handler.py #数据库连接引擎
│ │ ├── logger.py #日志记录模块
│ │ ├── main.py #主逻辑交互程序
│ │ ├── transaction.py #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户
│ ├── db #用户数据存储的地方
│ │ ├── __init__.py
│ │ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
│ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件
│ │ └── .json #新创建的用户账户示例文件
│ │ └── .json #一个用户账户示例文件
│ │ └── .json #一个用户账户示例文件
│ │ └── .json #管理用户账户示例文件
│ └── log #日志目录
│ ├── access.log #用户访问和操作的相关日志
│ └── login_in.log #登陆日志
└── shopping_mall #电子商城程序,需单独实现,主要实现购物的功能。
│ └── __init__.py
│ └── product.txt #存放商品的txt文件
│ └── shopping_list.txt #存放购物清单的txt.文件
│ └── shopping_mall.py #购物商城程序
├── 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目录下代码

 '''/bin/atm.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
import os,sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#print(base_dir)
sys.path.append(base_dir)
from core import main if __name__ == '__main__':
main.run() '''/bin/manage.py''' #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#管理端(提供管理接口,包括添加账户、用户额度,冻结账户)
#解冻账户
#from core.auth import login_required
from core import accounts
from core import transaction
#解冻账户
def unblock_account(acc_data):
user_input = input("请输入你要解冻的用户:")
flag = 0
#锁定用户
val = transaction.lock_or_not(user_input,flag)
if val == 0:
print("解冻成功!")
return
#冻结账户
def block_account(acc_data):
'''
冻结账户初步构想是,在linux里把他的权限改掉;
或者将其文件改名
:param acc_data:
:return:
'''
user_input = input("请输入你要冻结的用户:")
flag = 1
#锁定用户
val = transaction.lock_or_not(user_input,flag)
if val == 0:
print("冻结成功!")
return #添加账户、用户额度
def add_account(acc_data):
account = {
"id": None,
"balance": None,
"expire_date": None,
"enroll_date": None,
"credit": None,
"pay_day": None,
"password": None,
"status": None
}
menu = {
0: "账户(数字):",
1: "余额:",
2: "到期时间:",
3: "办卡时间:",
4: "信用额度:",
5: "还款日期:",
6: "密码:",
7: "默认:"}
menu_user = {
0: "id",
1: "balance",
2: "expire_date",
3: "enroll_date",
4: "credit",
5: "pay_day",
6: "password",
7: "status"
}
for i in range(8):
data = input("%s" % menu[i]).strip()
account['%s' % menu_user[i]] = data
accounts.dump_account(account)#写入文件
print("创建成功!")
return def logout(acc_data):
exit("程序退出!")
#管理界面主程序
def manage_main(acc_data): menu = u'''
---------管理界面---------
1.添加账户
2.冻结账户
3.解冻账户
4.退出'''
menu_dic = {
'': add_account,
'': block_account,
'': unblock_account,
'': logout
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input("请输入你的选择:")
if user_option in menu_dic:
menu_dic[user_option](acc_data)
else:
print("\033[31;1m选择不存在!\033[0m") .

2.conf目录下代码

 '''/conf/Settings.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#参数配置文件
import os,sys,logging BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#/Atm DATABASE = {
'engine': 'file_storage',
'name': 'accounts',
'path': "%s/db" % BASE_DIR#../Atm
} LOG_LEVEL = logging.INFO
LOG_TYPES = {
'transaction': 'transaction.log',
'access': 'access.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},
}

3.core目录下代码

 '''/core/accounts.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#用于从文件里加载和存储账户数据
import json,time
from core import db_handler
from conf import Settings #返回账户余额和其他基础信息(返回最新的数据)
def load_current_balance(account_id):
'''
返回账户余额和其他基础信息
:param account_id: 用户账户的名字
:return: 返回最新读到的数据文件中的最新数据
'''
# db_path = db_handler.db_handler(settings.DATABASE)
# account_file = "%s/%s.json" %(db_path,account_id)
#
db_api = db_handler.db_handler()
data = db_api("select * from accounts where account=%s" % account_id)#在进行操作的时候在读取一遍数据中的数据(保证数据的最新)
return data#返回读取到的数据 # with open(account_file) as f:
# acc_data = json.load(f)
# return acc_data #写入文件数据
def dump_account(account_data):
''' :param account_data:
:return:
'''
db_api = db_handler.db_handler()
data = db_api("update accounts where account=%s" % account_data['id'],account_data = account_data) # db_path = db_handler.db_handler(settings.DATABASE)
# account_file = "%s/%s.json" %(db_path,account_data['id'])
# with open(account_file, 'w') as f:
# acc_data = json.dump(account_data,f)
return True

accounts.py

 '''/core/auth.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#用户认证模块
import json,time,os
from core import db_handler
from bin import manage
from conf import Settings
from core import logger
#装饰器(用于验证账户是否登陆过)
def login_required(func):
'''
验证用户是否登陆
:return:
'''
def wrapper(*args,**kwargs):
if args[0].get('is_authenticated'):
return func(*args,**kwargs)
else:
exit("用户不能认证")
return wrapper def acc_auth(account,password):
'''
账户验证函数
:return:
'''
db_path = db_handler.db_handler()
account_file = "%s/%s.json" %(db_path,account)
print(account_file)
if os.path.isfile(account_file):
with open(account_file,'r') as f:
account_data = json.load(f)
if account_data['password'] == password:
exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))
if time.time() >exp_time_stamp:
print("\033[31;1m[%s]账户已经注销,请重新申领账户!\033[0m" % account)
else: #passed the authentication
return account_data
else:
print("\033[31;1m账号或密码错误,请重新输入!\033[0m")
else:
print("\033[31;1m[%s]账户不存在!\033[0m" % account) def acc_auth2(account,password):
'''
优化版认证接口
:param
account:信用卡账户
password:信用卡密码
:return: 返回读取到的数据文件的所有账户数据
'''
db_api = db_handler.db_handler()
data = db_api("select * from accounts where account=%s" %account)#此处返回值为db_handler.py中的
# 得到的所有数据(读取到的这个账户的所有数据)赋值给data
if data["status"] == 2:#判断是否为管理者
manage.manage_main(data)
if data['status'] == 1:
print("你的账户已经被冻结,请联系管理员!\n")
option = input("请按b退出!")
if option == "b":
exit("程序已经退出!")
if data['password'] == password:#判断data中的password数据是否恒等于输入的password(此处如果继续执行,则账户密码完全正确)
#time.mktime 返回用秒数来表示时间的浮点数。
#实例结果:time.mktime(t) : 1234915418.000000
#time.strptime 根据指定的格式把一个时间字符串解析为时间元组
#实例结果:time.strptime(string[, format])
exp_time_stamp = time.mktime(time.strptime(data['expire_date'],"%Y-%m-%d"))#将数据文件中的expire_data时间
# 转为以秒计数的时间赋值给exp_time_stamp
if time.time() > exp_time_stamp:#判断当前以秒计算的数据是否大于数据文件中的数据
print("\033[31;1m[%s]账户以及过期,请重新激活!\033[0m" % account)
else:
return data#没有超时,则返回读取到的数据文件的所有内容
else:
print("\033[31;1m帐户名或者密码错误!\033[0m") def acc_login(user_data,log_obj):
'''
账户登陆函数
:param
user_data:用户信息数据,只存在内存中
:return: 账户密码都对的情况下,返回所有账户数据
'''
retry_count = 0#初始化重试次数
while user_data['is_authenticated'] is not True and retry_count < 3:#如果没有验证过,或循环此时没超过三次就执行下面的
account = input("\033[32;1m账户:\033[0m").strip()#输入账户
password = input("\033[32;1m密码:\033[0m").strip()#输入密码
auth = acc_auth2(account,password)#解耦,将输入的账户和密码传入到acc_auth2函数中,进行验证
# (最后返回的是读取到的输入正确账户的所有数据)赋值给auth
if auth:
user_data['is_authenticated'] = True#登陆成功,将只存在与内存中的数据中的是否验证改为True
user_data['account_id'] = account#将只存在与内存中的数据中的账户id改为账户名字(开始输入的帐户名)
return auth#这一步操作就是验证此账户是否登陆,然后返回账户的所有数据(数据文件中的所有数据)
retry_count += 1
else:
log_obj.error("[%s]账户太多次尝试" % account)
exit()

auth.py

 '''/core/db_handler.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#数据库连接引擎
#处理所有数据库交互
import json,time,os
from conf import Settings #解析文件数据路径
def file_db_handle(conn_params):
'''
解析数据库文件路径
:return:
'''
#print('file db:',conn_params)
return file_execute #数据库句柄
def db_handler():
'''
连接数据库
:return:
'''
conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params
if conn_params['engine'] == 'file_storage':#判断Settings下的DABASE是什么引擎,这里只用文件文件引擎
return file_db_handle(conn_params)#则把Settings下的DABASE的数据传给file_db_handle并返回
elif conn_params['engine'] == 'mysql':
pass#支持扩展,此次只作为一个说明 #文件执行
def file_execute(sql,**kwargs):
'''
传入sql语句,及其他变量,
:param sql: sql语句操作得到结果
:param kwargs: 其他得变量
:return:
'''
conn_params = Settings.DATABASE#把Settings下的DATABASE的数据赋值给conn_params,再一次赋值意味着得到最新得数据
db_path = '%s/%s' % (conn_params['path'],conn_params['name'])#数据库的文件路径 ../db/accounts
#print(sql,db_path)#sql = select * from accounts where account=%s %account(此时这个account等于程序开始时要求哟用户输入得数据)
sql_list = sql.split('where')#将上面得sql语句以where分开,(sql_list列表内容:'select * from accounts' ,"account='account' ")
#print(sql_list)
#startswith() 方法用于检查字符串是否是以指定子字符串开头,
# 如果是则返回 True,否则返回False。如果参数 beg 和 end 指定值,
# 则在指定范围内检查。
if sql_list[0].startswith('select') and len(sql_list) > 1:#判断sql_list列表中得第一个字符是select并且列表的长度是大于1的
column,val = sql_list[1].strip().split('=')#将sql_list列表第二个数据先去掉默认空格,并且以‘=’为界分开放入--》
#-->column = account , val = '此处为开始程序输入的账户'
#Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
if column == 'account':#判断是否为account,然后做指定的操作(这里使用的是account)
account_file = '%s/%s.json' % (db_path,val)#这一步得到数据文件路径的文件绝对路径
#print(account_file)
if os.path.isfile(account_file):#使用绝对路径判断是否为文件,返回True
with open(account_file,'r') as f:#以只对的方式打开文件并把文件句柄赋值给f(用with方法打开不用自己写关闭文件的方法)
account_data = json.load(f)#json加载文件赋值给account_data
return account_data#返回account_data数据(将.json文件中的数据都都出来返回)
else:
exit("\033[31;1m[%s]账户不存在!\033[0m" % val)#若判断不是,则返回没有此用户
#写入数据
elif sql_list[0].startswith('update') and len(sql_list) > 1:
column, val = sql_list[1].strip().split('=')#将帐户名写入到val中
if column == 'account':
account_file = "%s/%s.json" % (db_path,val)
# if os.path.isfile(account_file):
account_data = kwargs.get("account_data")#得到账户数据
with open(account_file,'w') as f:
acc_data = json.dump(account_data,f)
#print(acc_data)
return True

db_handler.py

 '''/core/logger.py'''

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#日志记录模块,处理所有日志工作 import logging
from conf import Settings def logger(log_type):
#创建日志
logger = logging.getLogger(log_type)
logger.setLevel(Settings.LOG_LEVEL) #创建控制台处理程序并将级别设置为调试
ch = logging.StreamHandler()
ch.setLevel(Settings.LOG_LEVEL)
#创建文件处理程序并设置级别为警告
log_file = "%s/logs/%s" %(Settings.BASE_DIR,Settings.LOG_TYPES[log_type])
fh = logging.FileHandler(log_file)
fh.setLevel(Settings.LOG_LEVEL)
#创建格式化程序
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levename)s- %(message)s') #添加格式化的CH和FH
ch.setFormatter(formatter)
fh.setFormatter(formatter) #添加CH和FH到loggerh
logger.addHandler(ch)
logger.addHandler(fh) return logger #应用程序代码
'''logger.debug('debug message')
'''

logger.py

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户
from conf import Settings
from core import accounts
from core import logger def make_transaction(log_obj,account_data,tran_type,amount,**kwargs):
'''
处理所有用户的所有交易
:param log_obj:
:param account_data: 用户最新的数据
:param tran_type: 交易类型
:param amount: 交易数量
:param other: 主要用于日志使用
:return: 返回最新的账户数据
'''
amount = float(amount)#转换为浮点型
if tran_type in Settings.TRANSACTION_TYPE:#判断传入的类型是否在配置参数里面
interest = amount * Settings.TRANSACTION_TYPE[tran_type]["interest"]#根据交易类型计算利息赋值给interest
old_balance = account_data['balance']#读取数据中账户余额
#还款操作
if Settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':#因为是信用卡,所以还款时提升可使用余额的操作,故计为加plus
new_balance = old_balance + amount + interest#执行的是信用卡的还款操作,计算方法是,旧余额+还款的钱和利息=最后的账户可用余额
#取现\转账操作
elif Settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':#因为是信用卡,所以取现都是降低可用余额的操作
new_balance = old_balance - amount - interest
#只属于转账的
if kwargs.get('re_account'):
#print(kwargs[0],kwargs[1])
re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据
re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值
re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中
print(re_account_data)
accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中
if new_balance < 0:
print("\033[31;1m[%s]账户的信用余额不足以支付此次交易[-%s],你当前的余额是[%s]\033[0m"
% (account_data['creat'], (amount + interest), old_balance))
return
#转账
'''
elif Settings.TRANSACTION_TYPE[tran_type] == 'transfer' :
new_balance = old_balance - amount - interest#自己账户的最新余额
#读取转入的账户,写入转入金额
print(kwargs[0],kwargs[1])
re_account_data = accounts.load_current_balance(kwargs.get('re_account'))#得到要转入账户的所有数据
re_account_balance = re_account_data['balance'] + amount#得到转入账户余额的最新值
re_account_data['balance'] = re_account_balance#将最新的余额全部写入账户的余额中
print(re_account_data)
accounts.dump_account(re_account_data)#将最新的账户所有数据写入到文件中
''' account_data['balance'] = new_balance#将最新的余额写入到账户数据中
print(account_data)
accounts.dump_account(account_data)#将最新的账户余额写回文件
#写入日志
#log_obj.info('账户:%s,操作:%s,数量:%s,利息:%s' %(account_data['id'],tran_type,amount,interest))
return account_data
else:
print("\033[31;1m%s交易类型不存在\033[0m" % tran_type)
#冻结或者锁定用户
def lock_or_not(account,flag):
data = accounts.load_current_balance(account) if data["status"] == 1:
print("该账户已经锁定!")
if data['status']:
data["status"] = flag
accounts.dump_account(data)
return 0

transaction.py

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
#主程序句柄模块,处理所有用户交互内容
from core import auth
from core import accounts
from core import logger
from core import transaction
from core.auth import login_required
from shopping_mall import shopping_mall
from bin import manage
import time #交易日志
trans_logger = logger.logger('transaction')
#访问日志
access_logger = logger.logger('access') #临时账户数据,仅存在于内存中
user_data = {
'account_id':None,
'is_authenticated':False,
'account_data':None
} #账户信息
def account_info(acc_data):
print(user_data)
#还款
@login_required#装饰器,判断用户是否登陆
def repay(acc_data):
'''
打印当前余额,让用户偿还账单
:param acc_data:
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])#将用户账户名字传入到load_current_balance中
#返回最新的用户数据赋值给 account_data
current_balance = '''
---------银行信息----------
信用额度: %s
可用余额: %s
''' %(account_data['credit'],account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
repay_amount = input("\033[33;1m输入你要还款的金额:\033[0m").strip()#还款金额
if len(repay_amount) > 0 and repay_amount.isdigit():
#print('ddd 00')
#将数据传入make_transaction中(交易日志,用户数据,交易类型,还款金额)进行操作,最后返回的是最新操作之后的账户数据
new_balance = transaction.make_transaction(trans_logger,account_data,'repay',repay_amount)
if new_balance:
print('''\033[42;1m最新的余额:%s\033[0m''' %(new_balance['balance']))
else:
print('\033[31;1m[%s]是无效的账户!\033[0m' % repay_amount)
if repay_amount == 'b':
back_flag =True
#取款
@login_required
def withdraw(acc_data):
'''
打印当前余额,让用户执行取款操作
:param acc_data:
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
# 将用户账户名字传入到load_current_balance中
# 返回最新的用户数据赋值给 account_data
current_balance = ''' --------- 银行信息 --------
信用额度: %s
账户余额: %s''' % (account_data['credit'], account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
withdraw_amount = input("\033[33;1m输入取款金额:\033[0m").strip()
if withdraw_amount == 'b':
return
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[42;1m最新余额:%s\033[0m''' %(new_balance['balance']))
else:
print('\033[31;1m[%s]是无效的账户!\033[0m' % withdraw_amount) #转账
@login_required
def transfer(acc_data):
'''
打印当前余额,转账操作函数
:param acc_data:用户数据
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
# 将用户账户名字传入到load_current_balance中
# 返回最新的用户数据赋值给 account_data
current_balance = ''' --------- 银行信息 --------
信用额度: %s
账户余额: %s''' % (account_data['credit'], account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
reciprocal_account = input("\033[31;1m请输入对方帐户名:\033[0m").strip()#输入对方账户信息
transfer_amount = input("\033[31;1m转账金额:\033[0m").strip()#转账金额
if reciprocal_account or transfer_amount == 'b' :
return
if len(transfer_amount) > 0 and transfer_amount.isdigit():
new_balance = transaction.make_transaction(trans_logger,account_data,'transfer',
transfer_amount,re_account = reciprocal_account)
if new_balance:
print("\033[41;1m转账成功!\033[0m")
print("\033[42;1m您当前的余额为:%s\033[0m" %(new_balance["balance"]))
else:
print('\033[31;1m[%s] \033[0m') #账单
@login_required
def pay_check(acc_data):
pass
#退出
def logout(acc_data):
exit("程序已经退出!")
#购物商城
def shopping_mall_this(acc_data):
shopping_mall.main_menu(acc_data)
#管理窗口
def goto_manage():
manage.manage_main(user_data)
#菜单
def interactive(acc_data):
'''
与用户交互
:param acc_data: 验证过的用户的所用数据
:return:
'''
menu = u'''
-----------银行----------
\033[32;1m
1.账户信息
2.还款
3.取款
4.转账
5.账单
6.退出
\033[0m
'''
menu_dic = {
'': account_info,
'': repay,
'': withdraw,
'': transfer,
'': pay_check,
'': logout,
}
exit_flag = False
while not exit_flag:
print(menu)#打印出菜单,供用户选择
user_option = input("请输入你的选择:").strip()#输入用户的选择,过滤掉空格
if user_option == 'b':
return
if user_option in menu_dic:#用户的选择如果在这个菜单里
#print('accdata',acc_data)
menu_dic[user_option](acc_data)#用户选择执行的功能,把acc_data验证过的用户的所有数据(数据文件中的数据)
else:
print("\033[31;1m选择不存在!\033[0m")
#带有购物商场的主菜单
def main_menu(acc_data):
main_menu = u'''
----------主菜单---------
\033[32;1m
1.购物商城
2.银行卡操作
3.退出
\033[0m
'''
main_menu_dic = {
'':shopping_mall_this,
'':interactive,
'':logout,
}
exit_flag = False
while not exit_flag:
print(main_menu)
user_option = input("请输入你的选择:").strip()
if user_option == 'b':
return
if user_option in main_menu_dic:
main_menu_dic[user_option](acc_data)
else:
print("\033[31;1m选择不存在!\033[0m")
def run():
'''
当程序启动时,这个程序开始运行,处理关于用户的所有交互的内容
'''
acc_data = auth.acc_login(user_data,access_logger)#程序从这里开始,执行auth下的acc_login函数
# (返回的是验证过的正确的账户数据)赋值给acc_data(此时这里的数据为输入账户名字的数据文件的数据)
if user_data['is_authenticated']:
user_data['account_data'] = acc_data#把账户所有信息传给账户开始时的临时的账户数据空字典,
# 把所有的数据文件传给账户的账户数据里面,
#interactive(user_data)#把user_data里的所有数据传入菜单函数,进行下一步操作
main_menu(user_data)

main.py

4.db下目录下代码

/db/accounts/123.json

 {"pay_day": "", "enroll_date": "2018-02-19", "credit": "", "balance": "", "id": "", "expire_date": "2032-01-01", "password": "", "status": 0}

123.json

5.logs目录下代码

/logs/access.log&transaction.log

6.shopping_mall下代码

/shopping_mall/product.txt&shopping_list.txt

 #!/usr/bin/env python
#-*- Coding:utf-8 -*-
# Author:Eric.Shen
# !/usr/bin/env python
# -*- Coding:utf-8 -*-
# Author:Eric.Shen
# 2018.02.06
# path python3.5
# 优化版的购物车
# 用户入口:
# 1.商品的信息存到文件里
# 2.已购商品,余额记录
# 商家入口:
# 1.可以添加商品 2.修改商品价格
# 存储商品列表
import fileinput
from core import accounts product_list = []
f = open("D:\\Python_train\\day4\\Atm\\shopping_mall\\product.txt", "r") # 打开文件
for line in f.readlines():
line = line.strip() # 去掉最后一个换行符
index, item = line.split(":") # 以冒号分割得到前后两个数据
product_list.append((index, item)) # 添加的数据
f.close() def print_product_list():
for index, item in enumerate(product_list):
print(index, item) # 用户入口
# 用户购物
def user_shopping(account_data):
#salary = input("请输入你的薪水:")
salary = account_data['account_data']['balance']
print_product_list()
if salary > 0:
shopping_list = [] # 存放用户购物车清单
while True:
option = input("喜欢那个就买哪个(对应的标号):")
if option.isdigit():
option = int(option)
if option >= 0 and option <= len(product_list):
p_item = product_list[option] # 用户选择的商品
# print(product_list)
# print(p_item[1])
c_num = int(p_item[1])
if salary >= c_num:
shopping_list.append(p_item)
salary -= c_num
print("添加购物车成功,你的余额还有%s" % (salary))
else:
print("你的余额不足,只剩%s元" % (salary))
else:
print("输入错误,请重新输入!")
elif option == "q":
print("----------------购物清单---------------")
for s_list in shopping_list:
print(s_list)
print("你的余额为%s" % (salary))
account_data['account_data']['balance'] = salary
#print(account_data)
accounts.dump_account(account_data['account_data'])#写入文件
print("..........exit.........")
exit()
else:
print("无效的输入")
else:
exit("余额不足!") # 商家入口
# 商家添加商品
def add_product():
name_of_product = input("请输入你要添加的商品名字:")
price_of_product = input("请输入你要添加商品的价格:")
f = open("product.txt", "a")
f.write(str("\n" + name_of_product) + ": %s" % (price_of_product))
f.close()
print("添加成功!\nexit----------") # 修改商品价格
def change_price():
print_product_list() # 打印商品列表
choice = input("请输入你的选择:")
# name_of_change = input("请输入你要改变的商品名字")
price_of_change = input("请输入你要改变商品的价格:")
if choice.isdigit():
choice = int(choice)
if choice >= 0 and choice <= len(product_list):
p_item = product_list[choice] # 选择的商品
# c_num = int(p_item[1])#转换成int类型
for line in fileinput.input("product.txt", inplace="%s" % (choice)): # 对输入的选择行进行修改
line = line.replace("%s" % (p_item[1]), "%s" % (price_of_change)).strip()
print(line)
exit("修改成功!")
else:
print("输入无效")
else:
if choice == "q":
exit("退出") def main_menu(account_data):
print("--------------------------"
"--------------------------"
"\n"
" 欢迎进入购物菜单 "
"\n"
"\n"
"商家请按b,用户请按c\n"
"--------------------------"
"--------------------------")
c_num = input("请输入你的选择:") # 使用者选择
if c_num == "b":
print("--------------------------"
"--------------------------"
"\n"
" 欢迎进入商家界面 "
"\n"
"\n"
"添加商品请按a,修改价格请按c\n"
"--------------------------"
"--------------------------")
c_num2 = input("请输入你的选择:")
if c_num2 == "a":
# 实现添加商品功能
add_product()
if c_num2 == "c":
# 实现商品价格修改功能
change_price()
else:
print("输入有误!")
if c_num == "c":
print("--------------------------"
"--------------------------"
"\n"
" 欢迎进入用户界面 "
"\n"
"\n" "--------------------------"
"--------------------------")
# 购物功能
print(account_data)
user_shopping(account_data)
else:
print("输入有误程序退出!")

shopping_mall

五、README

 作者:Eric.shen
此次系统的设计仅用来学习python,开始于2018.2.13-19完(此系统,日志部分没有完善留着日后补充现在还没学到)
作业需求: 模拟实现一个ATM + 购物商城程序:
1.额度 15000或自定义
2.实现购物商城,买东西加入 购物车,调用信用卡接口结账
3.可以提现,手续费5%
4.每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息(没写)
5.支持多账户登录
6.支持账户间转账
7.记录每月日常消费流水
8.提供还款接口
9.ATM记录操作日志
10.提供管理接口,包括添加账户、用户额度,冻结账户等。。。
11.用户认证用装饰器 一、软件定位,软件的基本功能。
实现一个简单的atm与购物车程序,
二、运行代码的方法: 安装环境、启动命令等。
用Python3.5写的,语法就是至此之前所学的,直接打开运行即可
三、目录结构。 ├── ATM #ATM主程目录
│ ├── __init__.py
│ ├── bin #ATM 执行文件 目录
│ │ ├── __init__.py
│ │ ├── atm.py #ATM 执行程序
│ │ ├── manage.py #信用卡管理
│ ├── conf #配置文件
│ │ ├── __init__.py
│ │ └── Settings.py #配置参数
│ ├── core #主要程序逻辑都 在这个目录 里
│ │ ├── __init__.py
│ │ ├── accounts.py #用于从文件里加载和存储账户数据
│ │ ├── auth.py #用户认证模块及主要功能函数
│ │ ├── db_handler.py #数据库连接引擎
│ │ ├── logger.py #日志记录模块
│ │ ├── main.py #主逻辑交互程序
│ │ ├── transaction.py #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户
│ ├── db #用户数据存储的地方
│ │ ├── __init__.py
│ │ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
│ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件
│ │ └── 123.json #新创建的用户账户示例文件
│ │ └── 1234.json #一个用户账户示例文件
│ │ └── 123456.json #一个用户账户示例文件
│ │ └── 6230001.json #管理用户账户示例文件
│ └── log #日志目录
│ ├── access.log #用户访问和操作的相关日志
│ └── login_in.log #登陆日志
└── shopping_mall #电子商城程序,需单独实现,主要实现购物的功能。
│ └── __init__.py
│ └── product.txt #存放商品的txt文件
│ └── shopping_list.txt #存放购物清单的txt.文件
│ └── shopping_mall.py #购物商城程序
├── 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则可以对用户进行管理,解冻用户、冻结用户、申领新卡
①添加账户
②冻结账户
③解冻账户
④退出
五、常见问题说明。
日志没有实现,账单没有实现

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

product.txt

iphone:
Mac pro:
Bike:
Watch:
Coffe:
Python book:
Book:

shopping_list.txt

('Coffe', )
('Pychon book', )

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

欢迎多多提提意见

Python学习--------------Atm+购物车系统的更多相关文章

  1. python实现简单购物车系统(练习)

    #!Anaconda/anaconda/python #coding: utf-8 #列表练习,实现简单购物车系统 product_lists = [('iphone',5000), ('comput ...

  2. python以ATM+购物车剖析一个项目的由来及流程

    ATM+购物车 一个项目是如何从无到有的 ''' 项目的由来,几个阶段 0.采集项目需求 1.需求分析 2.程序的架构设计 3.分任务开发 4.测试 5.上线运行 ''' 需求分析: # 对项目需求进 ...

  3. python学习:购物车程序

    购物车程序 product_list = [ ('mac',9000), ('kindle',800), ('tesla',900000), ('python book',105), ('bike', ...

  4. Python学习---Django路由系统【all】

    Django URL (路由系统) Django URL (路由系统): URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL模式以及要为该URL模式调用的视图函数之间的映 ...

  5. ATM+购物车系统

    ATM目录 start.py import os,sys from core import src base_path=os.path.dirname(os.path.dirname(__file__ ...

  6. Python学习之购物车

    实现功能: 程序启动,提示用户输入用户名和密码,程序读取余额文件last_salary.txt内容(文件不存在则自动创建),若文件内容为空则提示“首次登录,请输入工资”: 用户可以输入商品编号进行购买 ...

  7. python 学习分享-购物车实操篇

    程序要求如下: '''购物车程序: 启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 允许用户根据商品编号购买商品 用户选择商品后,检测余额是否够,够就直接扣款,不够就 ...

  8. ATM系统和购物车系统 不需要文件支撑

    目录 ATM系统 购物车系统 ATM系统 #coding=utf8 #Version:python 3.6.4 #Tools:Python 2019.9.7 _data_ = '2019/9/7/01 ...

  9. [Python学习]错误篇二:切换当前工作目录时出错——FileNotFoundError: [WinError 3] 系统找不到指定的路径

    REFERENCE:<Head First Python> ID:我的第二篇[Python学习] BIRTHDAY:2019.7.13 EXPERIENCE_SHARING:解决切换当前工 ...

随机推荐

  1. opencv---JPEG图像质量检测代码

    参考:http://blog.csdn.net/trent1985/article/details/50904173 根据国外一篇大牛的文章:No-Reference Perceptual Quali ...

  2. Table Generator 表格样式生成代码

    <style type="text/css"> .tg {border-collapse:collapse;border-spacing:0;} .tg td{font ...

  3. ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解

    笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 ASP.NET Core MVC 基础后,开始学习 ASP.NET Core 的运行原理.发现应用程序有一个非常主要的 “传导体” ...

  4. Hibernae

    开始尝试挺java ee的课程,马士兵老师的 1.ssh的整个框架体系 spring会贯穿在整个过程之中 2.Hibernate的整个框架体系 3. 4. 5. 6.

  5. VS相关

    快速显示函数名称 ctrl+alt+T 显示函数参数说明 ctrl+shift+space,光标放在函数里面 link 1123错误,vs2010的问题. 点击工程-属性-ManifestTool-I ...

  6. C#调用python文件执行

    我的电脑环境是使用.net framework4.5.1,如果在调试过程中调不通请注意 我用的是Visual studion 2017,python组件下载地址:http://ironpython.c ...

  7. Ing_制作在线QQ

    制作在线QQ的具体步骤 1.首先登录到http://is.qq.com/webpresence/code.shtml 网站2.选择风格3.填写相关数据4.生成网页代码5.复制代码到“写字板”,另存文件 ...

  8. 小白之selenium+python关于cookies绕开登录2

    首先,由于新开始在博客园中写随笔,可能在内容的布局方面就不太懂,导致布局很丑,各位见谅,但是字还是原来的那字,内容还是原来的内容,少了点包装, 下面是对cookie的扩展知识 1.配置文件存储在哪里? ...

  9. 大厂面试官:Java工程师的“十项全能”

    想要成为合格的Java程序员或工程师到底需要具备哪些专业技能,在面试之前到底需要准备哪些东西呢?面试时面试官想了解你的什么专业技能,以下都是一个合格Java软件工程师所要具备的. 一.专业技能 熟练的 ...

  10. A - 摆仙果

    题目描述 Adrian, Bruno与Goran三人参加了仙界的宴会,宴会开始之前先准备了一些仙果供三人品尝,但是仙果的摆放有顺序要求,如果把仙果摆错了位置,仙果就会消失而无法品尝到. 由于三人是第一 ...