python作业---模拟实现一个ATM + 购物商城程序

作业需求: 
模拟实现一个ATM + 购物商城程序

额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
支持多账户登录
支持账户间转账
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器

作业思路
实现购物商城和信用卡的ATM功能
本程序有6个模块,实现了购物和ATM的取款、还款、转账、账单查看和用户管理的功能。


程序结构:
test
├── README
├── ATM #ATM主程目录
│ ├── __init__.py
│ ├── bin #ATM 执行文件 目录
│ │ ├── __init__.py
│ │ ├── atm.py #ATM 执行程序
│ ├── conf #配置文件
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── core #主要程序逻辑都 在这个目录 里
│ │ ├── __init__.py
│ │ ├── accounts.py #用于从文件里加载和存储账户数据
│ │ ├── auth.py #用户认证模块
│ │ ├── db_handle.py #数据库连接引擎
│ │ ├── log.py #日志记录模块
│ │ ├── main.py #主逻辑交互程序
│ │ └── transaction.py #记账\还钱\取钱等所有的与账户金额相关的操作都 在这
│ ├── db #用户数据存储的地方
│ │ ├── __init__.py
│ │ └── accounts #存各个用户的账户数据 ,一个用户一个文件
│ │ └── zcl.json #一个用户账户示例文件
│ └── log #日志目录
│ ├── __init__.py
│ ├── access.log #用户访问和操作的相关日志
│ └── transactions.log #所有的交易日志
└── shopping #电子商城程序
├── shopping_mol #购物商城的程序
└── __init__.py

开始先运行atm.py时执行程序,直接到main下,输入正确用户zcl和密码abc,才能进行下一步的操作,然后列出atm的功能列表(还款、取款、转账、查看等)
shopping是一个独立的程序,调用了还款的金额,购物结束后把剩余的金额在写入到文件中,存入到信用卡中。


流程图

 

shopping_mol

 1 import os,json
 2 
 3 dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 4 print(dir)
 5 file="%s/ATM/db/accounts/zcl.json"%dir
 6 print(file)
 7 with open(file, "r", encoding="utf-8") as f:
 8     account_data = json.load(f)
 9     print(account_data)
10 
11 
12 
13 product_list =[
14     ("Apple Iphone",6000),
15     ("Apple Watch",4600),
16     ("Books",600),
17     ("Bike",750),
18     ("cups",120),
19     ("Apple",50),
20     ("banana",60),
21 ]
22 shopping_list =[]
23 salary = account_data["balance"]
24 
25 while True:
26     for index,item in enumerate(product_list):
27         print (index,item)
28     user_choice = input ("Enter the serial number:")
29     if user_choice.isdigit():
30         user_choice = int (user_choice)
31         if user_choice <len (product_list) and user_choice >=0:
32             p_item = product_list[user_choice]
33             if p_item[1] <= salary:
34                 shopping_list.append(p_item)
35                 salary -= p_item[1]
36                 with open(file,"w+",encoding="utf-8") as f:
37                     account_data["balance"]=salary
38                     print(account_data)
39                     json.dump(account_data,f)
40                 print ("Added %s into your shopping cart,your current balance is %s"%(p_item,salary))
41             else:
42                 print ("Your balance is not enough!!")
43         else:
44             print ("The goods you entered do not exist")
45 
46     elif user_choice == "q":
47         print ("====shopping list====")
48         for p in shopping_list:
49             print (p)
50         print ("Your current balance is %s"%salary)
51         exit()
52     else:
53         print ("invalid option")
View Code

 

 

atm

 1 #ATM程序的执行文件
 2 import os
 3 import sys
 4 
 5 dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))   #找到路径
 6 sys.path.insert(0,dir)                 # 添加路径
 7 
 8 
 9 print(dir)
10 print(sys.path)
11 
12 #将main.py里面的所有代码封装成main变量
13 from core import main
14 
15 if __name__ == '__main__':
16     main.run()
View Code

 

