python买东西_Python学习笔记-练习编写ATM+购物车(购物商城)

作业需求:

模拟实现一个ATM + 购物商城程序:

1.额度 15000或自定义

2.实现购物商城,买东西加入 购物车,调用信用卡接口结账

3.可以提现,手续费5%

4.支持多账户登录

5.支持账户间转账

6.记录每月日常消费流水

7.提供还款接口

8.ATM记录操作日志

9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。

10.用户认证用装饰器

一、软件定位,软件的基本功能。

实现一个简单的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则可以对用户进行管理,解冻用户、冻结用户、申领新卡

①添加账户

②冻结账户

③解冻账户

④退出

五、常见问题说明。

日志没有实现,账单没有

六、以下为功能架构及部分实现功能代码

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- Coding:utf-8 -*-

4

5 importos,sys6

7

8 BASE_DIR_Atm = os.path.dirname(os.path.dirname(__file__))9 BASE_DIR_PRO = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))10

11 sys.path.append(BASE_DIR_Atm)12 sys.path.append(BASE_DIR_PRO)13

14 print(sys.path)15

16 from core importmain17

18 if __name__ == '__main__':19 main.run()

online/Atm/bin/arm.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 importos,logging5 BASE_DIR_Atm = os.path.dirname(os.path.dirname(__file__))6

7 DATABASE ={8 'engine':'file_storage',9 'name':'account',10 'path':"%s/dbs" %BASE_DIR_Atm11 }12

13 LOG_LEVEL =logging.INFO14 LOG_TYPES ={15 'transaction':'transaction.log',16 'access':'access.log'

17 }18

19 #发生交易的配置类型

20 TRANSACTION_TYPE ={21 'repay':{'action':'plus','interest':0}, #还款

22 'withdrawal':{'action':'minus','interest':0.05}, #取现扣费,即降低可用余额

23 'transfer':{'action':'minus','interest':0.05}, #转账扣费,即降低可用余额

24 'consumption':{'action':'minus','interest':0} #消费

25 }

online/Atm/conf/settings.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 #用于从文件里加载和存储账户数据

5 importjson6 from core importdb_handler7 from conf importsettings8

9 defload_current_balance(account_id):10 '''

11 返回账号余额其他信息12 :param account_id:用户账户的名字13 :return:返回最新读到的数据文件中的最新数据14 '''

15 db_path =db_handler.db_handler()16 account_file = "%s/%s.json" %(db_path,account_id)17 with open(account_file,'r') as f:18 acc_data =json.load(f)19 returnacc_data20

21 #写入文件

22 defdump_account(account_data):23 db_path =db_handler.db_handler()24 account_file = "%s/%s.json" %(db_path,account_data['id'])25 with open(account_file,'w') as f:26 acc_data =json.dump(account_data,f)27 return True

online/Atm/core/accounts.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 #用户认证模块

5 importos,json,time6 from core importdb_handler7

8 #装饰器(用于验证账户是否登陆过)

9 deflogin_required(func):10 def wrapper(*args,**kwargs):11 if args[0].get('is_authenticated'):12 return func(*args,**kwargs)13 else:14 exit("用户认证失败")15 returnwrapper16

17 defacc_auth(account,password):18 '''

19 账号验证函数20 :param account:21 :param password:22 :return:23 '''

24 db_path =db_handler.db_handler()25 account_file = '%s/%s.json' %(db_path,account)26 #print('account_file:',account_file)

27 #print('account_file:',type(account_file))

28 ifos.path.isfile(account_file):29 with open(account_file,'r') as f:30 account_data =json.load(f)31 if account_data['password'] ==password:32 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'],"%Y-%m-%d"))33 if time.time() >exp_time_stamp:34 print("\033[31;1m[%s]账户已经注销,请重新申领账户!\033[0m" %account)35 else:36 returnaccount_data37 else:38 print("\033[31;1m账号或密码错误,请重新输入!\033[0m")39 else:40 print("\033[31;1m[%s]账户不存在!---\033[0m" %account)41

