ATM carrito arquitectura de tres niveles +

artículos carrito ATM

ATM + simulación para lograr un programa de centro comercial.

El programa implementa un registro de inicio de sesión normal de usuario, pago de prepago en efectivo y otras funciones, y es compatible con la función del centro comercial en línea.

Cuando el saldo de la cuenta es suficiente para pagar el precio de las materias primas, el pago de débito, el saldo es insuficiente, no puede pagar, tienda de mercancía de compra personal de compras.

Si el usuario dispone de funciones de administrador, también es compatible con el inicio de sesión del administrador. Ver las necesidades específicas de las necesidades de algunos de los proyectos.


la arquitectura de tres niveles

El desarrollo del proyecto, la claridad del diseño es muy importante. Su importancia se refleja en al menos tres aspectos: una estructura clara, mantenibilidad, alta escalabilidad.

diseño común estructura del proyecto, de tres niveles de diseño de arquitectura es muy práctico. Este modo de diseño de arquitectura de todo el programa se divide en tres capas:

  • Vista de usuario de la capa: la interacción del usuario, el usuario puede aceptar datos de entrada, un mensaje de la pantalla.
  • Lógicos capa de interfaz: parámetros de recepción pasa sobre la capa de vista, a ser tratados de acuerdo con el nivel lógico determinar llamada de datos y devuelve un resultado a la capa de vista del usuario.
  • capa de tratamiento de datos: recibir parámetros pasados ​​sobre la capa de interfaz, supresiones hacer el cambio de datos de búsqueda.
# 优点:结构清晰,职责明了。扩展性强,好维护。对数据比较安全。
# 缺点:每个功能都要跨越逻辑接口层,不能直接访问数据库,所以效率会降下来。


Los requisitos del proyecto

1.额度15000或自定义     -->  注册功能
2.实现购物商城,买东西加入购物车,调用信用卡接口结账  --> 购物功能、支付功能
3.可以提现,手续费5%   --> 提现功能
4.支持多账户登录  --> 登录功能,登录失败三次冻结账户
5.支持账户间转账  --> 转账功能
6.记录日常消费 -->  记录流水功能
7.提供还款接口 -->  还款功能
8.ATM记录操作日志 --> 记录日志功能
9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。 ---> 管理员功能
10.用户认证用装饰器  --> 登录认证装饰器

función de extracción

# 展示给用户选择的功能(用户视图层)
1、注册功能
2、登录功能
3、查看余额
4、提现功能
5、还款功能
6、转账功能
7、查看流水
8、购物功能
9、查看购物车
10、管理员功能

Realización de las ideas

Anterior resumen del proyecto es también acerca de la ATM, pero ese proyecto todas las funciones en un archivo py; este resumen del proyecto no puede hacer eso de nuevo, esta vez para regular el punto.

Sabemos que la especificación del directorio de desarrollo de software, es decir, de acuerdo a diferentes funciones en el código del programa en diferentes archivos (carpetas), el proyecto también utilizan esta especificación.

Además, se estudiaron los tres niveles de diseño de la arquitectura del proyecto, será una función de tres niveles, responsabilidades claras de cada parte.

Por lo tanto, esta especificación directorio de desarrollo de software basado en proyectos, utilizando el principio de la arquitectura de tres capas, la escritura de código para cada función específica.


Marco del proyecto

estructura de tres niveles del diseño del proyecto. El contacto directo de la capa de vista del usuario. El usuario selecciona una función diferente, el usuario ver distintas funciones en la capa.

En vista de la capa de usuario, los datos de entrada de usuario, y entonces el usuario ver los datos de usuario de capa para la capa de interfaz lógica, la interfaz de capa de interfaz de llama a los datos de la capa, un acceso lógico a los datos pertinentes del usuario, el procesamiento para hacer una determinación lógica, entonces la lógica el análisis de la parte posterior de datos y / o información a la vista del usuario de la capa presenta al usuario.

Estructura del programa : seguir la especificación del directorio de software abierto

