Python购物流程结合ATM接口实现

2024-06-08 22:32

本文主要是介绍Python购物流程结合ATM接口实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

ATM购物作业要求:

  • 额度15000¥或自定义
  • 实现购物商城,买东西加入购物车,调用信用卡接口结账
  • 可以提现,手续费5%
  • 每月22号出账单,每月10号为还款日,过期未还,按欠款总额的万分之5,每日计息
  • 支持多账户登录
  • 支持账户间转账
  • 记录每月日常消费流水记录
  • 提供还款接口
  • ATM记录操作日志
  • 提供管理接口,包括添加账户、用户额度、冻结账户等

程序要求:
分级目录,包含以下文件夹:

  • bin可执行文件
    - atm.py start启动进入
    - shopping.py 购物程序
    - 要求每个程序块不超过10行

  • config 配置文件
    -user_db数据库
    -log_format日志格式化

  • modules/core/lib核心文件(不依赖其他文件,可通用的.py)
    -提供的接口文件

  • src连接文件(所有的业务逻辑代码)
    -代码逻辑的实现模块

  • log日志输出保存文件夹

  • db数据库保存文件夹

文件目录

在ATM总文件夹下,建立bin、config、db、lib、src文件夹,如下图:
这里写图片描述

如何在不同文件夹下调用其他文件的py程序呢?

这里写图片描述

利用如下代码增加路径,并且位置有讲究:

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(_file_))))#增加当前绝对路径

放错位置的sys.path.append:
这里写图片描述

调整sys.path.append上下位置后,可顺利执行:
这里写图片描述
还包括了“F:\My_PyCharm_Code”路径

bin文件

admin.py

只用于管理员的登录管理程序:
1、创建账户
2、删除账户
3、冻结账户
4、查询账户
5、添加管理员账户

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'import os
import sys
path_dir = sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))#增加当前绝对路径
for item in sys.path:print(item)
from src import admin as src_admin
if __name__ == "__main__":src_admin.run()

client.py

只用于普通账户的
1、账户信息
2、还款
3、取款
4、转账
5、账单

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import sys
import ossys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src import client as src_clientif __name__ == "__main__":src_client.run()

crontab.py

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
from src import crontab as src_crontabif __name__ == "__main__":src_crontab.run()

config文件

settings.py

这里存放了管理员的数据库db路径和普通用户成员的数据库路径:

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'import osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))ADMIN_DIR_FOLDER = os.path.join(BASE_DIR,'db','admin')USER_DIR_FOLDER = os.path.join(BASE_DIR,'db','userinfo')

探讨os模块的作用:

如果少写一个os.path.dirname的情况:
就是所在py文件路径

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import osBASE_DIR = os.path.dirname(os.path.abspath(__file__))
# USER_DIR_FOLDER = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR,"db","admin")))
print(BASE_DIR)

这里写图片描述

如果加上os.path.dirname的情况,会将上一级路径添上:

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# USER_DIR_FOLDER = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR,"db","admin")))
print(BASE_DIR)

这里写图片描述

如果加上os.path.join的情况,会将路径相拼接:

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
USER_DIR_FOLDER = os.path.join(BASE_DIR,"db","admin")
print(USER_DIR_FOLDER)

这里写图片描述

os.path.dirname的情况:
与以上os.path.join的区别
os.path.exists用于判断路径是否存在:

if not os.path.exists(os.path.join(settings.ADMIN_DIR_FOLDER,username)):
print("用户名不存在")

避免“FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。”的错误!

os.walk用于读取路径文件夹和文件:
它是遍历文件夹下所有的文件:
其中

  1. root表示string,代表目录的路径;
  2. sub_folders表示list,包含了当前dirpath路径下所有的子目录名字(不包含目录路径);
  3. files表示list,包含了当前dirpath路径下所有的非目录子文件的名字(不包含目录路径);
print("有以下管理员:")for root, sub_folders, files in os.walk(settings.ADMIN_DIR_FOLDER):print(files)

这里写图片描述

注意,sub_folders和 files均不包含路径信息,如需完整路径,可使用os.path.join(root, sub_folders)

# image directoriesfor name in files:images.append(os.path.join(root, name))# get 10 sub-folder namesfor name in sub_folders:temp.append(os.path.join(root, name))

os.listdir()用于读取仅当前路径下的文件名:
os.listdir()函数得到的是仅当前路径下的文件名,不包括子目录中的文件,所以需要使用递归的方法得到全部文件名。

# -*- coding: utf-8 -*-
import osdef listdir(path, list_name):for file in os.listdir(path):file_path = os.path.join(path, file)if os.path.isdir(file_path):listdir(file_path, list_name)elif os.path.splitext(file_path)[1]=='.jpeg':list_name.append(file_path)

