This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
devicehub-teal/ereuse_devicehub/resources/tradedocument/models.py

181 lines
6 KiB
Python
Raw Normal View History

2021-10-04 11:35:51 +00:00
import copy
from contextlib import suppress
2022-09-26 06:14:04 +00:00
2021-05-13 11:35:46 +00:00
from citext import CIText
2021-06-15 11:11:49 +00:00
from flask import g
2021-05-19 07:47:14 +00:00
from sortedcontainers import SortedSet
2021-06-15 11:11:49 +00:00
from sqlalchemy import BigInteger, Column, Sequence
2022-09-26 06:14:04 +00:00
from sqlalchemy.dialects.postgresql import UUID
2021-06-15 11:11:49 +00:00
from sqlalchemy.orm import backref
2021-05-13 11:35:46 +00:00
2022-09-26 06:14:04 +00:00
from ereuse_devicehub.db import db
2021-06-15 11:11:49 +00:00
from ereuse_devicehub.resources.enums import Severity
2022-09-26 06:14:04 +00:00
from ereuse_devicehub.resources.models import Thing
from ereuse_devicehub.resources.user.models import User
2023-03-21 11:08:13 +00:00
from ereuse_devicehub.teal.db import CASCADE_OWN, URL
2021-05-13 11:35:46 +00:00
2021-05-19 07:47:14 +00:00
_sorted_documents = {
'order_by': lambda: TradeDocument.created,
2022-09-26 06:14:04 +00:00
'collection_class': SortedSet,
2021-05-19 07:47:14 +00:00
}
2022-09-26 06:14:04 +00:00
class TradeDocument(Thing):
2021-05-13 11:35:46 +00:00
"""This represent a document involved in a trade action.
Every document is added to a lot.
When this lot is converted in one trade, the action trade is added to the document
and the action trade need to be confirmed for the both users of the trade.
This confirmation can be revoked and this revoked need to be ConfirmRevoke for have
some efect.
2021-06-15 11:11:49 +00:00
This documents can be invoices or list of devices or certificates of erasure of
2021-05-13 11:35:46 +00:00
one disk.
Like a Devices one document have actions and is possible add or delete of one lot
if this lot don't have a trade
The document is saved in the database
"""
id = Column(BigInteger, Sequence('device_seq'), primary_key=True)
id.comment = """The identifier of the device for this database. Used only
internally for software; users should not use this.
"""
# type = Column(Unicode(STR_SM_SIZE), nullable=False)
date = Column(db.DateTime)
date.comment = """The date of document, some documents need to have one date
"""
id_document = Column(CIText())
2022-09-26 06:14:04 +00:00
id_document.comment = (
"""The id of one document like invoice so they can be linked."""
)
2021-05-13 11:35:46 +00:00
description = Column(db.CIText())
description.comment = """A description of document."""
2022-09-26 06:14:04 +00:00
owner_id = db.Column(
UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
default=lambda: g.user.id,
)
2021-05-13 11:35:46 +00:00
owner = db.relationship(User, primaryjoin=owner_id == User.id)
2022-09-26 06:14:04 +00:00
lot_id = db.Column(UUID(as_uuid=True), db.ForeignKey('lot.id'), nullable=False)
lot = db.relationship(
'Lot',
backref=backref(
'documents', lazy=True, cascade=CASCADE_OWN, **_sorted_documents
),
primaryjoin='TradeDocument.lot_id == Lot.id',
)
2021-05-19 07:47:14 +00:00
lot.comment = """Lot to which the document is associated"""
2021-05-13 11:35:46 +00:00
file_name = Column(db.CIText())
file_name.comment = """This is the name of the file when user up the document."""
2021-06-15 10:38:02 +00:00
file_hash = Column(db.CIText())
file_hash.comment = """This is the hash of the file produced from frontend."""
2021-06-15 11:11:49 +00:00
url = db.Column(URL())
2021-06-15 10:38:02 +00:00
url.comment = """This is the url where resides the document."""
weight = db.Column(db.Float())
2022-09-26 06:14:04 +00:00
weight.comment = (
"""This is the weight of one container than this document express."""
)
2021-05-13 11:35:46 +00:00
__table_args__ = (
db.Index('document_id', id, postgresql_using='hash'),
# db.Index('type_doc', type, postgresql_using='hash')
)
@property
def actions(self) -> list:
"""All the actions where the device participated, including:
1. Actions performed directly to the device.
2. Actions performed to a component.
3. Actions performed to a parent device.
Actions are returned by descending ``created`` time.
"""
2021-06-24 09:41:14 +00:00
return sorted(self.actions_docs, key=lambda x: x.created)
2021-05-13 11:35:46 +00:00
2021-06-22 14:53:10 +00:00
@property
def trading(self):
"""The trading state, or None if no Trade action has
ever been performed to this device. This extract the posibilities for to do"""
confirm = 'Confirm'
need_confirm = 'Need Confirmation'
double_confirm = 'Document Confirmed'
2021-06-22 14:53:10 +00:00
revoke = 'Revoke'
revoke_pending = 'Revoke Pending'
confirm_revoke = 'Document Revoked'
2021-10-04 11:35:51 +00:00
ac = self.last_action_trading()
if not ac:
return
2021-06-22 14:53:10 +00:00
if ac.type == 'ConfirmRevokeDocument':
# can to do revoke_confirmed
return confirm_revoke
2021-05-13 11:35:46 +00:00
if ac.type == 'RevokeDocument':
if ac.user == g.user:
# can todo revoke_pending
return revoke_pending
else:
# can to do confirm_revoke
return revoke
2021-05-13 11:35:46 +00:00
if ac.type == 'ConfirmDocument':
if ac.user == self.owner:
if self.owner == g.user:
# can to do revoke
return confirm
else:
# can to do confirm
return need_confirm
else:
# can to do revoke
return double_confirm
2021-05-13 11:35:46 +00:00
@property
def total_weight(self):
"""Return all weight than this container have."""
2021-09-10 12:07:35 +00:00
weight = self.weight or 0
for x in self.actions:
if not x.type == 'MoveOnDocument' or not x.weight:
continue
if self == x.container_from:
continue
weight += x.weight
return weight
2022-09-26 06:14:04 +00:00
def get_url(self) -> str:
if self.url:
return self.url.to_text()
return ''
2021-10-04 11:35:51 +00:00
def last_action_trading(self):
"""which is the last action trading"""
with suppress(StopIteration, ValueError):
actions = copy.copy(self.actions)
actions.sort(key=lambda x: x.created)
2022-09-26 06:14:04 +00:00
t_trades = [
'Trade',
'Confirm',
'ConfirmRevokeDocument',
'RevokeDocument',
'ConfirmDocument',
]
2021-10-04 11:35:51 +00:00
return next(e for e in reversed(actions) if e.t in t_trades)
2021-05-13 11:35:46 +00:00
def _warning_actions(self, actions):
"""Show warning actions"""
2021-05-13 11:35:46 +00:00
return sorted(ev for ev in actions if ev.severity >= Severity.Warning)
def __lt__(self, other):
2022-11-30 09:23:51 +00:00
if self.id and other.id:
return self.id < other.id
return False
2021-05-13 11:35:46 +00:00
def __str__(self) -> str:
return '{0.file_name}'.format(self)