Merge pull request #48 from eReuse/feature/46-device-stock-control

Feature/46-device-stock-control
This commit is contained in:
cayop 2020-08-17 18:11:48 +02:00 committed by GitHub
commit 24578e7188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 150 additions and 28 deletions

View File

@ -30,31 +30,23 @@ class DeviceRow(OrderedDict):
self['Tag 1'] = self['Tag 2'] = self['Tag 3'] = ''
for i, tag in zip(range(1, 3), device.tags):
self['Tag {}'.format(i)] = format(tag)
self['Serial Number'] = device.serial_number
self['Model'] = device.model
self['Manufacturer'] = device.manufacturer
# self['State'] = device.last_action_of()
self['Serial Number'] = convert_none_to_empty_str(device.serial_number)
self['Model'] = convert_none_to_empty_str(device.model)
self['Manufacturer'] = convert_none_to_empty_str(device.manufacturer)
self['Registered in'] = format(device.created, '%c')
try:
self['Physical state'] = device.last_action_of(*states.Physical.actions()).t
except:
except LookupError:
self['Physical state'] = ''
try:
self['Trading state'] = device.last_action_of(*states.Trading.actions()).t
except:
except LookupError:
self['Trading state'] = ''
try:
self['Price'] = device.price
except:
self['Price'] = ''
self['Price'] = convert_none_to_empty_str(device.price)
if isinstance(device, d.Computer):
self['Processor'] = device.processor_model
self['RAM (MB)'] = device.ram_size
self['Data Storage Size (MB)'] = device.data_storage_size
if isinstance(device, d.Mobile):
self['Display Size'] = device.display_size
self['RAM (MB)'] = device.ram_size
self['Data Storage Size (MB)'] = device.data_storage_size
self['Processor'] = convert_none_to_empty_str(device.processor_model)
self['RAM (MB)'] = convert_none_to_empty_str(device.ram_size)
self['Data Storage Size (MB)'] = convert_none_to_empty_str(device.data_storage_size)
rate = device.rate
if rate:
self['Rate'] = rate.rating
@ -135,3 +127,47 @@ class DeviceRow(OrderedDict):
self['{} {} Speed (MHz)'.format(type, i)] = component.speed
# todo add Display, NetworkAdapter, etc...
class StockRow(OrderedDict):
def __init__(self, device: d.Device) -> None:
super().__init__()
self.device = device
self['Type'] = convert_none_to_empty_str(device.t)
if isinstance(device, d.Computer):
self['Chassis'] = device.chassis
else:
self['Chassis'] = ''
self['Serial Number'] = convert_none_to_empty_str(device.serial_number)
self['Model'] = convert_none_to_empty_str(device.model)
self['Manufacturer'] = convert_none_to_empty_str(device.manufacturer)
self['Registered in'] = format(device.created, '%c')
try:
self['Physical state'] = device.last_action_of(*states.Physical.actions()).t
except LookupError:
self['Physical state'] = ''
try:
self['Trading state'] = device.last_action_of(*states.Trading.actions()).t
except LookupError:
self['Trading state'] = ''
self['Price'] = convert_none_to_empty_str(device.price)
self['Processor'] = convert_none_to_empty_str(device.processor_model)
self['RAM (MB)'] = convert_none_to_empty_str(device.ram_size)
self['Data Storage Size (MB)'] = convert_none_to_empty_str(device.data_storage_size)
rate = device.rate
if rate:
self['Rate'] = rate.rating
self['Range'] = rate.rating_range
assert isinstance(rate, RateComputer)
self['Processor Rate'] = rate.processor
self['Processor Range'] = rate.processor_range
self['RAM Rate'] = rate.ram
self['RAM Range'] = rate.ram_range
self['Data Storage Rate'] = rate.data_storage
self['Data Storage Range'] = rate.data_storage_range
def convert_none_to_empty_str(s):
if s is None:
return ''
return s

View File

@ -10,7 +10,7 @@ import flask
import flask_weasyprint
import teal.marshmallow
from boltons import urlutils
from flask import make_response
from flask import make_response, g
from teal.cache import cache
from teal.resource import Resource
@ -18,7 +18,8 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.resources.action import models as evs
from ereuse_devicehub.resources.device import models as devs
from ereuse_devicehub.resources.device.views import DeviceView
from ereuse_devicehub.resources.documents.device_row import DeviceRow
from ereuse_devicehub.resources.documents.device_row import DeviceRow, StockRow
class Format(enum.Enum):
@ -106,7 +107,7 @@ class DocumentView(DeviceView):
class DevicesDocumentView(DeviceView):
@cache(datetime.timedelta(minutes=1))
def find(self, args: dict):
query = self.query(args)
query = (x for x in self.query(args) if x.owner_id == g.user.id)
return self.generate_post_csv(query)
def generate_post_csv(self, query):
@ -129,7 +130,7 @@ class DevicesDocumentView(DeviceView):
class StockDocumentView(DeviceView):
# @cache(datetime.timedelta(minutes=1))
def find(self, args: dict):
query = self.query(args)
query = (x for x in self.query(args) if x.owner_id == g.user.id)
return self.generate_post_csv(query)
def generate_post_csv(self, query):
@ -138,13 +139,13 @@ class StockDocumentView(DeviceView):
cw = csv.writer(data)
first = True
for device in query:
d = DeviceRow(device)
d = StockRow(device)
if first:
cw.writerow(d.keys())
first = False
cw.writerow(d.values())
output = make_response(data.getvalue())
output.headers['Content-Disposition'] = 'attachment; filename=export.csv'
output.headers['Content-Disposition'] = 'attachment; filename=devices-stock.csv'
output.headers['Content-type'] = 'text/csv'
return output
@ -183,8 +184,11 @@ class DocumentDef(Resource):
devices_view = DevicesDocumentView.as_view('devicesDocumentView',
definition=self,
auth=app.auth)
devices_view = app.auth.requires_auth(devices_view)
stock_view = StockDocumentView.as_view('stockDocumentView', definition=self)
stock_view = app.auth.requires_auth(stock_view)
self.add_url_rule('/devices/', defaults=d, view_func=devices_view, methods=get)
stock_view = StockDocumentView.as_view('stockDocumentView', definition=self, auth=app.auth)