本例:

 print("有以下账户:")for sub_folders in os.listdir(settings.USER_DIR_FOLDER):print(sub_folders)

这里写图片描述

lib文件

commons.py

用于密文的设置,md5加密:

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import hashlibdef md5(arg):"""md5加密:param arg::return:"""obj = hashlib.md5()obj.update(bytes(arg,encoding='utf-8'))#转为字节return obj.hexdigest()def check_paypasswd(CURRENT_USER_INFO,paypasswd):if md5(paypasswd) == CURRENT_USER_INFO['pay_passwd']:return Trueelse:print("支付密码错误!")return False

密文的读取与判断:

user_dict = json.load(open(os.path.join(settings.ADMIN_DIR_FOLDER,username),'r'))
if username == user_dict['username'] and commons.md5(password)==user_dict['password']:CURRENT_USER_INFO['is_authenticated']=TrueCURRENT_USER_INFO['current_user'] = usernamereturn True

src文件

backend文件logger.py

# _*_coding:utf-8_*_
__author__ = 'Alex_XT'
import logging
import os
from config import settingsdef get_logger(card_num, struct_time):if struct_time.tm_mday < 23:file_name = "%s_%s_%d" % (struct_time.tm_year, struct_time.tm_mon, 22)#2017_9_22else:file_name = "%s_%s_%d" % (struct_time.tm_year, struct_time.tm_mon + 1, 22)#2017_10_22file_handler = logging.FileHandler(os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),encoding='utf-8'#用于中文编码输出)fmt = logging.Formatter(fmt="%(asctime)s:  %(name)s:  %(message)s")file_handler.setFormatter(fmt)logger1 = logging.Logger('user_logger', level=logging.INFO)logger1.addHandler(file_handler)return logger1

admin.py

# _*_coding:utf-8_*_
__author__ = 'Alex_XT'import os
import json
from lib import commons
from config import settingsCURRENT_USER_INFO = {'is_authenticated': False, 'current_user': None}def init():"""初始化管理员信息:return:"""dic = {'username': 'Alex', 'password': commons.md5('123')}# 以dic['username']名字命名文件json.dump(dic, open(os.path.join(settings.ADMIN_DIR_FOLDER, dic['username']), 'w', encoding='utf-8'))def create_user():"""创建账户:return:"""card_num = input("请输入新卡号:").strip()# card_num = "6222040209028810"# 创建目录:在card_num下创建#                   'record'#                   "basic_info.json"if not os.path.exists(os.path.join(settings.USER_DIR_FOLDER, card_num, 'record')):os.makedirs(os.path.join(settings.USER_DIR_FOLDER, card_num, 'record'))else:print("该账户已存在!继续执行,信息会被覆盖!!!")base_info = {'username': input("username:"),  # 'Tim','card': card_num,'password': commons.md5(input("password:")),  # '123''pay_passwd': commons.md5(input("pay_passwd:")),  # '123'"credit": 15000,  # 信用卡额度"balance": 15000,  # 本月可用额度"saving": 0,  # 储蓄金额"enroll_date": "2016-01-01","expire_date": "2021-01-01",'status': 0,  # 0 = normal,1 = locked, 2 = disabled"debt": [],  # 欠款记录,如:# [{'date':"2015-04-10","total_debt":80000,"balance_debt":5000},{'date':"2015-05-10","total_debt":80000,"balance_debt":5000}]}json.dump(base_info, open(os.path.join(settings.USER_DIR_FOLDER, card_num, "basic_info.json"), 'w'))print("创建成功!")def remove_user():"""移除用户:return:"""passdef locked_user():"""冻结账户:return:"""passdef search():"""搜索用户:return:"""search_obj = input("1、管理员信息\n2、普通用户信息\n信息查询序号>>:")if search_obj == "1":print("有以下管理员:")for root, sub_folders, files in os.walk(settings.ADMIN_DIR_FOLDER):print(files)info_obj = input("要查询的名字:")if not os.path.exists(os.path.join(settings.ADMIN_DIR_FOLDER,info_obj)):print("管理员名字写错了!")else:dic = json.load(open(os.path.join(settings.ADMIN_DIR_FOLDER,info_obj),'r'))print(dic)else:print("有以下账户:")for sub_folders in os.listdir(settings.USER_DIR_FOLDER):print(sub_folders)info_obj = input("要查询的账户:")if not os.path.exists(os.path.join(settings.USER_DIR_FOLDER,info_obj)):print("账户号写错了!")else:basic_info = json.load(open(os.path.join(settings.USER_DIR_FOLDER,info_obj,"basic_info.json"),'r'))print(basic_info)def add_admin():dic = {"username": input("新增管理员名字:"),"password": commons.md5(input("管理员密码:"))}if not os.path.exists(os.path.join(settings.ADMIN_DIR_FOLDER, dic['username'])):print("该管理员账户可用!")json.dump(dic, open(os.path.join(settings.ADMIN_DIR_FOLDER, dic['username']), 'w', encoding='utf-8'))else:print("该管理员已存在!请重新添加!")def main():menu = """1、创建账户2、删除账户3、冻结账户4、查询账户5、添加管理员账户"""print(menu)menu_dic = {'1': create_user,'2': remove_user,'3': locked_user,'4': search,'5': add_admin,}while True:user_option = input("请选择菜单序号>>:").strip()if user_option in menu_dic:menu_dic[user_option]()else:print("没有该选项!")def login():"""用户登录:return:"""while True:username = input("请输入用户名:")password = input("请输入密码:")if not os.path.exists(os.path.join(settings.ADMIN_DIR_FOLDER, username)):print("用户名不存在")else:user_dict = json.load(open(os.path.join(settings.ADMIN_DIR_FOLDER, username), 'r'))if username == user_dict['username'] and commons.md5(password) == user_dict['password']:CURRENT_USER_INFO['is_authenticated'] = TrueCURRENT_USER_INFO['current_user'] = usernamereturn Trueelse:print("密码错误!")def run():init()ret = login()if ret:main()

