Fix method call to `get_or_create_user()`
This commit is contained in:
parent
88deb71a26
commit
bacf14ece8
|
@ -3,33 +3,35 @@ 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_wtf import FlaskForm
|
||||||
|
from sqlalchemy.util import OrderedSet
|
||||||
|
from wtforms import (
|
||||||
|
BooleanField, DateField, FileField, FloatField, Form, HiddenField,
|
||||||
|
IntegerField, MultipleFileField, SelectField, StringField, TextAreaField,
|
||||||
|
URLField, validators)
|
||||||
|
from wtforms.fields import FormField
|
||||||
|
from wtforms.validators import ValidationError
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.action.models import RateComputer, Snapshot
|
from ereuse_devicehub.resources.action.models import RateComputer, Snapshot
|
||||||
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
|
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
|
||||||
from ereuse_devicehub.resources.action.schemas import \
|
from ereuse_devicehub.resources.action.schemas import \
|
||||||
Snapshot as SnapshotSchema
|
Snapshot as SnapshotSchema
|
||||||
from ereuse_devicehub.resources.action.views.snapshot import move_json, save_json
|
from ereuse_devicehub.resources.action.views.snapshot import (
|
||||||
from ereuse_devicehub.resources.device.models import (SAI, Cellphone, Computer,
|
move_json, save_json)
|
||||||
Device, Keyboard, MemoryCardReader,
|
from ereuse_devicehub.resources.device.models import (
|
||||||
Monitor, Mouse, Smartphone, Tablet)
|
SAI, Cellphone, Computer, Device, Keyboard, MemoryCardReader, Monitor,
|
||||||
from flask import g, request
|
Mouse, Smartphone, Tablet)
|
||||||
from flask_wtf import FlaskForm
|
|
||||||
from sqlalchemy.util import OrderedSet
|
|
||||||
from wtforms import (BooleanField, DateField, FileField, FloatField, Form,
|
|
||||||
HiddenField, IntegerField, MultipleFileField, SelectField,
|
|
||||||
StringField, TextAreaField, URLField, validators)
|
|
||||||
from wtforms.fields import FormField
|
|
||||||
from wtforms.validators import ValidationError
|
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.sync import Sync
|
from ereuse_devicehub.resources.device.sync import Sync
|
||||||
from ereuse_devicehub.resources.documents.models import DataWipeDocument
|
from ereuse_devicehub.resources.documents.models import DataWipeDocument
|
||||||
from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware
|
from ereuse_devicehub.resources.enums import Severity, 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
|
||||||
from ereuse_devicehub.resources.user.models import User
|
|
||||||
from ereuse_devicehub.resources.tradedocument.models import TradeDocument
|
from ereuse_devicehub.resources.tradedocument.models import TradeDocument
|
||||||
from ereuse_devicehub.resources.user.exceptions import InsufficientPermission
|
from ereuse_devicehub.resources.user.exceptions import InsufficientPermission
|
||||||
|
from ereuse_devicehub.resources.user.models import User
|
||||||
|
|
||||||
|
|
||||||
class LotDeviceForm(FlaskForm):
|
class LotDeviceForm(FlaskForm):
|
||||||
|
@ -42,12 +44,19 @@ class LotDeviceForm(FlaskForm):
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._lot = Lot.query.filter(Lot.id == self.lot.data).filter(
|
self._lot = (
|
||||||
Lot.owner_id == g.user.id).one()
|
Lot.query.filter(Lot.id == self.lot.data)
|
||||||
|
.filter(Lot.owner_id == g.user.id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
devices = set(self.devices.data.split(","))
|
devices = set(self.devices.data.split(","))
|
||||||
self._devices = Device.query.filter(Device.id.in_(devices)).filter(
|
self._devices = (
|
||||||
Device.owner_id == g.user.id).distinct().all()
|
Device.query.filter(Device.id.in_(devices))
|
||||||
|
.filter(Device.owner_id == g.user.id)
|
||||||
|
.distinct()
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
return bool(self._devices)
|
return bool(self._devices)
|
||||||
|
|
||||||
|
@ -75,8 +84,11 @@ class LotForm(FlaskForm):
|
||||||
self.id = kwargs.pop('id', None)
|
self.id = kwargs.pop('id', None)
|
||||||
self.instance = None
|
self.instance = None
|
||||||
if self.id:
|
if self.id:
|
||||||
self.instance = Lot.query.filter(Lot.id == self.id).filter(
|
self.instance = (
|
||||||
Lot.owner_id == g.user.id).one()
|
Lot.query.filter(Lot.id == self.id)
|
||||||
|
.filter(Lot.owner_id == g.user.id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if self.instance and not self.name.data:
|
if self.instance and not self.name.data:
|
||||||
self.name.data = self.instance.name
|
self.name.data = self.instance.name
|
||||||
|
@ -172,7 +184,9 @@ class UploadSnapshotForm(FlaskForm):
|
||||||
# this is a copy adaptated from ereuse_devicehub.resources.action.views.snapshot
|
# this is a copy adaptated from ereuse_devicehub.resources.action.views.snapshot
|
||||||
device = snapshot_json.pop('device') # type: Computer
|
device = snapshot_json.pop('device') # type: Computer
|
||||||
components = None
|
components = None
|
||||||
if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid):
|
if snapshot_json['software'] == (
|
||||||
|
SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid
|
||||||
|
):
|
||||||
components = snapshot_json.pop('components', None) # type: List[Component]
|
components = snapshot_json.pop('components', None) # type: List[Component]
|
||||||
if isinstance(device, Computer) and device.hid:
|
if isinstance(device, Computer) and device.hid:
|
||||||
device.add_mac_to_hid(components_snap=components)
|
device.add_mac_to_hid(components_snap=components)
|
||||||
|
@ -182,7 +196,9 @@ class UploadSnapshotForm(FlaskForm):
|
||||||
actions_device = set(e for e in device.actions_one)
|
actions_device = set(e for e in device.actions_one)
|
||||||
device.actions_one.clear()
|
device.actions_one.clear()
|
||||||
if components:
|
if components:
|
||||||
actions_components = tuple(set(e for e in c.actions_one) for c in components)
|
actions_components = tuple(
|
||||||
|
set(e for e in c.actions_one) for c in components
|
||||||
|
)
|
||||||
for component in components:
|
for component in components:
|
||||||
component.actions_one.clear()
|
component.actions_one.clear()
|
||||||
|
|
||||||
|
@ -252,14 +268,16 @@ class NewDeviceForm(FlaskForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.devices = {"Smartphone": Smartphone,
|
self.devices = {
|
||||||
|
"Smartphone": Smartphone,
|
||||||
"Tablet": Tablet,
|
"Tablet": Tablet,
|
||||||
"Cellphone": Cellphone,
|
"Cellphone": Cellphone,
|
||||||
"Monitor": Monitor,
|
"Monitor": Monitor,
|
||||||
"Mouse": Mouse,
|
"Mouse": Mouse,
|
||||||
"Keyboard": Keyboard,
|
"Keyboard": Keyboard,
|
||||||
"SAI": SAI,
|
"SAI": SAI,
|
||||||
"MemoryCardReader": MemoryCardReader}
|
"MemoryCardReader": MemoryCardReader,
|
||||||
|
}
|
||||||
|
|
||||||
if not self.generation.data:
|
if not self.generation.data:
|
||||||
self.generation.data = 1
|
self.generation.data = 1
|
||||||
|
@ -349,16 +367,18 @@ class NewDeviceForm(FlaskForm):
|
||||||
'height': self.height.data,
|
'height': self.height.data,
|
||||||
'depth': self.depth.data,
|
'depth': self.depth.data,
|
||||||
'variant': self.variant.data,
|
'variant': self.variant.data,
|
||||||
'image': self.image.data
|
'image': self.image.data,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.appearance.data or self.functionality.data:
|
if self.appearance.data or self.functionality.data:
|
||||||
json_snapshot['device']['actions'] = [{
|
json_snapshot['device']['actions'] = [
|
||||||
|
{
|
||||||
'type': 'VisualTest',
|
'type': 'VisualTest',
|
||||||
'appearanceRange': self.appearance.data,
|
'appearanceRange': self.appearance.data,
|
||||||
'functionalityRange': self.functionality.data
|
'functionalityRange': self.functionality.data,
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
|
|
||||||
upload_form = UploadSnapshotForm()
|
upload_form = UploadSnapshotForm()
|
||||||
upload_form.sync = Sync()
|
upload_form.sync = Sync()
|
||||||
|
@ -438,9 +458,13 @@ class TagDeviceForm(FlaskForm):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if self.delete:
|
if self.delete:
|
||||||
tags = Tag.query.filter(Tag.owner_id==g.user.id).filter(Tag.device_id==self.device_id)
|
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter(
|
||||||
|
Tag.device_id == self.device_id
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
tags = Tag.query.filter(Tag.owner_id==g.user.id).filter(Tag.device_id==None)
|
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter(
|
||||||
|
Tag.device_id == None
|
||||||
|
)
|
||||||
|
|
||||||
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
||||||
|
|
||||||
|
@ -450,8 +474,11 @@ class TagDeviceForm(FlaskForm):
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._tag = Tag.query.filter(Tag.id == self.tag.data).filter(
|
self._tag = (
|
||||||
Tag.owner_id == g.user.id).one()
|
Tag.query.filter(Tag.id == self.tag.data)
|
||||||
|
.filter(Tag.owner_id == g.user.id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
if not self.delete and self._tag.device_id:
|
if not self.delete and self._tag.device_id:
|
||||||
self.tag.errors = [("This tag is actualy in use.")]
|
self.tag.errors = [("This tag is actualy in use.")]
|
||||||
|
@ -465,8 +492,11 @@ class TagDeviceForm(FlaskForm):
|
||||||
|
|
||||||
if self.device_id or self.device.data:
|
if self.device_id or self.device.data:
|
||||||
self.device_id = self.device_id or self.device.data
|
self.device_id = self.device_id or self.device.data
|
||||||
self._device = Device.query.filter(Device.id == self.device_id).filter(
|
self._device = (
|
||||||
Device.owner_id == g.user.id).one()
|
Device.query.filter(Device.id == self.device_id)
|
||||||
|
.filter(Device.owner_id == g.user.id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -482,18 +512,27 @@ class TagDeviceForm(FlaskForm):
|
||||||
|
|
||||||
|
|
||||||
class NewActionForm(FlaskForm):
|
class NewActionForm(FlaskForm):
|
||||||
name = StringField('Name', [validators.length(max=50)],
|
name = StringField(
|
||||||
description="A name or title of the event. Something to look for.")
|
'Name',
|
||||||
|
[validators.length(max=50)],
|
||||||
|
description="A name or title of the event. Something to look for.",
|
||||||
|
)
|
||||||
devices = HiddenField()
|
devices = HiddenField()
|
||||||
date = DateField('Date', [validators.Optional()],
|
date = DateField(
|
||||||
|
'Date',
|
||||||
|
[validators.Optional()],
|
||||||
description="""When the action ends. For some actions like booking
|
description="""When the action ends. For some actions like booking
|
||||||
the time when it expires, for others like renting the
|
the time when it expires, for others like renting the
|
||||||
time that the end rents. For specific actions, it is the
|
time that the end rents. For specific actions, it is the
|
||||||
time in which they are carried out; differs from created
|
time in which they are carried out; differs from created
|
||||||
in that created is where the system receives the action.""")
|
in that created is where the system receives the action.""",
|
||||||
severity = SelectField('Severity', choices=[(v.name, v.name) for v in Severity],
|
)
|
||||||
|
severity = SelectField(
|
||||||
|
'Severity',
|
||||||
|
choices=[(v.name, v.name) for v in Severity],
|
||||||
description="""An indicator that evaluates the execution of the event.
|
description="""An indicator that evaluates the execution of the event.
|
||||||
For example, failed events are set to Error""")
|
For example, failed events are set to Error""",
|
||||||
|
)
|
||||||
description = TextAreaField('Description')
|
description = TextAreaField('Description')
|
||||||
lot = HiddenField()
|
lot = HiddenField()
|
||||||
type = HiddenField()
|
type = HiddenField()
|
||||||
|
@ -507,8 +546,11 @@ class NewActionForm(FlaskForm):
|
||||||
self._devices = OrderedSet()
|
self._devices = OrderedSet()
|
||||||
if self.devices.data:
|
if self.devices.data:
|
||||||
devices = set(self.devices.data.split(","))
|
devices = set(self.devices.data.split(","))
|
||||||
self._devices = OrderedSet(Device.query.filter(Device.id.in_(devices)).filter(
|
self._devices = OrderedSet(
|
||||||
Device.owner_id == g.user.id).all())
|
Device.query.filter(Device.id.in_(devices))
|
||||||
|
.filter(Device.owner_id == g.user.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
if not self._devices:
|
if not self._devices:
|
||||||
return False
|
return False
|
||||||
|
@ -570,19 +612,31 @@ class AllocateForm(NewActionForm):
|
||||||
|
|
||||||
|
|
||||||
class DataWipeDocumentForm(Form):
|
class DataWipeDocumentForm(Form):
|
||||||
date = DateField('Date', [validators.Optional()],
|
date = DateField(
|
||||||
description="Date when was data wipe")
|
'Date', [validators.Optional()], description="Date when was data wipe"
|
||||||
url = URLField('Url', [validators.Optional()],
|
)
|
||||||
description="Url where the document resides")
|
url = URLField(
|
||||||
success = BooleanField('Success', [validators.Optional()],
|
'Url', [validators.Optional()], description="Url where the document resides"
|
||||||
description="The erase was success or not?")
|
)
|
||||||
software = StringField('Software', [validators.Optional()],
|
success = BooleanField(
|
||||||
description="Which software has you use for erase the disks")
|
'Success', [validators.Optional()], description="The erase was success or not?"
|
||||||
id_document = StringField('Document Id', [validators.Optional()],
|
)
|
||||||
description="Identification number of document")
|
software = StringField(
|
||||||
file_name = FileField('File', [validators.DataRequired()],
|
'Software',
|
||||||
|
[validators.Optional()],
|
||||||
|
description="Which software has you use for erase the disks",
|
||||||
|
)
|
||||||
|
id_document = StringField(
|
||||||
|
'Document Id',
|
||||||
|
[validators.Optional()],
|
||||||
|
description="Identification number of document",
|
||||||
|
)
|
||||||
|
file_name = FileField(
|
||||||
|
'File',
|
||||||
|
[validators.DataRequired()],
|
||||||
description="""This file is not stored on our servers, it is only used to
|
description="""This file is not stored on our servers, it is only used to
|
||||||
generate a digital signature and obtain the name of the file.""")
|
generate a digital signature and obtain the name of the file.""",
|
||||||
|
)
|
||||||
|
|
||||||
def validate(self, extra_validators=None):
|
def validate(self, extra_validators=None):
|
||||||
is_valid = super().validate(extra_validators)
|
is_valid = super().validate(extra_validators)
|
||||||
|
@ -638,23 +692,39 @@ class DataWipeForm(NewActionForm):
|
||||||
|
|
||||||
|
|
||||||
class TradeForm(NewActionForm):
|
class TradeForm(NewActionForm):
|
||||||
user_from = StringField('Supplier', [validators.Optional()],
|
user_from = StringField(
|
||||||
|
'Supplier',
|
||||||
|
[validators.Optional()],
|
||||||
description="Please enter the supplier's email address",
|
description="Please enter the supplier's email address",
|
||||||
render_kw={'data-email': ""})
|
render_kw={'data-email': ""},
|
||||||
user_to = StringField('Receiver', [validators.Optional()],
|
)
|
||||||
|
user_to = StringField(
|
||||||
|
'Receiver',
|
||||||
|
[validators.Optional()],
|
||||||
description="Please enter the receiver's email address",
|
description="Please enter the receiver's email address",
|
||||||
render_kw={'data-email': ""})
|
render_kw={'data-email': ""},
|
||||||
confirm = BooleanField('Confirm', [validators.Optional()],
|
)
|
||||||
|
confirm = BooleanField(
|
||||||
|
'Confirm',
|
||||||
|
[validators.Optional()],
|
||||||
default=True,
|
default=True,
|
||||||
description="I need confirmation from the other user for every device and document.")
|
description="I need confirmation from the other user for every device and document.",
|
||||||
code = StringField('Code', [validators.Optional()],
|
)
|
||||||
description="If you don't need confirm, you need put a code for trace the user in the statistics.")
|
code = StringField(
|
||||||
|
'Code',
|
||||||
|
[validators.Optional()],
|
||||||
|
description="If you don't need confirm, you need put a code for trace the user in the statistics.",
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.user_from.render_kw['data-email'] = g.user.email
|
self.user_from.render_kw['data-email'] = g.user.email
|
||||||
self.user_to.render_kw['data-email'] = g.user.email
|
self.user_to.render_kw['data-email'] = g.user.email
|
||||||
self._lot = Lot.query.filter(Lot.id==self.lot.data).filter(Lot.owner_id==g.user.id).one()
|
self._lot = (
|
||||||
|
Lot.query.filter(Lot.id == self.lot.data)
|
||||||
|
.filter(Lot.owner_id == g.user.id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
def validate(self, extra_validators=None):
|
def validate(self, extra_validators=None):
|
||||||
is_valid = self.generic_validation(extra_validators=extra_validators)
|
is_valid = self.generic_validation(extra_validators=extra_validators)
|
||||||
|
@ -665,8 +735,12 @@ class TradeForm(NewActionForm):
|
||||||
self.code.errors = ["If you don't want confirm, you need a code"]
|
self.code.errors = ["If you don't want confirm, you need a code"]
|
||||||
is_valid = False
|
is_valid = False
|
||||||
|
|
||||||
if self.confirm.data and not (email_from and email_to) or email_to == email_from or \
|
if (
|
||||||
g.user.email not in [email_from, email_to]:
|
self.confirm.data
|
||||||
|
and not (email_from and email_to)
|
||||||
|
or email_to == email_from
|
||||||
|
or g.user.email not in [email_from, email_to]
|
||||||
|
):
|
||||||
|
|
||||||
errors = ["If you want confirm, you need a correct email"]
|
errors = ["If you want confirm, you need a correct email"]
|
||||||
self.user_to.errors = errors
|
self.user_to.errors = errors
|
||||||
|
@ -736,16 +810,14 @@ class TradeForm(NewActionForm):
|
||||||
# Create receiver (to) phantom account
|
# Create receiver (to) phantom account
|
||||||
if user_from and not user_to:
|
if user_from and not user_to:
|
||||||
assert g.user.email == user_from
|
assert g.user.email == user_from
|
||||||
user = self.create_user(code)
|
|
||||||
self.user_from = g.user
|
self.user_from = g.user
|
||||||
self.user_to = user
|
self.user_to = self.get_or_create_user(code)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create supplier (from) phantom account
|
# Create supplier (from) phantom account
|
||||||
if not user_from and user_to:
|
if not user_from and user_to:
|
||||||
assert g.user.email == user_to
|
assert g.user.email == user_to
|
||||||
user = self.create_user(code)
|
self.user_from = self.get_or_create_user(code)
|
||||||
self.user_from = user
|
|
||||||
self.user_to = g.user
|
self.user_to = g.user
|
||||||
|
|
||||||
def get_or_create_user(self, code):
|
def get_or_create_user(self, code):
|
||||||
|
@ -778,22 +850,37 @@ class TradeForm(NewActionForm):
|
||||||
|
|
||||||
|
|
||||||
class TradeDocumentForm(FlaskForm):
|
class TradeDocumentForm(FlaskForm):
|
||||||
url = URLField('Url', [validators.Optional()],
|
url = URLField(
|
||||||
|
'Url',
|
||||||
|
[validators.Optional()],
|
||||||
render_kw={'class': "form-control"},
|
render_kw={'class': "form-control"},
|
||||||
description="Url where the document resides")
|
description="Url where the document resides",
|
||||||
description = StringField('Description', [validators.Optional()],
|
)
|
||||||
|
description = StringField(
|
||||||
|
'Description',
|
||||||
|
[validators.Optional()],
|
||||||
render_kw={'class': "form-control"},
|
render_kw={'class': "form-control"},
|
||||||
description="")
|
description="",
|
||||||
id_document = StringField('Document Id', [validators.Optional()],
|
)
|
||||||
|
id_document = StringField(
|
||||||
|
'Document Id',
|
||||||
|
[validators.Optional()],
|
||||||
render_kw={'class': "form-control"},
|
render_kw={'class': "form-control"},
|
||||||
description="Identification number of document")
|
description="Identification number of document",
|
||||||
date = DateField('Date', [validators.Optional()],
|
)
|
||||||
|
date = DateField(
|
||||||
|
'Date',
|
||||||
|
[validators.Optional()],
|
||||||
render_kw={'class': "form-control"},
|
render_kw={'class': "form-control"},
|
||||||
description="")
|
description="",
|
||||||
file_name = FileField('File', [validators.DataRequired()],
|
)
|
||||||
|
file_name = FileField(
|
||||||
|
'File',
|
||||||
|
[validators.DataRequired()],
|
||||||
render_kw={'class': "form-control"},
|
render_kw={'class': "form-control"},
|
||||||
description="""This file is not stored on our servers, it is only used to
|
description="""This file is not stored on our servers, it is only used to
|
||||||
generate a digital signature and obtain the name of the file.""")
|
generate a digital signature and obtain the name of the file.""",
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
lot_id = kwargs.pop('lot')
|
lot_id = kwargs.pop('lot')
|
||||||
|
|
Reference in New Issue