Example #1
0
class MaterialBank(db.Document, Base):
    """
    MaterialBank class
    """
    meta = {
        'collection':
        'material_banks',
        'indexes': [{
            'fields': ['name'],
            'collation': {
                'locale': 'en',
                'strength': 1  # Considers case and diactritics
            }
        }]
    }
    name = db.StringField(required=True, unique=True, max_length=50)
    location = db.StringField(max_length=150)
    description = db.StringField(max_length=150)
    owner = db.ReferenceField(Supplier,
                              dbref=True,
                              reverse_delete_rule=db.NULLIFY)
    materials_available = db.ListField(
        db.ReferenceField(Material, dbref=True, reverse_delete_rule=db.PULL),
        validation=_validate_no_duplicate_objects)
    royalty = db.DecimalField(min_value=0, precision=2, default=0)
    date_added = db.DateTimeField(required=True,
                                  default=datetime.datetime.utcnow)
    is_active = db.BooleanField(default=True)

    def json(self):
        skip_items = []
        d_json = dict()
        for i in self:
            if i not in skip_items:
                if i == 'owner':  # Get name of object
                    d_json['owner_name'] = self[i].name if self[i] else ''
                elif i == 'materials_available':  # Get names list of materials
                    l = []
                    for m in self[i]:
                        l.append(m.name)
                    d_json['material_name_list'] = l
                elif self[i] is None:
                    d_json[i] = ''
                else:
                    d_json[i] = self[i]
        return d_json

    def save_to_db(self):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            self.save()
        except Exception as e:
            self.reload()
            raise e

    def update(self, **field_value):
        # Use owner_name and material_name_list instead of owner and materials_available
        for fv in field_value:
            if fv == 'owner_name':
                self.owner = Supplier.find_by_name(
                    field_value[fv]) if field_value[fv] else None
            elif fv == 'material_name_list':
                self.materials_available = [
                    Material.find_by_name(mn) for mn in field_value[fv]
                ]
            else:
                self[fv] = field_value[fv]
        return self.save_to_db()

    def set_owner(self, name):
        supplier = Supplier.find_by_name(name, False)
        if supplier:
            self.owner = supplier
            self.save_to_db()
        else:
            raise NameError(
                'Proveedor "{}" no encontrado en sistema. Favor de agregarlo primero.'
                .format(name))

    def add_materials(self, material_name):
        if not isinstance(material_name, list):
            material_name = [material_name]
        for i in material_name:
            try:
                material = Material.find_by_name(i)
                self.materials_available.append(material)
            except NameError:
                self.reload()
                raise NameError(
                    'Material "{}" no encontrado. Ningún material fue agregado. '
                    'Favor de agregar a lista de materiales primero. '.format(
                        i.upper()))
        self.save_to_db()

    def remove_material(self, material_name):
        if material_name.upper() in [i.name for i in self.materials_available]:
            material = Material.find_by_name(material_name)
            self.materials_required.remove(material)
            self.save_to_db()

        else:
            raise NameError(
                'Material "{}" no encontrado en lista de materiales de obra. '
                'Ningun material fue removido'.format(material_name.upper()))

    def get_list_of_materials(self):
        return [i.name for i in self.materials_available]

    @classmethod
    def add(cls,
            name,
            location=None,
            description=None,
            owner_name=None,
            material_name_list=None,
            royalty=None,
            is_active=None):
        owner = Supplier.find_by_name(owner_name) if owner_name else None
        materials_list = [
            Material.find_by_name(mn) for mn in material_name_list
        ] if material_name_list else []
        params = {
            'name': name,
            'location': location,
            'description': description,
            'owner': owner,
            'materials_available': materials_list,
            'royalty': royalty,
            'is_active': is_active
        }
        return cls(**params).save()

    @classmethod
    def find_by_id(cls, _id):
        return cls.objects(id=_id).first()

    @classmethod
    def find_by_name(cls, name, raise_if_none=True):
        origin = cls.objects(name__iexact=name).first()
        if not origin and raise_if_none:
            raise NameError('Banco: "{}" no encontrado.'.format(name.upper()))
        return origin

    @classmethod
    def get_list_by(cls, param):
        return [t[param] for t in cls.objects]

    @classmethod
    def get_active(cls):
        return [b.name for b in cls.objects if b.is_active]

    @classmethod
    def get_all(cls):
        return [i.json() for i in cls.objects]
