This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
devicehub-teal/ereuse_devicehub/resources/action/views/trade.py

361 lines
10 KiB
Python
Raw Permalink Normal View History

2021-05-10 09:47:56 +00:00
from flask import g
from teal.marshmallow import ValidationError
from ereuse_devicehub.db import db
from ereuse_devicehub.inventory.models import Transfer
from ereuse_devicehub.resources.action.models import (
Confirm,
ConfirmDocument,
ConfirmRevokeDocument,
Revoke,
RevokeDocument,
Trade,
)
from ereuse_devicehub.resources.lot.views import delete_from_trade
from ereuse_devicehub.resources.user.models import User
2021-05-10 09:47:56 +00:00
class TradeView:
2021-05-10 09:47:56 +00:00
"""Handler for manager the trade action register from post
2021-05-19 11:59:59 +00:00
request_post = {
'type': 'Trade',
'devices': [device_id],
'documents': [document_id],
'userFrom': user2.email,
'userTo': user.email,
'price': 10,
'date': "2020-12-01T02:00:00+00:00",
'lot': lot['id'],
'confirm': True,
}
2021-05-10 09:47:56 +00:00
"""
def __init__(self, data, resource_def, schema):
self.schema = schema
2021-06-07 15:12:30 +00:00
self.data = resource_def.schema.load(data)
self.data.pop('user_to_email', '')
self.data.pop('user_from_email', '')
2021-05-10 09:47:56 +00:00
self.create_phantom_account()
2021-06-07 15:12:30 +00:00
self.trade = Trade(**self.data)
2021-05-10 09:47:56 +00:00
db.session.add(self.trade)
self.create_confirmations()
2021-06-07 15:12:30 +00:00
self.create_automatic_trade()
self.create_transfer()
2021-05-10 09:47:56 +00:00
def post(self):
db.session().final_flush()
ret = self.schema.jsonify(self.trade)
ret.status_code = 201
db.session.commit()
return ret
def create_confirmations(self) -> None:
"""Do the first confirmation for the user than do the action"""
# if the confirmation is mandatory, do automatic confirmation only for
# owner of the lot
if self.trade.confirm:
2021-05-21 11:16:30 +00:00
if self.trade.devices:
confirm_devs = Confirm(
user=g.user, action=self.trade, devices=self.trade.devices
)
2021-05-21 11:16:30 +00:00
db.session.add(confirm_devs)
if self.trade.documents:
confirm_docs = ConfirmDocument(
user=g.user, action=self.trade, documents=self.trade.documents
)
2021-05-21 11:16:30 +00:00
db.session.add(confirm_docs)
2021-05-10 09:47:56 +00:00
return
# check than the user than want to do the action is one of the users
# involved in the action
2021-10-25 11:24:22 +00:00
if g.user not in [self.trade.user_from, self.trade.user_to]:
2021-06-02 11:46:28 +00:00
txt = "You do not participate in this trading"
raise ValidationError(txt)
2021-05-10 09:47:56 +00:00
confirm_from = Confirm(
user=self.trade.user_from, action=self.trade, devices=self.trade.devices
)
confirm_to = Confirm(
user=self.trade.user_to, action=self.trade, devices=self.trade.devices
)
2021-05-10 09:47:56 +00:00
db.session.add(confirm_from)
db.session.add(confirm_to)
def create_phantom_account(self) -> None:
"""
If exist both users not to do nothing
If exist from but not to:
search if exist in the DB
if exist use it
else create new one
The same if exist to but not from
"""
2021-06-07 15:12:30 +00:00
user_from = self.data.get('user_from')
user_to = self.data.get('user_to')
code = self.data.get('code')
if user_from and user_to:
2021-05-10 09:47:56 +00:00
return
2021-06-07 15:12:30 +00:00
if self.data['confirm']:
2021-05-10 09:47:56 +00:00
return
2021-06-07 15:12:30 +00:00
if user_from and not user_to:
assert g.user == user_from
email = "{}_{}@dhub.com".format(str(user_from.id), code)
2021-05-10 09:47:56 +00:00
users = User.query.filter_by(email=email)
if users.first():
user = users.first()
2021-06-07 15:12:30 +00:00
self.data['user_to'] = user
2021-05-10 09:47:56 +00:00
return
user = User(email=email, password='', active=False, phantom=True)
db.session.add(user)
2021-06-07 15:12:30 +00:00
self.data['user_to'] = user
2021-05-10 09:47:56 +00:00
2021-06-07 15:12:30 +00:00
if not user_from and user_to:
email = "{}_{}@dhub.com".format(str(user_to.id), code)
2021-05-10 09:47:56 +00:00
users = User.query.filter_by(email=email)
if users.first():
user = users.first()
2021-06-07 15:12:30 +00:00
self.data['user_from'] = user
2021-05-10 09:47:56 +00:00
return
user = User(email=email, password='', active=False, phantom=True)
db.session.add(user)
2021-06-07 15:12:30 +00:00
self.data['user_from'] = user
2021-05-10 09:47:56 +00:00
def create_transfer(self):
code = self.trade.code
confirm = self.trade.confirm
lot = self.trade.lot
user_from = None
user_to = None
if not self.trade.user_from.phantom:
user_from = self.trade.user_from
if not self.trade.user_to.phantom:
user_to = self.trade.user_to
if (user_from and user_to) or not code or confirm:
return
self.transfer = Transfer(
code=code, user_from=user_from, user_to=user_to, lot=lot
)
db.session.add(self.transfer)
2021-05-10 09:47:56 +00:00
def create_automatic_trade(self) -> None:
# not do nothing if it's neccesary confirmation explicity
if self.trade.confirm:
return
# Change the owner for every devices
for dev in self.trade.devices:
2021-06-07 15:12:30 +00:00
dev.change_owner(self.trade.user_to)
2021-05-10 09:47:56 +00:00
class ConfirmMixin:
2021-05-10 09:47:56 +00:00
"""
Very Important:
==============
All of this Views than inherit of this class is executed for users
than is not owner of the Trade action.
2021-05-10 09:47:56 +00:00
The owner of Trade action executed this actions of confirm and revoke from the
lot
2021-05-10 09:47:56 +00:00
"""
Model = None
def __init__(self, data, resource_def, schema):
self.schema = schema
a = resource_def.schema.load(data)
self.validate(a)
if not a['devices']:
2021-05-10 09:47:56 +00:00
raise ValidationError('Devices not exist.')
self.model = self.Model(**a)
def post(self):
db.session().final_flush()
ret = self.schema.jsonify(self.model)
ret.status_code = 201
db.session.commit()
return ret
class ConfirmView(ConfirmMixin):
"""Handler for manager the Confirmation register from post
request_confirm = {
'type': 'Confirm',
'action': trade.id,
'devices': [device_id]
}
2021-05-10 09:47:56 +00:00
"""
Model = Confirm
def validate(self, data):
"""If there are one device than have one confirmation,
then remove the list this device of the list of devices of this action
2021-05-10 09:47:56 +00:00
"""
real_devices = []
2021-11-11 21:50:07 +00:00
trade = data['action']
lot = trade.lot
2021-05-10 09:47:56 +00:00
for dev in data['devices']:
if dev.trading(lot, simple=True) not in [
'NeedConfirmation',
'NeedConfirmRevoke',
]:
2021-11-11 21:50:07 +00:00
raise ValidationError('Some devices not possible confirm.')
2021-05-10 09:47:56 +00:00
# Change the owner for every devices
for dev in data['devices']:
if dev.trading(lot) == 'NeedConfirmation':
2021-11-11 21:50:07 +00:00
user_to = data['action'].user_to
dev.change_owner(user_to)
2021-05-10 09:47:56 +00:00
class RevokeView(ConfirmMixin):
"""Handler for manager the Revoke register from post
request_revoke = {
'type': 'Revoke',
'action': trade.id,
'devices': [device_id],
}
2021-05-10 09:47:56 +00:00
"""
Model = Revoke
2021-06-04 17:27:01 +00:00
def __init__(self, data, resource_def, schema):
self.schema = schema
a = resource_def.schema.load(data)
self.validate(a)
2021-05-10 09:47:56 +00:00
def validate(self, data):
"""All devices need to have the status of DoubleConfirmation."""
devices = data['devices']
if not devices:
2021-06-04 17:27:01 +00:00
raise ValidationError('Devices not exist.')
2021-05-10 09:47:56 +00:00
2021-10-28 10:19:49 +00:00
lot = data['action'].lot
self.model = delete_from_trade(lot, devices)
class ConfirmDocumentMixin:
"""
Very Important:
==============
All of this Views than inherit of this class is executed for users
than is not owner of the Trade action.
The owner of Trade action executed this actions of confirm and revoke from the
lot
"""
Model = None
def __init__(self, data, resource_def, schema):
self.schema = schema
a = resource_def.schema.load(data)
self.validate(a)
if not a['documents']:
raise ValidationError('Documents not exist.')
self.model = self.Model(**a)
def post(self):
db.session().final_flush()
ret = self.schema.jsonify(self.model)
ret.status_code = 201
db.session.commit()
return ret
class ConfirmDocumentView(ConfirmDocumentMixin):
"""Handler for manager the Confirmation register from post
request_confirm = {
'type': 'Confirm',
'action': trade.id,
'documents': [document_id],
}
"""
Model = ConfirmDocument
def validate(self, data):
"""If there are one device than have one confirmation,
then remove the list this device of the list of devices of this action
"""
for doc in data['documents']:
ac = doc.trading
if not doc.trading in ['Confirm', 'Need Confirmation']:
txt = 'Some of documents do not have enough to confirm for to do a Doble Confirmation'
ValidationError(txt)
### End check ###
class RevokeDocumentView(ConfirmDocumentMixin):
"""Handler for manager the Revoke register from post
request_revoke = {
'type': 'Revoke',
'action': trade.id,
'documents': [document_id],
}
"""
Model = RevokeDocument
def validate(self, data):
"""All devices need to have the status of DoubleConfirmation."""
### check ###
if not data['documents']:
raise ValidationError('Documents not exist.')
for doc in data['documents']:
if not doc.trading in ['Document Confirmed', 'Confirm']:
txt = (
'Some of documents do not have enough to confirm for to do a revoke'
)
ValidationError(txt)
### End check ###
class ConfirmRevokeDocumentView(ConfirmDocumentMixin):
"""Handler for manager the Confirmation register from post
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': action_revoke.id,
'documents': [document_id],
}
"""
Model = ConfirmRevokeDocument
def validate(self, data):
"""All devices need to have the status of revoke."""
if not data['action'].type == 'RevokeDocument':
txt = 'Error: this action is not a revoke action'
ValidationError(txt)
for doc in data['documents']:
if not doc.trading == 'Revoke':
txt = 'Some of documents do not have revoke to confirm'
ValidationError(txt)