42 defacc_login(user_data,log_obj):43 '''

44 账户登陆函数45 :param user_data:用户信息数据,只存在内存中46 :param log_obj:47 :return: 账户密码都对的情况下,返回所有账户数据48 '''

49 retry_count = 0; #初始化重试次数为0

50 while user_data['is_authenticated'] is not True and retry_count < 3: #如果没有验证过,或循环此时没超过三次就执行下面的

51 account = input("\033[32;1m账户:\033[0m").strip()#输入账户

52 password = input("\033[32;1m密码:\033[0m").strip()#输入密码

53 auth = acc_auth(account,password) #解耦,将输入的账户和密码传入到acc_auth2函数中,进行验证最后返回的是读取到的输入正确账户的所有数据)赋值给auth

54 #print('auth:',auth)

55 ifauth:56 user_data['is_authenticated'] = True #登陆成功,将只存在与内存中的数据中的是否验证改为True

57 user_data['account_id'] = account #将只存在与内存中的数据中的账户id改为账户名字(开始输入的帐户名)

58 return auth #这一步操作就是验证此账户是否登陆,然后返回账户的所有数据(数据文件中的所有数据)

59 retry_count += 1

60 else:61 log_obj.error("[%s]账户太多次尝试" %account)62 exit()

online/Atm/core/auth.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 importos,sys,time,json5

6 from conf importsettings7

8

9

10 #数据库句柄

11 defdb_handler():12 '''

13 连接数据库14 :return:15 '''

16 conn_params = settings.DATABASE #conf下配置的数据库地址

17 #print("conn_params:",conn_params)

18 #print('conn_params:',type(conn_params))

19 if conn_params['engine'] == 'file_storage': #判断Settings下的DABASE是什么引擎,这里只用文件文件引擎

20 return file_db_handler(conn_params) #则把Settings下的DABASE的数据传给file_db_handle并返回

21 elif conn_params['engine'] == 'mysql':22 pass #支持数据源类型扩展

23

24 deffile_db_handler(conn_params):25 '''

26 file db操作27 :return:28 '''

29 #print('file_db:',conn_params)

30 db_path = '%s/%s' % (conn_params['path'],conn_params['name'])31 return db_path

online/Atm/core/db_handler.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 #日志记录模块,处理所有日志工作

5

6 importlogging7 from conf importsettings8

9 deflogger(log_type):10 #create logger

11 logger =logging.getLogger(log_type)12 logger.setLevel(settings.LOG_LEVEL)13

14 #创建控制台处理程序并将级别设置为调试

15 ch =logging.StreamHandler()16 ch.setLevel(settings.LOG_LEVEL)17

18 #创建文件处理程序并设置级别为警告

19 log_file = "%s/%s" %(settings.BASE_DIR_Atm,settings.LOG_TYPES[log_type])20 fh =logging.FileHandler(log_file)21 fh.setLevel(settings.LOG_LEVEL)22

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 returnlogger35 '''

36 #应用程序代码37 logger.debug('debug message')38 '''

online/Atm/core/logger.py

__author__ = 'ZFH'

#2018.09.26#-*- coding:utf-8 -*-

importos,time,sysfrom core importauthfrom core.auth importlogin_requiredfrom core importdb_handlerfrom core importloggerfrom core importtransactionfrom core importloggerfrom conf importsettingsfrom core importaccountsimportjson#访问日志

access_logger = logger.logger('access')#交易日志

trans_logger= logger.logger('transaction')#用户数据信息

user_data ={'account_id':None, #账号ID

'is_authenticated':False, #是否认证

'account_data':None #账号数据

}#调用log文件下的log方法,返回日志对象

defrun():#print("测试调用不同路径")

acc_data = auth.acc_login(user_data,access_logger) #程序从这里开始,执行auth下的acc_login函#print('acc_data:',acc_data)#(返回的是验证过的正确的账户数据)赋值给acc_data(此时这里的数据为输入账户名字的数据文件的数据)

if user_data['is_authenticated']:

user_data['account_data'] = acc_data #把账户所有信息传给账户开始时的临时的账户数据空字典,

#把所有的数据文件传给账户的账户数据里面,#print(acc_data)

