Merge pull request #179 from eReuse/bugfix/#177-trade

Bugfix/#177 trade
This commit is contained in:
cayop 2021-11-12 18:47:45 +01:00 committed by GitHub
commit 0daa9cf284
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 315 additions and 339 deletions

View file

@ -0,0 +1,43 @@
"""adding author action_device
Revision ID: d22d230d2850
Revises: 1bb2b5e0fae7
Create Date: 2021-11-10 17:37:12.304853
"""
import sqlalchemy as sa
from alembic import context
from alembic import op
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = 'd22d230d2850'
down_revision = '1bb2b5e0fae7'
branch_labels = None
depends_on = None
def get_inv():
INV = context.get_x_argument(as_dictionary=True).get('inventory')
if not INV:
raise ValueError("Inventory value is not specified")
return INV
def upgrade():
op.add_column('action_device',
sa.Column('author_id',
postgresql.UUID(),
nullable=True),
schema=f'{get_inv()}')
op.create_foreign_key("fk_action_device_author",
"action_device", "user",
["author_id"], ["id"],
ondelete="SET NULL",
source_schema=f'{get_inv()}',
referent_schema='common')
def downgrade():
op.drop_constraint("fk_action_device_author", "device", type_="foreignkey", schema=f'{get_inv()}')
op.drop_column('action_device', 'author_id', schema=f'{get_inv()}')

View file

@ -280,16 +280,16 @@ class ConfirmDef(ActionDef):
SCHEMA = schemas.Confirm
class ConfirmRevokeDef(ActionDef):
VIEW = None
SCHEMA = schemas.ConfirmRevoke
class RevokeDef(ActionDef):
VIEW = None
SCHEMA = schemas.Revoke
class ConfirmRevokeDef(ActionDef):
VIEW = None
SCHEMA = schemas.ConfirmRevoke
class TradeDef(ActionDef):
VIEW = None
SCHEMA = schemas.Trade

View file

@ -317,6 +317,14 @@ class ActionDevice(db.Model):
index=True,
server_default=db.text('CURRENT_TIMESTAMP'))
created.comment = """When Devicehub created this."""
author_id = Column(UUID(as_uuid=True),
ForeignKey(User.id),
nullable=False,
default=lambda: g.user.id)
# todo compute the org
author = relationship(User,
backref=backref('authored_actions_device', lazy=True, collection_class=set),
primaryjoin=author_id == User.id)
def __init__(self, **kwargs) -> None:
self.created = kwargs.get('created', datetime.now(timezone.utc))
@ -1610,11 +1618,11 @@ class Revoke(Confirm):
"""Users can revoke one confirmation of one action trade"""
class ConfirmRevoke(Confirm):
"""Users can confirm and accept one action revoke"""
# class ConfirmRevoke(Confirm):
# """Users can confirm and accept one action revoke"""
def __repr__(self) -> str:
return '<{0.t} {0.id} accepted by {0.user}>'.format(self)
# def __repr__(self) -> str:
# return '<{0.t} {0.id} accepted by {0.user}>'.format(self)
class Trade(JoinedTableMixin, ActionWithMultipleTradeDocuments):

View file

@ -445,16 +445,13 @@ class ActionStatus(Action):
@post_load
def put_rol_user(self, data: dict):
for dev in data['devices']:
if dev.trading in [None, 'Revoke', 'ConfirmRevoke']:
return data
trades = [ac for ac in dev.actions if ac.t == 'Trade']
if not trades:
return data
trade = trades[-1]
if trade.user_to != g.user:
if trade.user_from == g.user:
data['rol_user'] = trade.user_to
data['trade'] = trade
@ -588,6 +585,10 @@ class Revoke(ActionWithMultipleDevices):
raise ValidationError(txt)
class ConfirmRevoke(Revoke):
pass
class ConfirmDocument(ActionWithMultipleDocuments):
__doc__ = m.Confirm.__doc__
action = NestedOn('Action', only_query='id')
@ -642,7 +643,7 @@ class RevokeDocument(ActionWithMultipleDocuments):
class ConfirmRevokeDocument(ActionWithMultipleDocuments):
__doc__ = m.ConfirmRevoke.__doc__
__doc__ = m.ConfirmRevokeDocument.__doc__
action = NestedOn('Action', only_query='id')
@validates_schema
@ -669,66 +670,6 @@ class ConfirmRevokeDocument(ActionWithMultipleDocuments):
data['action'] = doc.actions[-1]
class ConfirmRevoke(ActionWithMultipleDevices):
__doc__ = m.ConfirmRevoke.__doc__
action = NestedOn('Action', only_query='id')
@validates_schema
def validate_revoke(self, data: dict):
for dev in data['devices']:
# if device not exist in the Trade, then this query is wrong
if not dev in data['action'].devices:
txt = "Device {} not exist in the trade".format(dev.devicehub_id)
raise ValidationError(txt)
for doc in data.get('documents', []):
# if document not exist in the Trade, then this query is wrong
if not doc in data['action'].documents:
txt = "Document {} not exist in the trade".format(doc.file_name)
raise ValidationError(txt)
@validates_schema
def validate_docs(self, data):
"""Check if there are or no one before confirmation,
This is not checked in the view becouse the list of documents is inmutable
"""
if not data['devices'] == OrderedSet():
return
documents = []
for doc in data['documents']:
actions = copy.copy(doc.actions)
actions.reverse()
for ac in actions:
if ac == data['action']:
# If document have the last action the action for confirm
documents.append(doc)
break
if ac.t == 'Revoke' and not ac.user == g.user:
# If document is revoke before you can Confirm now
# and revoke is an action of one other user
documents.append(doc)
break
if ac.t == ConfirmRevoke.t and ac.user == g.user:
# If document is confirmed we don't need confirmed again
break
if ac.t == Confirm.t:
# if onwer of trade confirm again before than this user Confirm the
# revoke, then is not possible confirm the revoke
#
# If g.user confirm the trade before do a ConfirmRevoke
# then g.user can not to do the ConfirmRevoke more
break
if not documents:
txt = 'No there are documents with revoke for confirm'
raise ValidationError(txt)
class Trade(ActionWithMultipleDevices):
__doc__ = m.Trade.__doc__
date = DateTime(data_key='date', required=False)

