Python之信用卡模拟程序 - 流年似水zlw

时间:2024-04-17 10:20:40

Python之信用卡模拟程序

最近在自学Python,出于练手目的,写了一个信用卡模拟程序,包括用户登录、购物商城、信用卡中心、后台管理等功能。

整体需求如下:

  1. 额度 10000或自定义
  2. 实现用户登录和锁定
  3. 实现购物商城,加入购物车,调用信用卡接口结账等
  4. 可以提现,手续费5%
  5. 支持账户间转账
  6. 提供还款接口
  7. 记录日常消费流水
  8. 记录信用卡操作日志
  9. 可以查看账单和购物历史记录
  10. 每月25号出账单(暂未实现)
  11. 提供后台管理接口,包括添加账户,删除账户,冻结账户,发行信用卡,冻结信用卡等

参考博客地址: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)
credit_main.py

 

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        # 信用卡密码错误
errorcodes.py

  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
settings.py

  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 \'\'\'
templates.py

 

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()
initdb.py

  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
dbapi.py

 

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")
common.py

  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))
user.py

  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)
shopping.py

  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)
creditcard.py

 

再次声明,参考博客地址 https://www.cnblogs.com/wushank/p/5248916.html,表示感谢。