Commit c12d5d33 authored by Robin Trioux's avatar Robin Trioux
Browse files

New architecture, new GUI

-Everything is now handled by Singleton Managers, QDataManager,
QUimanager, QNFCManager
-Full object paradigm instead of dictionaries/json paradigm (clean code
vs flex code...)
-Money is now handled by a specialized class to prevent from float
approximation and ease the money formating
-New file architecture
-Colored console
-Added some piano...
parent f145ec60
class UIProperties:
def __init__(self):
self.text = (
[]
) # A list because there is several things we may want to show from an Atom (name,price,...)
self.foreground = None
self.background = None
self.icon = None
self.toolTip = None
def setTexts(self, text):
self.text = text
return self
def setText(self, text, index):
self.text[index] = text
return self
def setForeground(self, foreground):
self.foreground = foreground
return self
def setBackground(self, background):
self.background = background
return self
def setIcon(self, icon):
self.icon = icon
return self
def setToolTip(self, toolTip):
self.toolTip = toolTip
return self
def getTexts(self):
return self.text
def getText(self, index):
return self.text[index]
def getForeground(self):
return self.foreground
def getBackground(self):
return self.background
def getIcon(self):
return self.icon
def getToolTip(self):
return self.toolTip
class Atom:
def __init__(self):
self.ui = UIProperties()
def setTexts(self, text):
self.ui.setTexts(text)
return self
def setText(self, text, index):
self.ui.setText(text,index)
return self
def setForeground(self, foreground):
self.ui.setForeground(foreground)
return self
def setBackground(self, background):
self.ui.setBackground(background)
return self
def setIcon(self, icon):
self.ui.setIcon(icon)
return self
def setToolTip(self, toolTip):
self.ui.setToolTip(toolTip)
return self
def getTexts(self):
return self.ui.getTexts()
def getText(self, index):
return self.ui.getText(index)
def getForeground(self):
return self.ui.getForeground()
def getBackground(self):
return self.ui.getBackground()
def getIcon(self):
return self.ui.getIcon()
def getToolTip(self):
return self.ui.getToolTip()
class User(Atom):
def __init__(self):
super().__init__()
self.id = None # UID of the nfc card
self.balance = None
self.canDrink = None
def setId(self, id):
self.id = id
def setBalance(self, balance):
self.balance = balance
def setCanDrink(self, canDrink):
self.canDrink = canDrink
def getId(self):
return self.id
def getBalance(self):
return self.balance
def getCanDrink(self):
return self.canDrink
class Product(Atom):
def __init__(self):
super().__init__()
self.id = None # int64, used in db
self.name = None # pretty print
self.code = None # short name
self.price = None # The price is either updated when it's in a the selctor, either retreived from database when it's in history
self.quantity = None # When product is used as selector, quantity is 1 and when used in a basket, it may vary
def setId(self, id):
self.id = id
def setName(self, name):
self.name = name
def setCode(self, code):
self.code = code
def setPrice(self, price):
self.price = price
def setQuantity(self, quantity):
self.quantity = quantity
def getId(self):
return self.id
def getName(self):
return self.name
def getCode(self):
return self.code
def getPrice(self):
return self.price
def getQuantity(self):
return self.quantity
class Operation(Atom):
def __init__(self):
super().__init__()
self.id = None
self.label = None # human readable description gave by the server
self.refounded = None
# Could be usefull to show where the product has been bought
self.counterId = None
self.date = None
def setId(self, id):
self.id = id
def setLabel(self, label):
self.label = label
def setRefounded(self, refounded):
self.refounded = refounded
def setCounterId(self, counterId):
self.counterId = counterId
def setDate(self, date):
self.date = date
def getId(self):
return self.id
def getLabel(self):
return self.label
def getRefounded(self, refounded):
return self.refounded
def getCounterId(self):
return self.counterId
def getDate(self):
return self.date
class Buying(Operation):
def __init__(self):
super().__init__()
self.price = None # price the customer(s) actually paid
self.payments = None # List of all payment for this order since several users maybe concerned
self.basketItems = None # List of "Product", their unit price should be download from the history
def setPrice(self, price):
self.price = print
def setPayment(self, payments):
self.payments = payments
def setBasketItems(self, basketItems):
self.basketItems = basketItems
def getPrice(self):
return self.price
def getPayments(self):
return self.payments
def getBasketItems(self):
return self.basketItems
class Refilling(Operation):
def __init__(self):
super().__init__()
self.amount = None
def setAmount(self, amount):
self.amount = amount
def getAmount(self):
return self.amount
class Counter(Atom):
def __init__(self):
super().__init__()
self.id = None
self.name = None
def setId(self, id):
self.id = id
def setName(self, name):
self.name = name
def getId(self):
return self.id
def getName(self):
return self.name
from __future__ import print_function
import time
import swagger_client
from swagger_client.rest import ApiException
from pprint import pprint
import json
# For handle request MaxRetry exception
from urllib3.exceptions import *
from __future__ import print_function
import uuid
import grpc
from grpc import RpcError
import com_pb2
import com_pb2_grpc
from google.protobuf.timestamp_pb2 import Timestamp
from Atoms import *
class MachineConfigSingleton(type(swagger_client.Configuration)):
class ClientSingleton(type):
_instance = {}
def __call__(cls):
if cls not in cls._instance:
cls._instance[cls] = super(MachineConfigSingleton, cls).__call__()
cls._instance[cls] = super(ClientSingleton , cls).__call__()
return cls._instance[cls]
class Client(metaclass=ClientSingleton):
class MachineConfig(swagger_client.Configuration, metaclass=MachineConfigSingleton):
def __init__(self):
super().__init__()
self.counterID = 1
self.counterDict = {} # Ordered as dictionary
self.counterList = [] # Ordered as list
self.host = "http://127.0.0.1:5000"
# self.host = "http://192.168.2.101:5000"
self.defaultItemFileName = "ItemModel.json"
def setHost(self, host):
self.host = host
def setCounterID(self, counterID):
self.counterID = counterID
configuration = MachineConfig()
# create an instance of the API class
api_instance = swagger_client.DefaultApi(swagger_client.ApiClient(configuration))
def requestBuy(userUID, counterID, computerMAC, basket):
# basket format conversion
if isinstance(basket, dict) is True:
fBasket = []
for i in basket:
tempDict = {}
tempDict["product_code"] = i
tempDict["quantity"] = basket[i]
fBasket.append(tempDict)
else:
fBasket = basket
try:
body = swagger_client.Body(counterID, computerMAC, fBasket)
return api_instance.buy_user_uid_post(body, userUID)
except ApiException as e:
if e.status == 401:
print("User {}: Insufficient balance".format(userUID))
elif e.status == 404:
print("User {}: Not found".format(userUID))
return None
except MaxRetryError as e:
return None
def requestRefilling(userUID, counterID, computerMAC, amount):
try:
body = swagger_client.Body1(counterID, computerMAC, amount)
return api_instance.refilling_user_uid_post(body, userUID)
except MaxRetryError:
return None
def requestGeneralHistory(historySize):
raise NotImplementedError
def requestUserHistory(userUID, historySize):
try:
return api_instance.get_user_history_user_uid_history_size_post(historySize, userUID)
except ApiException as e:
return None
except MaxRetryError as e:
print("Unable to establish connexion with the server")
return None
def requestCounterHistory(counterID, historySize):
try:
return api_instance.get_counter_history_counter_id_history_size_post(historySize, counterID)
except ApiException as e:
return None
except MaxRetryError as e:
print("Unable to establish connexion with the server")
return None
def requestComputerHistory(computerMAC, historySize):
try:
return api_instance.get_computer_history_computer_mac_history_size_post(historySize, computerMAC)
except ApiException as e:
return None
except MaxRetryError:
return None
def requestRefund(transactionID, counterID, computerMAC):
try:
body = swagger_client.Body2(counterID, computerMAC)
return api_instance.refund_transaction_id_post(body, transactionID)
except ApiException as e:
if e.status == 404:
print("Refund failed: Transaction not found")
return None
except MaxRetryError:
return None
def requestCounterProduct(counterID):
try:
return api_instance.get_counter_products_counter_id_post(counterID)
except ApiException as e:
print("Counter product request failed: Counter not found")
except MaxRetryError:
return None
def requestUserBalance(uid):
try:
return api_instance.get_user_balance_user_uid_post(uid)
except ApiException as e:
if e.status == 404:
print("User {} not found".format(uid))
return None
except MaxRetryError as e:
return None
def requestCounterList():
try:
return api_instance.get_counter_list_get()
except ApiException as e:
if e.status == 404:
print("No counter found")
return None
except MaxRetryError as e:
return None
def requestTransfert(sender, receiver, amount):
try:
body = swagger_client.Body3(receiver, sender, amount)
return api_instance.transfer_money_post(body)
except ApiException as e:
if e.status == 401:
print("Not enough money")
elif e.status == 404:
print("User not found")
return None
except MaxRetryError as e:
return None
self.serverAddress=None
self.channel = None
self.stub = None
def requestBuy(self,**kwargs):
"""
int64 counter_id
string device_uuid
repeated Payment payments
repeated BasketItem basket
"""
# Mockup
mockupProduct = Product()
mockupProduct.price = 8
mockupProduct.quantity = 2
mockupProduct.name = "Bouteille"
mockupProduct.id = 0
mockupProduct.code = "BOUBOU"
buying = Buying()
buying.date = Timestamp().GetCurrentTime()
buying.id = 1
buying.label = "label"
buying.price = 16
buying.refounded = False
buying.counterId = 0
buying.basketItems = [mockupProduct]
return mockupProduct
def requestRefilling(self, **kwargs):
"""
string customer_id
int64 counter_id
string device_uuid
PaymentMethod payment_method
double amount
"""
# Mockup
refilling = Refilling()
refilling.amount = 42
refilling.counterId = 0
refilling.date = Timestamp().GetCurrentTime()
refilling.id = 2
refilling.label = "label"
refilling.refounded = False
return refilling
def requestHistory(self, **kwargs):
pass
def requestRefund(self, **kwargs):
pass
def requestCounterProduct(self, **kwargs):
"""
int64 counter_id
"""
# Mockup
mockupProduct1 = Product()
mockupProduct1.name = "Coca"
mockupProduct1.price = 1
mockupProduct1.quantity = 1
mockupProduct1.id = 0
mockupProduct1.code = "COCA"
mockupProduct2 = Product()
mockupProduct2.name = "Bièrre"
mockupProduct2.price = 2
mockupProduct2.quantity = 1
mockupProduct2.id = 1
mockupProduct2.code = "BIBINE"
products = {"Soft": mockupProduct1, "Alcool": mockupProduct2}
return products
def requestUserBalance(self, **kwargs):
"""
string customer_id
"""
# Mockup
return 30
def requestCounterList(self, **kwargs):
"""No parameters requiered"""
# Mockup
counter = Counter()
counter.id = 0
counter.name = "BAR 0"
counterList = [counter]
return counterList
def requestTransfert(self, **kwargs):
pass
from termcolor import colored
# At the moment I assume we only print single strings
def printE(string): #Error
print(colored("ERROR: " + str(string),'red'))
def printW(string): #Warning
print(colored("WARNING: " + str(string),'yellow'))
def printN(string): #Nice
print(colored(str(string),'green'))
def printD(string): #Debug
print(colored("DEBUG: "+ str(string),''))
def printI(string): #Info
print(colored(string, 'cyan'))
def printNFC(string): #NFC message
print(colored(string,'magenta'))
#Suggestion: create printEE, printEEE, printWW, printWWW ... to create a hierarchy among the message
# could be usefull to filter the message to print in the future ...
#Suggestion: create a singleton class to handle all of these...
\ No newline at end of file
from money import Money
from babel.numbers import format_currency
# money is based on Decimal, this class handle perfect float representation
# every single amount of money should be generated through this library to avoid float virgule problem
# e.g with regular float 1.1 + 1.2 = 2.30000000000000003
# with money/Decimal class 1.1 + 1.2 = 2.30
#money could theoricaly handle multi device program, here we just need euro so we create a specialized class
class Eur(Money):
def __init__(self,amount=0):
super().__init__(amount=amount,currency='EUR')
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import PyQt5.QtCore
import PyQt5.QtGui
from QManager import *
from QNFC import *
from QUtils import *
from QItemTree import *
from Client import *
from QRefillerTab import *
from QCounterTab import *
import json
# de transaction
# Shared variables
PWD = os.getcwd() + "/"
# Get item tree
# INITIALISATION
dm = QDataManager()
uim = QUIManager()
nfcm = QNFCManager()