View file

@ -3,7 +3,7 @@ from sqlalchemy.util import OrderedSet
from teal.marshmallow import ValidationError
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.action.models import (Trade, Confirm, ConfirmRevoke,
from ereuse_devicehub.resources.action.models import (Trade, Confirm,
Revoke, RevokeDocument, ConfirmDocument,
ConfirmRevokeDocument)
from ereuse_devicehub.resources.user.models import User
@ -181,17 +181,17 @@ class ConfirmView(ConfirmMixin):
then remove the list this device of the list of devices of this action
"""
real_devices = []
trade = data['action']
lot = trade.lot
for dev in data['devices']:
ac = dev.last_action_trading
if ac.type == Confirm.t and not ac.user == g.user:
real_devices.append(dev)
data['devices'] = OrderedSet(real_devices)
if dev.trading(lot, simple=True) not in ['NeedConfirmation', 'NeedConfirmRevoke']:
raise ValidationError('Some devices not possible confirm.')
# Change the owner for every devices
for dev in data['devices']:
user_to = data['action'].user_to
dev.change_owner(user_to)
if dev.trading(lot) == 'NeedConfirmation':
user_to = data['action'].user_to
dev.change_owner(user_to)
class RevokeView(ConfirmMixin):
@ -215,57 +215,12 @@ class RevokeView(ConfirmMixin):
def validate(self, data):
"""All devices need to have the status of DoubleConfirmation."""
### check ###
if not data['devices']:
devices = data['devices']
if not devices:
raise ValidationError('Devices not exist.')
for dev in data['devices']:
if not dev.trading == 'TradeConfirmed':
txt = 'Some of devices do not have enough to confirm for to do a revoke'
ValidationError(txt)
### End check ###
ids = {d.id for d in data['devices']}
lot = data['action'].lot
self.model = delete_from_trade(lot, ids)
class ConfirmRevokeView(ConfirmMixin):
"""Handler for manager the Confirmation register from post
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': action_revoke.id,
'devices': [device_id]
}
"""
Model = ConfirmRevoke
def validate(self, data):
"""All devices need to have the status of revoke."""
if not data['action'].type == 'Revoke':
txt = 'Error: this action is not a revoke action'
ValidationError(txt)
for dev in data['devices']:
if not dev.trading == 'Revoke':
txt = 'Some of devices do not have revoke to confirm'
ValidationError(txt)
devices = OrderedSet(data['devices'])
data['devices'] = devices
# Change the owner for every devices
# data['action'] == 'Revoke'
trade = data['action'].action
for dev in devices:
dev.reset_owner()
trade.lot.devices.difference_update(devices)
self.model = delete_from_trade(lot, devices)
class ConfirmDocumentMixin():

View file

@ -15,7 +15,7 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.query import things_response
from ereuse_devicehub.resources.action.models import (Action, Snapshot, VisualTest,
InitTransfer, Live, Allocate, Deallocate,
Trade, Confirm, ConfirmRevoke, Revoke)
Trade, Confirm, Revoke)
from ereuse_devicehub.resources.action.views import trade as trade_view
from ereuse_devicehub.resources.action.views.snapshot import SnapshotView, save_json, move_json
from ereuse_devicehub.resources.action.views.documents import ErasedView
@ -235,9 +235,9 @@ class ActionView(View):
revoke = trade_view.RevokeView(json, resource_def, self.schema)
return revoke.post()
if json['type'] == ConfirmRevoke.t:
confirm_revoke = trade_view.ConfirmRevokeView(json, resource_def, self.schema)
return confirm_revoke.post()
if json['type'] == 'ConfirmRevoke':
revoke = trade_view.RevokeView(json, resource_def, self.schema)
return revoke.post()
if json['type'] == 'RevokeDocument':
revoke = trade_view.RevokeDocumentView(json, resource_def, self.schema)

View file

@ -89,7 +89,6 @@ class Metrics(MetricsMix):
trade['status_receiver_created'] = self.act.created
return
# import pdb; pdb.set_trace()
# necesitamos poder poner un cambio de estado de un trade mas antiguo que last_trade
# lo mismo con confirm
@ -148,9 +147,7 @@ class Metrics(MetricsMix):
if the action is one trade action, is possible than have a list of confirmations.
Get the doble confirm for to know if this trade is confirmed or not.
"""
if self.device.trading == 'TradeConfirmed':
return True
return False
return self.device.trading(self.act.lot, simple=True)
def get_trade(self):
"""

View file

@ -1,5 +1,6 @@
import pathlib
import copy
import time
from flask import g
from contextlib import suppress
from fractions import Fraction
@ -311,75 +312,90 @@ class Device(Thing):
return history
@property
def trading(self):
def tradings(self):
return {str(x.id): self.trading(x.lot) for x in self.actions if x.t == 'Trade'}
def trading(self, lot, simple=None):
"""The trading state, or None if no Trade action has
ever been performed to this device. This extract the posibilities for to do"""
# trade = 'Trade'
confirm = 'Confirm'
need_confirm = 'NeedConfirmation'
double_confirm = 'TradeConfirmed'
revoke = 'Revoke'
revoke_pending = 'RevokePending'
confirm_revoke = 'ConfirmRevoke'
# revoke_confirmed = 'RevokeConfirmed'
# return the correct status of trade depending of the user
# #### CASES #####
# User1 == owner of trade (This user have automatic Confirmation)
# =======================
# if the last action is => only allow to do
# ==========================================
# Confirmation not User1 => Revoke
# Confirmation User1 => Revoke
# Revoke not User1 => ConfirmRevoke
# Revoke User1 => RevokePending
# RevokeConfirmation => RevokeConfirmed
#
#
# User2 == Not owner of trade
# =======================
# if the last action is => only allow to do
# ==========================================
# Confirmation not User2 => Confirm
# Confirmation User2 => Revoke
# Revoke not User2 => ConfirmRevoke
# Revoke User2 => RevokePending
# RevokeConfirmation => RevokeConfirmed
ac = self.last_action_trading
if not ac:
ever been performed to this device. This extract the posibilities for to do.
This method is performed for show in the web.
If you need to do one simple and generic response you can put simple=True for that."""
if not hasattr(lot, 'trade'):
return
first_owner = self.which_user_put_this_device_in_trace()
Status = {0: 'Trade',
1: 'Confirm',
2: 'NeedConfirmation',
3: 'TradeConfirmed',
4: 'Revoke',
5: 'NeedConfirmRevoke',
6: 'RevokeConfirmed'}
if ac.type == confirm_revoke:
# can to do revoke_confirmed
return confirm_revoke
trade = lot.trade
user_from = trade.user_from
user_to = trade.user_to
status = 0
last_user = None
if ac.type == revoke:
if ac.user == g.user:
# can todo revoke_pending
return revoke_pending
else:
# can to do confirm_revoke
return revoke
if not hasattr(trade, 'acceptances'):
return Status[status]
if ac.type == confirm:
if not first_owner:
return
for ac in self.actions:
if ac.t not in ['Confirm', 'Revoke']:
continue
if ac.user == first_owner:
if first_owner == g.user:
# can to do revoke
return confirm
else:
# can to do confirm
return need_confirm
else:
# can to do revoke
return double_confirm
if ac.user not in [user_from, user_to]:
continue
if ac.t == 'Confirm' and ac.action == trade:
if status in [0, 6]:
if simple:
status = 2
continue
status = 1
last_user = ac.user
if ac.user == user_from and user_to == g.user:
status = 2
if ac.user == user_to and user_from == g.user:
status = 2
continue
if status in [1, 2]:
if last_user != ac.user:
status = 3
last_user = ac.user
continue
if status in [4, 5]:
status = 3
last_user = ac.user
continue
if ac.t == 'Revoke' and ac.action == trade:
if status == 3:
if simple:
status = 5
continue
status = 4
last_user = ac.user
if ac.user == user_from and user_to == g.user:
status = 5
if ac.user == user_to and user_from == g.user:
status = 5
continue
if status in [4, 5]:
if last_user != ac.user:
status = 6
last_user = ac.user
continue
if status in [1, 2]:
status = 6
last_user = ac.user
continue
return Status[status]
@property
def revoke(self):
@ -485,15 +501,15 @@ class Device(Thing):
def which_user_put_this_device_in_trace(self):
"""which is the user than put this device in this trade"""
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
actions.reverse()
last_ac = None
# search the automatic Confirm
for ac in actions:
if ac.type == 'Trade':
return last_ac.user
if ac.type == 'Confirm':
last_ac = ac
action_device = [x for x in ac.actions_device if x.device == self][0]
if action_device.author:
return action_device.author
return ac.author
def change_owner(self, new_user):
"""util for change the owner one device"""