ATM&Shop/
|-- conf
|	|-- setting.py				# 项目配置文件
|-- core
|	|-- admin.py				# 管理员视图层函数
|	|-- current_user.py			# 记录当前登录用户信息[username, is_admin]
|	|-- shop.py					# 购物相关视图层函数
|	|-- src.py					# 主程序(包含用户视图层函数、atm主函数)
|-- db
|	|-- db_handle.py			# 数据处理层函数 
|	|-- goods_data.json			# 商品信息文件
|	|-- users_data				# 用户信息json文件夹
|	|	|-- xliu.json			# 用户信息文件:username|password|balance|my_flow|my_cart等
|	|	|-- egon.json
|-- interface					# 逻辑接口
|	|-- admin_interface.py			# 管理员逻辑接口层函数
|	|-- bank_interface.py			# 银行相关逻辑接口层函数
|	|-- shop_interface.py			# 购物相关逻辑接口层函数
|	|-- user_interface.py			# 用户相关逻辑接口层函数
|-- lib						
|	|-- tools.py		# 公用函数:加密|登录装饰器权限校验|记录流水|日志等
|-- log					# 日志文件夹
|	|-- operation.log
|	|-- transaction.log
|-- readme.md
|-- run.py				# 项目启动文件

Entorno operativo

- windows10, 64位
- python3.8
- pycharm2019.3

análisis funcional de Registro de la arquitectura de tres niveles

Errores Ver capas de función de registro : núcleo / src.py

from lib.tools import hash_md5, auto
from core.current_user import login_user
from interface.user_interface import register_interface


@auto('注册')
def register():
    print('注册页面'.center(50, '-'))
    while 1:
        name = input('请输入用户名:').strip()
        pwd = input('请输入密码:').strip()
        re_pwd = input('请确认密码:').strip()
        if pwd != re_pwd:
            print('两次密码输入不一致,请重新输入')
            continue
        flag, msg = register_interface(name, hash_md5(pwd))
        print(msg)
        if flag:
            break
            
# 注册功能用户视图层接收用户的注册信息:用户名|密码|确认密码
# 先做一个小逻辑判断,判断密码和确认密码是否一致?若不一致,则提示用户密码不一致从新输入
# 若密码一致,则将用户名和密码后的密码通过注册接口交给逻辑接口层
# 然后接受逻辑接口层的返回数据和信息,打印展示和下一步判断。

Register interfaces lógicas de capa funcional : interfaz / user_interface.py

from conf.settings import INIT_BALANCE
from core.current_user import login_user
from db import db_handle
from lib.tools import save_log


def register_interface(name, pwd):
    """
    注册接口
    :param name:
    :param pwd: 密码,密文
    :return:
    """
    user_dict = db_handle.get_user_info(name)
    if user_dict:
        return False, '用户名已经存在'
    user_dict = {
        'username': name,
        'password': pwd,
        'balance': INIT_BALANCE,
        'is_admin': False,
        'is_locked': False,
        'login_failed_counts': 0,
        'my_cart': {},
        'my_flow':{}
    }
    save_log('日常操作').info(f'{name}注册账号成功')
    db_handle.save_user_info(user_dict)
    return True, '注册成功'
# 注册功能逻辑接口层接收用户视图层传过来的用户名和密文密码,
# 通过调用数据处理层get_user_info函数,读用户文件,获取用户的信息字典
# 若用户信息字典存在,则该用户名已经被注册使用,则返回给用户视图层不能注册的信息
# 若用户信息字典不存在,则说明可以注册。
# 创建新用户信息字典,初始化相关数据,交给数据处理层save_user_info函数,并返回给用户视图层可以注册的信息。

capa de tratamiento de datos : db / db_handle.py

import os, json
from conf.settings import USER_DB_DIR


def get_user_info(name):
    user_file = os.path.join(USER_DB_DIR, f'{name}.json')
    if os.path.isfile(user_file):
        with open(user_file, 'rt', encoding='utf-8') as f:
            return json.load(f)
    else:
        return {}


def save_user_info(user_dict):
    user_dict['balance'] = round(user_dict['balance'], 2)
    user_file = os.path.join(USER_DB_DIR, f'{user_dict.get("username")}.json')
    with open(user_file, 'wt', encoding='utf-8') as f:
        json.dump(user_dict, f, ensure_ascii=False)

