Python之信用卡模拟程序
最近在自学Python,出于练手目的,写了一个信用卡模拟程序,包括用户登录、购物商城、信用卡中心、后台管理等功能。
整体需求如下:
- 额度 10000或自定义
- 实现用户登录和锁定
- 实现购物商城,加入购物车,调用信用卡接口结账等
- 可以提现,手续费5%
- 支持账户间转账
- 提供还款接口
- 记录日常消费流水
- 记录信用卡操作日志
- 可以查看账单和购物历史记录
- 每月25号出账单(暂未实现)
- 提供后台管理接口,包括添加账户,删除账户,冻结账户,发行信用卡,冻结信用卡等
参考博客地址:https://www.cnblogs.com/wushank/p/5248916.html
本次练习参考了上面博客地址内容,并做了一些修改,主要是将文件操作改为mysql数据库操作,并去掉了错误日志记录和自动出账单部分;
一、程序主要功能逻辑如下
本次信用卡模拟程序主要包括一下五部分功能: 1.登录系统 用于实现用户的登陆和各种校验,登陆成功进入用户中心,可以进行修改密码、查看账单和购物历史等; 2.进入商城 主要实现购物和结算功能,其中结算是调用信用卡模块的结算函数实现; 3.信用卡中心 包括查看信用卡信息、提现、转账、还款等操作,并记录操作日志; 4.后台管理 对于admin账号,可以登录后台管理系统,进行账户和信用卡的管理操作; 5.退出系统 账户退出登录;
二、程序所用到的数据库及字段如下
三、系统功能模块和目录结构
在目录结构中,conf为配置文件包,包括系统配置文件settings.py和显示模板文件templates.py;
dbhelper为数据库操作包,包括数据库初始化执行文件initdb.py和数据库操作接口文件dbapi.py;
models为程序中各种类包,包括用户类,购物类和信用卡类等;
credit_main.py是程序主文件,执行此文件开始程序逻辑;
四、各模块代码如下
1.credit_main.py 主程序文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 主程序文件 9 """ 10 from datetime import date, datetime 11 from models import common 12 from conf import templates 13 from models.user import Users 14 from models.shopping import Shopping 15 from models.creditcard import CreditCard 16 17 18 def do_login(userobj): 19 """ 20 主菜单的1号菜单,用户登录模块 21 :param userobj: 当前用户对象 22 :return: 23 """ 24 # 用户未登录,调用 Users类的登录模块 25 # 登录成功后,将该用户的相关属性信息赋给用户对象各属性值 26 userobj.login() 27 28 29 def user_center(userobj, today, weekoftoday): 30 """ 31 主菜单的1号菜单,个人中心模块 32 :param userobj: 当前用户对象 33 :param today: 菜单显示的日期 34 :param weekoftoday: 菜单显示的星期 35 :return: 36 """ 37 # 如果用户已经登录,菜单功能1变为个人中心,调用另一个菜单模板 index_user_center 38 while True: 39 print(templates.index_user_center.format( 40 userobj.name, today, common.numtochr(weekoftoday))) 41 #[1]修改密码 [2]修改资料 [3]我的账单 [4]购物记录 [5]注销 [6]返回 42 choose = common.input_msg( 43 "选择功能[1-6]: ", ("1", "2", "3", "4", "5", "6")).strip() 44 45 # 返回上级菜单 46 if choose == "6": 47 break 48 49 if choose == "1": 50 userobj.modify_password() 51 52 if choose == "2": 53 userobj.modify_user_info() 54 55 if choose == "3": 56 userobj.print_bill_history() 57 58 if choose == "4": 59 userobj.print_shopping_history() 60 61 if choose == "5": 62 userobj.logout() 63 break 64 65 66 def do_shopping(userobj): 67 """ 68 主菜单的2号菜单,购物商城模块,进行购物部分的所有处理 69 :param userobj: 一个用户对象,如果用户未登录,在支付模块会通过装饰器来登录 70 :return: 71 """ 72 # 实例化商城 73 shoppobj = Shopping() 74 while True: 75 print(templates.shopping_index_menu) 76 #[1] 购物 [2] 查看购物车 [3] 结算 [4] 退出 [5] 返回 77 choose = common.input_msg( 78 "选择功能[1-5]: ", ("1", "2", "3", "4", "5")).strip() 79 80 # 返回上级菜单 81 if choose == "5": 82 break 83 84 if choose == "1": 85 shoppobj.buy_shopping() 86 87 if choose == "2": 88 shoppobj.print_shopping_cart() 89 90 if choose == "3": 91 shoppobj.payfor_shopcart(userobj) 92 93 if choose == "4": 94 userobj.logout() 95 break 96 97 98 def card_center(userobj): 99 """ 100 主菜单的3号菜单,信用卡中心模块 101 :param userobj: 一个用户对象 102 :return: 103 """ 104 if userobj.islogin: 105 # 获取绑定的信息卡号 106 cardno = userobj.bindcard 107 # 获得信用卡对象 108 cardobj = CreditCard(cardno) 109 else: 110 # 未登录信用卡 111 while True: 112 cardno = input("请输入信用卡卡号: ").strip().lower() 113 if cardno.isnumeric(): 114 cardobj = CreditCard(cardno) 115 if cardobj.card_is_exists(): 116 pwd = input("请输入密码:") 117 if common.encrypt(pwd) == cardobj.password: 118 print("登录成功!") 119 break 120 else: 121 print("密码错误,请重新输入!") 122 continue 123 else: 124 print("卡号不存在,请重新输入!") 125 continue 126 else: 127 print("卡号无效!") 128 continue 129 130 while True: 131 print(templates.index_creditcard.format(cardno=cardobj.cardno)) 132 #【1】我的信用卡 【2】提现 【3】还款 【4】转账 【5】退出 【6】返回 133 choose = common.input_msg("请选择功能: ", ("1", "2", "3", "4", "5", "6")) 134 135 # 返回上级菜单 136 if choose == "6": 137 break 138 139 if choose == "1": 140 cardobj.print_creditcart() 141 142 if choose == "2": 143 cardobj.withdraw_money() 144 145 if choose == "3": 146 cardobj.payback_money() 147 148 if choose == "4": 149 cardobj.transfer_money() 150 151 if choose == "5": 152 userobj.logout() 153 break 154 155 156 def get_users(): 157 """ 158 显示用户的信息,用户新建、删除、解锁用户时显示用户基本信息 159 :return: 160 """ 161 username = common.input_msg("请输入用户名:") 162 # 创建一个用户实例 163 get_user = Users() 164 get_user.username = username 165 # 如果用户名存在,load用户信息成功 166 if get_user.load_user_info(): 167 # 先显示一下用户的信息 168 print(templates.user_info.format(username=get_user.username, 169 name=get_user.name, 170 mobile=get_user.mobile, 171 role=get_user.role, 172 isdel="否" if get_user.isdel == 0 else "是", 173 islocked="否" if get_user.islocked == 0 else "是", 174 bindcard=get_user.bindcard)) 175 return get_user 176 else: 177 print("用户名不存在!") 178 return False 179 180 181 def fill_card_info(): 182 """ 183 填充信用卡资料信息 184 :return: 返回一个信用卡对象 185 """ 186 while True: 187 cardno = common.input_msg("请输入卡号:") 188 cardobj = CreditCard(cardno) 189 if cardobj.card_is_exists(): 190 print("卡号已存在,请重新输入卡号", "ERROR") 191 continue 192 else: 193 break 194 195 password = common.input_msg("请输入密码:") 196 cardobj.password = common.encrypt(password) 197 cardobj.credit_total = common.input_msg( 198 "信用额度(default:{0}):".format(cardobj.credit_total)) 199 cardobj.credit_balance = cardobj.credit_total 200 cardobj.owner = common.input_msg("所有者:") 201 return cardobj 202 203 204 def manager(userobj): 205 """ 206 主菜单的4号菜单,后台管理模块 207 :param userobj: 当前登录用户对象 208 :return: 209 """ 210 if userobj.islogin: 211 if userobj.role == "admin": 212 while True: 213 print(templates.index_manage.format(username=userobj.name)) 214 #【1】创建用户 【2】删除用户 【3】解锁用户 215 #【4】发行信用卡 【5】冻结信用卡 【6】退出 【7】返回 216 choose = common.input_msg( 217 "请选择功能: ", ("1", "2", "3", "4", "5", "6", "7")) 218 # 返回上级菜单 219 if choose == "7": 220 break 221 222 if choose == "1": 223 new_user = Users() 224 new_user.init_user_info() 225 226 if choose == "2": 227 del_user = get_users() 228 if del_user: 229 confirm = common.input_msg( 230 "确定要删除此用户吗(y/n)?", ("y", "n")) 231 if confirm == "y": 232 del_user.del_user() 233 print("用户删除成功!") 234 235 if choose == "3": 236 unlock_user = get_users() 237 if unlock_user: 238 confirm = common.input_msg("确认解锁吗(y/n)?", ("y", "n")) 239 if confirm == "y": 240 unlock_user.unlock_user() 241 print("用户解锁成功!") 242 243 if choose == "4": 244 newcard = fill_card_info() 245 newcard.create_card() 246 print("发卡成功!") 247 248 if choose == "5": 249 cardno = common.input_msg("输入卡号:") 250 card = CreditCard(cardno) 251 if not card.card_is_exists(): 252 print("卡号不存在") 253 else: 254 # 调用模板显示卡信息 255 print(templates.card_info.format(cardno=card.cardno, 256 owner=card.owner, 257 total=card.credit_total, 258 balance=card.credit_balance, 259 status="正常" if card.frozenstatus == 0 else "冻结" 260 )) 261 confirm = common.input_msg( 262 "确认要冻结此卡吗(y/n)?", ("y", "n")) 263 if confirm == "y": 264 card.frozenstatus = \'X\' 265 card.update_card() 266 print("冻结成功!") 267 # 退出 268 if choose == "7": 269 userobj.logout() 270 break 271 else: 272 # 不是 admin 角色无权限 273 print("权限不够!") 274 else: 275 print("请先登录系统!") 276 userobj.login() 277 278 279 if __name__ == "__main__": 280 today = datetime.now().strftime("%Y-%m-%d") 281 weekoftoday = date.weekday(datetime.now()) 282 # 首先创建一个空的用户对象,各属性值为空 283 # 关于用户的各种操作都是针对该用户对象的处理 284 curruser = Users() 285 286 # -------------- 开始主程序 ------------------- # 287 while True: 288 # 如果用户登录了,显示登录的界面,未登录显示未登录的界面 289 if not curruser.islogin: 290 print(templates.index_default_menu.format( 291 "", today, common.numtochr(weekoftoday))) 292 else: 293 print(templates.index_logined_menu.format( 294 "欢迎您: {0}".format(curruser.name), today, common.numtochr(weekoftoday))) 295 296 #【1】登录系统 【2】进入商城 【3】信用卡中心 【4】后台管理 【5】退出系统 297 choose = common.input_msg( 298 "选择功能编号[1-5]: ", ("1", "2", "3", "4", "5")).strip() 299 300 # 5 退出系统 301 if choose == "5": 302 print(\'\n已退出!\') 303 break 304 305 # 1 用户登录 or 用户中心 306 if choose == "1": 307 if not curruser.islogin: 308 do_login(curruser) 309 else: 310 user_center(curruser, today, weekoftoday) 311 312 # 2 进入商城 313 if choose == "2": 314 do_shopping(curruser) 315 316 # 3 信用卡中心 317 if choose == "3": 318 card_center(curruser) 319 320 # 4 后台管理 321 if choose == "4": 322 manager(curruser)
2.conf 配置文件包
2.1错误代码文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月5日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 系统错误代码表 9 """ 10 NO_ERROR = 0 # 系统正常返回 11 USER_NOT_EXISTS = 1 # 用户名不存在 12 CARD_NOT_BINDED = 2 # 用户未绑定信用卡 13 BALANCE_NOT_ENOUGHT = 3 # 信用卡余额不足 14 CARD_OWNER_ERROR = 4 # 绑定卡时输入的卡号与卡的所有人不一致 15 CARD_PASS_ERROR = 5 # 信用卡密码错误
2.2 配置文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 系统参数配置文件 9 """ 10 import os 11 import sys 12 13 # 程序文件主目录 14 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 15 # print(BASE_DIR) 16 # 添加环境变量(临时的,程序退出则失效) 17 sys.path.append(BASE_DIR) 18 19 # 数据库信息 20 DATABASE = {\'ENGINE\': \'mysql\', 21 \'HOST\': \'127.0.0.1\', 22 \'PORT\': \'3306\', 23 \'DB\': \'card\', 24 \'USER\': \'root\', 25 \'PASSWORD\': \'root1234\', 26 } 27 28 # 用户登录失败最大次数 29 ERROR_MAX_COUNT = 3 30 # 日息费率 31 EXPIRE_DAY_RATE = 0.0005 32 # 转账、提现手续费 33 FETCH_MONEY_RATE = 0.05 34 # 信用额度 35 CREDIT_TOTAL = 10000 36 # 每月账单日期 37 STATEMENT_DAY = 25
2.3显示模板文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 系统菜单显示模板 9 """ 10 # 主程序中的主菜单 11 index_default_menu = \'\'\' 12 ------------------------------------------------------------------------- 13 信用卡 模拟程序 14 15 {0} 今天 {1} 星期{2} 16 ------------------------------------------------------------------------- 17 【1】登录系统 【2】进入商城 【3】信用卡中心 【4】后台管理 【5】退出系统 18 \'\'\' 19 20 # 主程序中的用户登录后的显示菜单 21 index_logined_menu = \'\'\' 22 ------------------------------------------------------------------------- 23 信用卡 模拟程序 24 25 {0} 今天 {1} 星期{2} 26 ------------------------------------------------------------------------- 27 【1】个人中心 【2】进入商城 【3】信用卡中心 【4】后台管理 【5】退出系统 28 \'\'\' 29 30 # 主程序中的用户中心菜单 31 index_user_center = \'\'\' 32 ========================================================================= 33 个人中心 34 35 当前用户:{0} 今天 {1} 星期{2} 36 ========================================================================= 37 [1]修改密码 [2]修改资料 [3]我的账单 [4]购物记录 [5]注销 [6]返回 38 \'\'\' 39 40 # 用户基本信息模板 41 user_info = \'\'\' 42 ------------------------------------------------------------------------------ 43 用户基本信息 44 45 用 户 名:{username} 姓 名:{name} 手 机:{mobile} 46 用户权限:{role} 是否锁定:{islocked} 是否删除:{isdel} 47 信用卡号:{bindcard} 48 ------------------------------------------------------------------------------ 49 \'\'\' 50 51 # 购物商城的主菜单 52 shopping_index_menu = \'\'\' 53 ============================================================================ 54 信用卡购物商城 55 56 ============================================================================ 57 [1]购物 [2]查看购物车 [3]结算 [4]退出 [5]返回 58 \'\'\' 59 60 61 # 信用卡管理模块主菜单 62 index_creditcard = \'\'\' 63 ============================================================================ 64 信用卡管理中心 65 66 卡号:{cardno} 67 ============================================================================ 68 [1]我的信用卡 [2]提现 [3]还款 [4]转账 [5]退出 [6]返回 69 \'\'\' 70 71 # 信用卡基本信息模板 72 card_info = \'\'\' 73 ------------------------------------------------------------------------------ 74 信用卡基本信息 75 76 卡号:{cardno} 所有人:{owner} 信用额度:{total} 剩余额度:{balance} 状态:{status} 77 ------------------------------------------------------------------------------ 78 \'\'\' 79 80 # 后台管理模板 81 index_manage = \'\'\' 82 ================================================================================== 83 后台管理 84 85 用户:{username} 86 ================================================================================== 87 [1]创建用户 [2]删除用户 [3]解锁用户 88 [4]发行信用卡 [5]冻结信用卡 [6]退出 [7]返回 89 \'\'\' 90 91 # 账单报表显示模板 92 report_bill = \'\'\' 93 ------------------------------------------------------------------------------ 94 用户中心 - 账单明细 95 96 卡号:{cardno} 账单时间:{startdate} 至 {enddate} 97 ------------------------------------------------------------------------------ 98 交易时间 交易类型 交易金额 流水号 99 {billdetail} 100 101 \'\'\' 102 103 # 购物历史记录显示模板 104 shopping_history = \'\'\' 105 ------------------------------------------------------------------------------ 106 用户中心 - 购物明细 107 108 用户:{username} 购物时间:{startdate} 至 {enddate} 109 ------------------------------------------------------------------------------ 110 \'\'\'
3.dbhelper 数据库操作文件包
3.1 初始化数据执行文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 数据库初始化模块,包括创建表和初始值 9 单独执行,一次即可 10 """ 11 import sys 12 import pymysql 13 from conf import settings 14 from models.common import encrypt 15 16 HOST = settings.DATABASE[\'HOST\'] 17 USER = settings.DATABASE[\'USER\'] 18 PASSWORD = settings.DATABASE[\'PASSWORD\'] 19 DB = settings.DATABASE[\'DB\'] 20 # 打开数据库连接 21 db = pymysql.connect(HOST, USER, PASSWORD, DB) 22 # 获取操作游标 23 cursor = db.cursor() 24 25 # 用户列表 26 user_list = { 27 "test": {"password": "1234", "name": "测试", "mobile": "12311111111", "islocked": \'\', "bindcard": \'\', 28 "role": "user", "isdel": \'\'}, 29 "admin": {"password": "1234", "name": "admin", "mobile": "12300000000", "islocked": \'\', "bindcard": \'\', 30 "role": "admin", "isdel": \'\'} 31 } 32 33 # 商品清单 34 shopping_list = ( 35 {"no": "101", "name": "进口牛奶 1L*12", "price": 95, }, 36 {"no": "102", "name": "乐虎饮料", "price": 120, }, 37 {"no": "103", "name": "意大利巧克力", "price": 205, }, 38 {"no": "104", "name": "阳澄湖大闸蟹", "price": 458, }, 39 {"no": "105", "name": "内蒙原味大瓜子", "price": 168, }, 40 {"no": "106", "name": "吉年干菌大礼包", "price": 256, }, 41 {"no": "201", "name": "佳能单反机身家庭套餐", "price": 9326}, 42 {"no": "202", "name": "360安全路由无线路由器", "price": 89}, 43 {"no": "203", "name": "小米 4c 高配版 全网通 ", "price": 1499}, 44 {"no": "204", "name": "华为(HUAWEI)荣耀手环", "price": 399}, 45 {"no": "205", "name": "步步高(BBK)家教机S2", "price": 3468}, 46 {"no": "206", "name": "Apple 13.3英寸笔记本", "price": 6988}, 47 {"no": "301", "name": "针织连衣裙假两件裙加厚", "price": 163}, 48 {"no": "302", "name": "修身圆领修身长袖连衣裙", "price": 235}, 49 {"no": "303", "name": "保暖小脚裤大码弹力铅笔裤", "price": 169}, 50 {"no": "304", "name": "连帽羽绒服男韩版修身外套", "price": 319}, 51 {"no": "305", "name": "猿人头袖英文字母印花男士", "price": 298}, 52 {"no": "306", "name": "加绒保暖套头卫衣 灰花灰", "price": 159} 53 ) 54 55 # 信用卡列表 56 creditcard_list = { 57 "1001012345": {"password": "1234", "credit_total": 10000, "credit_balance": 10000, 58 "owner": "test", "frozenstatus": \'\'}, 59 "1001010002": {"password": "1234", "credit_total": 10000, "credit_balance": 10000, 60 "owner": "admin", "frozenstatus": \'\'} 61 } 62 63 64 # 初始化用户数据表 userinfos 65 def init_db_users(): 66 # 如果表存在则删除 67 cursor.execute("DROP TABLE IF EXISTS userinfos") 68 # 编写SQL语句 69 sql = """CREATE TABLE userinfos ( 70 username CHAR(20) PRIMARY KEY NOT NULL, 71 password CHAR(100) NOT NULL, 72 name CHAR(20), 73 mobile CHAR(11), 74 islocked CHAR(1), 75 bindcard CHAR(10), 76 role CHAR(10), 77 isdel CHAR(1))""" 78 cursor.execute(sql) 79 sql = """INSERT INTO userinfos ( 80 username,password,name,mobile,islocked,bindcard,role,isdel) 81 VALUES (\'{0}\',\'{1[0]}\',\'{1[1]}\',{1[2]},\'{1[3]}\',\'{1[4]}\',\'{1[5]}\',\'{1[6]}\')""" 82 for user in user_list.keys(): 83 # 用户初始密码 84 tmppassword = user_list[user][\'password\'] 85 # 对密码进行加密 86 encrypassword = encrypt(tmppassword) 87 # 修改明文密码 88 user_list[user][\'password\'] = encrypassword 89 exe_sql = sql.format(user, tuple(user_list[user].values())) 90 cursor.execute(exe_sql) 91 db.commit() 92 93 94 # 初始化商品数据表 shopitems 95 def init_db_shopitems(): 96 # 如果表存在则删除 97 cursor.execute("DROP TABLE IF EXISTS shopitems") 98 # 编写SQL语句 99 sql = """CREATE TABLE shopitems ( 100 item CHAR(3) PRIMARY KEY NOT NULL, 101 name CHAR(100), 102 price FLOAT)""" 103 cursor.execute(sql) 104 sql = """INSERT INTO shopitems ( 105 item,name,price) 106 VALUES (\'{0}\',\'{1}\',{2})""" 107 for item in shopping_list: 108 exe_sql = sql.format(item[\'no\'], item[\'name\'], item[\'price\']) 109 cursor.execute(exe_sql) 110 db.commit() 111 112 113 # 初始化信用卡数据表 creditcards 114 def init_db_creditcards(): 115 # 如果表存在则删除 116 cursor.execute("DROP TABLE IF EXISTS creditcards") 117 # 编写SQL语句 118 sql = """CREATE TABLE creditcards ( 119 cardno CHAR(10) PRIMARY KEY NOT NULL, 120 password CHAR(100) NOT NULL, 121 credit_total FLOAT, 122 credit_balance FLOAT, 123 owner CHAR(20), 124 frozenstatus CHAR(1))""" 125 cursor.execute(sql) 126 sql = """INSERT INTO creditcards ( 127 cardno,password,credit_total,credit_balance,owner,frozenstatus) 128 VALUES (\'{0}\',\'{1[0]}\',\'{1[1]}\',{1[2]},\'{1[3]}\',\'{1[4]}\')""" 129 for card in creditcard_list.keys(): 130 # 用户初始密码 131 tmppassword = creditcard_list[card][\'password\'] 132 # 对密码进行加密 133 encrypassword = encrypt(tmppassword) 134 # 修改明文密码 135 creditcard_list[card][\'password\'] = encrypassword 136 exe_sql = sql.format(card, tuple(creditcard_list[card].values())) 137 cursor.execute(exe_sql) 138 db.commit() 139 140 141 # 初始化账单数据表 statements 142 def init_db_statements(): 143 # 如果表存在则删除 144 cursor.execute("DROP TABLE IF EXISTS statements") 145 # 编写SQL语句 146 sql = """CREATE TABLE statements ( 147 id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, 148 serialno CHAR(24), 149 cardno CHAR(10), 150 datetime DATETIME, 151 payfor CHAR(10), 152 cost FLOAT)""" 153 cursor.execute(sql) 154 db.commit() 155 156 157 # 初始化购物历史数据表 shoppings 158 def init_db_shoppings(): 159 # 如果表存在则删除 160 cursor.execute("DROP TABLE IF EXISTS shoppings") 161 # 编写SQL语句 162 sql = """CREATE TABLE shoppings ( 163 id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, 164 serialno CHAR(24), 165 username CHAR(20), 166 datetime DATETIME, 167 item CHAR(3), 168 name CHAR(100), 169 price FLOAT)""" 170 cursor.execute(sql) 171 db.commit() 172 173 174 # 初始化数据表 175 def init_database(): 176 # 数据表名称列表 177 tables = [\'users\', \'shopitems\', \'creditcards\', 178 \'statements\', \'shoppings\'] 179 for table in tables: 180 # 通过反射初始化数据表 181 if hasattr(sys.modules[__name__], "init_db_{0}".format(table)): 182 init_func = getattr( 183 sys.modules[__name__], "init_db_{0}".format(table)) 184 init_func() 185 print("table {0}.db create successfull".format(table)) 186 else: 187 print( 188 "init table {0} failed,no function init_db_{0} found".format(table)) 189 db.close() 190 191 192 if __name__ == "__main__": 193 init_database()
3.2数据库操作接口文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 数据库访问接口模块 9 提供数据库读写接口函数 10 """ 11 import pymysql 12 from conf import settings 13 14 HOST = settings.DATABASE[\'HOST\'] 15 USER = settings.DATABASE[\'USER\'] 16 PASSWORD = settings.DATABASE[\'PASSWORD\'] 17 DB = settings.DATABASE[\'DB\'] 18 # 打开数据库连接 19 db = pymysql.connect(HOST, USER, PASSWORD, DB) 20 # 获取操作游标 21 cursor = db.cursor() 22 23 24 def load_data_from_db(tabname): 25 """ 26 从指定的数据表中获取所有数据,并以字典的形式返回结果 27 :param tabename: 数据库表名 28 :return: 返回所有结果 29 """ 30 results = [] 31 # 编写SQL语句 32 sql = """select COLUMN_NAME from information_schema.COLUMNS 33 where table_name = \'%s\' and table_schema = \'card\' 34 order by ORDINAL_POSITION""" % tabname 35 cursor.execute(sql) 36 column_results = cursor.fetchall() 37 sql = """SELECT * FROM %s""" % tabname 38 cursor.execute(sql) 39 data_results = cursor.fetchall() 40 for data in data_results: 41 res = {} 42 for i in range(len(data)): 43 res[column_results[i][0]] = data[i] # field:value 44 results.append(res) 45 return results 46 47 48 def unload_data_to_db(exe_sql): 49 """ 50 根据SQL语句向指定的表中写入数据 51 :param exe_sql: 要执行的SQL语句 52 :return: 53 """ 54 cursor.execute(exe_sql) 55 db.commit() 56 57 58 def load_bill_report(cardno, startdate, enddate): 59 """ 60 从信用卡对账单中获取指定卡的对账信息数据, 获取某一个时间段内的数据 61 :param enddate: 查询记录的结束日期 62 :param startdate: 查询记录的开始日期 63 :param cardno: 信用卡卡号 64 :return: 信用卡对账单数据 ,返回结果为 list 数据类型 65 """ 66 results = [] 67 startdate = startdate + " 00:00:00" 68 enddate = enddate + " 00:00:00" 69 # 编写SQL语句 70 sql = """select * from statements 71 where cardno = \'%s\' and datetime >= \'%s\' and datetime <= \'%s\' 72 order by datetime""" % (cardno, startdate, enddate) 73 cursor.execute(sql) 74 data_results = cursor.fetchall() 75 for data in data_results: 76 # datetime,payfor,cost,serialno 77 results.append((data[3], data[4], data[5], data[1])) 78 return results 79 80 81 def load_shop_history(username, startdate, enddate): 82 """ 83 查找报表记录中的指定用户的购物历史记录,将结果存入到列表中 84 :param startdate: 开始日期 85 :param enddate: 结束日期 86 :return: 结果 dict_list 87 """ 88 results = {} 89 startdate = startdate + " 00:00:00" 90 enddate = enddate + " 00:00:00" 91 # 编写SQL语句 92 sql = """select * from shoppings 93 where username = \'%s\' and datetime >= \'%s\' and datetime <= \'%s\' 94 order by serialno""" % (username, startdate, enddate) 95 cursor.execute(sql) 96 data_results = cursor.fetchall() 97 for data in data_results: 98 serialno = data[1] 99 if serialno in results.keys(): 100 results[serialno][\'cost\'] += data[6] 101 results[serialno][\'detail\'].append((data[4], data[5], data[6])) 102 else: 103 res = {} 104 res[\'time\'] = data[3] 105 res[\'cost\'] = data[6] 106 res[\'detail\'] = [] 107 res[\'detail\'].append((data[4], data[5], data[6])) 108 results[serialno] = res 109 return results
4.models 类文件和共用函数文件
4.1 公共函数文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月2日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 公共函数模块 9 """ 10 import time 11 import hashlib 12 from datetime import datetime, date 13 14 15 def numtochr(num_of_weekday): 16 """ 17 将数字星期转换为中文数字 18 :param num_of_weekday: 星期几的数字字符( 0,1,2,3,4,5,6) 19 :return: 中文 星期几 20 """ 21 chrtuple = (\'一\', \'二\', \'三\', \'四\', \'五\', \'六\', \'日\') 22 num = int(num_of_weekday) 23 return chrtuple[num] 24 25 26 def input_msg(message, limit_value=tuple()): 27 """ 28 判断输入的信息,为空继续输入,不为空返回输入的信息 29 :param message: input()函数的提示信息 30 :param limit_value: 对输入的值有限制,必须为limit_value的值;ex:("admin","user") 31 :return: 返回输入的信息 32 """ 33 while True: 34 input_value = input(message).strip().lower() 35 if not input_value: 36 print("\n输入不能为空!\n") 37 elif len(limit_value) > 0: 38 if input_value not in limit_value: 39 print("\n输入的值不正确,请重新输入!\n") 40 else: 41 break 42 else: 43 break 44 return input_value 45 46 47 def encrypt(string): 48 """ 49 字符串加密函数 50 :param string: 待加密的字符串 51 :return: 返回加密过的字符串 52 """ 53 ha = hashlib.md5() 54 ha.update(string.encode(\'utf-8\')) 55 result = ha.hexdigest() 56 return result 57 58 59 def create_serialno(): 60 """ 61 生成一个消费、转账、提款时的流水号,不重复 62 :return: 流水号 63 """ 64 serno = "{0}{1}".format( 65 datetime.now().strftime("%Y%m%d%H%M%S"), str(int(time.time()))) 66 return serno 67 68 69 def input_date(msg, default_date): 70 """ 71 对输入的日期进行判断是否正确 yyyy-mm-dd or yyyy-m-d 72 :param msg:输入提示信息 73 :param default_date: 默认日期 74 :return:返回日期 str类型 75 """ 76 while True: 77 strdate = input(msg).strip() 78 if not strdate: 79 strdate = default_date 80 try: 81 date_list = strdate.split("-") 82 result = date( 83 int(date_list[0]), int(date_list[1]), int(date_list[2])) 84 break 85 except ValueError: 86 print("输入日期不合法,请重新输入!") 87 continue 88 return result.strftime("%Y-%m-%d")
4.2用户类文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月1日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 用户类模块 9 """ 10 from datetime import date 11 from dbhelper import dbapi 12 from models import common 13 from models.creditcard import CreditCard 14 from conf import settings, templates 15 16 17 class Users(object): 18 """ 19 用户类,包含用户所有属性及相关方法 20 """ 21 22 def __init__(self): 23 self.username = "" # 登录名 24 self.password = "" # 登录密码 25 self.name = "" # 姓名 26 self.mobile = "" # 手机 27 self.islocked = \'\' # 是否锁定 28 self.bindcard = "" # 绑定卡 29 self.role = "user" # 账户权限 30 self.isdel = \'\' # 用户删除标识 31 32 self.islogin = False # 登录状态 33 self.trycount = 0 # 登录尝试次数 34 35 self.database = \'userinfos\' 36 self.dict_user = {} # 所有用户信息 37 self.get_users_info() 38 39 def get_users_info(self): 40 """ 41 加载所有用户信息 42 """ 43 self.dict_user.clear() 44 user_data = dbapi.load_data_from_db(self.database) 45 for user in user_data: 46 username = user[\'username\'] 47 del user[\'username\'] 48 self.dict_user[username] = user 49 # print(self.dict_user) 50 51 def login(self): 52 """ 53 用户登录函数,输入用户名和密码后调用user_login进行登录验证 54 登录成功后将各属性值赋给该用户对象 55 :return: 56 """ 57 # 未到达错误最大次数则可一直输入 58 while self.trycount < settings.ERROR_MAX_COUNT: 59 self.username = input("用户名: ") 60 password = input("密 码: ") 61 if not self.user_exists(): 62 print("用户名不存在!") 63 continue 64 65 # 调用用户登录方法进行登录 66 self.login_check(password) 67 68 # 用户删除就直接退出 69 if self.isdel: 70 print("该用户已删除,请联系系统管理员!") 71 self.trycount = 0 72 break 73 74 # 用户锁定就直接退出 75 if self.islocked: 76 print("该用户已被锁定,请联系系统管理员!") 77 self.trycount = 0 78 break 79 80 # 登录成功 退出登录 81 if self.islogin: 82 print("登陆成功!") 83 break 84 else: 85 print("用户名密码错误!") 86 else: 87 # 失败次数达到3次,锁定账户 88 self.islocked = \'X\' 89 # 更新用户信息 90 self.dict_user[self.username]["islocked"] = self.islocked 91 self.update_user() 92 print("输入错误次数过多,账号已锁定,请联系系统管理员!") 93 94 # 将用户的登录尝试次数恢复初始值 0 95 self.trycount = 0 96 97 def login_check(self, password): 98 """ 99 用户登录验证模块,对用户对象进行判断 100 :param password: 输入的密码 101 :return: 102 """ 103 104 details = self.dict_user[self.username] 105 # 账号是否已删除 106 if details["isdel"] == \'\': 107 # 账号是否被锁定 108 if details["islocked"] == \'\': 109 # 账户未锁定,对输入的密码加密并验证 110 password = common.encrypt(password) 111 if details["password"] == password: 112 self.islogin = True 113 self.name = details["name"] 114 self.mobile = details["mobile"] 115 self.islocked = details["islocked"] 116 self.bindcard = details["bindcard"] 117 self.role = details["role"] 118 self.isdel = details["isdel"] 119 self.password = password 120 else: 121 # 密码错误,失败次数+1 122 self.trycount += 1 123 else: 124 # 账户锁定了 125 self.islocked = \'X\' 126 else: 127 # 账户删除了 128 self.isdel = \'X\' 129 130 def user_exists(self): 131 """ 132 判断用户名是否存在,存在返回True, 否则返回False 133 :return: True / False 134 """ 135 if self.username in list(self.dict_user.keys()): 136 return True 137 else: 138 return False 139 140 def update_user(self): 141 """ 142 用户数据更新方法 143 :return: 144 """ 145 user_data = self.dict_user[self.username] 146 sql = """REPLACE INTO userinfos ( 147 username,password,name,mobile,islocked,bindcard,role,isdel) 148 VALUES (\'{0}\',\'{1[0]}\',\'{1[1]}\',{1[2]},\'{1[3]}\',\'{1[4]}\',\'{1[5]}\',\'{1[6]}\')""" 149 exe_sql = sql.format(self.username, tuple(user_data.values())) 150 dbapi.unload_data_to_db(exe_sql) 151 152 def del_user(self): 153 """ 154 删除用户,逻辑删除 155 :return: 156 """ 157 self.isdel = \'X\' 158 self.dict_user[self.username]["isdel"] = self.isdel 159 self.update_user() 160 print("已标记删除!") 161 162 def unlock_user(self): 163 """ 164 账号解锁 165 :return: 166 """ 167 self.islocked = \'\' 168 self.dict_user[self.username]["islocked"] = self.islocked 169 self.update_user() 170 print("已解锁!") 171 172 def modify_password(self): 173 """ 174 用户中心 - 修改密码 175 :return: 176 """ 177 while True: 178 new_password = input("输入新密码: ").strip() 179 confirm_password = input("再次输入确认密码:").strip() 180 if not new_password or not confirm_password: 181 print("密码不能为空,请重新输入!") 182 continue 183 if new_password != confirm_password: 184 print("两次输入密码不一致,请重新输入!") 185 continue 186 break 187 password = common.encrypt(new_password) 188 self.password = password 189 self.dict_user[self.username]["password"] = self.password 190 self.update_user() 191 print("密码修改成功!") 192 193 def modify_user_info(self): 194 """ 195 用户中心 - 修改用户信息 196 :return: 197 """ 198 frmuser = templates.user_info.format( 199 username=self.username, 200 name=self.name, 201 mobile=self.mobile, 202 bindcard=self.bindcard, 203 role=self.role, 204 islocked="是" if self.islocked == \'X\' else "否", 205 isdel="是" if self.isdel == \'X\' else "否" 206 ) 207 # 打印用户信息 208 print(frmuser) 209 210 # 开始修改 211 print("请输入新的资料,若不更新直接回车:") 212 new_name = input("姓名({0}): ".format(self.name)) 213 new_mobile = input("手机({0}): ".format(self.mobile)) 214 self.name = self.name if len(new_name) == 0 else new_name 215 self.mobile = self.mobile if len(new_mobile) == 0 else new_mobile 216 # 输入信用卡卡号 217 while True: 218 new_bindcard = input("绑定卡({0}): ".format(self.bindcard)) 219 if len(new_bindcard) > 0: 220 # 创建一个卡对象 221 cardobj = CreditCard(new_bindcard) 222 if not cardobj.card_is_exists(): 223 print("您输入的卡号不存在!") 224 elif cardobj.owner != self.username: 225 print("您输入的卡号非法,请联系系统管理员!") 226 else: # 卡号有效 227 self.bindcard = new_bindcard 228 break 229 else: 230 break 231 # 更新用户资料 232 self.dict_user[self.username]["name"] = self.name 233 self.dict_user[self.username]["mobile"] = self.mobile 234 self.dict_user[self.username]["bindcard"] = self.bindcard 235 self.update_user() 236 print("用户资料更新成功!") 237 238 def logout(self): 239 """ 240 注销当前用户,将系统各属性置空 241 :return: 242 """ 243 self.islogin = False 244 self.bindcard = "" 245 self.mobile = "" 246 self.name = "" 247 self.password = "" 248 self.username = "" 249 print("已注销!") 250 251 @staticmethod 252 def user_auth(func): 253 """ 254 用户登录验证装饰器, userobj 为登录用户对象,未登录时可以传入一个空对象 255 :param func: 被装饰的函数 256 :return: 257 """ 258 259 def auth_check(self, userobj): 260 # 用户还未登录 261 if not userobj.islogin: 262 print("用户未登录,请先登录系统!") 263 264 # 用户登录 265 userobj.login() 266 # 登录成功则会获取到相应属性值 267 if userobj.islogin: 268 return func(self, userobj) 269 else: 270 print("登录失败,请联系系统管理员!") 271 272 else: 273 return func(self, userobj) 274 275 return auth_check 276 277 def init_user_info(self): 278 """ 279 创建用户,完善用户资料信息 280 :return: 281 """ 282 while True: 283 self.username = input("登录用户名(小写字母):").strip().lower() 284 if not self.username: 285 print("用户名不能为空") 286 elif self.user_exists(): 287 print("该用户名已存在") 288 else: 289 break 290 291 password = common.input_msg("密码:") 292 self.password = common.encrypt(password) 293 self.name = common.input_msg("姓名:") 294 self.mobile = common.input_msg("手机:") 295 self.role = common.input_msg("用户权限(user/admin):", ("admin", "user")) 296 self.create_user() 297 print("用户创建成功!") 298 299 def create_user(self): 300 """ 301 新创建一个用户,将用户数据同步写入到数据库文件 302 :return: 303 """ 304 user_data = ( 305 self.password, self.name, self.mobile, self.islocked, self.bindcard, self.role, self.isdel) 306 sql = """INSERT INTO userinfos ( 307 username,password,name,mobile,islocked,bindcard,role,isdel) 308 VALUES (\'{0}\',\'{1[0]}\',\'{1[1]}\',{1[2]},\'{1[3]}\',\'{1[4]}\',\'{1[5]}\',\'{1[6]}\')""" 309 exe_sql = sql.format(self.username, user_data) 310 dbapi.unload_data_to_db(exe_sql) 311 312 def load_user_info(self): 313 """ 314 根据用户名获取用户信息 315 :return: 用户对象 316 """ 317 if self.user_exists(): 318 user_detail = self.dict_user[self.username] 319 self.name = user_detail["name"] 320 self.mobile = user_detail["mobile"] 321 self.bindcard = user_detail["bindcard"] 322 self.islocked = user_detail["islocked"] 323 self.role = user_detail["role"] 324 self.isdel = user_detail["isdel"] 325 return True 326 else: 327 return False 328 329 def get_date(self): 330 """ 331 用户输入一个时间段,如果显示报表是要提供开始、结束日期,返回开始,结束时间 332 :return: 字典格式,{"start":startdate, "end": enddate} 333 """ 334 startdate = common.input_date( 335 "输入查询开始日期(yyyy-mm-dd)[default:当月1号]: ", date.today().strftime("%Y-%m-01")) 336 enddate = common.input_date( 337 "输入查询结束日期(yyyy-mm-dd)[default: 今天]: ", date.today().strftime("%Y-%m-%d")) 338 return {"start": startdate, "end": enddate} 339 340 def print_bill_history(self): 341 """ 342 个人中心-账单明细 打印模块 343 :return: 344 """ 345 dates = self.get_date() 346 startdate = dates["start"] 347 enddate = dates["end"] 348 # 保存所有账单流水的记录列表,数据为一个字符串 349 msglist = list() 350 # 获取符合条件的账单明细记录 351 recordlist = dbapi.load_bill_report( 352 self.bindcard, startdate, enddate) 353 for record in recordlist: 354 tmpmsg = "{time} {costtype} {cost} {crdno}".format(time=record[0], 355 costtype=record[ 356 1].ljust(10), 357 cost=str( 358 record[2]).ljust(6), 359 crdno=record[3]) 360 msglist.append(tmpmsg) 361 # 填充模板并打印 362 print(templates.report_bill.format(cardno=self.bindcard, 363 startdate=startdate, 364 enddate=enddate, 365 billdetail="\n".join(msglist) 366 )) 367 368 def print_shopping_history(self): 369 """ 370 个人中心 - 购物历史记录打印模块 371 :return: 372 """ 373 date_between = self.get_date() 374 start = date_between["start"] 375 end = date_between["end"] 376 # 通过dbapi获得要查询的记录列表 377 recordlist = dbapi.load_shop_history(self.username, start, end) 378 print(templates.shopping_history.format(username=self.username, 379 startdate=start, 380 enddate=end)) 381 382 if not recordlist: 383 print("无购物记录!") 384 else: 385 for record in recordlist.keys(): 386 # 获取消费信息 387 item = recordlist[record] 388 print("\n流水号:{0} 时间:{1} 消费金额:{2}\n".format(record, 389 item["time"], 390 item["cost"])) 391 392 print("|{0}|{1}|{2}|".format( 393 \'商品编号\'.center(10), \'商品名称\'.center(30), \'商品价格(RMB)\'.center(10))) 394 print(\'-\' * 100) 395 396 for rec in item[\'detail\']: 397 item = rec[0] 398 name = rec[1] 399 price = rec[2] 400 print(\'|{0}|{1}|{2}|\'.format( 401 item.center(10), name.strip().ljust(30), price))
4.3购物类文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月4日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 购物类模块 9 """ 10 from datetime import datetime 11 from models import common 12 from dbhelper import dbapi 13 from models.user import Users 14 from models.creditcard import CreditCard 15 16 17 class Shopping(object): 18 """ 19 购物类,包含购物相关所有属性及方法 20 """ 21 22 def __init__(self): 23 # 所有商品信息 24 self.shop_market = {} 25 # 购物车列表 26 self.shopping_cart = [] 27 # 购物总费用 28 self.shopping_cost = 0 29 30 self.database = \'shopitems\' 31 self.get_shop_market() 32 33 def get_shop_market(self): 34 """ 35 获取购物商城所有商品信息,存入类字段(shop_market) 36 :return: 37 """ 38 self.shop_market.clear() 39 item_data = dbapi.load_data_from_db(self.database) 40 for item in item_data: 41 itemid = item[\'item\'] 42 del item[\'item\'] 43 self.shop_market[itemid] = item 44 # print(self.shop_market) 45 46 def buy_shopping(self): 47 """ 48 购物函数 49 :return: 50 """ 51 choose_flag = True 52 while choose_flag: 53 # 显示所有商品列表 54 self.print_goods_list() 55 goods_id = input("\n选择商品编号,加入购物车(q返回上一级): ").strip().lower() 56 if not goods_id: 57 continue 58 # 返回上一级 59 if goods_id == "q": 60 choose_flag = False 61 continue 62 63 # 将选择商品加入购物车 64 result = self.add_shopping_cart(goods_id) 65 if result: 66 # 添加成功,显示购物车所有商品信息 67 self.print_shopping_list() 68 print("\n已将商品加入购物车!") 69 # 是否继续添加 70 while True: 71 donext = input("继续购物(y) or 返回上一级(q):").strip().lower() 72 if donext == "y": 73 break 74 elif donext == "q": 75 choose_flag = False 76 break 77 else: 78 continue 79 else: 80 # 添加购物车失败 81 print("添加购物车失败,请检查输入商品编号是否正确!") 82 continue 83 84 def print_goods_list(self): 85 """ 86 将商品列表中的商品信息输出到屏幕 87 :return: 88 """ 89 print("|{0}|{1}|{2}|".format( 90 \'商品编号\'.center(10), \'商品名称\'.center(30), \'商品价格(RMB)\'.center(10))) 91 print(\'-\' * 100) 92 93 for item in self.shop_market.keys(): 94 name = self.shop_market[item][\'name\'] 95 price = self.shop_market[item][\'price\'] 96 print(\'|{0}|{1}|{2}|\'.format( 97 item.center(10), name.strip().ljust(30), price)) 98 99 def add_shopping_cart(self, goodsid): 100 """ 101 根据用户输入的商品编号,将商品编号加入购物车,如果商品编号不存在返回False,添加成功返回True 102 :param goodsid: 商品编号 103 :return: 成功 True / 失败 False 104 """ 105 if goodsid in self.shop_market.keys(): 106 self.shopping_cart.append(goodsid) 107 self.shopping_cost += self.shop_market[goodsid][\'price\'] 108 return True 109 else: 110 return False 111 112 def print_shopping_list(self): 113 """ 114 将购物车中的商品信息输出到屏幕 115 :return: 116 """ 117 print("|{0}|{1}|{2}|".format( 118 \'商品编号\'.center(10), \'商品名称\'.center(30), \'商品价格(RMB)\'.center(10))) 119 print(\'-\' * 100) 120 121 for item in self.shopping_cart: 122 name = self.shop_market[item][\'name\'] 123 price = self.shop_market[item][\'price\'] 124 print(\'|{0}|{1}|{2}|\'.format( 125 item.center(10), name.strip().ljust(30), price)) 126 127 def print_shopping_cart(self): 128 """ 129 查看购物车中的商品信息 130 :return: 131 """ 132 self.print_shopping_list() 133 print("当前购物车共有 {0} 件商品,合计 {1} 元 !".format(len(self.shopping_cart), 134 self.shopping_cost)) 135 136 @Users.user_auth 137 def payfor_shopcart(self, userobj): 138 """ 139 购物车结算模块,功能包括:购物车付款、购物记录保存 140 :param userobj:用户对象 141 :return: 142 """ 143 # 判断用户是否绑定信用卡 144 if not userobj.bindcard: 145 # 用户没有绑定信用卡,直接返回错误,在外层绑卡 146 print("用户没有绑定信用卡!") 147 else: 148 # 用户绑定了信用卡了, 获取信用卡信息(实例化对象) 149 cardobj = CreditCard(userobj.bindcard) 150 # 卡余额够吗 151 if cardobj.credit_balance < self.shopping_cost: 152 print("您的信用卡本月额度不够! ") 153 else: 154 # 生成一个流水号 155 serno = common.create_serialno() 156 # 调用卡的支付模块进行支付 157 cardobj.card_pay(self.shopping_cost, 1, serno) 158 159 # 记录购物流水 160 self.record_shopping( 161 serno, userobj.username, self.shopping_cart) 162 # 购物结算完成后将对象的购物车清空, 购物车商品总价清0 163 self.shopping_cart.clear() 164 self.shopping_cost = 0 165 print("结算成功!") 166 167 def record_shopping(self, serno, username, shopping_cart): 168 """ 169 记录购物流水 170 :param serno:流水号 171 :param username:用户名 172 :param shopping_cart:购物车对象 173 :return: 174 """ 175 for item in shopping_cart: 176 name = self.shop_market[item][\'name\'] 177 price = self.shop_market[item][\'price\'] 178 sql = """INSERT INTO shoppings ( 179 serialno,username,datetime,item,name,price) 180 VALUES (\'{0}\',\'{1}\',\'{2}\',{3},\'{4}\',\'{5}\')""" 181 date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 182 exe_sql = sql.format( 183 serno, username, date_time, item, name, price) 184 dbapi.unload_data_to_db(exe_sql)
4.4信用卡类文件
1 # coding:utf-8 2 \'\'\' 3 Created on 2020年5月2日 4 5 @author: 00004854c 6 \'\'\' 7 """ 8 信用卡类模块 9 """ 10 from datetime import datetime 11 from models import common 12 from dbhelper import dbapi 13 from conf import settings, templates, errorcodes 14 15 16 class CreditCard(object): 17 """ 18 信用卡类,包含信用卡所有属性及相关方法 19 """ 20 21 def __init__(self, cardno): 22 # 信用卡卡号 23 self.cardno = cardno 24 # 信用卡密码 25 self.password = "" 26 # 信用卡额度 27 self.credit_total = settings.CREDIT_TOTAL 28 # 信用卡透支余额 29 self.credit_balance = settings.CREDIT_TOTAL 30 # 卡所有者 31 self.owner = "" 32 # 信用卡状态(是否冻结) 33 self.frozenstatus = \'\' 34 35 # 信用卡日息 36 self.dayrate = settings.EXPIRE_DAY_RATE 37 # 提现手续费率 38 self.feerate = settings.FETCH_MONEY_RATE 39 40 self.database = \'creditcards\' 41 # 所有信用卡数据 42 self.credit_card = {} 43 self.get_card_info() 44 45 def get_card_info(self): 46 """ 47 加载所有信用卡信息 48 :return: 49 """ 50 self.credit_card.clear() 51 card_data = dbapi.load_data_from_db(self.database) 52 for card in card_data: 53 cardno = card[\'cardno\'] 54 del card[\'cardno\'] 55 self.credit_card[cardno] = card 56 if self.card_is_exists(): 57 currcard = self.credit_card[self.cardno] 58 self.password = currcard[\'password\'] 59 self.credit_total = currcard[\'credit_total\'] 60 self.credit_balance = currcard[\'credit_balance\'] 61 self.owner = currcard[\'owner\'] 62 self.frozenstatus = currcard[\'frozenstatus\'] 63 64 def print_creditcart(self): 65 """ 66 显示信用卡信息 67 """ 68 print(templates.card_info.format(cardno=self.cardno, 69 owner=self.owner, 70 total=self.credit_total, 71 balance=self.credit_balance, 72 status="正常" if self.frozenstatus == \'\' else "冻结" 73 )) 74 75 def withdraw_money(self): 76 """ 77 提现 78 """ 79 if self.frozenstatus == \'X\': 80 print("卡已冻结,请联系系统管理员!") 81 else: 82 print("信用卡提现将收取 {0}% 的手续费!".format( 83 settings.FETCH_MONEY_RATE * 100)) 84 while True: 85 cost = common.input_msg("请输入要提现的金额(q返回):") 86 if cost == "q": 87 break 88 try: 89 cost = float(cost) 90 except: 91 print("输入错误!") 92 continue 93 cardpasswd = common.input_msg("请输入信用卡密码:") 94 # 执行提现操作 95 totalfee = cost + cost * self.feerate 96 check_result = self.pay_check(totalfee, cardpasswd) 97 if check_result == errorcodes.NO_ERROR: 98 # 扣取提现金额并写入数据库,生成账单 99 self.card_pay(cost, 3, common.create_serialno()) 100 # 扣取手续费并写入数据库, 生成账单 101 self.card_pay( 102 cost * self.feerate, 4, common.create_serialno()) 103 print("已完成提现!") 104 break 105 elif check_result == errorcodes.BALANCE_NOT_ENOUGHT: 106 print("信用卡可透支余额不足!") 107 elif check_result == errorcodes.CARD_PASS_ERROR: 108 print("信用卡密码错误!") 109 110 def payback_money(self): 111 """ 112 还款 113 """ 114 while True: 115 if self.credit_balance == self.credit_total: 116 print("无需还款!") 117 break 118 119 pay_fee = common.input_msg("请输入还款金额:") 120 try: 121 pay_fee = float(pay_fee) 122 except: 123 print("输入错误!") 124 continue 125 need_pay = self.credit_total - self.credit_balance 126 if pay_fee > need_pay: 127 print("输入金额超过应还金额!") 128 break 129 130 # 更新已还款金额 = 现在还的金额 + 已经还的金额 131 self.credit_balance += pay_fee 132 # 还款成功 133 print("还款成功") 134 # 是否继续 135 iscontinue = common.input_msg( 136 "继续还款吗(y/n)?", ("y", "n")) 137 if iscontinue == "n" and self.credit_balance != self.credit_total: 138 print("您尚未全部还款,请在还款日前尽快还款!") 139 break 140 141 def transfer_money(self): 142 """ 143 转账 144 """ 145 if self.frozenstatus == 1: 146 print("此卡已冻结,请联系客服!") 147 else: 148 print("信用卡转账将收取 {0}% 的手续费!".format( 149 settings.FETCH_MONEY_RATE * 100), "NOTICE") 150 while True: 151 trans_cardno = common.input_msg("请输入要转账的卡号(q返回):") 152 if trans_cardno == "q": 153 break 154 155 if trans_cardno.isnumeric(): 156 # 生成一个卡对象, 验证卡号是否存在 157 trans_cardobj = CreditCard(trans_cardno) 158 159 # 卡号不存在返回主菜单 160 if not trans_cardobj.card_is_exists: 161 print("卡号不存在,请确认!", "ERROR") 162 break 163 164 # 卡号存在 165 while True: 166 trans_cost = common.input_msg("请输入要转账的金额: ") 167 try: 168 trans_cost = float(trans_cost) 169 break 170 except: 171 print("输入错误!") 172 continue 173 comfirm = common.input_msg("确定要给卡号 {0} 转入人民币 {1} 元吗(y/n)?".format(trans_cardobj.cardno, 174 trans_cost), ("y", "n")) 175 if comfirm == "y": 176 cardpasswd = common.input_msg("请输入信用卡密码:") 177 178 # 执行转账操作 179 totalfee = trans_cost + trans_cost * self.feerate 180 check_result = self.pay_check(totalfee, cardpasswd) 181 if check_result == errorcodes.NO_ERROR: 182 # 先扣款,生成消费流水账单 183 self.card_pay( 184 trans_cost, 2, common.create_serialno()) 185 # 扣手续费, 生成消费流水账单 186 self.card_pay( 187 trans_cost * self.feerate, 4, common.create_serialno()) 188 # 给对方卡充值,并写入数据库文件 189 trans_cardobj.credit_balance += trans_cost 190 trans_cardobj.update_card() 191 print("转账完成!") 192 break 193 elif check_result == errorcodes.BALANCE_NOT_ENOUGHT: 194 print("信用卡可透支余额不足!") 195 elif check_result == errorcodes.CARD_PASS_ERROR: 196 print("信用卡密码错误!") 197 else: 198 print("输入错误!", "ERROR") 199 200 def card_is_exists(self): 201 """ 202 判断信用卡是否存在,存在返回True, 否则返回False 203 :return: True / False 204 """ 205 if self.cardno in list(self.credit_card.keys()): 206 return True 207 else: 208 return False 209 210 def update_card(self): 211 """ 212 信用卡数据更新方法 213 :return: 214 """ 215 card_data = self.credit_card[self.cardno] 216 sql = """REPLACE INTO creditcards ( 217 cardno,password,credit_total,credit_balance,owner,frozenstatus) 218 VALUES (\'{0}\',\'{1[0]}\',{1[1]},{1[2]},\'{1[3]}\',\'{1[4]}\')""" 219 exe_sql = sql.format(self.cardno, tuple(card_data.values())) 220 dbapi.unload_data_to_db(exe_sql) 221 222 def card_pay(self, cost, paytype, sereialno): 223 """ 224 信用卡支付,从信用卡可透支余额中扣费 225 :param sereialno: 流水号 226 :param cost: 消费金额 float类型 227 :param paytype: 消费类型 int类型 ( 1:消费、2:转账、3:提现、4:手续费 ) 对于2,3类型的支付要扣手续费,单记录一条流水单 228 :return: 229 """ 230 if paytype == 1: 231 payfor = "消费" 232 elif paytype == 2: 233 payfor = "转账" 234 elif paytype == 3: 235 payfor = "提现" 236 elif paytype == 4: 237 payfor = "手续费" 238 else: 239 payfor = "未知" 240 241 # 支付扣款 242 self.credit_balance -= cost 243 self.credit_card[self.cardno][\'credit_balance\'] = self.credit_balance 244 self.update_card() 245 246 # 记录消费流水对账单 247 self.record_statement(sereialno, payfor, cost) 248 249 def record_statement(self, serno, payfor, cost): 250 """ 251 记录对账单 252 :param serno:流水号 253 :param payfor:消费类型 254 :param cost:消费金额 255 :return: 256 """ 257 sql = """INSERT INTO statements ( 258 serialno,cardno,datetime,payfor,cost) 259 VALUES (\'{0}\',\'{1}\',\'{2}\',\'{3}\',{4})""" 260 date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 261 exe_sql = sql.format( 262 serno, self.cardno, date_time, payfor, cost) 263 dbapi.unload_data_to_db(exe_sql) 264 265 def pay_check(self, cost, password): 266 """ 267 转账、提现时验证操作,判断卡的余额与支付密码是否正确。并返回错误类型码 268 :param cost: 转账、提现金额(包含手续费) 269 :param password: 支付密码 270 :return: 错误码 271 """ 272 totalfee = cost 273 if common.encrypt(password) != self.password: 274 return errorcodes.CARD_PASS_ERROR 275 elif totalfee > self.credit_balance: 276 return errorcodes.BALANCE_NOT_ENOUGHT 277 else: 278 return errorcodes.NO_ERROR 279 280 def create_card(self): 281 """ 282 新发行一张信用卡 283 :return: 284 """ 285 card_data = (self.password, self.credit_total, 286 self.credit_balance, self.owner, self.frozenstatus) 287 sql = """INSERT INTO creditcards ( 288 cardno,password,credit_total,credit_balance,owner,frozenstatus) 289 VALUES (\'{0}\',\'{1[0]}\',{1[1]},{1[2]},\'{1[3]}\',\'{1[4]}\')""" 290 exe_sql = sql.format(self.cardno, card_data) 291 dbapi.unload_data_to_db(exe_sql)
再次声明,参考博客地址 https://www.cnblogs.com/wushank/p/5248916.html,表示感谢。