View File

@ -93,6 +93,18 @@ def user(app: Devicehub) -> UserClient:
return client
@pytest.fixture()
def user2(app: Devicehub) -> UserClient:
"""Gets a client with a logged-in dummy user."""
with app.app_context():
password = 'foo'
email = 'foo2@foo.com'
user = create_user(email=email, password=password)
client = UserClient(app, user.email, password, response_wrapper=app.response_class)
client.login()
return client
def create_user(email='foo@foo.com', password='foo') -> User:
user = User(email=email, password=password)
user.individuals.add(Person(name='Timmy'))

View File

@ -0,0 +1,2 @@
Type,Chassis,Serial Number,Model,Manufacturer,Registered in,Physical state,Trading state,Price,Processor,RAM (MB),Data Storage Size (MB),Rate,Range,Processor Rate,Processor Range,RAM Rate,RAM Range,Data Storage Rate,Data Storage Range
Desktop,Microtower,d1s,d1ml,d1mr,Tue Jul 2 10:35:10 2019,,,,p1ml,0,0,1.0,Very low,1.0,Very low,1.0,Very low,1.0,Very low
1 Type Chassis Serial Number Model Manufacturer Registered in Physical state Trading state Price Processor RAM (MB) Data Storage Size (MB) Rate Range Processor Rate Processor Range RAM Rate RAM Range Data Storage Rate Data Storage Range
2 Desktop Microtower d1s d1ml d1mr Tue Jul 2 10:35:10 2019 p1ml 0 0 1.0 Very low 1.0 Very low 1.0 Very low 1.0 Very low

View File

@ -0,0 +1,34 @@
type: Snapshot
uuid: 123e4567-e89b-12d3-a456-426655440000
version: '11.0'
software: Workbench
elapsed: 4
device:
type: Desktop
chassis: Microtower
serialNumber: d2s
model: d1ml
manufacturer: d1mr
actions:
- type: VisualTest
appearanceRange: A
functionalityRange: B
components:
- type: GraphicCard
serialNumber: gc1s
model: gc1ml
manufacturer: gc1mr
- type: RamModule
serialNumber: rm1s
model: rm1ml
manufacturer: rm1mr
speed: 1333
- type: Processor
serialNumber: p1s
model: p1mla
manufacturer: p1mr
speed: 1.6
actions:
- type: BenchmarkProcessor
rate: 2410
elapsed: 11

View File

@ -1,11 +1,12 @@
import pytest
import teal.marshmallow
from ereuse_utils.test import ANY
import csv
from datetime import datetime
from io import StringIO
from pathlib import Path
import pytest
import teal.marshmallow
from ereuse_utils.test import ANY
from ereuse_devicehub.client import Client, UserClient
from ereuse_devicehub.resources.action.models import Snapshot
from ereuse_devicehub.resources.documents import documents
@ -223,4 +224,37 @@ def test_export_multiple_different_devices(user: UserClient):
for row in export_csv:
del row[8]
assert fixture_csv[:3] == export_csv
assert fixture_csv == export_csv
@pytest.mark.mvp
def test_report_devices_stock_control(user: UserClient, user2: UserClient):
"""Test export device information in a csv file."""
snapshot, _ = user.post(file('basic.snapshot'), res=Snapshot)
snapshot2, _ = user2.post(file('basic.snapshot2'), res=Snapshot)
csv_str, _ = user.get(res=documents.DocumentDef.t,
item='stock/',
accept='text/csv',
query=[('filter', {'type': ['Computer']})])
f = StringIO(csv_str)
obj_csv = csv.reader(f, f)
export_csv = list(obj_csv)
# Open fixture csv and transform to list
with Path(__file__).parent.joinpath('files').joinpath('basic-stock.csv').open() as csv_file:
obj_csv = csv.reader(csv_file)
fixture_csv = list(obj_csv)
assert user.user['id'] != user2.user['id']
assert len(export_csv) == 2
assert isinstance(datetime.strptime(export_csv[1][5], '%c'), datetime), \
'Register in field is not a datetime'
# Pop dates fields from csv lists to compare them
fixture_csv[1] = fixture_csv[1][:5] + fixture_csv[1][6:]
export_csv[1] = export_csv[1][:5] + export_csv[1][6:]
assert fixture_csv[0] == export_csv[0], 'Headers are not equal'
assert fixture_csv[1] == export_csv[1], 'Computer information are not equal'