settings

 1 #配置文件
 2 import logging
 3 import os
 4 
 5 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#找到路径
 6 
 7 LOGIN_LEVEL = logging.INFO#定义日志的记录级别
 8 
 9 DATABASE = {
10     "db_tool":"file_storage",  #文件存储,这里可拓展成数据库形式的
11     "name":"accounts",         #db下的文件名
12     "path":"%s/db"%BASE_DIR
13 }
14 #print(DATABASE)
15 #日志类型
16 LOGIN_TYPE={
17     "access":"access.log",
18     "transaction":"transaction.log"
19 }
20 
21 #用户交易类型,每个类型对应一个字典,包括帐户金额变动方式,利息
22 TRANSACTION_TYPE={
23     "repay":{"action":"plus","interest":0},
24     "withdraw":{"action":"minus","interest":0.05},
25     "transfer":{"action":"minus","interest":0}
26 }
View Code

 

account

 1 """
 2 用于处理用户信息的load or dump
 3 每进行一个操作就将信息更新到数据库
 4 """
 5 from core import db_handle
 6 from conf import settings
 7 import json
 8 
 9 def load_account(account_id):
10     """
11     将用户信息从文件中load出来
12     :return: 用户信息的字典
13     """
14     #返回路径  ATM/db/accounts
15     db_path = db_handle.handle(settings.DATABASE)
16     account_file = "%s/%s.json" % (db_path, account_id)
17     with open(account_file, "r", encoding="utf-8") as f:
18         account_data =  json.load(f)
19         return account_data
20 
21 
22 def dump_account(account_data):
23     """
24     将已更改的用户信息更新到用户文件
25     :param account_data: 每操作后用户的信息
26     :return:
27     """
28     db_path = db_handle.handle(settings.DATABASE)
29     account_file = "%s/%s.json" % (db_path, account_data["id"])
30     with open(account_file, "w+", encoding="utf-8") as f:
31         json.dump(account_data, f)
32 
33     print("dump success")
View Code

 

 

auth

 1 #认证模块
 2 import os
 3 import json
 4 import time
 5 
 6 from core import db_handle
 7 from conf import settings
 8 
 9 def access_auth(account,password,log_obj):
10     """
11     下面的access_login调用access_auth方法,用于登陆
12     :param acount: 用户名
13     :param password: 密码
14     :return:如果未超期,返回字典,超期则打印相应提示
15    """
16     db_path=db_handle.handle(settings.DATABASE) #调用db_handle下的handle方法,返回路径/db/accounts
17     print(db_path)
18     account_file="%s/%s.json"%(db_path,account)  #用户文件
19     print(account_file)
20     if os.path.isfile(account_file):                 #如果用户文件存在(即用户存在)
21         with open(account_file,"r",encoding="utf-8") as f:  #打开文件
22             account_data = json.load(f)       #file_data为字典形式
23             print(account_data)
24             if account_data["password"]==password:
25                 expire_time=time.mktime(time.strptime(account_data["expire_date"],"%Y-%m-%d"))
26                 #print(expire_time)
27                 #print(time.strptime(account_data["expire_date"],"%Y-%m-%d"))
28                 if time.time()>expire_time:     #如果信用卡已超期
29                     log_obj.error("Account [%s] had expired,Please contract the bank" % account)
30                     print("Account %s had expired,Please contract the bank"%account)
31                 else:                         #信用卡未超期,返回用户数据的字典
32                     #print("return")
33                     log_obj.info("Account [%s] logging success" % account)
34                     return account_data
35             else:
36                 log_obj.error("Account or Passworddoes not correct!")
37                 print("Account or Passworddoes not correct!")
38     else:#用户不存在
39         log_obj.error("Account [%s] does not exist!" % account)
40         print("Account [%s] does not exist!"%account)
41 
42 
43 def access_login(user_data,log_obj):
44     """
45     用记登陆,当登陆失败超过三次则退出
46     :param user_data: main.py里面的字典
47     :return:若用户帐号密码正确且信用卡未超期,返回用户数据的字典
48     """
49     retry=0
50     while not user_data["is_authenticated"] and retry<3:
51         account=input("Account:").strip()
52         password= input("Password:").strip()   #用户帐号密码正确且信用卡未超期,返回用户数据的字典
53         user_auth_data=access_auth(account,password,log_obj)
54         if user_auth_data:
55             user_data["is_authenticated"]=True   #用户认证为True
56             user_data["account_id"]=account       #用户帐号ID为帐号名
57             print("welcome %s"%account)
58             return user_auth_data
59         retry+=1
60     else:
61         print("Account [%s] try logging too many times..." % account)
62         log_obj.error("Account [%s] try logging too many times..." % account)
63         exit()
View Code

 

 

