196 lines
7.0 KiB
Python
196 lines
7.0 KiB
Python
from datetime import datetime
|
|
import enum
|
|
import hashlib
|
|
import os
|
|
from flask import current_app
|
|
from jinja2 import Markup
|
|
from formity.extensions import db, cache
|
|
from sqlalchemy import event
|
|
from sqlalchemy.ext.hybrid import hybrid_property
|
|
from formity.utils import get_diff
|
|
|
|
class Status(enum.Enum):
|
|
new = 1
|
|
confirmed = 2
|
|
allocated = 3
|
|
fulfilled = 4
|
|
rejected = 5
|
|
spam = 6
|
|
delegated = 7
|
|
intransit = 8
|
|
shippingpending = 9
|
|
pickuppending = 10
|
|
|
|
|
|
class PostalCode(db.Model):
|
|
postalcode = db.Column(db.String, primary_key=True)
|
|
address = db.Column(db.String, nullable=False)
|
|
city = db.Column(db.String, nullable=False)
|
|
voivodeship = db.Column(db.String, nullable=False)
|
|
county = db.Column(db.String, nullable=False)
|
|
def __str__(self):
|
|
return '{}/{}/{}/{}'.format(self.postalcode, self.city, self.county, self.voivodeship)
|
|
|
|
|
|
class FaceshieldRequest(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
entity_info = db.Column(db.String)
|
|
full_name = db.Column(db.String)
|
|
phone_number = db.Column(db.String)
|
|
email = db.Column(db.String)
|
|
extra = db.Column(db.String)
|
|
|
|
faceshield_front_required = db.Column(db.Integer, default=0, server_default='0')
|
|
faceshield_model = db.Column(db.String)
|
|
|
|
faceshield_full_required = db.Column(db.Integer, default=0, server_default='0')
|
|
|
|
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
|
updated = db.Column(db.DateTime, default=datetime.utcnow, nullable=False,
|
|
onupdate=datetime.utcnow)
|
|
|
|
ua = db.Column(db.String)
|
|
ip = db.Column(db.String)
|
|
|
|
status = db.Column(db.Enum(Status), default=Status.new, server_default='new', nullable=False)
|
|
remarks = db.Column(db.String)
|
|
|
|
faceshield_front_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
faceshield_full_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
|
|
adapter_3m_dar_required = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_easybreath_dar_required = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_rd40_dar_required = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_secura_dar_required = db.Column(db.Integer, default=0, server_default='0')
|
|
|
|
adapter_3m_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_easybreath_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_rd40_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
adapter_secura_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
|
|
|
|
delivery_method = db.Column(db.String, default='shipping')
|
|
|
|
shipping_name = db.Column(db.String)
|
|
shipping_street = db.Column(db.String)
|
|
shipping_postalcode = db.Column(db.String)
|
|
shipping_city = db.Column(db.String)
|
|
|
|
shipping_latitude = db.Column(db.Float)
|
|
shipping_longitude = db.Column(db.Float)
|
|
|
|
shipping_provider = db.Column(db.String)
|
|
shipping_id = db.Column(db.String)
|
|
|
|
postalcode_info = db.relationship(PostalCode, primaryjoin='remote(PostalCode.postalcode) == foreign(FaceshieldRequest.shipping_postalcode)')
|
|
parent_id = db.Column(db.Integer, db.ForeignKey(id))
|
|
parent_shipment = db.relationship('FaceshieldRequest', remote_side=id, backref='children')
|
|
|
|
handling_orga = db.Column(db.String, default='hswaw', server_default='hswaw', nullable=False)
|
|
handling_orga_info = db.relationship('Orga', primaryjoin='remote(Orga.id) == foreign(FaceshieldRequest.handling_orga)')
|
|
|
|
def __str__(self):
|
|
return Markup('<a href="/admin/request_unfiltered/edit/?id={}">#{} {}</a> ({})').format(self.id, self.id, self.entity_info, self.status.name)
|
|
|
|
def __repr__(self):
|
|
return '<FaceshieldRequest {} ({})>'.format(self.id, self.status.name)
|
|
|
|
@property
|
|
def label_count(self):
|
|
if self.faceshield_full_delivered % 150 == 0 and self.faceshield_full_delivered // 150 > 1:
|
|
return self.faceshield_full_delivered // 150
|
|
return 1
|
|
|
|
@cache.memoize(timeout=10 * 60)
|
|
def fetch_shipping_info(self):
|
|
if self.shipping_provider == 'kurjerzy':
|
|
from shipping.kurjerzy import Kurjerzy
|
|
k = Kurjerzy(current_app)
|
|
k.authenticate()
|
|
return k.shipment_info(self.shipping_id)
|
|
|
|
return None
|
|
|
|
def refresh_shipping_info(self):
|
|
cache.delete_memoized(self.fetch_shipping_info, self)
|
|
|
|
@property
|
|
def shipping_info(self):
|
|
return self.fetch_shipping_info()
|
|
|
|
|
|
def changelog_default_user_id():
|
|
from flask_login import current_user
|
|
return current_user.get_id() if current_user and current_user.get_id() else 'nobody'
|
|
|
|
|
|
class RequestChange(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
request_id = db.Column(db.Integer, db.ForeignKey(FaceshieldRequest.id))
|
|
request = db.relationship(FaceshieldRequest, backref='changelog')
|
|
|
|
user_id = db.Column(db.String, nullable=False, default=changelog_default_user_id)
|
|
|
|
state_before = db.Column(db.JSON)
|
|
state_after = db.Column(db.JSON)
|
|
remarks = db.Column(db.String)
|
|
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
|
|
|
|
|
class Orga(db.Model):
|
|
id = db.Column(db.String, primary_key=True)
|
|
name = db.Column(db.String)
|
|
|
|
shipping_name = db.Column(db.String)
|
|
shipping_full_name = db.Column(db.String)
|
|
shipping_street = db.Column(db.String)
|
|
shipping_number = db.Column(db.String)
|
|
shipping_postalcode = db.Column(db.String)
|
|
shipping_city = db.Column(db.String)
|
|
shipping_phone_number = db.Column(db.String)
|
|
shipping_email = db.Column(db.String)
|
|
|
|
|
|
class ExternalUser(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
email = db.Column(db.String, nullable=False)
|
|
_password = db.Column('password', db.String, nullable=False)
|
|
remarks = db.Column(db.String)
|
|
orga = db.Column(db.String, db.ForeignKey(Orga.id))
|
|
|
|
def _hash(self, salt, password):
|
|
return hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 213700).hex()
|
|
|
|
@hybrid_property
|
|
def password(self):
|
|
return self._password
|
|
|
|
@password.setter
|
|
def password(self, new_pass):
|
|
# hack: do not double hash
|
|
if self._password == new_pass:
|
|
return
|
|
salt = hashlib.sha256(os.urandom(16)).hexdigest()
|
|
self._password = salt + ':' + self._hash(salt, new_pass)
|
|
|
|
def check_password(self, password):
|
|
salt, h = self.password.split(':')
|
|
return self._hash(salt, password) == h
|
|
|
|
@event.listens_for(FaceshieldRequest, 'after_update')
|
|
def on_request_change(mapper, connection, target):
|
|
try:
|
|
before, after = get_diff(target)
|
|
except Exception as exc:
|
|
# xD
|
|
before, after = {'diff': 'failed'}, {'diff': 'failed'}
|
|
|
|
if before or after:
|
|
@event.listens_for(db.session, "after_flush", once=True)
|
|
def receive_after_flush(session, context):
|
|
db.session.add(RequestChange(
|
|
request_id=target.id,
|
|
state_before=before,
|
|
state_after=after,
|
|
))
|