# 数据处理层函数:通过用户名获取用户信息字典;若用户存在则返回用户信息字典,用户不存在则返回空字典
# save_user_info函数,接收逻辑接口层的接口,将用户信息字典序列化保存到独立文件,以用户名命名文件名

Mención ahora función de análisis de la estructura de tres niveles

Retirar capas funcionales vista de usuario : núcleo / src.py

from lib.tools import auth, is_number, auto
from core.current_user import login_user
from interface.bank_interface import withdraw_interface


@auto('提现')
@auth
def withdraw():
    print('提现页面'.center(50, '-'))
    while 1:
        amounts = input('请输入体现金额:').strip()
        if not is_number(amounts):
            print('请输入合法的体现金额')
            continue
        flag, msg = withdraw_interface(login_user[0], float(amounts))
        print(msg)
        if flag:
            break
 
# 提现功能用户视图层:在用在用户登录之后才能使用(利用函数装饰器auth实现登录校验)
# 接收用户输入提现金额,先做小逻辑判断用户输入金额是否是数字(支持小数),通过工具函数is_number实现
# 然后将合法提现金额转成浮点数通过提现接口交给提现逻辑接口层
# 打印逻辑接口层返回的数据并做判断

Retirar interfaces lógicas de capa funcional : interfaz / bank_interface.py

from db import db_handle
from conf.settings import SERVICE_FEE_RATIO
from lib.tools import save_flow, save_log


def withdraw_interface(name, amounts):
    user_dict = db_handle.get_user_info(name)
    amounts_and_fee = amounts * (1 + SERVICE_FEE_RATIO)
    if amounts_and_fee > user_dict.get('balance'):
        save_log('提现').info(f'{name}提现{amounts}元,余额不足提现失败')
        return False, '账户余额不足'

    user_dict['balance'] -= amounts_and_fee
    msg = f'{name}提现{amounts}元'
    save_flow(user_dict, '提现', msg)
    save_log('提现').info(msg)
    db_handle.save_user_info(user_dict)
    return True, f'提现金额{amounts}元, 账户余额:{user_dict["balance"]}元'

# 通过用户名调用数据处理层函数get_user_info获取用户信息字典金额获取用户的账户余额
# 计算出用户提现金额的本金和手续费,判断本金和手续费是否大于账户余额
# 若大于账户余额,则无法提现,将提示信息返回给提现用户视图层
# 否则,从账户余额中扣除提现金额和手续费
# 调用数据处理层save_user_info,保存用户的信息
# 将提现成功信息返回给用户视图层

Compras análisis funcional de la arquitectura de tres niveles

Compras funcional capa de vista de usuario : núcleo / shop.py

from core.current_user import login_user
from lib.tools import auth, auto
from conf.settings import GOODS_CATEGOTY
from interface.shop_interface import get_goods_interface, shopping_interface
from interface.shop_interface import put_in_mycart_interface


@auto('网上商城')
@auth
def shopping():
    print('网上商城'.center(50, '-'))
    username = login_user[0]
    new_goods = []      # 存放用户本次选择的商品
    while 1:
        for k, v in GOODS_CATEGOTY.items():
            print(f'({k}){v}')

        category = input('请选择商品类型编号(结算Y/退出Q):').strip().lower()
        if category == 'y':
            if not new_goods:
                print('您本次没有选择商品,无法结算')
                continue
            else:
                flag, msg = shopping_interface(username, new_goods)
                print(msg)
                if not flag:
                    put_in_mycart_interface(username, new_goods)
                break

        elif category == 'q':
            if not new_goods: break
            put_in_mycart_interface(username, new_goods)
            break

        if category not in GOODS_CATEGOTY:
            print('您选择的编号不存在,请重新选择')
            continue

        goods_list = get_goods_interface(GOODS_CATEGOTY[category])
        while 1:
            for index, item in enumerate(goods_list, 1):
                name, price = item
                print(f'{index}: {name}, {price}元')
            choice = input('请输入商品的编号(返回B):').strip().lower()
            if choice == 'b':
                break
            if not choice.isdigit() or int(choice) not in range(1, len(goods_list)+1):
                print('您输入的商品编号不存在,请重新输入')
                continue
            name, price = goods_list[int(choice)-1]
            counts = input(f'请输入购买{name}的个数:').strip()
            if not counts.isdigit() and counts == '0':
                print('商品的个数是数字且不能为零')
                continue
            new_goods.append([name, price, int(counts)])

