From bc8944a4980c6b0fd72aa46f0cd6aa3ddd1a380e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 5 Jul 2022 18:09:47 +0200 Subject: [PATCH] add manual edit placeholder --- ereuse_devicehub/inventory/forms.py | 165 +++++++++++++++++- ereuse_devicehub/inventory/views.py | 37 +++- ereuse_devicehub/resources/device/models.py | 28 +++ .../templates/inventory/device_create.html | 32 ++-- .../templates/inventory/device_detail.html | 3 +- .../inventory/upload_placeholder.html | 7 + requirements.txt | 2 + tests/files/placeholder_test.xls | Bin 5632 -> 6144 bytes tests/test_render_2_0.py | 142 ++++++++++++++- 9 files changed, 391 insertions(+), 25 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 27e29c7c..aed0d7da 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -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,9 +484,12 @@ class NewDeviceForm(FlaskForm): return True def save(self, commit=True): - for n in range(self.amount.data): - self.reset_ids() - self.create_device() + if self._obj: + self.edit_device() + else: + for n in range(self.amount.data): + self.reset_ids() + self.create_device() if commit: db.session.commit() @@ -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 diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 975e6d4a..fad3abad 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -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//device/add/', view_func=DeviceCreateView.as_view('lot_device_add'), ) +devices.add_url_rule( + '/device/edit//', view_func=DeviceEditView.as_view('device_edit') +) devices.add_url_rule( '/tag/devices/add/', view_func=TagLinkDeviceView.as_view('tag_devices_add') ) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 1b6ae451..0a6a17e4 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -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 diff --git a/ereuse_devicehub/templates/inventory/device_create.html b/ereuse_devicehub/templates/inventory/device_create.html index 433d42ef..a8bcf221 100644 --- a/ereuse_devicehub/templates/inventory/device_create.html +++ b/ereuse_devicehub/templates/inventory/device_create.html @@ -34,7 +34,7 @@
-