需求:
1.额度1500或自定义 2.实现购物商城,买东西加入 购物车,调用信用卡接口结账 3.可以提现、存款、余额查询和转账等 4.打印指定日期间购物清单 5.支持多账户 6.ATM记录操作所有日志 7.提供管理接口,包括查询账户、添加账户、注销账户,冻结解冻账户等 8.日志功能用装饰器
写这个小项目之前先构思了一下,画个流程图,然后设置好代码的目录结构,实现方式等,把框架写好了,接下来就是一个个小功能的实现啦。
流程图如下:
代码目录结构如下:
我先写了一个用户类,专门提供用户管理。主要功能如下:
1、账户信息查询
2、添加新账户
3、删除账户
4、修改密码
5、修改手机号
6、冻结账户
7、解冻账户
8、修改账户信用额度
把一些环境变量信息写在conf目录下的settings.py里
# -*- coding: utf-8 -*- import time import os from core import users as u # 管理员账号密码 adminName = 'admin' adminPassword = 'admin' # 当前时间 timeYear = time.strftime('%Y%m%d', time.localtime(time.time())) timeDay = time.strftime('%H%M%S', time.localtime(time.time())) # 信用卡额度 creditLimit = 15000 # 用户信息文件 userInfoFile = "../db/user-info.json" # 商品信息文件 goodsInfoFile = '../db/goods-info.json' # 用户购物车文件 def ShoppingCarFile(username,year=timeYear,day=timeDay): dirs = '../db/shoppinCar/%s' % username if not os.path.exists(dirs): os.makedirs(dirs) shoppingInfoFile = '%s/shopping-info_%s%s.json' % (dirs,year,day) #print(shoppingInfoFile) return shoppingInfoFile # 日志文件 logFile = '../log/atm.log' # log功能,使用装饰器 def log(func): def wrapper(*args, **kwargs): users = u.Users().getUser() f = open(logFile, "a", encoding="utf-8") if func.__doc__ != '查询余额' and func.__doc__ != '修改密码': f.write('%s\t%s%s%s元\n' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),users[args[1]]['username'],func.__doc__,args[-1])) else: f.write('%s\t%s%s\n' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),users[args[1]]['username'],func.__doc__)) f.close() return func(*args, **kwargs) return wrapper
接下来就是开始写core目录下的users.py了,把以上的各个小功能逐一实现。
# -*- coding: utf-8 -*- import os,sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from conf import settings as ss import json class Users(object): '''用户类,管理用户接口''' def getUser(self): '''获取账户信息''' try: with open(ss.userInfoFile, "r", encoding="utf-8") as f: users = json.load(f) #print(users) except: print('have no users inof!') users = {} return users def setUser(self,users): '''重新写入账户信息''' with open(ss.userInfoFile, 'w') as f : json.dump(users , f , indent="\t") #print(users) def checkUser(self,username): '''检查用户是否存在''' users = self.getUser() for userID in users.keys(): if username == users[userID]['username']: #print('账户名已存在!') return True return False def getUserID(self,username): '''通过账户名获取账户id值''' users = self.getUser() for userID in users.keys(): if username == users[userID]['username']: return userID print('账户不存在!!!') return self.turnBack() def addUser(self,username,password,phone=None,limit=ss.creditLimit,isLock=False): '''添加账户''' users=self.getUser() # 字典key值自动加1 max_id = "000000" if users != {}: max_id = max(users.keys()) userID = str(int(max_id) + 1).zfill(6) # id自动+1,补足6位 users[userID] = { 'username':username, 'password':password, 'phone':phone, 'limit':limit, 'isLock':isLock } self.setUser(users) print(''.center(50,'#')) print('账户\033[42;1m%s\033[0m添加成功' % users[userID]['username']) print('账户名: %s' % users[userID]['username']) print('手机号: %s' % users[userID]['phone']) print('信用卡额度: %s' % users[userID]['limit']) print(''.center(50,'#')) return True def delUser(self,userID): '''账户注销''' users=self.getUser() try: print('账户\033[41;1m%s\033[0m已删除!' % users[userID]['username']) users.pop(userID) except: print('账户不存在!') return False self.setUser(users) return True def frozenUser(self,userID): '''冻结账户''' users=self.getUser() users[userID]['isLock'] = True self.setUser(users) print('账户%s已冻结!' % users[userID]['username'] ) def thawUser(self,userID): '''解冻账户''' users=self.getUser() users[userID]['isLock'] = False self.setUser(users) print('账户%s已解除冻结!' % users[userID]['username'] ) def userLoggin(self): '''用户登录验证''' for i in range (1,4): username = input('请输入用户名:') if self.checkUser(username): userID = self.getUserID(username) users=self.getUser() if users[userID]['isLock']: print('账户已被冻结,请联系管理员!') exit(-1) password = input('请输入密码:') if self.checkPassword(userID,password): return username,userID else: print('密码错误!') else: print('账户不存在!') print('操作过于频繁!') return False,False def checkPassword(self,userID,password): '''校验密码是否正确''' users = self.getUser() if password == users[userID]['password']: return True else: return False @ss.log def changePasswd(self,userID): '''修改密码''' for i in range(1,4): old_passwd = input('请输入旧密码:') # 校验旧密码是否正确 check = self.checkPassword(userID,old_passwd) if check: for j in range(1,4): if j == 3: print('操作过于频繁') return False new_passwd1 = input('请输入新密码:') if len(new_passwd1) < 8: print('密码不能少于8位!') continue if new_passwd1 == old_passwd: print('新密码不能和旧密码一样!') continue new_passwd2 = input('请再次确认新密码:') if new_passwd1 != new_passwd2: print('两次输入的密码不一致!') continue else: users=self.getUser() users[userID]['password'] = new_passwd1 self.setUser(users) print('密码修改成功!') return True else: print('旧密码输入错误!') print('操作过于频繁。') return False def changePhone(self,userID,phone): '''修改手机号''' users=self.getUser() users[userID]['phone'] = phone self.setUser(users) print('手机号修改完成!') print('账户名: %s' % users[userID]['username']) print('手机号: %s' % users[userID]['phone']) def changeLimit(self,userID,limit): '''修改账户信用额度''' users=self.getUser() users[userID]['limit'] = limit self.setUser(users) print('账户%s的信用额度已更新为%s' % (users[userID]['username'],users[userID]['limit'])) def turnBack(self): '''返回上级菜单''' print(''.center(15,'*')) print( "1、返回上级") print( "2、退出") print(''.center(15,'*')) while True: choise = input("请选择:") if choise == '1': self.userManagement() elif choise == '2': print ("谢谢使用!") exit(-1) else: print ("输入有误,请重新输入!") def userManagement(self): '''账户管理,总入口函数''' print('''请选择账户管理操作: 1、账户信息查询 2、添加新账户 3、删除账户 4、修改密码 5、修改手机号 6、冻结账户 7、解冻账户 8、修改账户信用额度''') while True: choise=input().strip() if choise.isdigit(): if '1' == choise: # 账户信息查询 users = self.getUser() print(''.center(50,'#')) for i in users.keys(): print('账户名: %s' % users[i]['username']) print('手机号: %s' % users[i]['phone']) print('信用卡额度: %s' % users[i]['limit']) print(''.center(50,'#')) self.turnBack() break elif '2' == choise: # 添加新账户 username = input('请输入用户名:') # 校验用户名是否已存在 if self.checkUser(username): print('账户已存在!') self.turnBack() break password = input('请输入密码:') phone = input('请输入手机号:') self.addUser(username,password,phone) self.turnBack() break elif '3' == choise: # 删除账户 username = input('请输入要删除的账号名:') userID = self.getUserID(username) self.delUser(userID) self.turnBack() break elif '4' == choise: # 修改密码 username = input('请输入要修改密码的账号名:') userID = self.getUserID(username) self.changePasswd(userID) self.turnBack() break elif '5' == choise: # 修改手机号 username = input('请输入要修改手机号的账号名:') userID = self.getUserID(username) phone = input('请输入新手机号:') self.changePhone(userID,phone) self.turnBack() break elif '6' == choise: # 冻结账户 username = input('请输入要冻结的账号名:') userID = self.getUserID(username) self.frozenUser(userID) self.turnBack() break elif '7' == choise: # 解冻账户 username = input('请输入要解除冻结的账号名:') userID = self.getUserID(username) self.thawUser(userID) self.turnBack() break elif '8' == choise: # 修改账户信用额度 username = input('请输入要更改信用额度的账号名:') userID = self.getUserID(username) limit = input('请输入要更改的信用额度:') if limit.isdigit(): self.changeLimit(userID,limit) else: print('输入无效,更新失败!') self.turnBack() break else: print('请输入有效数字!') else: print('请输入有效数字!') def run(): users=Users() users.userManagement() if __name__ == '__main__': run()
把用户类实现后,接下来是管理员的商品类啦,可以实现商品的上架、下架、修改商品价格已经商品查询功能等
# -*- coding: utf-8 -*- import os,sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from conf import settings as ss import json class Goods(object): '''商品类''' def getGoods(self): '''获取账户信息''' try: with open(ss.goodsInfoFile, "r", encoding="utf-8") as f: goods = json.load(f) #print(goods) except: print('have no goods inof!') goods = [] #print(goods) return goods def setGoods(self,goods): '''写入商品信息''' with open(ss.goodsInfoFile, "w", encoding="utf-8") as f: json.dump(goods, f, ensure_ascii=False, indent="\t") def printGoods(self): '''打印商品列表''' goods = self.getGoods() print(''.center(20,'-')) print('所有商品列表如下:') print(''.center(20,'-')) print('序号\t\t名称\t\t价格') print(''.center(20,'-')) for name,price in goods: print(goods.index([name,price]), '\t', name,"\t",price) print(''.center(20,'-')) def checkPrice(self,price): '''校验输入的价格是否为有效数字''' if price.isdigit(): return int(price.strip()) else: print('请输入有效数字!') return False def checkName(self,name): '''校验商品名称是否存在''' goods = self.getGoods() for goodName,price in goods: if name == goodName: return True return False def goodsShelves(self): '''商品上架''' name = input("请输入要上架的商品名称").strip() if self.checkName(name): print('商品已存在!') return False price=input("请输入该商品的价格") if self.checkPrice(price): goods = self.getGoods() goods.append([name,int(price)]) print('商品\033[32;1m%s\033[0m已上架完成!价格为:\033[32;1m%s\033[0m' % (name,int(price))) self.setGoods(goods) return True def goodDelete(self): '''商品下架''' name = input("请输入要下架的商品名称").strip() if not self.checkName(name): print('商品不存在!') return False else: goods = self.getGoods() for goodName,goodsPrice in goods: if goodName == name: goods.remove([goodName,goodsPrice]) #print(goods) print('商品\033[41;1m%s\033[0m已下架成功!' % name) self.setGoods(goods) return True def goodSearch(self,name): '''商品搜索查询''' if not self.checkName(name): print('商品不存在!') return False else: goods = self.getGoods() for goodName,goodsPrice in goods: if name == goodName: # 获取商品在list中的index值 index = goods.index([goodName,goodsPrice]) #print(index) print('商品价格为:') print(name,'\t',goods[index][1]) return (goods,index,True) def goodModify(self,name): '''修改商品价格''' goods,index,Flag = self.goodSearch(name) #print(Flag,'\n',goods,"\n",index) price=input("请要修改商品的价格") if self.checkPrice(price): goods[index][1] = int(price) self.setGoods(goods) print('商品价格修改完成!') print(goods[index][0],"\t","\033[32;1m%s\033[0m" % goods[index][1] ) return True def turnBack(self): '''返回上级菜单''' print(''.center(15,'*')) print( "1、返回上级") print( "2、退出") print(''.center(15,'*')) while True: choise = input("请选择:") if choise == '1': self.goodManagement() elif choise == '2': print ("谢谢使用!") exit(-1) else: print ("输入有误,请重新输入!") def goodManagement(self): '''用户选择''' print("请选择操作:") print("1、打印商品列表") print("2、商品上架") print("3、商品下架") print("4、修改商品价格") print("5、商品查询") while True: choice = input().strip() if choice.isdigit(): choice = int(choice) if 1 == choice: # 打印商品列表 self.printGoods() self.turnBack() break elif 2 == choice: # 商品上架 self.goodsShelves() self.turnBack() break elif 3 == choice: # 商品下架 self.goodDelete() self.turnBack() break elif 4 == choice: # 修改商品价格 name = input("请要修改商品价格的名称:").strip() self.goodModify(name) self.turnBack() break elif 5 == choice: # 商品查询 name = input("请输入要查询商品价格的名称:").strip() self.goodSearch(name) self.turnBack() break else: print("输入有误,请重新输入") else: print("请输入有效数字!") def run(): goods = Goods() goods.goodManagement() if __name__ == '__main__': run()
emmm,管理员的两大块就完成啦,接下来就是普通用户的一些操作啦,这个开发顺序也是要稍微注意一下的,先实现管理员的功能,就有了普通用户的信息嘛,然后再实现普通用户,这就可以直接用已有的账户信息啦,然后接着实现ATM功能,再实现购物功能,这样购物结算的时候就可以调用AMT结算啦。
废话不多说,看看ATM类的主要功能:
1、存款
2、取款
3、转账
4、查询余额
5、修改密码
# -*- coding: utf-8 -*- import os,sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import users as u from conf import settings as ss class ATM(object): '''ATM类''' @ss.log def deposit(self,userID,money): '''存款''' # 调用用户类的获取用户信息方法 users = u.Users().getUser() try: users[userID]['money'] = int(users[userID]['money']) + money except: # 第一次存钱 users[userID]['money'] = money # 调用用户类,重新写入用户信息 u.Users().setUser(users) #print('账户%s已存入%s元!' % (users[userID]['username'],money) ) #print('总余额为: %s 元' % users[userID]['money']) return True @ss.log def withdrawals(self,userID,money): '''取款''' users = u.Users().getUser() try: int(users[userID]['money']) if money > users[userID]['money']: print('余额不足!!') return False else: users[userID]['money'] -= money except: print('余额不足!') return False u.Users().setUser(users) #print('账户%s已取出%s元!' % (users[userID]['username'],money) ) #print('总余额为: %s 元' % users[userID]['money']) return True @ss.log def transfer(self,userID1,userID2,money): '''转账''' # 直接调用取款、存款函数,取款成功了再存款。 if self.withdrawals(userID1,money): self.deposit(userID2,money) return True return False @ss.log def queryBalance(self,userID): '''查询余额''' users = u.Users().getUser() try: print('账户%s的余额为:\n%s元' % (users[userID]['username'],users[userID]['money'])) except: print('账户%s的余额为:\n0元' % (users[userID]['username'])) def turnBack(self,userID): '''返回上级菜单''' print(''.center(15,'*')) print( "1、返回上级") print( "2、退出") print(''.center(15,'*')) while True: choise = input("请选择:") if choise == '1': self.atmOperation(userID) elif choise == '2': print ("谢谢使用!") exit(-1) else: print ("输入有误,请重新输入!") def inputMoney(self,userID): '''输入金额''' money = input() if money.isdigit(): return int(money) else: print('输入不是有效数字!') return self.turnBack(userID) def atmOperation(self,userID): '''ATM操作,总入口函数''' print('''请选择: 1、存款 2、取款 3、转账 4、查询余额 5、修改密码''') while True: choise=input().strip() if '1' == choise: # 存款 print('请输入存款金额:') money = self.inputMoney(userID) self.deposit(userID,money) print('存入%s元成功!' % (money)) self.turnBack(userID) break elif '2' == choise: # 取款 print('请输入取款金额!') money = self.inputMoney(userID) if self.withdrawals(userID,money): print('已取出%s元!请收好!' % (money)) self.turnBack(userID) break elif '3' == choise: # 转账 username = input('请输入要转账的账户名:') checkUser = u.Users().checkUser(username) if checkUser: print('请输入要转账金额:') money = self.inputMoney(userID) userID2 = u.Users().getUserID(username) if self.transfer(userID,userID2,money): print('已成功向%s转账%s元!' % (username, money)) else: print('账户不存在!') self.turnBack(userID) break elif '4' == choise: # 查询余额 self.queryBalance(userID) self.turnBack(userID) break elif '5' == choise: # 修改密码 u.Users().changePasswd(userID) self.turnBack(userID) break else: print('输入有误!') def run(): atm = ATM() print('欢迎登录瑞士银行!!') # 登录验证,通过后返回userID值 username,userID = u.Users().userLoggin() if userID: atm.atmOperation(userID) if __name__ == '__main__': run()
接下来就是普通用户的购物,这个比其他功能复杂点的地方就是不同的用户购物信息要分类存储。
# -*- coding: utf-8 -*- import os,sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import goods as g from core import atm as a from conf import settings as ss from core import users as u import json class ShoppingCar(object): '''用户购物''' def getBuyList(self,username): '''读取用户购物车清单''' try: with open(ss.ShoppingCarFile(username), "r", encoding="utf-8") as f: buyList = json.load(f) #print(buyList) except: print('have no goods inof!') buyList = [] #print(buyList) return buyList def setBuyList(self,username,buyList): '''将用户购物清单写入文件中''' with open(ss.ShoppingCarFile(username), "w", encoding="utf-8") as f: json.dump(buyList, f, ensure_ascii=False, indent="\t") def printBuyList(self,username): '''打印购物车列表''' sum = 0 buyList = self.getBuyList(username) print(''.center(20,'-')) print('购买商品列表如下:') print(''.center(20,'-')) print('名称\t\t价格') print(''.center(20,'-')) for name,price in buyList: print(name,"\t",price) sum = sum + int(price) print(''.center(20,'-')) print('总计:\t %s' % sum) return sum def buyList(self,username,choice): '''请选择购物''' buyList = self.getBuyList(username) goods = g.Goods().getGoods() if choice < len(goods) and choice >=0: print(goods[choice]) buyList.append(goods[choice]) #print(buyList) self.setBuyList(username,buyList) print('加入购物车成功') else: print('商品未上架!') return buyList def shopping(self,username,userID): '''购物''' goods = g.Goods().printGoods() print(goods) while True: print('请选择,停止购物按q') choice = input().strip() if choice != 'q': if choice.isdigit(): choice = int(choice) self.buyList(username,choice) else: print('请输入有效数字!') else: # 获取购物车总价 sum = self.printBuyList(username) print('开始结算!') n = 2 while n >=0: password = input('请输入银行卡密码:') if u.Users().checkPassword(userID,password): # 调用银行卡接口结算 if a.ATM().withdrawals(userID,sum): print('结算成功!') return True else: print('结算失败!') else: if n !=0: print('密码错误!你还有%s次尝试机会!' % n) else: print('尝试次数已用完,结算失败!') n -=1 # 清空本次购物信息 #buyList = ['结算失败!'] #self.setBuyList(username, buyList) os.remove(ss.ShoppingCarFile(username)) return False def run(): s = ShoppingCar() print('欢迎登录XXX网上购物商城!') # 登录验证,通过后返回userID值 username,userID = u.Users().userLoggin() if userID: s.shopping(username,userID) if __name__ == '__main__': run()
最后就是写一个总的入口功能啦,在bin/main.py里去实现调用以上各个功能。
# -*- coding: utf-8 -*- # 2019/7/10 16:57 import os,sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import goods as g from core import atm as a from conf import settings as ss from core import users as u from core import shopping as s def checkAdmin(): '''校验管理员账号密码''' i = 2 while i >= 0: username = input('请输入管理员账号:') if username == ss.adminName: j = 2 while j >= 0: password = input('请输入管理员密码:') if password == ss.adminPassword: return True else: print('管理员密码输入有误!') if j == 0: print('账号已锁定,请10分钟后重新尝试!') return False else: print('你还有%s次尝试机会!' % j) j -=1 else: print('管理员账号输入有误!') if i != 0: print('你还有%s次尝试机会!' % i) else: print('账号已锁定,请10分钟后重新尝试!') i -=1 return False def averageUser(): '''普通用户操作''' print('''请选择操作: 1、购买商品 2、ATM操作''') while True: choice = input().strip() if '1' == choice: s.run() break elif '2' == choice: a.run() break else: print('输入有误!') def adminManagement(): '''管理员操作''' print('''请选择操作: 1、商品管理 2、用户管理''') while True: choice = input().strip() if '1' == choice: g.run() break elif '2' == choice: u.run() break else: print('输入有误!') def run(): '''程序入口函数''' print('''欢迎进入ATM+购物程序! 请选择操作: 1、普通用户 2、管理员''') while True: choice = input().strip() if '1' == choice: averageUser() break elif '2' == choice: if checkAdmin(): adminManagement() break else: print('输入有误!') if __name__ == '__main__': run()
再给ATM的操作加上日志功能,这里用了装饰器,直接应用到ATM操作的函数上,而不改变原来函数的调用方式。就写了一个log函数,放在settings.py里啦,就不再单独写一个py文件。
源码链接:https://github.com/caiqinxiong/ATM-Shopping.git