client.py

# _*_coding:utf-8_*_
__author__ = 'Alex_XT'
import os
import time
import json
from lib import commons
from config import settings
from src.backend import loggerCURRENT_USER_INFO = {}def dump_current_user_info():json.dump(CURRENT_USER_INFO,open(os.path.join(settings.USER_DIR_FOLDER, CURRENT_USER_INFO['card'], "basic_info.json"), 'w'))def write_record(message):"""账户记录:param message::return:"""struct_time = time.localtime()logger_obj = logger.get_logger(CURRENT_USER_INFO['card'], struct_time)logger_obj.info(message)def account_info():"""账户信息:return:"""print(CURRENT_USER_INFO)def repay():"""还款:return:"""passdef withdraw():"""提现提现时,优先从自己余额中拿,如果余额不足,则使用信用卡(额度限制),提现需要手续费5%:return:"""num = float(input("请输入提现金额>>:"))if CURRENT_USER_INFO['saving'] >= num:CURRENT_USER_INFO['saving'] -= numwrite_record('%s - 储蓄账户:%d ' % ('提现', num))dump_current_user_info()else:temp = num - CURRENT_USER_INFO['saving']if CURRENT_USER_INFO['balance'] > (temp + temp * 0.05):CURRENT_USER_INFO['balance'] -= tempCURRENT_USER_INFO['balance'] -= temp * 0.05write_record('%s - 储蓄账户:%f  信用卡账户:%f  手续费:%f' % ('提现', CURRENT_USER_INFO['saving'], temp, temp * 0.05))else:print("账户余额不足,无法完成体现!")def transfer():"""转账:return:"""passdef print_bil():passdef go_shopping():Product_List = [("Air Conditioner",50000),("Mac", 12000),("Apple", 5800), ("Bike", 800), ("Python", 80),  ("NoteBook", 10)]  # 使用了元组Current_List = []while True:print("---index      product     price---")for index, item in enumerate(Product_List):print("{}{}{}{}{}{}$".format(" " * 3, index, " " * 10, item[0], " " * 9, item[1]))print("\033[31;1m 按q退出购物\033[0m")choose_item = input("Choose index: ")if choose_item.isdigit():choose_item = int(choose_item)if (choose_item < len(Product_List)) and (choose_item >= 0):Current_pro = Product_List[choose_item]if Current_pro[1] < CURRENT_USER_INFO['saving']:CURRENT_USER_INFO['saving'] -= Current_pro[1]Current_List.append(Current_pro)print(" Your Current List:%s   Saving is: %s Balance is: \033[31;1m %s \033[0m" % (Current_List, CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))write_record('%s - 储蓄账户:%f ' % ('消费', Current_pro[1]))dump_current_user_info()elif Current_pro[1] < CURRENT_USER_INFO['balance']:print("\033[43;1m Your saving money is not enough!!!  %s\033[0m" % CURRENT_USER_INFO['saving'])Current_List.append(Current_pro)print(" Your Current List:%s   Saving is: %s Balance is: \033[31;1m %s \033[0m" % (Current_List, CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))choose_pay = input("请选择付款方式:\n1、储蓄余额+信用卡;\n2、只信用卡;")if choose_pay == "1":paypasswd = input("你选择了另外支付用信用卡消费,请输入支付密码:")temp = Current_pro[1] - CURRENT_USER_INFO['saving']if commons.check_paypasswd(CURRENT_USER_INFO,paypasswd) and CURRENT_USER_INFO['balance'] > (temp):CURRENT_USER_INFO['balance'] -= tempmessage = '%s - 储蓄账户:%f - 信用卡支付:%f' % ('消费', CURRENT_USER_INFO['saving'], temp)write_record(message)CURRENT_USER_INFO['saving'] = 0dump_current_user_info()print(" Your Current List:%s   Saving is: %s Balance is: \033[31;1m %s \033[0m" % (Current_List, CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))print(message)elif choose_pay == "2":paypasswd = input("你只选择了信用卡消费,请输入支付密码:")if commons.check_paypasswd(CURRENT_USER_INFO,paypasswd) and CURRENT_USER_INFO['balance'] > (Current_pro[1]):CURRENT_USER_INFO['balance'] -= Current_pro[1]message = '%s - 信用卡支付:%f' % ('消费', Current_pro[1])write_record(message)dump_current_user_info()print(" Your Current List:%s   Saving is: %s Balance is: \033[31;1m %s \033[0m" % (Current_List, CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))print(message)else:print("余额不足,请退出!!!")else:print("\033[41;1m Invalid index! Continue... \033[0m")continueelif choose_item == "q":print("-------Your List-------")for item in Current_List:print(item[0], "--->>", item[1])# exit("Final saving is: \033[31;1m %s \033[0m  ,final balance is: %s" % (#     CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))print("Final saving is: \033[31;1m %s \033[0m  ,final balance is: %s" % (CURRENT_USER_INFO['saving'], CURRENT_USER_INFO['balance']))breakelse:print("\033[41;1m Wrong Command! Continue...\033[0m")continuedef main():menu = '''1、账户信息2、还款3、取款/提现4、转账5、账单6、购物'''menu_dic = {'1': account_info,'2': repay,'3': withdraw,'4': transfer,'5': print_bil,'6': go_shopping,}while True:print(menu)user_option = input("选择菜单序号>>:").strip()if user_option in menu_dic:menu_dic[user_option]()else:print("该选项不存在!")def init(basic_info):CURRENT_USER_INFO.update(basic_info)def login():"""登录:return:"""while True:card_num = input("卡号:")  # "6222040209028810"if not os.path.exists(os.path.join(settings.USER_DIR_FOLDER, card_num)):print("卡号不存在!")else:password = input("请输入密码:")basic_info = json.load(open(os.path.join(settings.USER_DIR_FOLDER, card_num, "basic_info.json"), 'r'))if basic_info['password'] == commons.md5(password):init(basic_info)print("登录成功!")return Trueelse:print("密码错误!")def run():ret = login()if ret:main()

