Merge pull request #303 from eReuse/features/transfer-3493-3492-3510
Features/transfer 3493 3492 3510
This commit is contained in:
commit
97653058c6
|
@ -8,6 +8,9 @@ ml).
|
||||||
## master
|
## master
|
||||||
|
|
||||||
## testing
|
## testing
|
||||||
|
- [added] #303 Add export Lots.
|
||||||
|
- [added] #303 Add export relating lots with devices.
|
||||||
|
- [added] #303 To do possible add and remove one device in one lot transfer.
|
||||||
|
|
||||||
## [2.2.0 rc1] - 2022-06-07
|
## [2.2.0 rc1] - 2022-06-07
|
||||||
- [added] #212 Server side render parser Workbench Snapshots.
|
- [added] #212 Server side render parser Workbench Snapshots.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from citext import CIText
|
from citext import CIText
|
||||||
|
from flask import g
|
||||||
from sqlalchemy import Column, Integer
|
from sqlalchemy import Column, Integer
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import backref, relationship
|
from sqlalchemy.orm import backref, relationship
|
||||||
|
@ -43,6 +44,15 @@ class Transfer(Thing):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def type_transfer(self):
|
||||||
|
if self.user_from == g.user:
|
||||||
|
return 'Outgoing'
|
||||||
|
|
||||||
|
if self.user_to == g.user:
|
||||||
|
return 'Incoming'
|
||||||
|
|
||||||
|
return 'Temporary'
|
||||||
|
|
||||||
|
|
||||||
class DeliveryNote(Thing):
|
class DeliveryNote(Thing):
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
|
||||||
|
|
|
@ -33,6 +33,7 @@ from ereuse_devicehub.parser.models import SnapshotsLog
|
||||||
from ereuse_devicehub.resources.action.models import Trade
|
from ereuse_devicehub.resources.action.models import Trade
|
||||||
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Device
|
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Device
|
||||||
from ereuse_devicehub.resources.documents.device_row import ActionRow, DeviceRow
|
from ereuse_devicehub.resources.documents.device_row import ActionRow, DeviceRow
|
||||||
|
from ereuse_devicehub.resources.enums import SnapshotSoftware
|
||||||
from ereuse_devicehub.resources.hash_reports import insert_hash
|
from ereuse_devicehub.resources.hash_reports import insert_hash
|
||||||
from ereuse_devicehub.resources.lot.models import Lot
|
from ereuse_devicehub.resources.lot.models import Lot
|
||||||
from ereuse_devicehub.resources.tag.model import Tag
|
from ereuse_devicehub.resources.tag.model import Tag
|
||||||
|
@ -476,6 +477,8 @@ class ExportsView(View):
|
||||||
'metrics': self.metrics,
|
'metrics': self.metrics,
|
||||||
'devices': self.devices_list,
|
'devices': self.devices_list,
|
||||||
'certificates': self.erasure,
|
'certificates': self.erasure,
|
||||||
|
'lots': self.lots_export,
|
||||||
|
'devices_lots': self.devices_lots_export,
|
||||||
}
|
}
|
||||||
|
|
||||||
if export_id not in export_ids:
|
if export_id not in export_ids:
|
||||||
|
@ -577,6 +580,111 @@ class ExportsView(View):
|
||||||
}
|
}
|
||||||
return flask.render_template('inventory/erasure.html', **params)
|
return flask.render_template('inventory/erasure.html', **params)
|
||||||
|
|
||||||
|
def lots_export(self):
|
||||||
|
data = StringIO()
|
||||||
|
cw = csv.writer(data, delimiter=';', lineterminator="\n", quotechar='"')
|
||||||
|
|
||||||
|
cw.writerow(
|
||||||
|
[
|
||||||
|
'Lot Id',
|
||||||
|
'Lot Name',
|
||||||
|
'Lot Type',
|
||||||
|
'Transfer Status',
|
||||||
|
'Transfer Code',
|
||||||
|
'Transfer Date',
|
||||||
|
'Transfer Creation Date',
|
||||||
|
'Transfer Update Date',
|
||||||
|
'Transfer Description',
|
||||||
|
'Devices Number',
|
||||||
|
'Devices Snapshots',
|
||||||
|
'Devices Placeholders',
|
||||||
|
'Delivery Note Number',
|
||||||
|
'Delivery Note Date',
|
||||||
|
'Delivery Note Units',
|
||||||
|
'Delivery Note Weight',
|
||||||
|
'Receiver Note Number',
|
||||||
|
'Receiver Note Date',
|
||||||
|
'Receiver Note Units',
|
||||||
|
'Receiver Note Weight',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
for lot in Lot.query.filter_by(owner=g.user):
|
||||||
|
delivery_note = lot.transfer and lot.transfer.delivery_note or ''
|
||||||
|
receiver_note = lot.transfer and lot.transfer.receiver_note or ''
|
||||||
|
wb_devs = 0
|
||||||
|
placeholders = 0
|
||||||
|
|
||||||
|
for dev in lot.devices:
|
||||||
|
snapshots = [e for e in dev.actions if e.type == 'Snapshot']
|
||||||
|
if not snapshots or snapshots[-1].software not in [
|
||||||
|
SnapshotSoftware.Workbench
|
||||||
|
]:
|
||||||
|
placeholders += 1
|
||||||
|
elif snapshots[-1].software in [SnapshotSoftware.Workbench]:
|
||||||
|
wb_devs += 1
|
||||||
|
|
||||||
|
row = [
|
||||||
|
lot.id,
|
||||||
|
lot.name,
|
||||||
|
lot.type_transfer(),
|
||||||
|
lot.transfer and (lot.transfer.closed and 'Closed' or 'Open') or '',
|
||||||
|
lot.transfer and lot.transfer.code or '',
|
||||||
|
lot.transfer and lot.transfer.date or '',
|
||||||
|
lot.transfer and lot.transfer.created or '',
|
||||||
|
lot.transfer and lot.transfer.updated or '',
|
||||||
|
lot.transfer and lot.transfer.description or '',
|
||||||
|
len(lot.devices),
|
||||||
|
wb_devs,
|
||||||
|
placeholders,
|
||||||
|
delivery_note and delivery_note.number or '',
|
||||||
|
delivery_note and delivery_note.date or '',
|
||||||
|
delivery_note and delivery_note.units or '',
|
||||||
|
delivery_note and delivery_note.weight or '',
|
||||||
|
receiver_note and receiver_note.number or '',
|
||||||
|
receiver_note and receiver_note.date or '',
|
||||||
|
receiver_note and receiver_note.units or '',
|
||||||
|
receiver_note and receiver_note.weight or '',
|
||||||
|
]
|
||||||
|
cw.writerow(row)
|
||||||
|
|
||||||
|
return self.response_csv(data, "lots_export.csv")
|
||||||
|
|
||||||
|
def devices_lots_export(self):
|
||||||
|
data = StringIO()
|
||||||
|
cw = csv.writer(data, delimiter=';', lineterminator="\n", quotechar='"')
|
||||||
|
head = [
|
||||||
|
'DHID',
|
||||||
|
'Lot Id',
|
||||||
|
'Lot Name',
|
||||||
|
'Lot Type',
|
||||||
|
'Transfer Status',
|
||||||
|
'Transfer Code',
|
||||||
|
'Transfer Date',
|
||||||
|
'Transfer Creation Date',
|
||||||
|
'Transfer Update Date',
|
||||||
|
]
|
||||||
|
cw.writerow(head)
|
||||||
|
|
||||||
|
for dev in self.find_devices():
|
||||||
|
for lot in dev.lots:
|
||||||
|
row = [
|
||||||
|
dev.devicehub_id,
|
||||||
|
lot.id,
|
||||||
|
lot.name,
|
||||||
|
lot.type_transfer(),
|
||||||
|
lot.transfer and (lot.transfer.closed and 'Closed' or 'Open') or '',
|
||||||
|
lot.transfer and lot.transfer.code or '',
|
||||||
|
lot.transfer and lot.transfer.date or '',
|
||||||
|
lot.transfer and lot.transfer.created or '',
|
||||||
|
lot.transfer and lot.transfer.updated or '',
|
||||||
|
]
|
||||||
|
cw.writerow(row)
|
||||||
|
|
||||||
|
return self.response_csv(
|
||||||
|
data, "Devices_Incoming_and_Outgoing_Lots_Spreadsheet.csv"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SnapshotListView(GenericMixin):
|
class SnapshotListView(GenericMixin):
|
||||||
template_name = 'inventory/snapshots_list.html'
|
template_name = 'inventory/snapshots_list.html'
|
||||||
|
|
|
@ -151,6 +151,16 @@ class Lot(Thing):
|
||||||
"""Gets the lots that are not under any other lot."""
|
"""Gets the lots that are not under any other lot."""
|
||||||
return cls.query.join(cls.paths).filter(db.func.nlevel(Path.path) == 1)
|
return cls.query.join(cls.paths).filter(db.func.nlevel(Path.path) == 1)
|
||||||
|
|
||||||
|
def type_transfer(self):
|
||||||
|
# Used in reports lots_export.csv
|
||||||
|
if not self.transfer:
|
||||||
|
return 'Temporary'
|
||||||
|
if self.transfer.user_from == g.user:
|
||||||
|
return 'Outgoing'
|
||||||
|
if self.transfer.user_to == g.user:
|
||||||
|
return 'Incoming'
|
||||||
|
return ''
|
||||||
|
|
||||||
def add_children(self, *children):
|
def add_children(self, *children):
|
||||||
"""Add children lots to this lot.
|
"""Add children lots to this lot.
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ class LotView(View):
|
||||||
query = query.filter(Lot.name.ilike(args['search'] + '%'))
|
query = query.filter(Lot.name.ilike(args['search'] + '%'))
|
||||||
lots = query.paginate(per_page=6 if args['search'] else query.count())
|
lots = query.paginate(per_page=6 if args['search'] else query.count())
|
||||||
return things_response(
|
return things_response(
|
||||||
self.schema.dump(lots.items, many=True, nested=2),
|
self.get_lots_dump(lots),
|
||||||
lots.page,
|
lots.page,
|
||||||
lots.per_page,
|
lots.per_page,
|
||||||
lots.total,
|
lots.total,
|
||||||
|
@ -120,6 +120,17 @@ class LotView(View):
|
||||||
)
|
)
|
||||||
return jsonify(ret)
|
return jsonify(ret)
|
||||||
|
|
||||||
|
def get_lots_dump(self, lots):
|
||||||
|
lots_dump = self.schema.dump(lots.items, many=True, nested=2)
|
||||||
|
for lot in lots.items:
|
||||||
|
if not lot.transfer:
|
||||||
|
continue
|
||||||
|
for _lot in lots_dump:
|
||||||
|
if _lot['id'] == str(lot.id):
|
||||||
|
_lot['transfer'] = lot.type_transfer()
|
||||||
|
break
|
||||||
|
return lots_dump
|
||||||
|
|
||||||
def visibility_filter(self, query):
|
def visibility_filter(self, query):
|
||||||
query = (
|
query = (
|
||||||
query.outerjoin(Trade)
|
query.outerjoin(Trade)
|
||||||
|
@ -141,7 +152,9 @@ class LotView(View):
|
||||||
|
|
||||||
# temporary
|
# temporary
|
||||||
if lot_type == "temporary":
|
if lot_type == "temporary":
|
||||||
return query.filter(Lot.trade == None).filter(Lot.transfer == None)
|
return query.filter(Lot.trade == None).filter(
|
||||||
|
or_(Lot.transfer == None, Transfer.date == None)
|
||||||
|
)
|
||||||
|
|
||||||
if lot_type == "incoming":
|
if lot_type == "incoming":
|
||||||
return query.filter(
|
return query.filter(
|
||||||
|
|
|
@ -681,17 +681,32 @@ async function processSelectedDevices() {
|
||||||
|
|
||||||
return lot;
|
return lot;
|
||||||
});
|
});
|
||||||
let lotsList = [];
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "true").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "indetermined").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "false").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList = lotsList.flat(); // flat array
|
|
||||||
|
|
||||||
listHTML.html("");
|
listHTML.html("");
|
||||||
lotsList.forEach(lot => templateLot(lot, selectedDevices, listHTML, actions));
|
const lot_temporary = lots.filter(lot => !lot.transfer);
|
||||||
|
appendMenu(lot_temporary, listHTML, templateLot, selectedDevices, actions, "Temporary");
|
||||||
|
|
||||||
|
const lot_incoming = lots.filter(lot => lot.transfer && lot.transfer == "Incoming");
|
||||||
|
appendMenu(lot_incoming, listHTML, templateLot, selectedDevices, actions, "Incoming");
|
||||||
|
|
||||||
|
const lot_outgoing = lots.filter(lot => lot.transfer && lot.transfer == "Outgoing");
|
||||||
|
appendMenu(lot_outgoing, listHTML, templateLot, selectedDevices, actions, "Outgoing");
|
||||||
|
|
||||||
lotsSearcher.enable();
|
lotsSearcher.enable();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
listHTML.html("<li style=\"color: red; text-align: center\">Error feching devices and lots<br>(see console for more details)</li>");
|
listHTML.html("<li style=\"color: red; text-align: center\">Error feching devices and lots<br>(see console for more details)</li>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendMenu(lots, listHTML, templateLot, selectedDevices, actions, title) {
|
||||||
|
let lotsList = [];
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "true").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "indetermined").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "false").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList = lotsList.flat(); // flat array
|
||||||
|
|
||||||
|
listHTML.append(`<li style="color: black; text-align: center">${ title }<hr /></li>`);
|
||||||
|
lotsList.forEach(lot => templateLot(lot, selectedDevices, listHTML, actions));
|
||||||
|
}
|
||||||
|
|
|
@ -646,17 +646,30 @@ async function processSelectedDevices() {
|
||||||
return lot;
|
return lot;
|
||||||
})
|
})
|
||||||
|
|
||||||
let lotsList = [];
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "true").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "indetermined").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList.push(lots.filter(lot => lot.state == "false").sort((a, b) => a.name.localeCompare(b.name)));
|
|
||||||
lotsList = lotsList.flat(); // flat array
|
|
||||||
|
|
||||||
listHTML.html("");
|
listHTML.html("");
|
||||||
lotsList.forEach(lot => templateLot(lot, selectedDevices, listHTML, actions));
|
const lot_temporary = lots.filter(lot => !lot.transfer);
|
||||||
|
appendMenu(lot_temporary, listHTML, templateLot, selectedDevices, actions, "Temporary");
|
||||||
|
|
||||||
|
const lot_incoming = lots.filter(lot => lot.transfer && lot.transfer == "Incoming");
|
||||||
|
appendMenu(lot_incoming, listHTML, templateLot, selectedDevices, actions, "Incoming");
|
||||||
|
|
||||||
|
const lot_outgoing = lots.filter(lot => lot.transfer && lot.transfer == "Outgoing");
|
||||||
|
appendMenu(lot_outgoing, listHTML, templateLot, selectedDevices, actions, "Outgoing");
|
||||||
|
|
||||||
lotsSearcher.enable();
|
lotsSearcher.enable();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
listHTML.html("<li style=\"color: red; text-align: center\">Error feching devices and lots<br>(see console for more details)</li>");
|
listHTML.html("<li style=\"color: red; text-align: center\">Error feching devices and lots<br>(see console for more details)</li>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendMenu(lots, listHTML, templateLot, selectedDevices, actions, title) {
|
||||||
|
let lotsList = [];
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "true").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "indetermined").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList.push(lots.filter(lot => lot.state == "false").sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
lotsList = lotsList.flat(); // flat array
|
||||||
|
|
||||||
|
listHTML.append(`<li style="color: black; text-align: center">${ title }<hr /></li>`);
|
||||||
|
lotsList.forEach(lot => templateLot(lot, selectedDevices, listHTML, actions));
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,29 @@
|
||||||
</a>
|
</a>
|
||||||
</li><!-- End Search Icon-->
|
</li><!-- End Search Icon-->
|
||||||
|
|
||||||
|
<li class="nav-item dropdown pe-3">
|
||||||
|
|
||||||
|
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
|
||||||
|
<span class="d-none d-md-block dropdown-toggle ps-2 pb-3 pt-3">Reports</span>
|
||||||
|
</a><!-- End Profile Iamge Icon -->
|
||||||
|
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow profile">
|
||||||
|
<li class="dropdown-header">
|
||||||
|
<h6>Exports</h6>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item d-flex align-items-center" href="{{ url_for('inventory.export', export_id='lots') }}">
|
||||||
|
<i class="bi bi-file-spreadsheet"></i>
|
||||||
|
<span>Lots Spreadsheet</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="nav-item dropdown pe-3">
|
<li class="nav-item dropdown pe-3">
|
||||||
|
|
||||||
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
|
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
|
||||||
|
|
|
@ -247,9 +247,9 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:export_file('metrics')" class="dropdown-item">
|
<a href="javascript:export_file('devices_lots')" class="dropdown-item">
|
||||||
<i class="bi bi-file-spreadsheet"></i>
|
<i class="bi bi-file-spreadsheet"></i>
|
||||||
Metrics Spreadsheet
|
Devices Incoming and Outgoing Lots Spreadsheet
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
2
tests/files/devices_lots.csv
Normal file
2
tests/files/devices_lots.csv
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
DHID;Lot Id;Lot Name;Lot Type;Transfer Status;Transfer Code;Transfer Date;Transfer Creation Date;Transfer Update Date
|
||||||
|
O48N2;c43a0d06-0c77-4a74-9c95-086645fbc534;lot1;Temporary;;;;;
|
|
2
tests/files/lots.csv
Normal file
2
tests/files/lots.csv
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Lot Id;Lot Name;Lot Type;Transfer Status;Transfer Code;Transfer Date;Transfer Creation Date;Transfer Update Date;Transfer Description;Devices Number;Devices Snapshots;Devices Placeholders;Delivery Note Number;Delivery Note Date;Delivery Note Units;Delivery Note Weight;Receiver Note Number;Receiver Note Date;Receiver Note Units;Receiver Note Weight
|
||||||
|
cca691c4-b221-4882-924c-30cd545c0182;lot1;Temporary;;;;;;;1;1;0;;;;;;;;
|
|
|
@ -3,16 +3,20 @@ import datetime
|
||||||
import json
|
import json
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from flask import g
|
||||||
from flask.testing import FlaskClient
|
from flask.testing import FlaskClient
|
||||||
from flask_wtf.csrf import generate_csrf
|
from flask_wtf.csrf import generate_csrf
|
||||||
|
|
||||||
from ereuse_devicehub.client import UserClient, UserClientFlask
|
from ereuse_devicehub.client import UserClient, UserClientFlask
|
||||||
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.devicehub import Devicehub
|
from ereuse_devicehub.devicehub import Devicehub
|
||||||
from ereuse_devicehub.resources.action.models import Snapshot
|
from ereuse_devicehub.resources.action.models import Snapshot
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
from ereuse_devicehub.resources.lot.models import Lot
|
from ereuse_devicehub.resources.lot.models import Lot
|
||||||
|
from ereuse_devicehub.resources.user.models import User
|
||||||
from tests import conftest
|
from tests import conftest
|
||||||
|
|
||||||
|
|
||||||
|
@ -1309,3 +1313,75 @@ def test_edit_notes_with_closed_transfer(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 'Receiver Note updated error!' in body
|
assert 'Receiver Note updated error!' in body
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_export_devices_lots(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
user3.get('/inventory/lot/add/')
|
||||||
|
lot_name = 'lot1'
|
||||||
|
data = {
|
||||||
|
'name': lot_name,
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
}
|
||||||
|
user3.post('/inventory/lot/add/', data=data)
|
||||||
|
lot = Lot.query.filter_by(name=lot_name).one()
|
||||||
|
|
||||||
|
device = snap.device
|
||||||
|
g.user = User.query.one()
|
||||||
|
device.lots.update({lot})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
uri = "/inventory/export/devices_lots/?ids={id}".format(id=snap.device.devicehub_id)
|
||||||
|
|
||||||
|
body, status = user3.get(uri)
|
||||||
|
assert status == '200 OK'
|
||||||
|
|
||||||
|
export_csv = [line.split(";") for line in body.split("\n")]
|
||||||
|
|
||||||
|
with Path(__file__).parent.joinpath('files').joinpath(
|
||||||
|
'devices_lots.csv'
|
||||||
|
).open() as csv_file:
|
||||||
|
obj_csv = csv.reader(csv_file, delimiter=';', quotechar='"')
|
||||||
|
fixture_csv = list(obj_csv)
|
||||||
|
|
||||||
|
assert fixture_csv[0] == export_csv[0], 'Headers are not equal'
|
||||||
|
assert fixture_csv[1][2:] == export_csv[1][2:], 'Computer information are not equal'
|
||||||
|
UUID(export_csv[1][1])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_export_lots(user3: UserClientFlask):
|
||||||
|
snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
user3.get('/inventory/lot/add/')
|
||||||
|
lot_name = 'lot1'
|
||||||
|
data = {
|
||||||
|
'name': lot_name,
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
}
|
||||||
|
user3.post('/inventory/lot/add/', data=data)
|
||||||
|
lot = Lot.query.filter_by(name=lot_name).one()
|
||||||
|
|
||||||
|
device = snap.device
|
||||||
|
g.user = User.query.one()
|
||||||
|
device.lots.update({lot})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
uri = "/inventory/export/lots/"
|
||||||
|
|
||||||
|
body, status = user3.get(uri)
|
||||||
|
assert status == '200 OK'
|
||||||
|
|
||||||
|
export_csv = [line.split(";") for line in body.split("\n")]
|
||||||
|
|
||||||
|
with Path(__file__).parent.joinpath('files').joinpath(
|
||||||
|
'lots.csv'
|
||||||
|
).open() as csv_file:
|
||||||
|
obj_csv = csv.reader(csv_file, delimiter=';', quotechar='"')
|
||||||
|
fixture_csv = list(obj_csv)
|
||||||
|
|
||||||
|
assert fixture_csv[0] == export_csv[0], 'Headers are not equal'
|
||||||
|
assert fixture_csv[1][1:] == export_csv[1][1:], 'Computer information are not equal'
|
||||||
|
UUID(export_csv[1][0])
|
||||||
|
|
Reference in a new issue