main_menu(user_data)defaccount_info(acc_data):'''账户信息

:param acc_data:账户信息

:return:'''account_info=acc_data

creidt= account_info['account_data']['credit']

balance= account_info['account_data']['balance']

pay_day= account_info['account_data']['pay_day']print('creidt: %s \n balance: %s \n pay_day: %s' %(creidt,balance,pay_day))deflogin_out(acc_data):'''用户退出登录

:param acc_data: 退出用户

:return:'''exit('退出')defmain_menu(acc_data):'''展现主菜单,并让用户选择功能

1.银行卡操作

2.购物商城

3.退出

:param acc_data: 传入赋值的临时账户信息

:return:'''main_menu= u'''--------主菜单--------

\033[32;1m

1.银行卡操作

2.购物商城

e.退出

\033[0m'''main_menu_dic={'1':'银行卡操作','2':'购物商城','e':'直接退出',

}

exit_flag=Falsewhile notexit_flag:print(main_menu)

user__main_option= input('请输入您的选择的操作:').strip()if user__main_option inmain_menu_dic:#print('acc_data:',acc_data)

if user__main_option == 'e':

login_out(acc_data)return

else:

interactive(acc_data,user__main_option)else:print('\033[31;1m选择不存在!\033[0m')definteractive(acc_data,user__main_option):'''处理主菜单选择

:param acc_data: 缓存记录的用户信息

:param user__main_option: 主菜单用户选择

:return:'''

if user__main_option == '1':

interactive_bank(acc_data)elif user__main_option == '2':

interactive_shaopping(acc_data)returninteractivedefinteractive_shaopping(acc_data):'''展现购物菜单

:param acc_data: 缓存记录的用户信息

:return:'''

return

definteractive_bank(acc_data):'''展现银行卡主菜单,并让用户选择功能

1.查看账户

2.取款

3.还款

4.转账

5.账单

e.直接退出

返回上一层

:param acc_data: 传入赋值的临时账户信息

:param user_option: 传入用户上一层选择

:return:'''

print('进入下一个菜单')

main_menu_bank= u'''--------银行卡主菜单--------

\033[32;1m

1.查看账户

2.取款

3.还款

4.转账

5.账单

e.直接退出

\033[0m'''main_menu_bank_dic={'1':'查看账户','2':'取款','3':'还款','4':'转账','5':'账单','e':'直接退出',

}

exit_flag=Falsewhile notexit_flag:print(main_menu_bank)

user_option= input('请输入您的选择的操作(\033[32;1m返回上一层请输入r\033[0m):').strip()if user_option inmain_menu_bank_dic:if user_option == 'e':

login_out(acc_data)break

elif user_option == '1':

account_info(acc_data)

user_option= input('\033[32;1m返回上一层请输入r\033[0m:').strip()if user_option == 'r':

interactive_bank(acc_data)else:print('\033[31;1m选择不存在!\033[0m返回上一层请输入r,直接退出请输入e')

account_info(acc_data)

user_option= input('\033[32;1m返回上一层请输入r\033[0m:').strip()if user_option =='r':

interactive_bank(acc_data)elif user_option == 'e':

login_out(acc_data)break

elif user_option == '2':

withdrawal(acc_data)elif user_option == '3':

repay(acc_data)elif user_option == 'r':returnmain_menu(acc_data)else:print('\033[31;1m选择不存在!请按提示重新输入!!!\033[0m')

@login_required#调用用户验证装饰器

defwithdrawal(acc_data):'''取款操作,打印可取款额度

:param acc_data:

:return:'''account_data= accounts.load_current_balance(acc_data['account_id'])

current_balance= '''---------银行信息----------

信用额度: %s

可用余额: %s

账单日: %s''' % (account_data['credit'],account_data['balance'],account_data['pay_day'])print(current_balance)

withdrawal_flag=Falsewhile notwithdrawal_flag:

withdrawal_amount= input("\033[33;1m输入取款金额:\033[0m").strip()if len(withdrawal_amount) > 0 andwithdrawal_amount.isdigit():#将数据传入make_transaction中(交易日志,用户数据,交易类型,还款金额)进行操作,最后返回的是最新操作之后的账户数据