crontab.py

#_*_coding:utf-8_*_
__author__ = 'Alex_XT'
import os
import json
import timefrom config import settings
from src.backend import loggerdef main():card_list = os.listdir(settings.USER_DIR_FOLDER)for card in card_list:basic_info = json.load(open(os.path.join(settings.USER_DIR_FOLDER,card,'basic_info.json')))struct_time = time.localtime()#循环账单列表,为每月的欠款计息,并写入到当月账单中for item in basic_info['debt']:interest = item['total_debt']*0.0005if basic_info['saving']>=interest:basic_info['saving']-=interestelse:temp = interest-basic_info['saving']basic_info['balance']-=templogger_obj = logger.get_logger(card,struct_time)logger_obj.info("欠款利息 - %f - 备注:未还款日期%s;共欠款%f,未还款%f" % (interest, item['date'], item['total_debt'], item['balance_debt']))json.dump(basic_info,open(os.path.join(settings.USER_DIR_FOLDER, basic_info['card'], "basic_info.json"), 'w'))# 如果当前等于10号(9号之前)#   当前余额为负值,则将值添加到账单列表中,开始计息,同时,本月可用额度恢复。if struct_time.tm_mday == 11 and basic_info['credit']>basic_info['balance']:date = time.struct_time("%Y-%m-%d")dic = {"date":date,"total_debt":basic_info['credit']-basic_info['balance'],"balance_debt":basic_info['credit']-basic_info['balance'],}basic_info['debt'].append(dic)#恢复可用额度basic_info['balance']=basic_info['credit']json.dump(basic_info,open(os.path.join(settings.USER_DIR_FOLDER,basic_info['card'],"basic_info.json"),'w'))def run():main()

实现效果

管理员

这里写图片描述

普通用户

登录
这里写图片描述
提现
这里写图片描述
购物
这里写图片描述

付款
这里写图片描述
退出
这里写图片描述
流水账信息
这里写图片描述

代码下载

代码下载链接地址

参考

【1】python实现购物车程序 - 快递小可的博客 - CSDN博客
http://blog.csdn.net/sxingming/article/details/52334488
【2】Python获取指定文件夹下的文件名 - CSDN博客
http://blog.csdn.net/lsq2902101015/article/details/51305825

这篇关于Python购物流程结合ATM接口实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1043495

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3