db_handle

 1 #处理与数据库的交互,若是file_db_storage,返回路径
 2 
 3 def file_db_handle(database):
 4     """
 5      数据存在文件
 6      :param database:
 7      :return: 返回路径  ATM1/db/accounts
 8     """
 9     db_path="%s/%s"%(database["path"],database["name"])
10     #print(db_path)
11     return db_path
12 
13 # def mysql_db_handle(database):
14 #     """
15 #     处理mysql数据库,这里用文件来存数据,
16 #     保留这个方法主要为了程序拓展性
17 #     :return:
18 #     """
19 #     pass
20 
21 def handle(database):
22     """
23     对某种数据库形式处于是
24     本程序用的是文件处理file_storage
25     :param database: settings里面的DATABASE
26     :return: 返回路径
27     """
28     if database["db_tool"]=="file_storage":
29         return file_db_handle(database)
30     # if database["db_tool"]=="mysql":
31     #     return mysql_db_handle(database)
View Code

 

 

log

 1 import logging
 2 from conf import settings
 3 from core import db_handle
 4 
 5 def log(logging_type):
 6     """
 7       main模块调用access_logger = log.log("access")
 8      :param logging_type: "access"
 9      return: 返回logger日志对象
10     """
11     logger=logging.getLogger(logging_type)  #传日志用例,生成日志对象
12     logger.setLevel(settings.LOGIN_LEVEL)   #设置日志级别
13 
14     ch = logging.StreamHandler()     #日志打印到屏幕,获取对象
15     ch.setLevel(settings.LOGIN_LEVEL)
16 
17     # 获取文件日志对象及日志文件
18     log_file="%s/log/%s"%(settings.BASE_DIR,settings.LOGIN_TYPE[logging_type])
19     fh = logging.FileHandler(log_file)
20     fh.setLevel(settings.LOGIN_LEVEL)
21 
22     # 日志格式
23     formatter=logging.Formatter("%(asctime)s-%(name)s-%(levelname)s-%(message)s")
24 
25     # 输出格式
26     ch.setFormatter(formatter)
27     fh.setFormatter(formatter)
28 
29     #把日志打印到指定的handler
30     logger.addHandler(ch)
31     logger.addHandler(fh)
32 
33     return logger    #log方法返回logger对象
View Code

 

 

transaction

 1 """
 2 交易模块,处理用户金额移动
 3 """
 4 from conf import settings
 5 from core import account
 6 from core import log
 7 
 8 def make_transaction(account_data,transcation_type,amount,log_obj,**kwargs):
 9     """
10     处理用户的交易
11     :param account_data:字典,用户的帐户信息
12     :param transaction_type:用户交易类型,repay or withdraw...
13     :param amount:交易金额
14     :return:用户交易后帐户的信息
15     """
16     amount=float(amount)  #将字符串类型转换为float类型
17     if transcation_type in settings.TRANSACTION_TYPE:
18         interest=amount*settings.TRANSACTION_TYPE[transcation_type]["interest"]   #利息计算
19         old_balace= account_data["balance"]  #用户原金额
20         print(interest,old_balace)
21         # 如果帐户金额变化方式是"plus",加钱
22         if settings.TRANSACTION_TYPE[transcation_type]["action"]=="plus":
23             new_balance=old_balace+amount+interest
24             log_obj.info("Your account repay%s,your account new balance is %s"%(amount,new_balance))
25             # 如果帐户金额变化方式是"minus",减钱
26         elif settings.TRANSACTION_TYPE[transcation_type]["action"]=="minus":
27             new_balance=old_balace-amount-interest
28             log_obj.info("Your account withdraw%s,your account new balance is %s" % (amount, new_balance))
29             if new_balance<0:
30                 print("Your Credit [%s] is not enough for transaction [-%s], "
31                       "and Now your current balance is [%s]" % (account_data["credit"], (amount+interest), old_balace))
32                 return
33         account_data["balance"]=new_balance
34         account.dump_account(account_data)    #调用core下account模块将已更改的用户信息更新到用户文件
35         return account_data
36     else:
37         print("Transaction is not exist!")
View Code

 

 