Example #2
0
class Driver(db.Document, Base):
    """
    Driver model
    """
    meta = {
        'collection':
        'drivers',
        'indexes': [
            {
                'fields': ['name'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            },
            {
                'fields': ['last_name'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            }
        ]
    }

    name = db.StringField(required=True, max_length=50)
    last_name = db.StringField(unique_with='name',
                               required=True,
                               max_length=50)
    date_added = db.DateTimeField(required=True,
                                  default=datetime.datetime.utcnow)

    def clean(self):
        """
        Makes sure there are no duplicated name + last_name combinatino
        """
        search_driver = self.find_by_full_name(name=self.name,
                                               last_name=self.last_name,
                                               raise_if_none=False)
        if search_driver:
            if search_driver.id != self.id:
                raise db.ValidationError(
                    'Combinación Nombre+Apellido ya ha sido dado de alta: ')

    def json(self):
        skip_items = []
        d_json = dict()
        for i in self:
            d_json[i] = self[i]
        return d_json

    def save_to_db(self):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            self.save()
        except Exception as e:
            self.reload()
            raise e

    def update(self, **field_value):
        for fv in field_value:
            self[fv] = field_value[fv]
        return self.save_to_db()

    @classmethod
    def add(cls, **kwargs):
        return cls(**kwargs).save()

    @classmethod
    def find_by_id(cls, _id):
        return cls.objects(id=_id).first()

    @classmethod
    def find_by_full_name(cls, name, last_name, raise_if_none=True):
        driver = cls.objects(name__iexact=name,
                             last_name__iexact=last_name).first()
        if not driver and raise_if_none:
            raise NameError('Conductor "{}" no encontrado.'.format(name + " " +
                                                                   last_name))
        return driver

    @classmethod
    def get_all(cls):
        return [i.json() for i in cls.objects]
Example #3
0
class Material(db.Document, Base):
    """
    Material model
    """
    meta = {
        'collection':
        'materials',
        'indexes': [{
            'fields': ['name'],
            'collation': {
                'locale': 'en',
                'strength': 1  # Considers case and diactritics
            }
        }]
    }
    name = db.StringField(required=True, unique=True, max_length=50)
    description = db.StringField(max_length=150)

    # is_active = db.BooleanField(required=True, default=True)

    def json(self):
        skip_items = []
        d_json = dict()
        for i in self:
            if i not in skip_items:
                if self[i] is None:
                    d_json[i] = ''
                else:
                    d_json[i] = self[i]
        return d_json

    def save_to_db(self):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            return self.save()
        except Exception as e:
            self.reload()
            raise e

    def update(self, **field_value):
        for fv in field_value:
            self[fv] = field_value[fv]
        return self.save_to_db()

    @classmethod
    def add(cls, **field_value):
        return cls(**field_value).save()

    @classmethod
    def find_by_id(cls, _id):
        return cls.objects(id=_id).first()

    @classmethod
    def find_by_name(cls, name, raise_if_none=True):
        customer = cls.objects(name__iexact=name).first()
        if not customer and raise_if_none:
            raise NameError('"{}" no encontrado.'.format(name))
        return customer

    @classmethod
    def get_list_by(cls, param):
        return [t[param] for t in cls.objects]

    @classmethod
    def get_all(cls):
        return [i.json() for i in cls.objects]
Example #4
0
class Truck(db.Document, Base):
    """
    Truck model
    """
    meta = {
        'collection':
        'trucks',
        'indexes': [
            {
                'fields': ['id_code'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            },
            {
                'fields': ['serial_number'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            },
            {
                'fields': ['plate'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            }
        ]
    }
    # meta = {'collection': 'trucks'}
    id_code = db.StringField(required=True, unique=True, max_length=50)
    brand = db.StringField(max_length=50)
    color = db.StringField(max_length=50)
    serial_number = db.StringField(required=True,
                                   unique=True,
                                   sparse=True,
                                   max_length=50)
    plate = db.StringField(required=False,
                           unique=True,
                           sparse=True,
                           max_length=50)  # mark as required???
    capacity = db.IntField(required=True, min_value=0)
    driver = db.ReferenceField(Driver,
                               dbref=True,
                               reverse_delete_rule=db.NULLIFY)
    owner = db.ReferenceField(Supplier,
                              dbref=True,
                              reverse_delete_rule=db.NULLIFY)
    date_added = db.DateTimeField(required=True,
                                  default=datetime.datetime.utcnow)
    is_active = db.BooleanField(required=True, default=True)

    def json(self, driver_id=False):
        """

        :param driver_id: If true, driver_full_name shows ID value, instead of full name tupple
        :return:
        """
        skip_items = []
        d_json = dict()
        for i in self:
            if i not in skip_items:
                if i == 'driver':
                    if driver_id:
                        d_json[
                            'driver_full_name'] = self[i].id if self[i] else ''
                    else:
                        d_json['driver_full_name'] = (
                            self[i].name, self[i].last_name
                        ) if self[i] else ''  # tupple: (name, last_name)
                elif i == 'owner':
                    d_json['owner_name'] = self[i].name if self[i] else ''
                elif self[i] is None:
                    d_json[i] = ''
                else:
                    d_json[i] = self[i]
        return d_json

    def save_to_db(self):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            self.save()
        except Exception as e:
            self.reload()
            raise e

    def update(self, **field_value):
        # Use owner_name and driver_full_name instead of owner and materials_available
        for fv in field_value:
            if fv == 'owner_name':
                self.owner = Supplier.find_by_name(
                    field_value[fv]) if field_value[fv] else None
            elif fv == 'driver_full_name':
                if field_value[fv] and not isinstance(field_value[fv], tuple):
                    raise TypeError(
                        'Driver name must be a tuple with format ("name","last_name")'
                    )
                self.driver = Driver.find_by_full_name(
                    field_value[fv][0],
                    field_value[fv][1]) if field_value[fv] else None
            elif fv == 'plate':
                self.plate = field_value[fv] if field_value[fv] else None
            else:
                self[fv] = field_value[fv]
        return self.save_to_db()

    def set_driver(self, name, last_name):
        driver = Driver.find_by_full_name(name, last_name)
        self.driver = driver
        self.save_to_db()

    def set_owner(self, name):
        supplier = Supplier.find_by_name(name, False)
        if supplier:
            self.owner = supplier
            self.save_to_db()
        else:
            raise NameError(
                'Proveedor "{}" no encontrado en sistema. Favor de agregarlo primero.'
                .format(name))

    @classmethod
    def add(cls,
            id_code,
            serial_number,
            capacity,
            brand=None,
            color=None,
            plate=None,
            owner_name=None,
            driver_full_name=None,
            is_active=None):
        owner = Supplier.find_by_name(owner_name) if owner_name else None
        if driver_full_name and not isinstance(driver_full_name, tuple):
            raise TypeError(
                'Driver name must be a tuple with format ("name","last_name")')
        driver = Driver.find_by_full_name(
            driver_full_name[0],
            driver_full_name[1]) if driver_full_name else None
        params = {
            'id_code': id_code.upper(),
            'serial_number': serial_number.upper(),
            'brand': brand,
            'color': color,
            'plate': plate.upper() if plate else None,
            'capacity': capacity,
            'driver': driver,
            'owner': owner,
            'is_active': is_active
        }
        return cls(**params).save()

    @classmethod
    def find_by_id(cls, _id):
        return cls.objects(id=_id).first()

    @classmethod
    def find_by_idcode(cls, id_code, raise_if_none=True):
        truck = cls.objects(id_code__iexact=id_code).first()
        if not truck and raise_if_none:
            raise NameError(
                'Camion codigo "{}" no encontrado.'.format(id_code))
        return truck

    @classmethod
    def get_list_by(cls, param):
        return [t[param] for t in cls.objects]

    @classmethod
    def find_by(cls, field, value):
        return cls.objects(**{field + '__iexact': value}).first()

    @classmethod
    def get_active(cls):
        return [t.id_code for t in cls.objects if t.is_active]

    @classmethod
    def get_all(cls):
        return [i.json() for i in cls.objects]
Example #5
0
class Trip(db.Document, Base):
    """
    Trip model
    """
    meta = {'collection': 'trips'}
    trip_id = db.SequenceField(primary_key=True)
    truck = db.StringField(required=False, validation=validate_truck_options)
    material = db.StringField(required=True,
                              validation=validate_material_options)
    amount = db.IntField(required=True, min_value=0)
    origin = db.StringField(required=True,
                            validation=validate_location_options)
    destination = db.StringField(required=False,
                                 validation=validate_location_options)
    client = db.StringField(required=False)
    sender_user = db.StringField(required=True,
                                 validation=validate_user_options)
    sender_comment = db.StringField(required=False, max_length=100)
    sent_datetime = db.DateTimeField(required=True,
                                     default=datetime.datetime.utcnow)
    finalizer_user = db.StringField(validation=validate_user_options)
    finalizer_comment = db.StringField(required=False, max_length=100)
    finalized_datetime = db.DateTimeField()
    status = db.StringField(required=False, choices=STATUS_LIST)
    is_return = db.BooleanField(defaul=False)
    type = db.StringField(required=True, choices=TRIP_TYPES_LIST)

    def json(self):
        trip_dict = dict()
        for i in self:
            if (i in ['sender_comment', 'finalizer_comment', 'client', 'destination', 'truck', 'finalizer_user']) and \
                    (self[i] is None):  # (i == 'sender_comment' or i == 'finalizer_comment')
                trip_dict[i] = ''
            else:
                trip_dict[i] = self[i]
        return trip_dict

    def save_to_db(self, validation=True):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            self.save(validate=validation)
        except Exception as e:
            self.reload()
            raise e

    def finalize(self, username, status, finalizer_comment=None):
        """
        Move trip to complete or canceled.
        :param username: username of user doing the operation
        :param status: "complete" or "canceled"
        :param finalizer_comment: optional comment
        :return:
        """
        self.status = status
        self.finalizer_user = username
        self.finalizer_comment = finalizer_comment
        self.finalized_datetime = datetime.datetime.utcnow()
        self.save_to_db(
            validation=False
        )  # This is a temporary solution, instead code logic to execute validate_x_options

    @classmethod
    def create(cls,
               truck_id,
               material_name,
               origin_name,
               sender_username,
               type,
               status='in_progress',
               destination_name=None,
               client_name=None,
               sender_comment=None,
               amount=None,
               is_return=None):
        params = {
            'truck': truck_id.upper() if truck_id else None,
            'material': material_name.upper(),
            'origin': origin_name.upper(),
            'destination':
            destination_name.upper() if destination_name else None,
            'client': client_name.upper() if client_name else None,
            'sender_user': sender_username,
            'sender_comment': sender_comment,
            'amount':
            amount if amount else Truck.find_by_idcode(truck_id).capacity,
            'status': status,
            'is_return': is_return,
            'type': type
        }
        return cls(**params).save()

    @classmethod
    def find_by_tripid(cls, trip_id, raise_if_none=True):
        trip = cls.objects(trip_id__iexact=trip_id).first()
        if not trip and raise_if_none:
            raise NameError('Viaje "#{}" no existe'.format(trip_id))
        return trip

    @classmethod
    def get_all(cls):
        return [trip.json() for trip in cls.objects]

    @classmethod
    def get_trucks_in_trip(cls):
        return list(
            dict.fromkeys([t.truck
                           for t in cls.objects(status='in_progress')]))
Example #6
0
class User(db.Document, UserMixin):
    """
    User Model
    """
    meta = {
        'collection':
        'users',
        'indexes': [
            {
                'fields': ['username'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            },
            {
                'fields': ['email'],
                'collation': {
                    'locale': 'en',
                    'strength': 1  # Considers case and diactritics
                }
            }
        ]
    }

    username = db.StringField(unique=True, required=True, max_length=25)
    hashed_pwd = db.StringField(required=True)
    name = db.StringField(max_length=50)
    last_name = db.StringField(max_length=50)
    email = db.EmailField(unique=True, sparse=True, max_length=100)
    role = db.StringField(required=True, choices=ROLES, default='operator')
    date_added = db.DateTimeField(required=True,
                                  default=datetime.datetime.utcnow())

    def json(self):
        skip_items = ['id', 'hashed_pwd']
        d_json = dict()
        for i in self:
            if i not in skip_items:
                if self[i] is None:
                    d_json[i] = ''
                else:
                    d_json[i] = self[i]
        return d_json

    def save_to_db(self):
        """
        Try to save instance. If there is an error, it reload info from DB to discard changes.
        :param self:
        :return:
        """
        try:
            self.save()
        except Exception as e:
            self.reload()
            raise e

    def set_password(self, password):
        self.hashed_pwd = generate_password_hash(password)
        self.save()

    def check_password(self, password):
        return check_password_hash(self.hashed_pwd, password)

    def update(self, **field_value):
        for fv in field_value:
            if fv == 'password':
                self.hashed_pwd = generate_password_hash(
                    field_value['password'])
            elif fv == 'email' and field_value['email'] == '':
                self['email'] = None
            elif fv == 'email' or fv == 'username':
                self[fv] = field_value[fv].lower()
            else:
                self[fv] = field_value[fv]
        self.save_to_db()

    @classmethod
    def add(cls,
            username,
            password,
            email=None,
            name='',
            last_name='',
            role='operator'):
        email = None if (email == '' or email is None) else email.lower()
        return cls(username=username.lower(),
                   hashed_pwd=generate_password_hash(password),
                   email=email,
                   name=name,
                   last_name=last_name,
                   role=role).save()

    @classmethod
    def find_by_username(cls, username, raise_if_none=True):
        user = cls.objects(username__iexact=username).first()
        if not user and raise_if_none:
            raise NameError('Usuario {} no encontrado.'.format(username))
        return user

    @classmethod
    def find_by_id(cls, _id):
        return cls.objects(id=_id).first()

    @classmethod
    def find_by(cls, field, value):
        return cls.objects(**{field: value})

    @classmethod
    def get_all(cls):
        return [u.json() for u in cls.objects]

    @classmethod
    def get_list_by(cls, param, lower=False):
        if lower:
            return [
                t[param].lower() if t[param] else t[param] for t in cls.objects
            ]
        return [t[param] for t in cls.objects]