Merge pull request #284 from eReuse/bugfix/3385-bug-date-allocate
fixed bugs of allocate
This commit is contained in:
commit
776c27a082
|
@ -1,4 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
|
|
||||||
|
@ -667,6 +668,10 @@ class AllocateForm(ActionFormMix):
|
||||||
self.start_time.errors = ['Not a valid date value.!']
|
self.start_time.errors = ['Not a valid date value.!']
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if start_time > datetime.datetime.now().date():
|
||||||
|
self.start_time.errors = ['Not a valid date value.!']
|
||||||
|
return False
|
||||||
|
|
||||||
if start_time and end_time and end_time < start_time:
|
if start_time and end_time and end_time < start_time:
|
||||||
error = ['The action cannot finish before it starts.']
|
error = ['The action cannot finish before it starts.']
|
||||||
self.end_time.errors = error
|
self.end_time.errors = error
|
||||||
|
@ -679,23 +684,100 @@ class AllocateForm(ActionFormMix):
|
||||||
|
|
||||||
def check_devices(self):
|
def check_devices(self):
|
||||||
if self.type.data == 'Allocate':
|
if self.type.data == 'Allocate':
|
||||||
|
return self.check_allocate()
|
||||||
|
if self.type.data == 'Deallocate':
|
||||||
|
return self.check_deallocate()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_allocate(self):
|
||||||
txt = "You need deallocate before allocate this device again"
|
txt = "You need deallocate before allocate this device again"
|
||||||
for device in self._devices:
|
for device in self._devices:
|
||||||
if device.allocated:
|
# | Allo - Deallo | Allo - Deallo |
|
||||||
|
|
||||||
|
allocates = [
|
||||||
|
ac for ac in device.actions if ac.type in ['Allocate', 'Deallocate']
|
||||||
|
]
|
||||||
|
allocates.sort(key=lambda x: x.start_time)
|
||||||
|
allocates.reverse()
|
||||||
|
last_deallocate = None
|
||||||
|
last_allocate = None
|
||||||
|
for ac in allocates:
|
||||||
|
if (
|
||||||
|
ac.type == 'Deallocate'
|
||||||
|
and ac.start_time.date() < self.start_time.data
|
||||||
|
):
|
||||||
|
# allow to do the action
|
||||||
|
break
|
||||||
|
|
||||||
|
# check if this action is between an old allocate - deallocate
|
||||||
|
if ac.type == 'Deallocate':
|
||||||
|
last_deallocate = ac
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (
|
||||||
|
ac.type == 'Allocate'
|
||||||
|
and ac.start_time.date() > self.start_time.data
|
||||||
|
):
|
||||||
|
last_deallocate = None
|
||||||
|
last_allocate = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ac.type == 'Allocate':
|
||||||
|
last_allocate = ac
|
||||||
|
|
||||||
|
if last_allocate or not last_deallocate:
|
||||||
self.devices.errors = [txt]
|
self.devices.errors = [txt]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
device.allocated = True
|
device.allocated = True
|
||||||
|
return True
|
||||||
|
|
||||||
if self.type.data == 'Deallocate':
|
def check_deallocate(self):
|
||||||
txt = "Sorry some of this devices are actually deallocate"
|
txt = "Sorry some of this devices are actually deallocate"
|
||||||
for device in self._devices:
|
for device in self._devices:
|
||||||
if not device.allocated:
|
allocates = [
|
||||||
|
ac for ac in device.actions if ac.type in ['Allocate', 'Deallocate']
|
||||||
|
]
|
||||||
|
allocates.sort(key=lambda x: x.start_time)
|
||||||
|
allocates.reverse()
|
||||||
|
last_deallocate = None
|
||||||
|
last_allocate = None
|
||||||
|
|
||||||
|
for ac in allocates:
|
||||||
|
# check if this action is between an old allocate - deallocate
|
||||||
|
# | Allo - Deallo | Allo - Deallo |
|
||||||
|
# | Allo |
|
||||||
|
if (
|
||||||
|
ac.type == 'Allocate'
|
||||||
|
and ac.start_time.date() > self.start_time.data
|
||||||
|
):
|
||||||
|
last_allocate = None
|
||||||
|
last_deallocate = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ac.type == 'Allocate' and not last_deallocate:
|
||||||
|
last_allocate = ac
|
||||||
|
break
|
||||||
|
|
||||||
|
if (
|
||||||
|
ac.type == 'Deallocate'
|
||||||
|
and ac.start_time.date() > self.start_time.data
|
||||||
|
):
|
||||||
|
last_deallocate = ac
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ac.type == 'Deallocate':
|
||||||
|
last_allocate = None
|
||||||
|
|
||||||
|
if last_deallocate or not last_allocate:
|
||||||
|
self.devices.errors = [txt]
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not last_deallocate and not last_allocate:
|
||||||
self.devices.errors = [txt]
|
self.devices.errors = [txt]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
device.allocated = False
|
device.allocated = False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
import pathlib
|
import pathlib
|
||||||
import time
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
@ -358,7 +357,6 @@ class Device(Thing):
|
||||||
from ereuse_devicehub.resources.device import states
|
from ereuse_devicehub.resources.device import states
|
||||||
|
|
||||||
with suppress(LookupError, ValueError):
|
with suppress(LookupError, ValueError):
|
||||||
# import pdb; pdb.set_trace()
|
|
||||||
return self.last_action_of(*states.Physical.actions())
|
return self.last_action_of(*states.Physical.actions())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -407,7 +405,7 @@ class Device(Thing):
|
||||||
def tradings(self):
|
def tradings(self):
|
||||||
return {str(x.id): self.trading(x.lot) for x in self.actions if x.t == 'Trade'}
|
return {str(x.id): self.trading(x.lot) for x in self.actions if x.t == 'Trade'}
|
||||||
|
|
||||||
def trading(self, lot, simple=None):
|
def trading(self, lot, simple=None): # noqa: C901
|
||||||
"""The trading state, or None if no Trade action has
|
"""The trading state, or None if no Trade action has
|
||||||
ever been performed to this device. This extract the posibilities for to do.
|
ever been performed to this device. This extract the posibilities for to do.
|
||||||
This method is performed for show in the web.
|
This method is performed for show in the web.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import csv
|
import csv
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -686,6 +687,34 @@ def test_action_allocate_error_dates(user3: UserClientFlask):
|
||||||
assert dev.actions[-1].type != 'Allocate'
|
assert dev.actions[-1].type != 'Allocate'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_action_allocate_error_future_dates(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
dev = snap.device
|
||||||
|
uri = '/inventory/device/'
|
||||||
|
user3.get(uri)
|
||||||
|
start_time = (datetime.datetime.now() + datetime.timedelta(1)).strftime('%Y-%m-%d')
|
||||||
|
end_time = (datetime.datetime.now() + datetime.timedelta(10)).strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': start_time,
|
||||||
|
'end_time': end_time,
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
body, status = user3.post(uri, data=data)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert 'Action Allocate error' in body
|
||||||
|
assert 'Not a valid date value.!' in body
|
||||||
|
assert dev.actions[-1].type != 'Allocate'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
def test_action_deallocate(user3: UserClientFlask):
|
def test_action_deallocate(user3: UserClientFlask):
|
||||||
|
@ -707,7 +736,7 @@ def test_action_deallocate(user3: UserClientFlask):
|
||||||
uri = '/inventory/action/allocate/add/'
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
|
||||||
user3.post(uri, data=data)
|
user3.post(uri, data=data)
|
||||||
assert dev.actions[-1].type == 'Allocate'
|
assert dev.allocated_status.type == 'Allocate'
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'csrf_token': generate_csrf(),
|
'csrf_token': generate_csrf(),
|
||||||
|
@ -720,11 +749,200 @@ def test_action_deallocate(user3: UserClientFlask):
|
||||||
}
|
}
|
||||||
body, status = user3.post(uri, data=data)
|
body, status = user3.post(uri, data=data)
|
||||||
assert status == '200 OK'
|
assert status == '200 OK'
|
||||||
assert dev.actions[-1].type == 'Deallocate'
|
assert dev.allocated_status.type == 'Deallocate'
|
||||||
assert 'Action "Deallocate" created successfully!' in body
|
assert 'Action "Deallocate" created successfully!' in body
|
||||||
assert dev.devicehub_id in body
|
assert dev.devicehub_id in body
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_action_deallocate_error(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
dev = snap.device
|
||||||
|
uri = '/inventory/device/'
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-05-01',
|
||||||
|
'end_time': '2000-06-01',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert dev.allocated_status.type == 'Allocate'
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-01',
|
||||||
|
'end_time': '2000-02-01',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
body, status = user3.post(uri, data=data)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert dev.allocated_status.type != 'Deallocate'
|
||||||
|
assert 'Action Deallocate error!' in body
|
||||||
|
assert 'Sorry some of this devices are actually deallocate' in body
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_action_allocate_deallocate_error(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
dev = snap.device
|
||||||
|
uri = '/inventory/device/'
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-01',
|
||||||
|
'end_time': '2000-01-01',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert dev.allocated_status.type == 'Allocate'
|
||||||
|
assert len(dev.actions) == 13
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-02-01',
|
||||||
|
'end_time': '2000-02-01',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
body, status = user3.post(uri, data=data)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert dev.allocated_status.type == 'Deallocate'
|
||||||
|
assert len(dev.actions) == 14
|
||||||
|
|
||||||
|
# is not possible to do an allocate between an allocate and an deallocate
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-15',
|
||||||
|
'end_time': '2000-01-15',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert dev.allocated_status.type == 'Deallocate'
|
||||||
|
# assert 'Action Deallocate error!' in body
|
||||||
|
# assert 'Sorry some of this devices are actually deallocate' in body
|
||||||
|
#
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-15',
|
||||||
|
'end_time': '2000-01-15',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 14
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_action_allocate_deallocate_error2(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
dev = snap.device
|
||||||
|
uri = '/inventory/device/'
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-10',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 13
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-20',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
body, status = user3.post(uri, data=data)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert len(dev.actions) == 14
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-02-10',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = '/inventory/action/allocate/add/'
|
||||||
|
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 15
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-02-20',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 16
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Allocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-25',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 17
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
'type': "Deallocate",
|
||||||
|
'severity': "Info",
|
||||||
|
'devices': "{}".format(dev.id),
|
||||||
|
'start_time': '2000-01-27',
|
||||||
|
'end_users': 2,
|
||||||
|
}
|
||||||
|
user3.post(uri, data=data)
|
||||||
|
assert len(dev.actions) == 18
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
def test_action_toprepare(user3: UserClientFlask):
|
def test_action_toprepare(user3: UserClientFlask):
|
||||||
|
|
Reference in New Issue