main

  1 """
  2 主逻辑交互模块
  3 """
  4 from core import auth
  5 from core import log
  6 from core import transaction
  7 from core import account
  8 from conf import settings
  9 from core import db_handle
 10 
 11 import os
 12 
 13 
 14 #用户数据信息
 15 user_data = {
 16     'account_id':None,          #帐号ID
 17     'is_authenticated':False,  #是否认证
 18     'account_data':None        #帐号数据
 19 
 20 }
 21 
 22 #调用log文件下的log方法,返回日志对象
 23 access_logger = log.log("access")
 24 transaction_logger = log.log("transaction")
 25 
 26 
 27 
 28 def account_info(access_data):
 29     """
 30     access_data:包括ID,is_authenticaed,用户帐号信息
 31     查看用户帐户信息
 32     :return:
 33     """
 34     print(access_data)
 35 
 36 
 37 
 38 
 39 def repay(access_data):
 40     """
 41     access_data:包括ID,is_authenticaed,用户帐号信息
 42     还款
 43     :return:
 44     """
 45     print(access_data)
 46     print("repay")
 47     #调用account模块的load_account方法,从数据库从load出用户信息
 48     account_data = account.load_account(access_data["account_id"])
 49     print(account_data)
 50     current_balance = """
 51     -------------BALANCE INFO--------------
 52     Credit:%s
 53     Balance:%s
 54     """ % (account_data["credit"], account_data["balance"])
 55     back_flag = False
 56     while not back_flag:
 57         print(current_balance)
 58         repay_amount = input("\033[31;1mInput repay amount(b=back):\033[0m").strip()
 59         #如果用户输入整型数字
 60         if len(repay_amount) > 0 and repay_amount.isdigit():
 61             #调用transaction模块的方法,参数分别是用户帐户信息,交易类型,交易金额
 62             new_account_data = transaction.make_transaction(account_data, "repay", repay_amount,transaction_logger)
 63             if new_account_data:
 64                 print("\033[42;1mNew Balance:%s\033[0m" % new_account_data["balance"])
 65 
 66         else:
 67             print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % repay_amount)
 68 
 69         if repay_amount =="b" or repay_amount == "back":
 70             back_flag = True
 71 
 72 def withdraw(access_data):
 73     """
 74     取款
 75     :return:
 76     """
 77     print(access_data)
 78     print("withdraw")
 79     # 调用account模块的load_account方法,从数据库从load出用户信息
 80     account_data = account.load_account(access_data["account_id"])
 81     print(account_data)
 82     current_balance = """
 83        -------------BALANCE INFO--------------
 84        Credit:%s
 85        Balance:%s
 86        """ % (account_data["credit"], account_data["balance"])
 87     back_flag = False
 88     while not back_flag:
 89         print(current_balance)
 90         withdraw_amount = input("\033[31;1mInput withdraw amount(b=back):\033[0m").strip()
 91         # 如果用户输入整型数字
 92         if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
 93             # 调用transaction模块的方法,参数分别是用户帐户信息,交易类型,交易金额
 94             new_account_data = transaction.make_transaction(account_data, "withdraw", withdraw_amount,transaction_logger)
 95             if new_account_data:
 96                 print("\033[42;1mNew Balance:%s\033[0m" % new_account_data["balance"])
 97 
 98         else:
 99             print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % withdraw_amount)