View file

@ -1,7 +1,7 @@
import datetime
from marshmallow import post_load, pre_load, fields as f
from marshmallow.fields import Boolean, Date, DateTime, Float, Integer, List, Str, String, UUID
from marshmallow.fields import Boolean, Date, DateTime, Float, Integer, List, Str, String, UUID, Dict
from marshmallow.validate import Length, OneOf, Range
from sqlalchemy.util import OrderedSet
from stdnum import imei, meid
@ -50,12 +50,11 @@ class Device(Thing):
description='The lots where this device is directly under.')
rate = NestedOn('Rate', dump_only=True, description=m.Device.rate.__doc__)
price = NestedOn('Price', dump_only=True, description=m.Device.price.__doc__)
# trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__)
trading = SanitizedStr(dump_only=True, description='')
tradings = Dict(dump_only=True, description='')
physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__)
traking= EnumField(states.Traking, dump_only=True, description=m.Device.physical.__doc__)
traking = EnumField(states.Traking, dump_only=True, description=m.Device.physical.__doc__)
usage = EnumField(states.Usage, dump_only=True, description=m.Device.physical.__doc__)
revoke = UUID(dump_only=True)
revoke = UUID(dump_only=True)
physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor')
production_date = DateTime('iso',
description=m.Device.updated.comment,

View file

@ -37,7 +37,6 @@ class Trading(State):
Trade = e.Trade
Confirm = e.Confirm
Revoke = e.Revoke
ConfirmRevoke = e.ConfirmRevoke
Cancelled = e.CancelTrade
Sold = e.Sell
Donated = e.Donate

View file

@ -1,4 +1,5 @@
import uuid
from sqlalchemy.util import OrderedSet
from collections import deque
from enum import Enum
from typing import Dict, List, Set, Union
@ -13,7 +14,7 @@ from teal.resource import View
from ereuse_devicehub.db import db
from ereuse_devicehub.query import things_response
from ereuse_devicehub.resources.device.models import Device, Computer
from ereuse_devicehub.resources.action.models import Trade, Confirm, Revoke, ConfirmRevoke
from ereuse_devicehub.resources.action.models import Trade, Confirm, Revoke
from ereuse_devicehub.resources.lot.models import Lot, Path
@ -230,7 +231,7 @@ class LotDeviceView(LotBaseChildrenView):
return
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
Device.owner==g.user))
Device.owner == g.user))
lot.devices.update(devices)
@ -246,7 +247,8 @@ class LotDeviceView(LotBaseChildrenView):
return
if lot.trade:
return delete_from_trade(lot, ids)
devices = Device.query.filter(Device.id.in_(ids)).all()
return delete_from_trade(lot, devices)
if not g.user == lot.owner:
txt = 'This is not your lot'
@ -258,49 +260,45 @@ class LotDeviceView(LotBaseChildrenView):
lot.devices.difference_update(devices)
def delete_from_trade(lot: Lot, ids: Set[int]):
users = [lot.trade.user_from.id, lot.trade.user_to.id]
if not g.user.id in users:
def delete_from_trade(lot: Lot, devices: List):
users = [lot.trade.user_from, lot.trade.user_to]
if g.user not in users:
# theoretically this case is impossible
txt = 'This is not your trade'
raise ma.ValidationError(txt)
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
Device.owner_id.in_(users)))
# we need lock the action revoke for devices than travel for futures trades
for dev in devices:
if dev.owner not in users:
txt = 'This is not your device'
raise ma.ValidationError(txt)
# Now we need to know which devices we need extract of the lot
without_confirms = set() # set of devs without confirms of user2
drop_of_lot = []
without_confirms = []
for dev in devices:
if dev.trading(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']:
drop_of_lot.append(dev)
dev.reset_owner()
# if the trade need confirmation, then extract all devs than
# have only one confirmation and is from the same user than try to do
# now the revoke action
if lot.trade.confirm:
for dev in devices:
# if have only one confirmation
# then can be revoked and deleted of the lot
# Confirm of dev.trading mean that there are only one confirmation
# and the first user than put this device in trade is the actual g.user
if dev.trading == 'Confirm':
without_confirms.add(dev)
dev.reset_owner()
if not lot.trade.confirm:
drop_of_lot.append(dev)
without_confirms.append(dev)
dev.reset_owner()
# we need to mark one revoke for every devs
revoke = Revoke(action=lot.trade, user=g.user, devices=devices)
revoke = Revoke(action=lot.trade, user=g.user, devices=set(devices))
db.session.add(revoke)
if not lot.trade.confirm:
# if the trade is with phantom account
without_confirms = devices
if without_confirms:
confirm_revoke = ConfirmRevoke(
action=revoke,
user=g.user,
devices=without_confirms
phantom = lot.trade.user_to
if lot.trade.user_to == g.user:
phantom = lot.trade.user_from
phantom_revoke = Revoke(
action=lot.trade,
user=phantom,
devices=set(without_confirms)
)
db.session.add(confirm_revoke)
lot.devices.difference_update(without_confirms)
lot.trade.devices = lot.devices
db.session.add(phantom_revoke)
lot.devices.difference_update(OrderedSet(drop_of_lot))
return revoke

View file

@ -328,7 +328,7 @@ def test_outgoinlot_status_actions(action_model: models.Action, user: UserClient
assert device['actions'][-1]['id'] == action['id']
assert action['author']['id'] == user.user['id']
assert action['rol_user']['id'] == user.user['id']
assert action['rol_user']['id'] == user2.user['id']
@pytest.mark.mvp
@ -386,14 +386,14 @@ def test_history_status_actions(user: UserClient, user2: UserClient):
assert action['id'] == str(device.status.id)
assert device.status.t == models.Recycling.t
assert [action['id']] == [str(ac.id) for ac in device.history_status]
# Case 2
action2 = {'type': models.Refurbish.t, 'devices': [device.id]}
action2, _ = user.post(action2, res=models.Action)
assert action2['id'] == str(device.status.id)
assert device.status.t == models.Refurbish.t
assert [action2['id']] == [str(ac.id) for ac in device.history_status]
# Case 3
lot, _ = user.post({'name': 'MyLot'}, res=Lot)
user.post({},
@ -1396,6 +1396,7 @@ def test_confirm_revoke(user: UserClient, user2: UserClient):
user.post(res=models.Action, data=request_post)
trade = models.Trade.query.one()
device = trade.devices[0]
request_confirm = {
'type': 'Confirm',
@ -1416,9 +1417,10 @@ def test_confirm_revoke(user: UserClient, user2: UserClient):
# Normal revoke
user2.post(res=models.Action, data=request_revoke)
# You can not to do one confirmation next of one revoke
user2.post(res=models.Action, data=request_confirm, status=422)
assert len(trade.acceptances) == 3
# You can to do one confirmation next of one revoke
user2.post(res=models.Action, data=request_confirm)
assert len(trade.acceptances) == 4
assert device.trading(trade.lot) == "TradeConfirmed"
@pytest.mark.mvp
@ -1455,7 +1457,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient):
item='{}/devices'.format(lot['id']),
query=devices[:7])
# the manager shares the temporary lot with the SCRAP as an incoming lot
# the manager shares the temporary lot with the SCRAP as an incoming lot
# for the SCRAP to confirm it
request_post = {
'type': 'Trade',
@ -1516,9 +1518,6 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient):
'type': 'Confirm',
'action': trade.id,
'devices': [
snap1['device']['id'],
snap2['device']['id'],
snap3['device']['id'],
snap4['device']['id'],
snap5['device']['id'],
snap6['device']['id'],
@ -1535,7 +1534,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient):
assert trade.devices[-1].actions[-1].user == trade.user_from
assert len(trade.devices[0].actions) == n_actions
# The manager remove one device of the lot and automaticaly
# The manager remove one device of the lot and automaticaly
# is create one revoke action
device_10 = trade.devices[-1]
lot, _ = user.delete({},
@ -1554,31 +1553,28 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient):
# the SCRAP confirms the revoke action
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device_10.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [
snap10['device']['id']
]
}
user2.post(res=models.Action, data=request_confirm_revoke)
assert device_10.actions[-1].t == 'ConfirmRevoke'
assert device_10.actions[-1].t == 'Revoke'
assert device_10.actions[-2].t == 'Revoke'
# assert len(trade.lot.devices) == len(trade.devices) == 9
# assert not device_10 in trade.devices
# check validation error
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device_10.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [
snap9['device']['id']
]
}
user2.post(res=models.Action, data=request_confirm_revoke, status=422)
# The manager add again device_10
# assert len(trade.devices) == 9
lot, _ = user.post({},
@ -1604,7 +1600,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient):
assert device_10.actions[-1].user == trade.user_from
assert device_10.actions[-2].t == 'Confirm'
assert device_10.actions[-2].user == trade.user_to
assert device_10.actions[-3].t == 'ConfirmRevoke'
assert device_10.actions[-3].t == 'Revoke'
# assert len(device_10.actions) == 13
@ -1756,7 +1752,7 @@ def test_trade_case1(user: UserClient, user2: UserClient):
item='{}/devices'.format(lot['id']),
query=devices[:-1])
# the manager shares the temporary lot with the SCRAP as an incoming lot
# the manager shares the temporary lot with the SCRAP as an incoming lot
# for the CRAP to confirm it
request_post = {
'type': 'Trade',
@ -1772,31 +1768,23 @@ def test_trade_case1(user: UserClient, user2: UserClient):
user.post(res=models.Action, data=request_post)
trade = models.Trade.query.one()
lot, _ = user.post({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=devices[-1:])
lot = trade.lot
device = trade.devices[0]
device1, device2 = trade.devices
assert device.actions[-2].t == 'Trade'
assert device.actions[-1].t == 'Confirm'
assert device.actions[-1].user == trade.user_to
assert device1.actions[-2].t == 'Trade'
assert device1.actions[-1].t == 'Confirm'
assert device1.actions[-1].user == trade.user_to
assert device2.actions[-2].t == 'Trade'
assert device2.actions[-1].t == 'Confirm'
assert device2.actions[-1].user == trade.user_to
user.delete({},
res=Lot,
item='{}/devices'.format(lot.id),
query=devices[:-1], status=200)
lot, _ = user.delete({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=devices, status=200)
assert device1.actions[-2].t == 'Revoke'
assert device1.actions[-1].t == 'ConfirmRevoke'
assert device1.actions[-1].user == trade.user_to
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-1].user == trade.user_to
assert device not in trade.lot.devices
assert device.trading(trade.lot) == 'RevokeConfirmed'
assert device.actions[-2].t == 'Confirm'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_to
@pytest.mark.mvp
@ -1855,12 +1843,13 @@ def test_trade_case2(user: UserClient, user2: UserClient):
# Normal revoke
user.post(res=models.Action, data=request_revoke)
assert device1.actions[-2].t == 'Revoke'
assert device1.actions[-1].t == 'ConfirmRevoke'
assert device1.actions[-2].t == 'Confirm'
assert device1.actions[-1].t == 'Revoke'
assert device1.actions[-1].user == trade.user_to
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-2].t == 'Confirm'
assert device2.actions[-1].t == 'Revoke'
assert device2.actions[-1].user == trade.user_to
assert device1.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -1868,7 +1857,6 @@ def test_trade_case2(user: UserClient, user2: UserClient):
def test_trade_case3(user: UserClient, user2: UserClient):
# the pRp (manatest_usecase_confirmationger) creates a temporary lot
lot, _ = user.post({'name': 'MyLot'}, res=Lot)
# The manager add 7 device into the lot
snap1, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
snap2, _ = user2.post(file('acer.happy.battery.snapshot'), res=models.Snapshot)
@ -1880,7 +1868,7 @@ def test_trade_case3(user: UserClient, user2: UserClient):
item='{}/devices'.format(lot['id']),
query=devices[:-1])
# the manager shares the temporary lot with the SCRAP as an incoming lot
# the manager shares the temporary lot with the SCRAP as an incoming lot
# for the CRAP to confirm it
request_post = {
'type': 'Trade',
@ -1915,9 +1903,10 @@ def test_trade_case3(user: UserClient, user2: UserClient):
item='{}/devices'.format(lot['id']),
query=devices[-1:], status=200)
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-2].t == 'Confirm'
assert device2.actions[-1].t == 'Revoke'
assert device2.actions[-1].user == trade.user_from
assert device2.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -1979,9 +1968,10 @@ def test_trade_case4(user: UserClient, user2: UserClient):
assert device1.actions[-2].t == 'Trade'
assert device1.actions[-1].t == 'Confirm'
assert device1.actions[-1].user == trade.user_to
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-2].t == 'Confirm'
assert device2.actions[-1].t == 'Revoke'
assert device2.actions[-1].user == trade.user_from
assert device2.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2036,8 +2026,8 @@ def test_trade_case5(user: UserClient, user2: UserClient):
assert device2.actions[-1].user == trade.user_from
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device2.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device2.id],
}
@ -2045,8 +2035,9 @@ def test_trade_case5(user: UserClient, user2: UserClient):
user.post(res=models.Action, data=request_confirm_revoke)
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-1].t == 'Revoke'
assert device2.actions[-1].user == trade.user_to
assert device2.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2106,8 +2097,8 @@ def test_trade_case6(user: UserClient, user2: UserClient):
assert device2.actions[-1].user == trade.user_to
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device2.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device2.id],
}
@ -2115,8 +2106,9 @@ def test_trade_case6(user: UserClient, user2: UserClient):
user2.post(res=models.Action, data=request_confirm_revoke)
assert device2.actions[-2].t == 'Revoke'
assert device2.actions[-1].t == 'ConfirmRevoke'
assert device2.actions[-1].t == 'Revoke'
assert device2.actions[-1].user == trade.user_from
assert device2.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2158,6 +2150,7 @@ def test_trade_case7(user: UserClient, user2: UserClient):
# Normal revoke
user2.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
lot, _ = user.delete({},
res=Lot,
@ -2165,14 +2158,14 @@ def test_trade_case7(user: UserClient, user2: UserClient):
query=devices, status=200)
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user2.post(res=models.Action, data=request_confirm_revoke)
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_from
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_to
@ -2182,6 +2175,7 @@ def test_trade_case7(user: UserClient, user2: UserClient):
assert device.actions[-4].user == trade.user_to
assert device.actions[-5].t == 'Trade'
assert device.actions[-5].author == trade.user_to
assert device.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2223,6 +2217,7 @@ def test_trade_case8(user: UserClient, user2: UserClient):
# Normal revoke
user2.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
request_revoke = {
'type': 'Revoke',
@ -2234,14 +2229,14 @@ def test_trade_case8(user: UserClient, user2: UserClient):
user.post(res=models.Action, data=request_revoke)
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user2.post(res=models.Action, data=request_confirm_revoke)
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_from
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_to
@ -2251,6 +2246,7 @@ def test_trade_case8(user: UserClient, user2: UserClient):
assert device.actions[-4].user == trade.user_to
assert device.actions[-5].t == 'Trade'
assert device.actions[-5].author == trade.user_to
assert device.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2303,6 +2299,7 @@ def test_trade_case9(user: UserClient, user2: UserClient):
# Normal revoke
user.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
assert device.owner == trade.user_to
@ -2312,8 +2309,8 @@ def test_trade_case9(user: UserClient, user2: UserClient):
query=devices[-1:], status=200)
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
@ -2321,7 +2318,7 @@ def test_trade_case9(user: UserClient, user2: UserClient):
assert device.owner == trade.user_from
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_to
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_from
@ -2331,6 +2328,7 @@ def test_trade_case9(user: UserClient, user2: UserClient):
assert device.actions[-4].user == trade.user_from
assert device.actions[-5].t == 'Trade'
assert device.actions[-5].author == trade.user_to
assert device.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2374,6 +2372,7 @@ def test_trade_case10(user: UserClient, user2: UserClient):
device1, device = trade.devices
assert device.owner == trade.user_from
# assert device.trading(trade.lot) == 'Confirm'
request_confirm = {
'type': 'Confirm',
@ -2383,6 +2382,7 @@ def test_trade_case10(user: UserClient, user2: UserClient):
# Normal confirm
user.post(res=models.Action, data=request_confirm)
# assert device.trading(trade.lot) == 'TradeConfirmed'
assert device.owner == trade.user_to
@ -2394,18 +2394,18 @@ def test_trade_case10(user: UserClient, user2: UserClient):
# Normal revoke
user2.post(res=models.Action, data=request_revoke)
assert device.trading(trade.lot) == 'Revoke'
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user.post(res=models.Action, data=request_confirm_revoke)
assert device.owner == trade.user_from
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_to
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_from
@ -2415,6 +2415,7 @@ def test_trade_case10(user: UserClient, user2: UserClient):
assert device.actions[-4].user == trade.user_from
assert device.actions[-5].t == 'Trade'
assert device.actions[-5].author == trade.user_to
assert device.trading(trade.lot) == 'RevokeConfirmed'
@pytest.mark.mvp
@ -2451,6 +2452,7 @@ def test_trade_case11(user: UserClient, user2: UserClient):
trade = models.Trade.query.one()
device1, device = trade.devices
assert device.trading(trade.lot) == 'Confirm'
request_confirm = {
'type': 'Confirm',
@ -2459,21 +2461,24 @@ def test_trade_case11(user: UserClient, user2: UserClient):
}
user2.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
lot, _ = user2.delete({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=devices[-1:], status=200)
assert device.trading(trade.lot) == 'Revoke'
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user.post(res=models.Action, data=request_confirm_revoke)
assert device.trading(trade.lot) == 'RevokeConfirmed'
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_to
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_from
@ -2519,6 +2524,7 @@ def test_trade_case12(user: UserClient, user2: UserClient):
trade = models.Trade.query.one()
device1, device = trade.devices
assert device.trading(trade.lot) == 'Confirm'
# Normal confirm
request_confirm = {
@ -2528,6 +2534,7 @@ def test_trade_case12(user: UserClient, user2: UserClient):
}
user2.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
request_revoke = {
'type': 'Revoke',
@ -2537,16 +2544,18 @@ def test_trade_case12(user: UserClient, user2: UserClient):
# Normal revoke
user2.post(res=models.Action, data=request_revoke)
assert device.trading(trade.lot) == 'Revoke'
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user.post(res=models.Action, data=request_confirm_revoke)
assert device.trading(trade.lot) == 'RevokeConfirmed'
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_to
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_from
@ -2597,6 +2606,8 @@ def test_trade_case13(user: UserClient, user2: UserClient):
query=devices[-1:])
device1, device = trade.devices
assert device1.trading(trade.lot) == 'NeedConfirmation'
assert device.trading(trade.lot) == 'Confirm'
request_confirm = {
'type': 'Confirm',
@ -2605,21 +2616,26 @@ def test_trade_case13(user: UserClient, user2: UserClient):
}
user.post(res=models.Action, data=request_confirm)
assert device1.trading(trade.lot) == 'Confirm'
assert device.trading(trade.lot) == 'TradeConfirmed'
lot, _ = user.delete({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=devices[-1:], status=200)
assert device1.trading(trade.lot) == 'Confirm'
assert device.trading(trade.lot) == 'Revoke'
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user2.post(res=models.Action, data=request_confirm_revoke)
assert device.trading(trade.lot) == 'RevokeConfirmed'
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_from
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_to
@ -2670,6 +2686,8 @@ def test_trade_case14(user: UserClient, user2: UserClient):
query=devices[-1:])
device1, device = trade.devices
assert device1.trading(trade.lot) == 'NeedConfirmation'
assert device.trading(trade.lot) == 'Confirm'
# Normal confirm
request_confirm = {
@ -2679,6 +2697,7 @@ def test_trade_case14(user: UserClient, user2: UserClient):
}
user.post(res=models.Action, data=request_confirm)
assert device.trading(trade.lot) == 'TradeConfirmed'
request_revoke = {
'type': 'Revoke',
@ -2688,16 +2707,18 @@ def test_trade_case14(user: UserClient, user2: UserClient):
# Normal revoke
user.post(res=models.Action, data=request_revoke)
assert device.trading(trade.lot) == 'Revoke'
request_confirm_revoke = {
'type': 'ConfirmRevoke',
'action': device.actions[-1].id,
'type': 'Revoke',
'action': trade.id,
'devices': [device.id],
}
user2.post(res=models.Action, data=request_confirm_revoke)
assert device.trading(trade.lot) == 'RevokeConfirmed'
assert device.actions[-1].t == 'ConfirmRevoke'
assert device.actions[-1].t == 'Revoke'
assert device.actions[-1].user == trade.user_from
assert device.actions[-2].t == 'Revoke'
assert device.actions[-2].user == trade.user_to
@ -2718,7 +2739,7 @@ def test_action_web_erase(user: UserClient, client: Client):
hash3 = hashlib.sha3_256(bfile.read()).hexdigest()
snap, _ = user.post(file('acer.happy.battery.snapshot'), res=models.Snapshot)
request = {'type': 'DataWipe', 'devices': [snap['device']['id']], 'name': 'borrado universal', 'severity': 'Info', 'description': 'nada que describir', 'url': 'http://www.google.com/', 'documentId': '33', 'endTime': '2021-07-07T22:00:00.000Z', 'filename': 'Certificado de borrado1.pdf', 'hash': hash3, 'success': 1, 'software': "Blanco"}
user.post(res=models.Action, data=request)
action = models.DataWipe.query.one()
for dev in action.devices:

View file

@ -181,14 +181,13 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient):
query=[('filter', {'type': ['Computer']})])
body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;'
body1_lenovo += 'foo2@foo.com;Supplier;False;Use;;'
body1_lenovo += 'foo2@foo.com;Supplier;NeedConfirmation;Use;;'
body2_lenovo = ';;0;0;Trade;0;0\n'
body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;'
body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;False;;;;;0;'
body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;NeedConfirmation;;;;;0;'
body2_acer = ';;0;0;Trade;0;4692.0\n'
# import pdb; pdb.set_trace()
assert body1_lenovo in csv_str
assert body2_lenovo in csv_str
assert body1_acer in csv_str
@ -203,7 +202,7 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient):
query=[('filter', {'type': ['Computer']})])
body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;'
body1_lenovo += 'foo2@foo.com;Supplier;False;Use;Use;'
body1_lenovo += 'foo2@foo.com;Supplier;NeedConfirmation;Use;Use;'
body2_lenovo = ';;0;0;Trade;0;0\n'
body2_acer = ';;0;0;Trade;0;4692.0\n'
@ -353,8 +352,8 @@ def test_bug_trade_confirmed(user: UserClient, user2: UserClient):
accept='text/csv',
query=[('filter', {'type': ['Computer']})])
body_not_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;False;"
body_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;True;"
body_not_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;NeedConfirmation;"
body_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;TradeConfirmed;"
assert body_not_confirmed in csv_not_confirmed
assert body_confirmed in csv_confirmed

View file

@ -66,7 +66,7 @@ def test_workbench_server_condensed(user: UserClient):
assert device['rate']['rating'] == 1
assert device['rate']['type'] == RateComputer.t
# TODO JN why haven't same order in actions on each execution?
assert device['actions'][2]['type'] == BenchmarkProcessor.t or device['actions'][2]['type'] == BenchmarkRamSysbench.t
assert any([ac['type'] in [BenchmarkProcessor.t, BenchmarkRamSysbench.t] for ac in device['actions']])
assert 'tag1' in [x['id'] for x in device['tags']]