add manual edit placeholder

This commit is contained in:
Cayo Puigdefabregas 2022-07-05 18:09:47 +02:00
parent 71518ca2a5
commit bc8944a498
9 changed files with 391 additions and 25 deletions

View File

@ -334,7 +334,12 @@ class NewDeviceForm(FlaskForm):
screen = FloatField('Screen size', [validators.Optional()])
def __init__(self, *args, **kwargs):
self._obj = kwargs.pop('_obj', None)
super().__init__(*args, **kwargs)
if self._obj:
self.type.data = self._obj.type
if not request.form:
self.reset_from_obj()
self.devices = {
"Laptop": Laptop,
"Desktop": Desktop,
@ -364,6 +369,45 @@ class NewDeviceForm(FlaskForm):
if not self.depth.data:
self.depth.data = 0.1
def reset_from_obj(self):
if not self._obj:
return
disabled = {'disabled': "disabled"}
appearance = self._obj.appearance()
functionality = self._obj.functionality()
if appearance:
appearance = appearance.name
if functionality:
functionality = functionality.name
self.type.render_kw = disabled
self.type.data = self._obj.type
self.amount.render_kw = disabled
self.id_device_supplier.data = self._obj.placeholder.id_device_supplier
self.phid.data = self._obj.placeholder.phid
self.pallet.data = self._obj.placeholder.pallet
self.info.data = self._obj.placeholder.info
self.serial_number.data = self._obj.serial_number
self.model.data = self._obj.model
self.manufacturer.data = self._obj.manufacturer
self.appearance.data = appearance
self.functionality.data = functionality
self.brand.data = self._obj.brand
self.generation.data = self._obj.generation
self.version.data = self._obj.version
self.weight.data = self._obj.weight
self.width.data = self._obj.width
self.height.data = self._obj.height
self.depth.data = self._obj.depth
self.variant.data = self._obj.variant
self.sku.data = self._obj.sku
self.image.data = self._obj.image
if self._obj.type in ['Smartphone', 'Tablet', 'Cellphone']:
self.imei.data = self._obj.imei
self.meid.data = self._obj.meid
if self._obj.type == 'ComputerMonitor':
self.resolution.data = self._obj.resolution_width
self.screen.data = self._obj.size
def validate(self, extra_validators=None): # noqa: C901
error = ["Not a correct value"]
is_valid = super().validate(extra_validators)
@ -403,7 +447,20 @@ class NewDeviceForm(FlaskForm):
self.meid.errors = error
is_valid = False
if self.phid.data and self.amount.data == 1:
if self.phid.data and self.amount.data == 1 and not self._obj:
dev = Placeholder.query.filter(
Placeholder.phid == self.phid.data, Device.owner == g.user
).first()
if dev:
msg = "Sorry, exist one snapshot device with this HID"
self.phid.errors = [msg]
is_valid = False
if (
self.phid.data
and self._obj
and self.phid.data != self._obj.placeholder.phid
):
dev = Placeholder.query.filter(
Placeholder.phid == self.phid.data, Device.owner == g.user
).first()
@ -427,6 +484,9 @@ class NewDeviceForm(FlaskForm):
return True
def save(self, commit=True):
if self._obj:
self.edit_device()
else:
for n in range(self.amount.data):
self.reset_ids()
self.create_device()
@ -466,7 +526,6 @@ class NewDeviceForm(FlaskForm):
'functionalityRange': self.functionality.data,
}
]
# import pdb; pdb.set_trace()
snapshot_json = schema.load(json_snapshot)
device = snapshot_json['device']
@ -501,6 +560,42 @@ class NewDeviceForm(FlaskForm):
)
return self.placeholder
def edit_device(self):
self._obj.placeholder.phid = self.phid.data or self._obj.placeholder.phid
self._obj.placeholder.id_device_supplier = self.id_device_supplier.data or None
self._obj.placeholder.info = self.info.data or None
self._obj.placeholder.pallet = self.pallet.data or None
self._obj.model = self.model.data
self._obj.manufacturer = self.manufacturer.data
self._obj.serial_number = self.serial_number.data
self._obj.brand = self.brand.data
self._obj.version = self.version.data
self._obj.generation = self.generation.data
self._obj.sku = self.sku.data
self._obj.weight = self.weight.data
self._obj.width = self.width.data
self._obj.height = self.height.data
self._obj.depth = self.depth.data
self._obj.variant = self.variant.data
self._obj.image = self.image.data
if self._obj.type == 'ComputerMonitor':
self._obj.resolution_width = self.resolution.data
self._obj.size = self.screen.data
if self._obj.type in ['Smartphone', 'Tablet', 'Cellphone']:
self._obj.imei = self.imei.data
self._obj.meid = self.meid.data
if self.appearance.data and self.appearance.data != self._obj.appearance().name:
self._obj.set_appearance(self.appearance.data)
if (
self.functionality.data
and self.functionality.data != self._obj.functionality().name
):
self._obj.set_functionality(self.functionality.data)
class TagDeviceForm(FlaskForm):
tag = SelectField('Tag', choices=[])
@ -1342,18 +1437,42 @@ class UploadPlaceholderForm(FlaskForm):
'Select a Placeholder File', [validators.DataRequired()]
)
def get_data_file(self):
files = request.files.getlist(self.placeholder_file.name)
if not files:
return False
_file = files[0]
if _file.content_type == 'text/csv':
delimiter = ';'
data = pd.read_csv(_file).to_dict()
head = list(data.keys())[0].split(delimiter)
values = [
{k: v.split(delimiter)} for x in data.values() for k, v in x.items()
]
data = {}
for i in range(len(head)):
data[head[i]] = {}
for x in values:
for k, v in x.items():
data[head[i]][k] = v[i]
else:
data = pd.read_excel(_file).to_dict()
return data
def validate(self, extra_validators=None):
is_valid = super().validate(extra_validators)
if not is_valid:
return False
files = request.files.getlist(self.placeholder_file.name)
if not files:
if not request.files.getlist(self.placeholder_file.name):
return False
data = pd.read_excel(files[0]).to_dict()
data = self.get_data_file()
header = [
'Phid',
'Model',
@ -1428,3 +1547,31 @@ class UploadPlaceholderForm(FlaskForm):
db.session.commit()
return self.placeholders
class EditPlaceholderForm(FlaskForm):
manufacturer = StringField('Manufacturer', [validators.Optional()])
model = StringField('Model', [validators.Optional()])
serial_number = StringField('Serial Number', [validators.Optional()])
id_device_supplier = StringField('Id Supplier', [validators.Optional()])
phid = StringField('Phid', [validators.DataRequired()])
pallet = StringField('Pallet', [validators.Optional()])
info = StringField('Info', [validators.Optional()])
def validate(self, extra_validators=None):
is_valid = super().validate(extra_validators)
if not is_valid:
return False
return True
def save(self, commit=True):
for device in self.placeholders:
db.session.add(device)
if commit:
db.session.commit()
return self.placeholders

View File

@ -273,10 +273,37 @@ class DeviceCreateView(GenericMixin):
return flask.render_template(self.template_name, **self.context)
class DeviceEditView(GenericMixin):
methods = ['GET', 'POST']
decorators = [login_required]
template_name = 'inventory/device_create.html'
def dispatch_request(self, id):
self.get_context()
device = (
Device.query.filter(Device.owner_id == current_user.id)
.filter(Device.devicehub_id == id)
.one()
)
form = NewDeviceForm(_obj=device)
self.context.update(
{
'page_title': 'Edit Device',
'form': form,
}
)
if form.validate_on_submit():
next_url = url_for('inventory.device_details', id=id)
form.save(commit=True)
messages.success('Device "{}" edited successfully!'.format(form.type.data))
return flask.redirect(next_url)
return flask.render_template(self.template_name, **self.context)
class TagLinkDeviceView(View):
methods = ['POST']
decorators = [login_required]
# template_name = 'inventory/device_list.html'
def dispatch_request(self):
form = TagDeviceForm()
@ -853,10 +880,11 @@ class UploadPlaceholderView(GenericMixin):
if lot_id:
lots = self.context['lots']
lot = lots.filter(Lot.id == lot_id).one()
for snap in snapshots:
lot.devices.add(snap.device)
for device in snapshots:
lot.devices.add(device)
db.session.add(lot)
db.session.commit()
messages.success('Placeholders uploaded successfully!')
return flask.render_template(self.template_name, **self.context)
@ -900,6 +928,9 @@ devices.add_url_rule(
'/lot/<string:lot_id>/device/add/',
view_func=DeviceCreateView.as_view('lot_device_add'),
)
devices.add_url_rule(
'/device/edit/<string:id>/', view_func=DeviceEditView.as_view('device_edit')
)
devices.add_url_rule(
'/tag/devices/add/', view_func=TagLinkDeviceView.as_view('tag_devices_add')
)

View File

@ -601,6 +601,34 @@ class Device(Thing):
args[POLYMORPHIC_ON] = cls.type
return args
def appearance(self):
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
with suppress(LookupError, ValueError, StopIteration):
action = next(e for e in reversed(actions) if e.type == 'VisualTest')
return action.appearance_range
def functionality(self):
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
with suppress(LookupError, ValueError, StopIteration):
action = next(e for e in reversed(actions) if e.type == 'VisualTest')
return action.functionality_range
def set_appearance(self, value):
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
with suppress(LookupError, ValueError, StopIteration):
action = next(e for e in reversed(actions) if e.type == 'VisualTest')
action.appearance_range = value
def set_functionality(self, value):
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
with suppress(LookupError, ValueError, StopIteration):
action = next(e for e in reversed(actions) if e.type == 'VisualTest')
action.functionality_range = value
def is_status(self, action):
from ereuse_devicehub.resources.device import states

View File

@ -34,7 +34,7 @@
<div>
<div class="form-group has-validation mb-2">
<label for="name" class="form-label">Type *</label>
<select id="type" class="form-control" name="type" required="">
<select id="type" class="form-control" name="type" required="" {% if form.type.render_kw.disabled %}disabled="disabled"{% endif %}>
<option value="">Select one Type</option>
<optgroup label="Computer">
<option value="Laptop"
@ -184,27 +184,33 @@
<div class="from-group has-validation mb-2">
<label for="model" class="form-label">{{ form.appearance.label }}</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="Z">
<input class="form-check-input" type="radio" name="appearance" value="Z"
{% if form.appearance.data == 'Z' %}checked="cheked"{% endif %}>
<label class="form-check-label">0. The device is new.</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="A">
<input class="form-check-input" type="radio" name="appearance" value="A"
{% if form.appearance.data == 'A' %}checked="checked"{% endif %}>
<label class="form-check-label">A. Like new (no visual damage))</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="B">
<input class="form-check-input" type="radio" name="appearance" value="B"
{% if form.appearance.data == 'B' %}checked="checked"{% endif %}>
<label class="form-check-label">B. In very good condition (small visual damage to hard-to-detect parts)</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="C">
<input class="form-check-input" type="radio" name="appearance" value="C"
{% if form.appearance.data == 'C' %}checked="checked"{% endif %}>
<label class="form-check-label">C. In good condition (small visual damage to easy-to-detect parts, not the screen))</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="D">
<input class="form-check-input" type="radio" name="appearance" value="D"
{% if form.appearance.data == 'D' %}checked="checked"{% endif %}>
<label class="form-check-label">D. It is acceptable (visual damage to visible parts, not on the screen)</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="appearance" value="E">
<input class="form-check-input" type="radio" name="appearance" value="E"
{% if form.appearance.data == 'E' %}checked="checked"{% endif %}>
<label class="form-check-label">E. It is unacceptable (substantial visual damage that may affect use)</label>
</div>
<small class="text-muted form-text">Rate the imperfections that affect the device aesthetically, but not its use.</small>
@ -220,19 +226,23 @@
<div class="from-group has-validation mb-2">
<label for="model" class="form-label">{{ form.functionality.label }}</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="functionality" value="A">
<input class="form-check-input" type="radio" name="functionality" value="A"
{% if form.functionality.data == 'A' %}checked="checked"{% endif %}>
<label class="form-check-label">A. Everything works perfectly (buttons, and no scratches on the screen)</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="functionality" value="B">
<input class="form-check-input" type="radio" name="functionality" value="B"
{% if form.functionality.data == 'B' %}checked="checked"{% endif %}>
<label class="form-check-label">B. There is a hard to press button or small scratches on the corners of the screen</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="functionality" value="C">
<input class="form-check-input" type="radio" name="functionality" value="C"
{% if form.functionality.data == 'C' %}checked="checked"{% endif %}>
<label class="form-check-label">C. A non-essential button does not work; the screen has multiple scratches on the corners</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="functionality" value="D">
<input class="form-check-input" type="radio" name="functionality" value="D"
{% if form.functionality.data == 'D' %}checked="checked"{% endif %}>
<label class="form-check-label">D. Multiple buttons do not work properly; the screen has severe damage that may affect use</label>
</div>
<small class="text-muted form-text">It qualifies the defects of a device that affect its use.</small>