# 购物功能用户视图层:需要用户先登录再使用
# 打印商品分类表,让用户选择分类编号,然后将分类编号传给逻辑接口层,获取该分类下的商品列表展示给用户。
# 用户继续选择该分类下的商品编号和购买的商品个数。此处会使用小逻辑判断用户的输入是否合法。
# 选择商品和商品个数后,会将选择的结果临时存放在列表new_goods中,用于用户退出时结算。
# 如果用户选择支付,则将用户名和用户选择的商品通过购物结构交给购物逻辑接口层。
# 若逻辑接口层返回的结果时支付成功,则退出购物;若返回的就过是支付失败则将new_goods的商品交给put_in_mycart_interface放进购物车接口。
# 如果用户选择退出,则直接将new_goods的商品交给put_in_mycart_interface放进购物车接口

Compras interfaces lógicas de capa funcional : interfaz / shop_interface.py

from db import db_handle
from interface.bank_interface import pay_interface
from lib.tools import save_log


def get_goods_interface(category):
    """
    根据分类获取商品
    :param category: 
    :return: 
    """
    return db_handle.get_goods_info(category)


def shopping_interface(name, new_goods):
    total_cost = 0
    for item in new_goods:
        *_, price, counts = item
        total_cost += price * counts
    flag = pay_interface(name, total_cost)
    if flag:
        return True, '支付成功,商品发货中....'
    else:
        return False, '账户余额不足,支付失败'


def put_in_mycart_interface(name, new_goods):
    user_dict = db_handle.get_user_info(name)
    my_cart = user_dict.get('my_cart')
    for item in new_goods:
        goods_name, price, counts = item
        if goods_name not in my_cart:
            my_cart[goods_name] = [price, counts]
        else:
            my_cart[goods_name][-1] += counts
    save_log('日常操作').info(f'{name}更新了购物车商品')
    db_handle.save_user_info(user_dict)

    
# 购物接口层函数,计算接收的商品的总价,然后调用并将总结交给银行支付接口
# 支付接口返回支付成功/失败的返回信息;若支付成功则返回给用户视图层支付成功的信息;否则是支付失败的信息

# 放进购物车接口:将用户石涂层传过来的商品保存到用户信息字典里面的my_cart字典中,并调用数据处理层的save_user_info含糊,保存用户信息。

# 获取商品接口get_goods_interface,接收用户视图层传过来的商品分类。然后将该分类信息返回给用户视图层

funcionamiento capa de procesamiento de datos de compras : db / db_handle.py

......

from conf.settings import GOODS_DB_FILE

def get_goods_info(category):
    with open(GOODS_DB_FILE, 'rt', encoding='utf-8') as f:
        all_goods_dict =  json.load(f)
        return all_goods_dict.get(category)

# 这个函数主要用来接收购物功能逻辑接口层get_goods_interface函数请求的商品分类,获取该分类下的所有商品返回给逻辑接口层再返回给用户视图层。

Pequeño resumen del conocimiento

archivo JSON problema de visualización de caracteres chinos

import json
with open(user_file, 'wt', encoding='utf-8') as f:
    json.dump(user_dict, f, ensure_ascii=False)

# 由于json序列化是可读序列化,即json文件存放的是字符串类型的数据(不像pickle是二进制不可读的数据)。
# 此外,json文件存放的是unic0de text。即如果存的字符是中午字符,则会被存储为unicode二进制数据,在这json文件里面看起来很不舒服。
# 这个问题可以通过 json.dump中的参数ensure_ascii=False解决,即中文字符不会转为二进制字节

fondos decimales reservas

# 本项目就涉及用户金额数据小数点保留问题。对于会计金融需要非常在意小数点保留问题上,不能简单使用int转整形
# 还不能使用float保留成浮点型,因为它的精度不够,且小数位不能控制
# 你可能会说round(1.2312, 2)可以设置小数点精度; 但round(0.00001, 2),想要的结果是0.01而得到的结果确实0.0