100 
101         if withdraw_amount == "b" or withdraw_amount == "back":
102             back_flag = True
103 
104 
105 def transfer(access_data):
106     """
107     转帐
108     :return:
109     """
110     print(access_data)
111     print("transfer")
112     # 调用account模块的load_account方法,从数据库从load出用户信息
113     account_data = account.load_account(access_data["account_id"])
114     print(account_data)
115     current_balance = """
116            -------------BALANCE INFO--------------
117            Credit:%s
118            Balance:%s
119            """ % (account_data["credit"], account_data["balance"])
120     back_flag = False
121     while not back_flag:
122         print(current_balance)
123         transfer_amount = input("\033[31;1mInput transfer amount(b=back):\033[0m").strip()
124         # 如果用户输入整型数字
125         if len(transfer_amount) > 0 and transfer_amount.isdigit():
126             # 调用transaction模块的方法,参数分别是用户帐户信息,交易类型,交易金额
127             new_account_data = transaction.make_transaction(account_data, "transfer", transfer_amount,transaction_logger)
128             if new_account_data:
129                 print("\033[42;1mNew Balance:%s\033[0m" % new_account_data["balance"])
130             new_account_data2 = transaction.make_transaction(account_data, "repay", new_account_data["balance"],transaction_logger)
131             if new_account_data2:
132                 print("\033[42;1mNew Balance2:%s\033[0m" % new_account_data2["balance"])
133 
134         else:
135             print("\033[31;1m%s is not valid amount,Only accept interger!\033[0m" % transfer_amount)
136 
137         if transfer_amount == "b" or transfer_amount == "back":
138             back_flag = True
139 
140 
141 def paycheck(access_data):
142     """
143     账单查看
144     :return:
145     """
146 
147     time=input("please input time(Y-M-D):")
148     log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOGIN_TYPE["transaction"])
149     print(log_file)
150     with open (log_file,"r",encoding="utf-8") as f :
151         for i in f.readlines():
152             if time == i[0:10]:
153                 print(i)
154             elif time == i[0:7]:
155                 print(i)
156             elif time == i[0:4]:
157                 print(i)
158 
159 
160 
161 
162 def logout(access_data):
163     """
164     退出登陆
165     :return:
166     """
167     q = input("If you want to quit,please input q:")
168     if q =="q":
169         exit()
170 
171 
172 def interactive(access_data,**kwargs):
173     """
174     用户交互
175     :return:
176     """
177     msg = (
178         """
179         -------------ZhangChengLiang Bank---------------
180         \033[31;1m
181         1.  账户信息
182         2.  存款
183         3.  取款
184         4.  转账
185         5.  账单
186         6.  退出
187         \033[0m"""
188     )
189     menu_dic = {
190         "1":account_info,
191         "2":repay,
192         "3":withdraw,
193         "4":transfer,
194         "5":paycheck,
195         "6":logout
196     }
197     flag = False
198     while not flag:
199         print(msg)
200         choice = input("<<<:").strip()
201         if choice in menu_dic:
202             #很重要!!省了很多代码,不用像之前一个一个判断!
203             menu_dic[choice](access_data)
204 
205         else:
206             print("\033[31;1mYou choice doesn't exist!\033[0m")
207 
208 
209 
210 def run():
211     """
212     当程序启动时调用,用于实现主要交互逻辑
213     :return:
214     """
215     # 调用认证模块,返回用户文件json.load后的字典,传入access_logger日志对象
216     access_data = auth.access_login(user_data, access_logger)
217     print("AA")
218     if user_data["is_authenticated"]:       #如果用户认证成功
219         print("has authenticated")
220         #将用户文件的字典赋给user_data["account_data"]
221         user_data["account_data"] = access_data
222         interactive(user_data)   #用户交互开始
View Code

 

 

.json

{"status": 0, "expire_date": "2021-01-01", "credit": 15000, "pay_day": 22, "balance": 13650, "enroll_date": "2016-01-02", "id": 22, "password": "abc"}

 

 

 

 

转载于:https://www.cnblogs.com/garrett0220/articles/6861418.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值