View File

@ -54,7 +54,8 @@
<div class="tab-content pt-2">
<div class="tab-pane fade show active" id="type">
<h5 class="card-title">Type Details</h5>
<h5 class="card-title">Details</h5>
{% if device.placeholder %}(<a href="{{ url_for('inventory.device_edit', id=device.devicehub_id)}}">edit</a>){% endif %}
<div class="row">
<div class="col-lg-3 col-md-4 label ">Type</div>

View File

@ -92,6 +92,13 @@
<div class="input-group has-validation">
{{ form.placeholder_file }}
</div>
{% if form.placeholder_file.errors %}
<p class="text-danger">
{% for error in form.placeholder_file.errors %}
{{ error }}<br/>
{% endfor %}
</p>
{% endif %}
</div>
<div>

View File

@ -49,3 +49,5 @@ pandas==1.3.5
numpy==1.21.6
odfpy==1.4.1
xlrd==2.0.1
openpyxl==3.0.10
et_xmlfile==1.1.0

Binary file not shown.

View File

@ -1634,10 +1634,150 @@ def test_add_placeholder_excel(user3: UserClientFlask):
'placeholder_file': excel,
}
user3.post(uri, data=data, content_type="multipart/form-data")
assert Device.query.count() == 1
assert Device.query.count() == 3
dev = Device.query.first()
assert dev.hid == 'laptop-sony-vaio-12345678'
assert dev.placeholder.phid == 'a123'
assert dev.placeholder.info == 'Good conditions'
assert dev.placeholder.pallet == '24A'
assert dev.placeholder.id_device_supplier == 'TTT'
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_add_placeholder_csv(user3: UserClientFlask):
uri = '/inventory/upload-placeholder/'
body, status = user3.get(uri)
assert status == '200 OK'
assert "Upload Placeholder" in body
file_path = Path(__file__).parent.joinpath('files').joinpath('placeholder_test.csv')
with open(file_path, 'rb') as excel:
data = {
'csrf_token': generate_csrf(),
'type': "Laptop",
'placeholder_file': excel,
}
user3.post(uri, data=data, content_type="multipart/form-data")
assert Device.query.count() == 3
dev = Device.query.first()
assert dev.hid == 'laptop-sony-vaio-12345678'
assert dev.placeholder.phid == 'a123'
assert dev.placeholder.info == 'Good conditions'
assert dev.placeholder.pallet == '24A'
assert dev.placeholder.id_device_supplier == 'TTT'
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_add_placeholder_ods(user3: UserClientFlask):
uri = '/inventory/upload-placeholder/'
body, status = user3.get(uri)
assert status == '200 OK'
assert "Upload Placeholder" in body
file_path = Path(__file__).parent.joinpath('files').joinpath('placeholder_test.ods')
with open(file_path, 'rb') as excel:
data = {
'csrf_token': generate_csrf(),
'type': "Laptop",
'placeholder_file': excel,
}
user3.post(uri, data=data, content_type="multipart/form-data")
assert Device.query.count() == 3
dev = Device.query.first()
assert dev.hid == 'laptop-sony-vaio-12345678'
assert dev.placeholder.phid == 'a123'
assert dev.placeholder.info == 'Good conditions'
assert dev.placeholder.pallet == '24A'
assert dev.placeholder.id_device_supplier == 'TTT'
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_add_placeholder_office_open_xml(user3: UserClientFlask):
uri = '/inventory/upload-placeholder/'
body, status = user3.get(uri)
assert status == '200 OK'
assert "Upload Placeholder" in body
file_path = (
Path(__file__).parent.joinpath('files').joinpath('placeholder_test.xlsx')
)
with open(file_path, 'rb') as excel:
data = {
'csrf_token': generate_csrf(),
'type': "Laptop",
'placeholder_file': excel,
}
user3.post(uri, data=data, content_type="multipart/form-data")
assert Device.query.count() == 3
dev = Device.query.first()
assert dev.hid == 'laptop-sony-vaio-12345678'
assert dev.placeholder.phid == 'a123'
assert dev.placeholder.info == 'Good conditions'
assert dev.placeholder.pallet == '24A'
assert dev.placeholder.id_device_supplier == 'TTT'
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_edit_laptop(user3: UserClientFlask):
uri = '/inventory/device/add/'
body, status = user3.get(uri)
assert status == '200 OK'
assert "New Device" in body
data = {
'csrf_token': generate_csrf(),
'type': "Laptop",
'serial_number': "AAAAB",
'model': "LC27T55",
'manufacturer': "Samsung",
'generation': 1,
'weight': 0.1,
'height': 0.1,
'depth': 0.1,
'id_device_supplier': "b2",
}
body, status = user3.post(uri, data=data)
assert status == '200 OK'
assert 'Device &#34;Laptop&#34; created successfully!' in body
dev = Device.query.one()
assert dev.type == 'Laptop'
assert dev.hid == 'laptop-samsung-lc27t55-aaaab'
assert dev.placeholder.phid == '1'
assert dev.placeholder.id_device_supplier == 'b2'
assert dev.serial_number == 'aaaab'
assert dev.model == 'lc27t55'
uri = '/inventory/device/edit/{}/'.format(dev.devicehub_id)
body, status = user3.get(uri)
assert status == '200 OK'
assert "Edit Device" in body
data = {
'csrf_token': generate_csrf(),
'type': "Laptop",
'serial_number': "AAAAC",
'model': "LC27T56",
'manufacturer': "Samsung",
'generation': 1,
'weight': 0.1,
'height': 0.1,
'depth': 0.1,
'id_device_supplier': "a2",
}
body, status = user3.post(uri, data=data)
assert status == '200 OK'
assert 'Device &#34;Laptop&#34; edited successfully!' in body
dev = Device.query.one()
assert dev.type == 'Laptop'
assert dev.hid == 'laptop-samsung-lc27t55-aaaab'
assert dev.placeholder.phid == '1'
assert dev.placeholder.id_device_supplier == 'a2'
assert dev.serial_number == 'aaaac'
assert dev.model == 'lc27t56'