resolve conflict
This commit is contained in:
commit
70f093e1a1
|
@ -7,6 +7,7 @@ repos:
|
||||||
rev: 5.9.3
|
rev: 5.9.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
# args: ["--profile", "black", "--filter-files"]
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 4.0.1
|
rev: 4.0.1
|
||||||
hooks:
|
hooks:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import click.testing
|
import click.testing
|
||||||
import ereuse_utils
|
|
||||||
import flask.cli
|
import flask.cli
|
||||||
|
import ereuse_utils
|
||||||
|
|
||||||
from ereuse_devicehub.config import DevicehubConfig
|
from ereuse_devicehub.config import DevicehubConfig
|
||||||
from ereuse_devicehub.devicehub import Devicehub
|
from ereuse_devicehub.devicehub import Devicehub
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
|
|
||||||
from boltons.urlutils import URL
|
from boltons.urlutils import URL
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
|
@ -139,7 +138,7 @@ class LotDeviceForm(FlaskForm):
|
||||||
|
|
||||||
return bool(self._devices)
|
return bool(self._devices)
|
||||||
|
|
||||||
def save(self):
|
def save(self, commit=True):
|
||||||
trade = self._lot.trade
|
trade = self._lot.trade
|
||||||
if trade:
|
if trade:
|
||||||
for dev in self._devices:
|
for dev in self._devices:
|
||||||
|
@ -149,12 +148,16 @@ class LotDeviceForm(FlaskForm):
|
||||||
if self._devices:
|
if self._devices:
|
||||||
self._lot.devices.update(self._devices)
|
self._lot.devices.update(self._devices)
|
||||||
db.session.add(self._lot)
|
db.session.add(self._lot)
|
||||||
|
|
||||||
|
if commit:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def remove(self):
|
def remove(self, commit=True):
|
||||||
if self._devices:
|
if self._devices:
|
||||||
self._lot.devices.difference_update(self._devices)
|
self._lot.devices.difference_update(self._devices)
|
||||||
db.session.add(self._lot)
|
db.session.add(self._lot)
|
||||||
|
|
||||||
|
if commit:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ class LotForm(FlaskForm):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
if self.instance and not self.instance.devices:
|
if self.instance and not self.instance.trade:
|
||||||
self.instance.delete()
|
self.instance.delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return self.instance
|
return self.instance
|
||||||
|
@ -541,9 +544,9 @@ class TagDeviceForm(FlaskForm):
|
||||||
if self.delete:
|
if self.delete:
|
||||||
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(
|
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(
|
||||||
device_id=self.device_id
|
device_id=self.device_id
|
||||||
)
|
).order_by(Tag.id)
|
||||||
else:
|
else:
|
||||||
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None)
|
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None).order_by(Tag.id)
|
||||||
|
|
||||||
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import csv
|
import csv
|
||||||
|
import logging
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
@ -6,10 +7,12 @@ import flask_weasyprint
|
||||||
from flask import Blueprint, g, make_response, request, url_for
|
from flask import Blueprint, g, make_response, request, url_for
|
||||||
from flask.views import View
|
from flask.views import View
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from werkzeug.exceptions import NotFound
|
from requests.exceptions import ConnectionError
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
|
from werkzeug.exceptions import NotFound
|
||||||
|
|
||||||
from ereuse_devicehub import messages
|
from ereuse_devicehub import messages
|
||||||
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.inventory.forms import (
|
from ereuse_devicehub.inventory.forms import (
|
||||||
AllocateForm,
|
AllocateForm,
|
||||||
DataWipeForm,
|
DataWipeForm,
|
||||||
|
@ -35,6 +38,8 @@ from ereuse_devicehub.resources.tag.model import Tag
|
||||||
# TODO(@slamora): rename base 'inventory.devices' --> 'inventory'
|
# TODO(@slamora): rename base 'inventory.devices' --> 'inventory'
|
||||||
devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory')
|
devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory')
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DeviceListMix(View):
|
class DeviceListMix(View):
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
|
@ -43,22 +48,28 @@ class DeviceListMix(View):
|
||||||
def get_context(self, lot_id):
|
def get_context(self, lot_id):
|
||||||
form_filter = FilterForm()
|
form_filter = FilterForm()
|
||||||
filter_types = form_filter.search()
|
filter_types = form_filter.search()
|
||||||
|
lots = (
|
||||||
lots = Lot.query.outerjoin(Trade) \
|
Lot.query.outerjoin(Trade)
|
||||||
.filter(or_(Trade.user_from == g.user,
|
.filter(
|
||||||
Trade.user_to == g.user,
|
or_(
|
||||||
Lot.owner_id == g.user.id)).distinct()
|
Trade.user_from == g.user,
|
||||||
|
Trade.user_to == g.user,
|
||||||
|
Lot.owner_id == g.user.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
lot = None
|
lot = None
|
||||||
tags = (
|
tags = (
|
||||||
Tag.query.filter(Tag.owner_id == current_user.id)
|
Tag.query.filter(Tag.owner_id == current_user.id)
|
||||||
.filter(Tag.device_id.is_(None))
|
.filter(Tag.device_id.is_(None))
|
||||||
.order_by(Tag.created.desc())
|
.order_by(Tag.id.asc())
|
||||||
)
|
)
|
||||||
|
|
||||||
if lot_id:
|
if lot_id:
|
||||||
lot = lots.filter(Lot.id == lot_id).one()
|
lot = lots.filter(Lot.id == lot_id).one()
|
||||||
devices = lot.devices
|
devices = lot.devices
|
||||||
if filter_types:
|
if "All" not in filter_types:
|
||||||
devices = [dev for dev in lot.devices if dev.type in filter_types]
|
devices = [dev for dev in lot.devices if dev.type in filter_types]
|
||||||
devices = sorted(devices, key=lambda x: x.updated, reverse=True)
|
devices = sorted(devices, key=lambda x: x.updated, reverse=True)
|
||||||
form_new_action = NewActionForm(lot=lot.id)
|
form_new_action = NewActionForm(lot=lot.id)
|
||||||
|
@ -145,10 +156,11 @@ class LotDeviceAddView(View):
|
||||||
def dispatch_request(self):
|
def dispatch_request(self):
|
||||||
form = LotDeviceForm()
|
form = LotDeviceForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.save()
|
form.save(commit=False)
|
||||||
messages.success(
|
messages.success(
|
||||||
'Add devices to lot "{}" successfully!'.format(form._lot.name)
|
'Add devices to lot "{}" successfully!'.format(form._lot.name)
|
||||||
)
|
)
|
||||||
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
messages.error('Error adding devices to lot!')
|
messages.error('Error adding devices to lot!')
|
||||||
|
|
||||||
|
@ -164,10 +176,11 @@ class LotDeviceDeleteView(View):
|
||||||
def dispatch_request(self):
|
def dispatch_request(self):
|
||||||
form = LotDeviceForm()
|
form = LotDeviceForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.remove()
|
form.remove(commit=False)
|
||||||
messages.success(
|
messages.success(
|
||||||
'Remove devices from lot "{}" successfully!'.format(form._lot.name)
|
'Remove devices from lot "{}" successfully!'.format(form._lot.name)
|
||||||
)
|
)
|
||||||
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
messages.error('Error removing devices from lot!')
|
messages.error('Error removing devices from lot!')
|
||||||
|
|
||||||
|
@ -218,6 +231,12 @@ class LotDeleteView(View):
|
||||||
|
|
||||||
def dispatch_request(self, id):
|
def dispatch_request(self, id):
|
||||||
form = LotForm(id=id)
|
form = LotForm(id=id)
|
||||||
|
if form.instance.trade:
|
||||||
|
msg = "Sorry, the lot cannot be deleted because have a trade action "
|
||||||
|
messages.error(msg)
|
||||||
|
next_url = url_for('inventory.devices.lotdevicelist', lot_id=id)
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
form.remove()
|
form.remove()
|
||||||
next_url = url_for('inventory.devices.devicelist')
|
next_url = url_for('inventory.devices.devicelist')
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
@ -262,7 +281,7 @@ class TagListView(View):
|
||||||
|
|
||||||
def dispatch_request(self):
|
def dispatch_request(self):
|
||||||
lots = Lot.query.filter(Lot.owner_id == current_user.id)
|
lots = Lot.query.filter(Lot.owner_id == current_user.id)
|
||||||
tags = Tag.query.filter(Tag.owner_id == current_user.id)
|
tags = Tag.query.filter(Tag.owner_id == current_user.id).order_by(Tag.id)
|
||||||
context = {
|
context = {
|
||||||
'lots': lots,
|
'lots': lots,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
|
@ -298,7 +317,18 @@ class TagAddUnnamedView(View):
|
||||||
context = {'page_title': 'New Unnamed Tag', 'lots': lots}
|
context = {'page_title': 'New Unnamed Tag', 'lots': lots}
|
||||||
form = TagUnnamedForm()
|
form = TagUnnamedForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.save()
|
try:
|
||||||
|
form.save()
|
||||||
|
except ConnectionError as e:
|
||||||
|
logger.error(
|
||||||
|
"Error while trying to connect to tag server: {}".format(e)
|
||||||
|
)
|
||||||
|
msg = (
|
||||||
|
"Sorry, we cannot create the unnamed tags requested because "
|
||||||
|
"some error happens while connecting to the tag server!"
|
||||||
|
)
|
||||||
|
messages.error(msg)
|
||||||
|
|
||||||
next_url = url_for('inventory.devices.taglist')
|
next_url = url_for('inventory.devices.taglist')
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
|
@ -474,6 +474,13 @@ class Device(Thing):
|
||||||
key=attrgetter('type')) # last test of each type
|
key=attrgetter('type')) # last test of each type
|
||||||
return self._warning_actions(current_tests)
|
return self._warning_actions(current_tests)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def verbose_name(self):
|
||||||
|
type = self.type or ''
|
||||||
|
manufacturer = self.manufacturer or ''
|
||||||
|
model = self.model or ''
|
||||||
|
return f'{type} {manufacturer} {model}'
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def __mapper_args__(cls):
|
def __mapper_args__(cls):
|
||||||
"""Defines inheritance.
|
"""Defines inheritance.
|
||||||
|
|
|
@ -59,18 +59,39 @@ function deviceSelect() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeLot() {
|
||||||
|
var devices = $(".deviceSelect");
|
||||||
|
if (devices.length > 0) {
|
||||||
|
$("#btnRemoveLots .text-danger").show();
|
||||||
|
} else {
|
||||||
|
$("#btnRemoveLots .text-danger").hide();
|
||||||
|
}
|
||||||
|
$("#activeRemoveLotModal").click();
|
||||||
|
}
|
||||||
|
|
||||||
function removeTag() {
|
function removeTag() {
|
||||||
var devices = $(".deviceSelect").filter(':checked');
|
var devices = $(".deviceSelect").filter(':checked');
|
||||||
var devices_id = $.map(devices, function(x) { return $(x).attr('data')});
|
var devices_id = $.map(devices, function(x) { return $(x).attr('data')});
|
||||||
if (devices_id.length > 0) {
|
if (devices_id.length == 1) {
|
||||||
var url = "/inventory/tag/devices/"+devices_id[0]+"/del/";
|
var url = "/inventory/tag/devices/"+devices_id[0]+"/del/";
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
|
} else {
|
||||||
|
$("#unlinkTagAlertModal").click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTag() {
|
function addTag() {
|
||||||
deviceSelect();
|
var devices = $(".deviceSelect").filter(':checked');
|
||||||
$("#addingTagModal").click();
|
var devices_id = $.map(devices, function(x) { return $(x).attr('data')});
|
||||||
|
if (devices_id.length == 1) {
|
||||||
|
$("#addingTagModal .pol").hide();
|
||||||
|
$("#addingTagModal .btn-primary").show();
|
||||||
|
} else {
|
||||||
|
$("#addingTagModal .pol").show();
|
||||||
|
$("#addingTagModal .btn-primary").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#addTagAlertModal").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function newTrade(action) {
|
function newTrade(action) {
|
||||||
|
|
|
@ -65,5 +65,5 @@ function printpdf() {
|
||||||
min_tag_side = (Math.min(height, width)/2) + border;
|
min_tag_side = (Math.min(height, width)/2) + border;
|
||||||
pdf.addImage(imgData, 'PNG', border, border, img_side, img_side);
|
pdf.addImage(imgData, 'PNG', border, border, img_side, img_side);
|
||||||
pdf.text(tag, max_tag_side, min_tag_side);
|
pdf.text(tag, max_tag_side, min_tag_side);
|
||||||
pdf.save('Tags.pdf');
|
pdf.save('Tag_'+tag+'.pdf');
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,14 @@
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect">
|
<link href="https://fonts.gstatic.com" rel="preconnect">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- JS Files -->
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
|
||||||
|
|
||||||
<!-- Vendor CSS Files -->
|
<!-- Vendor CSS Files -->
|
||||||
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<!-- Template Main CSS File -->
|
<!-- Template Main CSS File -->
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</select>
|
</select>
|
||||||
<input class="devicesList" type="hidden" name="device" />
|
<input class="devicesList" type="hidden" name="device" />
|
||||||
<p class="text-danger pol">
|
<p class="text-danger pol">
|
||||||
You need select first some device for adding this in a tag
|
You need select first one device and only one for add this in a tag
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="modal fade" id="unlinkTagErrorModal" tabindex="-1" style="display: none;" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Error Unlink Tag</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<p class="text-danger pol">
|
||||||
|
You need select first one device and only one for Unlink one Tag
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -31,7 +31,7 @@
|
||||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<div class="form-group has-validation mb-2">
|
<div class="form-group has-validation mb-2">
|
||||||
<label for="name" class="form-label">Type *</label>
|
<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="">
|
||||||
|
@ -369,7 +369,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -385,6 +385,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/create_device.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/create_device.js') }}"></script>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends "ereuse_devicehub/base_site.html" %}
|
{% extends "ereuse_devicehub/base_site.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
|
|
||||||
<div class="pagetitle">
|
<div class="pagetitle">
|
||||||
<h1>Inventory</h1>
|
<h1>Inventory</h1>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends "ereuse_devicehub/base_site.html" %}
|
{% extends "ereuse_devicehub/base_site.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
|
|
||||||
<div class="pagetitle">
|
<div class="pagetitle">
|
||||||
<h1>Inventory</h1>
|
<h1>Inventory</h1>
|
||||||
|
@ -33,9 +32,24 @@
|
||||||
<div class="card-body pt-3">
|
<div class="card-body pt-3">
|
||||||
<!-- Bordered Tabs -->
|
<!-- Bordered Tabs -->
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<h3><a href="{{ url_for('inventory.devices.lot_edit', id=lot.id) }}">{{ lot.name }}</a></h3>
|
<h3><a href="{{ url_for('inventory.devices.lot_edit', id=lot.id) }}">{{ lot.name }}</a></h3>
|
||||||
|
|
||||||
|
<div><!-- lot actions -->
|
||||||
|
{% if lot.is_temporary %}
|
||||||
|
<span class="d-none" id="activeRemoveLotModal" data-bs-toggle="modal" data-bs-target="#btnRemoveLots"></span>
|
||||||
|
<a class="me-2" href="javascript:removeLot()">
|
||||||
|
<i class="bi bi-trash"></i> Remove Lot
|
||||||
|
</a>
|
||||||
|
<a class="me-2" href="javascript:newTrade('user_from')">
|
||||||
|
<i class="bi bi-arrow-down-right"></i> Add supplier
|
||||||
|
</a>
|
||||||
|
<a href="javascript:newTrade('user_to')">
|
||||||
|
<i class="bi bi-arrow-up-right"></i> Add receiver
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -66,16 +80,6 @@
|
||||||
</button>
|
</button>
|
||||||
<span class="d-none" id="activeTradeModal" data-bs-toggle="modal" data-bs-target="#tradeLotModal"></span>
|
<span class="d-none" id="activeTradeModal" data-bs-toggle="modal" data-bs-target="#tradeLotModal"></span>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnLots">
|
<ul class="dropdown-menu" aria-labelledby="btnLots">
|
||||||
{% if lot and lot.is_temporary and not lot.devices %}
|
|
||||||
<li>
|
|
||||||
<a href="javascript:newAction('Use')" class="dropdown-item"
|
|
||||||
data-bs-toggle="modal" data-bs-target="#btnRemoveLots">
|
|
||||||
<i class="bi bi-trash"></i>
|
|
||||||
Remove Lot
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingLotModal">
|
<a href="javascript:void()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingLotModal">
|
||||||
<i class="bi bi-plus"></i>
|
<i class="bi bi-plus"></i>
|
||||||
|
@ -88,29 +92,6 @@
|
||||||
Remove selected devices from a lot
|
Remove selected devices from a lot
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% if lot.is_temporary %}
|
|
||||||
<li>
|
|
||||||
<a href="javascript:newTrade('user_from')" class="dropdown-item">
|
|
||||||
<i class="bi bi-plus"></i>
|
|
||||||
Add supplier
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="javascript:newTrade('user_to')" class="dropdown-item">
|
|
||||||
<i class="bi bi-plus"></i>
|
|
||||||
Add receiver
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if lot and not lot.is_temporary %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ url_for('inventory.devices.trade_document_add', lot_id=lot.id)}}" class="dropdown-item">
|
|
||||||
<i class="bi bi-plus"></i>
|
|
||||||
Add new document
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
||||||
|
@ -239,17 +220,19 @@
|
||||||
<i class="bi bi-tag"></i>
|
<i class="bi bi-tag"></i>
|
||||||
Tags
|
Tags
|
||||||
</button>
|
</button>
|
||||||
|
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||||
|
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnTags">
|
<ul class="dropdown-menu" aria-labelledby="btnTags">
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:addTag()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingTagModal">
|
<a href="javascript:addTag()" class="dropdown-item">
|
||||||
<i class="bi bi-plus"></i>
|
<i class="bi bi-plus"></i>
|
||||||
Add Tag to selected Devices
|
Add Tag to selected Device
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:removeTag()" class="dropdown-item">
|
<a href="javascript:removeTag()" class="dropdown-item">
|
||||||
<i class="bi bi-x"></i>
|
<i class="bi bi-x"></i>
|
||||||
Remove Tag from selected Devices
|
Remove Tag from selected Device
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -257,7 +240,7 @@
|
||||||
|
|
||||||
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
||||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-tag"></i>
|
<i class="bi bi-laptop"></i>
|
||||||
New Device
|
New Device
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||||
|
@ -276,6 +259,24 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if lot and not lot.is_temporary %}
|
||||||
|
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
||||||
|
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-book"></i>
|
||||||
|
Documents
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('inventory.devices.trade_document_add', lot_id=lot.id)}}" class="dropdown-item">
|
||||||
|
<i class="bi bi-plus"></i>
|
||||||
|
Add new document
|
||||||
|
<span class="caret"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="tab-content pt-2">
|
<div class="tab-content pt-2">
|
||||||
|
|
||||||
<h5 class="card-title">Computers</h5>
|
<h5 class="card-title">Computers</h5>
|
||||||
|
@ -317,7 +318,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('inventory.devices.device_details', id=dev.devicehub_id)}}">
|
<a href="{{ url_for('inventory.devices.device_details', id=dev.devicehub_id)}}">
|
||||||
{{ dev.type }} {{ dev.manufacturer }} {{ dev.model }}
|
{{ dev.verbose_name }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -387,16 +388,11 @@
|
||||||
{% include "inventory/data_wipe.html" %}
|
{% include "inventory/data_wipe.html" %}
|
||||||
{% include "inventory/trade.html" %}
|
{% include "inventory/trade.html" %}
|
||||||
{% include "inventory/alert_export_error.html" %}
|
{% include "inventory/alert_export_error.html" %}
|
||||||
|
{% include "inventory/alert_unlink_tag_error.html" %}
|
||||||
|
|
||||||
<!-- CDN -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
|
|
||||||
<!-- Custom Code -->
|
<!-- Custom Code -->
|
||||||
<script>
|
<script>
|
||||||
const table = new simpleDatatables.DataTable("table")
|
const table = new simpleDatatables.DataTable("table")
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<label for="name" class="form-label">Name</label>
|
<label for="name" class="form-label">Name</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<input type="text" name="name" class="form-control" required value="{{ form.name.data|default('', true) }}">
|
<input type="text" name="name" class="form-control" required value="{{ form.name.data|default('', true) }}">
|
||||||
|
@ -42,8 +42,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
{% if form.id %}
|
||||||
|
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form.id) }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -9,12 +9,15 @@
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Are you sure that you want to remove lot <strong>{{ lot.name }}</strong>?
|
Are you sure that you want to remove lot <strong>{{ lot.name }}</strong>?
|
||||||
|
<p class="text-danger">
|
||||||
|
There are devices in this lot, are you sure you want to delete it?
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
<a href="{{ url_for('inventory.devices.lot_del', id=lot.id)}}" type="button" class="btn btn-primary">
|
<a href="{{ url_for('inventory.devices.lot_del', id=lot.id)}}" type="button" class="btn btn-primary">
|
||||||
Save changes
|
Confirm
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<label for="code" class="form-label">code</label>
|
<label for="code" class="form-label">code</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<input type="text" name="code" class="form-control" required value="{{ form.code.data|default('', true) }}">
|
<input type="text" name="code" class="form-control" required value="{{ form.code.data|default('', true) }}">
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<label for="code" class="form-label">Amount</label>
|
<label for="code" class="form-label">Amount</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
{{ form.amount(class_="form-control") }}
|
{{ form.amount(class_="form-control") }}
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends "ereuse_devicehub/base_site.html" %}
|
{% extends "ereuse_devicehub/base_site.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
|
|
||||||
<div class="pagetitle">
|
<div class="pagetitle">
|
||||||
<h1>Inventory</h1>
|
<h1>Inventory</h1>
|
||||||
|
@ -35,7 +34,7 @@
|
||||||
<div class="col-lg-9 col-md-8">
|
<div class="col-lg-9 col-md-8">
|
||||||
{% if tag.device %}
|
{% if tag.device %}
|
||||||
<a href="{{url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}">
|
<a href="{{url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}">
|
||||||
{{ tag.device.manufacturer }} {{ tag.device.model }}
|
{{ tag.device.verbose_name }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -106,7 +105,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/qrcode.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/qrcode.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/jspdf.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/jspdf.min.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends "ereuse_devicehub/base_site.html" %}
|
{% extends "ereuse_devicehub/base_site.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
|
|
||||||
<div class="pagetitle">
|
<div class="pagetitle">
|
||||||
<h1>Inventory</h1>
|
<h1>Inventory</h1>
|
||||||
|
@ -59,7 +58,7 @@
|
||||||
<td>
|
<td>
|
||||||
{% if tag.device %}
|
{% if tag.device %}
|
||||||
<a href={{ url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}>
|
<a href={{ url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}>
|
||||||
{{ tag.device.type }} {{ tag.device.manufacturer }} {{ tag.device.model }}
|
{{ tag.device.verbose_name }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
@ -77,14 +76,8 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CDN -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
|
|
||||||
<!-- Custom Code -->
|
<!-- Custom Code -->
|
||||||
<script>
|
<script>
|
||||||
const table = new simpleDatatables.DataTable("table")
|
const table = new simpleDatatables.DataTable("table")
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<label for="tag" class="form-label">Tag</label>
|
<label for="tag" class="form-label">Tag</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
{{ form.tag(class_="form-control") }}
|
{{ form.tag(class_="form-control") }}
|
||||||
|
@ -48,9 +48,9 @@
|
||||||
</div>
|
</div>
|
||||||
<input class="devicesList" type="hidden" name="device" />
|
<input class="devicesList" type="hidden" name="device" />
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ referrer }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ referrer }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Unlink</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -35,22 +35,22 @@
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
{% if field != form.csrf_token %}
|
{% if field != form.csrf_token %}
|
||||||
<div class="col-12">
|
<div>
|
||||||
{{ field.label(class_="form-label") }}
|
{{ field.label(class_="form-label") }}
|
||||||
{{ field }}
|
{{ field }}
|
||||||
<small class="text-muted">{{ field.description }}</small>
|
<small class="text-muted">{{ field.description }}</small>
|
||||||
{% endif %}
|
{% if field.errors %}
|
||||||
{% if field.errors %}
|
|
||||||
<p class="text-danger">
|
<p class="text-danger">
|
||||||
{% for error in field.errors %}
|
{% for error in field.errors %}
|
||||||
{{ error }}<br/>
|
{{ error }}<br/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form._lot.id) }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form._lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<form method="post" enctype="multipart/form-data" class="row g-3 needs-validation" novalidate>
|
<form method="post" enctype="multipart/form-data" class="row g-3 needs-validation" novalidate>
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<label for="name" class="form-label">Select a Snapshot file</label>
|
<label for="name" class="form-label">Select a Snapshot file</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
{{ form.snapshot }}
|
{{ form.snapshot }}
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div>
|
||||||
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
||||||
<button class="btn btn-primary" type="submit">Send</button>
|
<button class="btn btn-primary" type="submit">Send</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,4 +3,4 @@ skip-string-normalization = true
|
||||||
target-version = ['py38']
|
target-version = ['py38']
|
||||||
|
|
||||||
[tool.isort]
|
[tool.isort]
|
||||||
multi_line_output = 4
|
profile = "black"
|
||||||
|
|
Reference in New Issue