# 此时可以导入decimal模块
import decimal
s = decimal.Decimal('0.00001')
print(s, type(s))		# 0.00001 <class 'decimal.Decimal'>
print(s.quantize(decimal.Decimal('0.01'), 'ROUND_UP'))	# 0.01

# 可惜的是本项目使用的是json文件,好像不能存decimal类型的数据。获取再转成字符串也行吧,回来再试试。

volver a los números de los partidos módulo en la aplicación del proyecto

import re
def is_number(your_str):    
    res = re.findall('^\d+\.?\d*$', your_str)
    if res:
        return True
    else:
        return False
    
# 匹配数字,判断输入的字符串是否是非负数

proyecto de módulo de cifrado hash de la contraseña

import hashlib

def hash_md5(info):
    m = hashlib.md5()
    m.update(info.encode('utf-8'))
    m.update('因为相信所以看见'.encode('utf-8'))	# 加盐处理
    return m.hexdigest()
# 用于密码加密

proyecto de tala módulo de registro

# 使用流程:
-1 在配置文件settings.py中配置日志字典LOGGING_DIC
-2 在lib/tools.py文件中封装日志记录函数,返回logger
def save_log(log_type):
    from conf.settings import LOGGING_DIC
    from logging import config, getLogger

    config.dictConfig(LOGGING_DIC)
    return getLogger(log_type)
-3 在逻辑接口层中调用save_log函数返回logger,使用logger.info(msg)记录日志

Módulo de importación - Evita problemas introdujo ciclos

# 两种方式避免循环导入问题
- 方式1:如果只有某一个函数需要导入自定义模块,则在函数局部作用域导入模块
- 方式2:后一个导入者使用import导入,不要使用from ... import ... 导入

objeto función añadir automáticamente el diccionario de errores

Este error se descubre a tiempo para pensar en más adelante, este proyecto debido a que el uso de la forma correcta para evitar este error. referencia específica este error el blog

# 自动将功能函数添加到core.src中的func_dict字典。
# 如果将func_dict字典放在一个单独的py文件中会方便避免这个bug
# 这个bug的主要原因在于:模块导入的先后顺序和搜索模块的顺序

resumen

Software especificación directorio de desarrollo

  • Todo el mundo a crear un estilo de especificación de directorio es diferente. No importa, la clave es eliminar toda la estructura organizativa del programa del proyecto.
  • especificación del directorio sigue el camino la mayoría de la gente usa tanto como sea posible, para que su legibilidad del código será más amigable.

proyecto de diseño de la arquitectura de tres niveles

  • la arquitectura de tres niveles se piensa esquema de desarrollo del proyecto. Una vez que este modelo de desarrollo, el tiempo para escribir código para distinguir diferentes niveles de funciones.
  • En estricta conformidad con las funciones de cada nivel, el código de las diferentes funciones en diferentes niveles, no ensucie, por lo que será muy fácil de manejar y mantener.
  • A veces, una demasiado simple acceso, directo a la capa de procesamiento de datos. Pero lo mejor es seguir la arquitectura de tres capas, no atraviesan la capa de interfaz lógica.

Los datos almacenados no es un fin, cualquiera que sea el objetivo

  • datos de objetos no se almacena, cuando los datos almacenados deben considerarse conveniente para tomar datos.
  • estructura de almacenamiento de datos y una buena manera de verificar la función de influencia al obtener los datos de codificación cantidad concisa y hermosa.
  • Algoritmos + Estructuras = programas de datos. Por lo tanto, buenas estructuras de datos, lo que lleva a la dificultad de acceso y fácil de datos y funciones.

El código de paquete, la reutilización de código tanto como sea posible

  • Los programas deben tanto como sea posible sin perder su función en virtud de un caso claro, ya que muchos consideran que la reutilización de código.
  • herramientas de múltiples funciones para escribir funciones genéricas, a la llamada de su uso en el programa.

archivos de origen del proyecto

archivos de código fuente del proyecto de disco de red Baidu, amigos interesados ​​pueden descargar la referencia.

Enlaces: https://pan.baidu.com/s/1GTL081h64tW2SwsHU8kTGw
código de extracción: fn6e

Supongo que te gusta

Origin www.cnblogs.com/the3times/p/12652726.html
Recomendado
Clasificación