new_balance = transaction.make_transaction(trans_logger,account_data,'withdrawal',withdrawal_amount)ifnew_balance:print('''\033[42;1m最新的余额:%s\033[0m''' %(new_balance['balance']))return

if withdrawal_flag == 'b':

withdrawal_flag==Trueelif withdrawal_amount == 'e':

interactive_bank(acc_data)else:print('\033[31;1m[%s]是无效的账户!\033[0m' %withdrawal_amount)if withdrawal_amount == 'b':

withdrawal_flag==True

@login_required#调用用户验证装饰器

defrepay(acc_data):'''还款操作,打印当前余额

:param acc_data:

:return:'''account_data= accounts.load_current_balance(acc_data['account_id'])

current_balance= '''---------银行信息----------

信用额度: %s

可用余额: %s

账单日: %s''' % (account_data['credit'],account_data['balance'],account_data['pay_day'])print(current_balance)

repay_flag=Falsewhile notrepay_flag:

repay_amount= input("\033[33;1m输入你要还款的金额(重选操作请输入e):\033[0m").strip()if len(repay_amount) > 0 andrepay_amount.isdigit():#将数据传入make_transaction中(交易日志,用户数据,交易类型,还款金额)进行操作,最后返回的是最新操作之后的账户数据

new_balance = transaction.make_transaction(trans_logger,account_data,'repay',repay_amount)ifnew_balance:print('''\033[42;1m最新的余额:%s\033[0m''' %(new_balance['balance']))return

if repay_amount == 'b':

repay_flag==Trueelif repay_amount == 'e':

interactive_bank(acc_data)else:print('\033[31;1m[%s]是无效的账户!\033[0m' %repay_amount)if repay_amount == 'b':

repay_flag== True

online/Atm/core/main.py

1 __author__ = 'ZFH'

2 #2018.09.26

3 #-*- coding:utf-8 -*-

4 #记账\还钱\取钱\与账户金额相关的操作,冻结或者锁定用户

5 #交易处理模块

6 from conf importsettings7 from core importdb_handler8 from core importaccounts9

10 importjson,time11

12 def make_transaction(log_obj,account_data,tran_type,amount,**kwargs):13 '''

14 处理所有用户的交易15 :param log_obj: 写入日志16 :param account_data:用户最新数据17 :param tran_type:交易类型18 :param amount:交易金额19 :param kwargs:其他参数20 :return:返回最新的账户数21 '''

22 amount = float(amount) #转换为浮点数

23 if tran_type in settings.TRANSACTION_TYPE: #判断传入的类型是否在配置参数里面

24 interest = round(amount * settings.TRANSACTION_TYPE[tran_type]['interest'],2) #根据交易类型计算利息赋值给interest

25 old_lalance = float(account_data['balance']) #读取数据中账户余额

26 #print('interest:',type(interest))

27 #print('amount:',type(amount))

28 #print('old_lalance:',type(old_lalance))

29

30 #还款操作

31 if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus': #因为是信用卡,所以需要判断操作操作,加plus

32 #print(settings.TRANSACTION_TYPE)

33 new_balance = old_lalance + amount + interest #执行的是信用卡的还款操作,计算方法是,旧余额+还款的钱和利息=最后的账户可用余额

34 #取现

35 elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus' and settings.TRANSACTION_TYPE[tran_type] == 'transfer': #因为是信用卡,所以取现都是降低可用余额的操作

36 pass

37 else:38 balance = old_lalance - amount -interest39 if balance >0:40 new_balance =balance41 else:42 print("\033[31;1m余额不足\033[0m")43 return

44

45 account_data['balance'] =new_balance46 #print(account_data)

47 accounts.dump_account(account_data)48 returnaccount_data49

50 else:51 print("\033[31;1m%s交易类型不存在\033[0m" % tran_type)

online/Atm/core/transaction.py

1 {"enroll_date": "2018-09-27", "id": "123", "expire_date": "2032-01-01", "status": 0, "password": "123", "pay_day": "22", "balance": 513.8, "credit": "15000"}

online/Atm/dbs/account/123.json

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值