예제 #1
0
 class T1:
     id = Integer(primary_key=True)
     code = String()
     val = Integer()
     parent = Many2One(model='Model.T1')
예제 #2
0
class Room:

    id = Integer(primary_key=True)
    name = String(label="Room name", nullable=False, index=True)
    capacity = Integer(label="Capacity", nullable=False)
예제 #3
0
            class Person:

                name = String(primary_key=True)
                invoiced_addresses = Many2Many(model=Model.Address)
                delivery_addresses = Many2Many(model=Model.Address)
 class Test:
     id = Integer(primary_key=True)
     name = String()
예제 #5
0
class User:
    """User declaration need for Auth"""

    login = String(primary_key=True, nullable=False)

    @classmethod
    def get_roles(cls, login):
        """Return the roles of an user

        :param login: str, login attribute of the user
        :rtype: list of str (name of the roles)
        """
        # cache the method
        roles = [login]
        user = cls.query().filter(cls.login == login).one_or_none()
        if user:
            for role in user.roles:
                roles.extend(role.roles_name)

        return list(set(roles))

    @classmethod
    def get_acl(cls, login, resource, params=None):
        """Retun the ACL for a ressource and a user

        Auth, does not implement any rule to compute ACL,
        This method allow all user to use the resource ask
        by controllers.

        For other configuration, this method must be overwrite

        :param login: str, login attribute of the user
        :param resource: str, name of a resource
        :param params: all options need to compute ACL
        """
        # cache the method
        return [(Allow, login, ALL_PERMISSIONS)]

    @classmethod
    def format_login_params(cls, request):
        """Return the login and password from query

        By default the query come from json_body and are named
        **login** and **password**

        If the entries come from another place, this method must be overwrite
        :param request: the request from the controllers
        """
        return request.json_body

    @classmethod
    def check_login(cls, login=None, password=None, **kwargs):
        """Check login / password

        This method raise an exception, because any credential
        is stored in this bloks

        .. warning::

            This method must be overwriting by anycredential blok


        :param login: str, the login attribute of the user
        :param password: str
        :param kwargs: any options need to validate credential
        """
        raise HTTPUnauthorized()

    @classmethod
    def get_login_location_to(cls, login, request):
        """Return the default path after the login"""
        return '/'

    @classmethod
    def get_logout_location_to(cls, request):
        """Return the default path after the logout"""
        return '/'
class Guest:
    id = Integer(primary_key=True)
    name = String(nullable=False)

    def __repr__(self):
        return "<Guest(name={self.name!r})>".format(self=self)
class Question:
    id = Integer(primary_key=True)
    name = String(label="Name", nullable=False)
    survey_id = Integer(foreign_key="Model.Survey=>id")
    position = Integer(label="Position", nullable=True)
예제 #8
0
 class Test2:
     id = Integer(primary_key=True)
     name = String()
     test_id = Integer(foreign_key=Model.Test.use('id'))
예제 #9
0
 class Test2:
     id = Integer(primary_key=True)
     name = String()
     test = One2One(model=Model.Test, backref='test2')
예제 #10
0
class Goods:
    """Main data type to represent physical objects managed by the system.

    The instances of this model are also
    the ultimate representation of the Goods "staying the same" or "becoming
    different" under the Operations, which is, ultimately, a subjective
    decision that has to be left to downstream libraires and applications, or
    even end users.

    For instance, everybody agrees that moving something around does not make
    it different. Therefore, the Move Operation uses the same Goods record
    in its outcome as in its input.
    On the other hand, changing a property could be considered enough an
    alteration of the physical object to consider it different, or not (think
    of recording some measurement that had not be done earlier.)
    """
    id = Integer(label="Identifier", primary_key=True)
    """Primary key."""

    type = Many2One(model='Model.Wms.Goods.Type', nullable=False, index=True)
    """The :class:`Goods Type <.Type>`"""

    code = String(label="Identifying code", index=True)
    """Uniquely identifying code.

    This should be about what one is ready to display as a barcode for handling
    the Goods. It's also meant to be shared with other applications if needed
    (rather than ids which are only locally unique).
    """

    properties = Many2One(label="Properties",
                          index=True,
                          model='Model.Wms.Goods.Properties')
    """Link to :class:`Properties`.

    .. seealso:: :ref:`goods_properties` for functional aspects.

    .. warning:: don't ever mutate the contents of :attr:`properties` directly,
                 unless what you want is precisely to affect all the Goods
                 records that use them directly.

    Besides their :attr:`type` and the fields meant for the Wms Base
    bloks logic, the Goods Model bears flexible data,
    called *properties*, that are to be
    manipulated as key/value pairs through the :meth:`get_property` and
    :meth:`set_property` methods.

    As far as ``wms_core`` is concerned, values of properties can be of any
    type, yet downstream applications and libraries can choose to make them
    direct fields of the :class:`Properties` model.

    Properties can be shared among several Goods records, for efficiency.
    The :meth:`set_property` implements the necessary Copy-on-Write
    mechanism to avoid unintentionnally modify the properties of many
    Goods records.

    Technically, this data is deported into the :class:`Properties`
    Model (see there on how to add additional properties). The properties
    column value can be None, so that we don't pollute the database with
    empty lines of Property records, although this is subject to change
    in the future.
    """
    def __str__(self):
        return "(id={self.id}, type={self.type})".format(self=self)

    def __repr__(self):
        return "Wms.Goods(id={self.id}, type={self.type!r})".format(self=self)

    def get_property(self, k, default=None):
        """Property getter, works like :meth:`dict.get`.

        Actually I'd prefer to simply implement the dict API, but we can't
        direcly inherit from UserDict yet. This is good enough to provide
        the abstraction needed for current internal wms_core calls.
        """
        if self.properties is None:
            return default

        return self.properties.get(k, default)

    def set_property(self, k, v):
        """Property setter.

        See remarks on :meth:`get_property`.

        This method implements a simple Copy-on-Write mechanism. Namely,
        if the properties are referenced by other Goods records, it
        will duplicate them before actually setting the wished value.
        """
        existing_props = self.properties
        if existing_props is None:
            self.properties = self.registry.Wms.Goods.Properties(
                flexible=dict())
        elif existing_props.get(k) != v:
            cls = self.__class__
            if cls.query(cls.id).filter(cls.properties == existing_props,
                                        cls.id != self.id).limit(1).count():
                self.properties = existing_props.duplicate()
        self.properties.set(k, v)
예제 #11
0
 class Test2:
     id = Integer(primary_key=True)
     name = String()
     test = Many2One(model=Model.Test, one2many="test2")
예제 #12
0
class Pizza(Resource):
    id = Integer(primary_key=True,
                 foreign_key=Resource.use('id').options(ondelete='cascade'))
    name = String(nullable=False)
예제 #13
0
 class T2:
     id = Integer(primary_key=True)
     code = String()
     val = Integer()
예제 #14
0
 class TestView:
     code = String(primary_key=True)
     val1 = Integer()
     val2 = Integer()
예제 #15
0
 class Engineer(Model.Employee):
     id = Integer(primary_key=True, foreign_key=Model.Employee.use('id'))
     engineer_name = String()
예제 #16
0
 class Test2:
     id = Integer(primary_key=True)
     name = String()
     test = Many2Many(model=Model.Test, many2many='test2')
class Track:
    id = Integer(primary_key=True)
    name = String(label="Name", nullable=False)
예제 #18
0
            class Test(Mixin.ForbidUpdate):

                id = Integer(primary_key=True)
                name = String()
class TodoList:
    id = Integer(primary_key=True)
    name = String(label="Name", unique=True, nullable=False)
예제 #20
0
            class Test(Mixin.ReadOnly):

                id = Integer(primary_key=True)
                name = String()
예제 #21
0
class Mapping:

    key = String(primary_key=True)
    model = String(primary_key=True,
                   foreign_key=Model.System.Model.use('name'))
    primary_key = Json(nullable=False)
    blokname = String(label="Blok name",
                      foreign_key=Model.System.Blok.use('name'))

    @hybrid_method
    def filter_by_model_and_key(self, model, key):
        """ SQLAlechemy hybrid method to filter by model and key

        :param model: model of the mapping
        :param key: external key of the mapping
        """
        return (self.model == model) & (self.key == key)

    @hybrid_method
    def filter_by_model_and_keys(self, model, *keys):
        """ SQLAlechemy hybrid method to filter by model and key

        :param model: model of the mapping
        :param key: external key of the mapping
        """
        return (self.model == model) & self.key.in_(keys)

    def remove_element(self, byquery=False):
        val = self.registry.get(self.model).from_primary_keys(
            **self.primary_key)
        logger.info("Remove entity for %r.%r: %r" % (
            self.model, self.key, val))
        val.delete(byquery=byquery, remove_mapping=False)

    @classmethod
    def multi_delete(cls, model, *keys, **kwargs):
        """ Delete all the keys for this model

        :param model: model of the mapping
        :param \*keys: list of the key
        :rtype: Boolean True if the mappings are removed
        """
        mapping_only = kwargs.get('mapping_only', True)
        byquery = kwargs.get('byquery', False)
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_keys(model, *keys))
        count = query.count()
        if count:
            if not mapping_only:
                query.all().remove_element(byquery=byquery)

            query.delete(synchronize_session='fetch', remove_mapping=False)
            cls.registry.expire_all()
            return count

        return 0

    @classmethod
    def delete(cls, model, key, mapping_only=True, byquery=False):
        """ Delete the key for this model

        :param model: model of the mapping
        :param key: string of the key
        :rtype: Boolean True if the mapping is removed
        """
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_key(model, key))
        count = query.count()
        if count:
            if not mapping_only:
                query.one().remove_element(byquery=byquery)

            query.delete(remove_mapping=False)
            return count

        return 0

    @classmethod
    def get_mapping_primary_keys(cls, model, key):
        """ return primary key for a model and an external key

        :param model: model of the mapping
        :param key: string of the key
        :rtype: dict primary key: value or None
        """
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_key(model, key))
        if query.count():
            pks = query.first().primary_key
            cls.check_primary_keys(model, *pks.keys())
            return pks

        return None

    @classmethod
    def check_primary_keys(cls, model, *pks):
        """ check if the all the primary keys match with primary keys of the
        model

        :param model: model to check
        :param pks: list of the primary keys to check
        :exception: IOMappingCheckException
        """
        for pk in cls.get_model(model).get_primary_keys():
            if pk not in pks:
                raise IOMappingCheckException(
                    "No primary key %r found in %r for model %r" % (
                        pk, pks, model))

    @classmethod
    def set_primary_keys(cls, model, key, pks, raiseifexist=True,
                         blokname=None):
        """ Add or update a mmping with a model and a external key

        :param model: model to check
        :param key: string of the key
        :param pks: dict of the primary key to save
        :param raiseifexist: boolean (True by default), if True and the entry
            exist then an exception is raised
        :param blokname: name of the blok where come from the mapping
        :exception: IOMappingSetException
        """
        if cls.get_mapping_primary_keys(model, key):
            if raiseifexist:
                raise IOMappingSetException(
                    "One value found for model %r and key %r" % (model, key))
            cls.delete(model, key)

        if not pks:
            raise IOMappingSetException(
                "No value to save %r for model %r and key %r" % (
                    pks, model, key))

        cls.check_primary_keys(model, *pks.keys())
        vals = dict(model=model, key=key, primary_key=pks)
        if blokname is not None:
            vals['blokname'] = blokname

        return cls.insert(**vals)

    @classmethod
    def set(cls, key, instance, raiseifexist=True, blokname=None):
        """ Add or update a mmping with a model and a external key

        :param model: model to check
        :param key: string of the key
        :param instance: instance of the model to save
        :param raiseifexist: boolean (True by default), if True and the entry
            exist then an exception is raised
        :param blokname: name of the blok where come from the mapping
        :exception: IOMappingSetException
        """
        pks = instance.to_primary_keys()
        return cls.set_primary_keys(instance.__registry_name__, key, pks,
                                    blokname=blokname,
                                    raiseifexist=raiseifexist)

    @classmethod
    def get(cls, model, key):
        """ return instance of the model with this external key

        :param model: model of the mapping
        :param key: string of the key
        :rtype: instance of the model
        """
        pks = cls.get_mapping_primary_keys(model, key)
        if pks is None:
            return None

        return cls.get_model(model).from_primary_keys(**pks)

    @classmethod
    def get_from_model_and_primary_keys(cls, model, pks):
        query = cls.query().filter(cls.model == model)
        for mapping in query.all():
            if mapping.primary_key == pks:
                return mapping

        return None

    @classmethod
    def get_from_entry(cls, entry):
        return cls.get_from_model_and_primary_keys(
            entry.__registry_name__, entry.to_primary_keys())

    @classmethod
    def __get_models(cls, models):
        """Return models name

        if models is not: return all the existing model
        if models is a list of instance model, convert them

        :params models: list of model
        """
        if models is None:
            models = cls.registry.System.Model.query().all().name
        elif not isinstance(models, (list, tuple)):
            models = [models]

        return [m.__registry_name__ if hasattr(m, '__registry_name__') else m
                for m in models]

    @classmethod
    def clean(cls, bloknames=None, models=None):
        """Clean all mapping with removed object linked::

            Mapping.clean(bloknames=['My blok'])

        .. warning::

            For filter only the no blokname::

                Mapping.clean(bloknames=[None])

        :params bloknames: filter by blok, keep the order to remove the mapping
        :params models: filter by model, keep the order to remove the mapping
        """
        if bloknames is None:
            bloknames = cls.registry.System.Blok.query().all().name + [None]
        elif not isinstance(bloknames, (list, tuple)):
            bloknames = [bloknames]
        models = cls.__get_models(models)

        removed = 0
        for blokname in bloknames:
            for model in models:
                query = cls.query().filter_by(blokname=blokname, model=model)
                for key in query.all().key:
                    if cls.get(model, key) is None:
                        cls.delete(model, key)
                        removed += 1

        return removed

    @classmethod
    def delete_for_blokname(cls, blokname, models=None, byquery=False):
        """Clean all mapping with removed object linked::

            Mapping.clean('My blok')

        .. warning::

            For filter only the no blokname::

                Mapping.clean(None)

        :params blokname: filter by blok
        :params models: filter by model, keep the order to remove the mapping
        """
        models = cls.__get_models(models)

        removed = 0
        for model in models:
            query = cls.query().filter_by(blokname=blokname, model=model)
            for key in query.all().key:
                if cls.get(model, key):
                    cls.delete(model, key, mapping_only=False, byquery=byquery)
                    cls.registry.flush()
                    removed += 1

        return removed
예제 #22
0
class Authorization:
    """A model to store autorization rules (permissions for users against an
    Anyblok model or a Pyramid resource)"""

    id = Integer(primary_key=True)
    order = Integer(default=100, nullable=False)

    resource = String()
    model = String(
        foreign_key=Declarations.Model.System.Model.use('name').options(
            ondelete="cascade"))
    primary_keys = Json(default={})
    filter = Json(default={})  # next step

    role = Many2One(model=User.Role,
                    foreign_key_options={'ondelete': 'cascade'})
    login = String(foreign_key=User.use('login').options(ondelete="cascade"))
    user = Many2One(model=User)
    perms = Json(default={})

    perm_create = JsonRelated(json_column='perms', keys=['create'])
    perm_read = JsonRelated(json_column='perms', keys=['read'])
    perm_update = JsonRelated(json_column='perms', keys=['update'])
    perm_delete = JsonRelated(json_column='perms', keys=['delete'])

    @classmethod
    def get_acl_filter_model(cls):
        """Return the Model to use to check the permission"""
        return {
            'User': cls.registry.User,
            'Role': cls.registry.User.Role,
        }

    @classmethod
    def get_acl(cls, login, resource, params=None):
        """Return the Pyramid ACL in function of the resource and user

        :param login: str, login of the user
        :param resource: str, name of the resource
        """
        # cache the method
        User = cls.registry.User
        Role = cls.registry.User.Role

        query = cls.query()
        query = query.filter(
            or_(cls.resource == resource, cls.model == resource))
        query = query.order_by(cls.order)
        Q1 = query.filter(cls.login == login)
        Q2 = query.join(cls.role).filter(Role.name.in_(User.get_roles(login)))
        res = []
        for query in (Q1, Q2):
            for self in query.all():
                allow_perms = []
                deny_perms = []
                perms = list((self.perms or {}).keys())
                perms.sort()
                for perm in perms:
                    p = self.perms[perm]
                    query = User.query()
                    query = query.filter(User.login == login)
                    query = query.join(User.roles)
                    if self.filter:
                        query = query.condition_filter(
                            self.filter, cls.get_acl_filter_model())

                    if 'condition' in p:
                        query = query.condition_filter(
                            p['condition'], cls.get_acl_filter_model())

                    ismatched = True if query.count() else False
                    if p.get('matched' if ismatched else 'unmatched') is True:
                        allow_perms.append(perm)
                    elif (p.get('matched' if ismatched else 'unmatched') is
                          False):
                        deny_perms.append(perm)

                if len(allow_perms):
                    res.append((Allow, login, allow_perms))

                if len(deny_perms):
                    res.append((Deny, login, deny_perms))

        res.append((Deny, login, ALL_PERMISSIONS))
        return res

    @classmethod
    def before_insert_orm_event(cls, mapper, connection, target):
        target.check_validity()

    @classmethod
    def before_update_orm_event(cls, mapper, connection, target):
        target.check_validity()

    def check_validity(self):
        """When creating or updating a User.Authorization, check that all rules
        objects exists or return an AuthorizationValidationException

        :exception: AuthorizationValidationException
        """
        if not (self.role or self.login or self.user or self.role_name):
            raise AuthorizationValidationException(
                "No role and login to apply in the authorization (%s)" % self)

        if not (self.resource or self.model):
            raise AuthorizationValidationException(
                "No resource and model to apply in the authorization (%s)" %
                self)

        if not self.model and self.primary_keys:
            raise AuthorizationValidationException(
                "Primary keys without model to apply in the authorization "
                "(%s)" % self)
예제 #23
0
class JourneyWish(Mixin.UuidColumn, Mixin.TrackModel, Mixin.WorkFlow):

    """This model has Model.JourneyWish as a namespace. It is intented for
       storing journey wishes that represents travels intentions.

       For instance, an intention may be caracterized by start date, with an
       a time frame delimited by earlier and latest departure times,
       departure and arrival stations, passengers, maximum price, etc...

       Implemented fields are the following :

           * Departure station : Many2One relationship with Model.Station
           * Arrival station : Many2One relationship with Model.Station
           * Start date : DateTime representing earlier time after which train
           may leave the departure station
           * End date : DateTime representing latest time after which train may
           leave departure station.
           * Passengers : Many2Many relationship to Model.Passenger
           * Transportation mean : String, containing type of transport
           required by user (train, coach, etc...)
           * Active : boolean that stores if wish has to be processed
           * Activation date : Date, represent the moment when the wish could
           start being processed"""

    user = Many2One(
        label="User", model=Model.User, nullable=False, one2many="wishes"
    )

    departure = Many2One(
        label="Departure Station",
        model=Model.Station,
        nullable=True,
        one2many="departures",
    )

    arrival = Many2One(
        label="Arrival Station",
        model=Model.Station,
        nullable=True,
        one2many="arrivals",
    )

    from_date = DateTime(label="Earlier Departure Date", nullable=True)
    end_date = DateTime(label="Latest Departure Date", nullable=True)
    activation_date = Date(label="Activation Date", nullable=True)

    passengers = Many2Many(
        model=Model.Passenger,
        join_table="join_passengers_by_wishes",
        remote_columns="uuid",
        local_columns="uuid",
        m2m_remote_columns="p_uuid",
        m2m_local_columns="w_uuid",
        many2many="wishes",
    )

    transportation_mean = String(
        label="Transportation Mean", default="any", nullable=True
    )

    active = Boolean(label="Active Wish", nullable=True)

    @classmethod
    def get_workflow_definition(cls):

        """This method is aimed at defining workflow used for model
           Model.JourneyWish"""

        return {
            "draft": {
                "default": True,
                "allowed_to": ["running", "pending"],
                "apply_change": "deactivate",
            },
            "running": {
                "allowed_to": ["cancelled", "expired"],
                "apply_change": "activate",
            },
            "pending": {
                "allowed_to": ["cancelled", "expired", "running"],
                "apply_change": "deactivate",
            },
            "expired": {"apply_change": "deactivate"},
            "cancelled": {"apply_change": "deactivate"},
        }

    def activate(self, from_state):

        if from_state == "draft" and not self.activation_date:
            self.activation_date = date.today()

        self.active = True

    def deactivate(self, from_state):
        self.active = False

    def check_state(self):

        """This method is aimed at being used in order to automatically set
           workflow state, depending on record attributes."""

        if self.state == "pending":
            # If wish is pending, check is activation_date is set
            if self.activation_date and self.activation_date <= date.today():
                self.state_to("running")

        elif self.state == "running":
            # If wish is already running, check that from_date is not in the
            # past

            try:
                now = datetime.now().astimezone()
            except ValueError:
                # Python3.5 and below do not support astimezone on 'naive'
                # dates provided by datetime.now()
                now = datetime.now(timezone.utc).astimezone()

            if self.from_date and self.from_date < now:
                self.state_to("expired")
예제 #24
0
class Arrival(Operation):
    """Operation to describe physical arrival of goods in some location.

    Arrivals store data about the expected or arrived Goods: properties, code…
    These are copied over to the corresponding Goods records in all
    cases and stay inert after the fact.

    In case the Arrival state is ``planned``,
    these are obviously only unchecked values,
    but in case it is ``done``, the actual meaning can depend
    on the application:

    - maybe the application won't use the ``planned`` state at all, and
      will only create Arrival after checking them,
    - maybe the application will inspect the Arrival properties, compare them
      to reality, update them on the created Goods and cancel downstream
      operations if needed, before calling :meth:`execute`.

    TODO maybe provide higher level facilities for validation scenarios.
    """
    TYPE = 'wms_arrival'

    id = Integer(label="Identifier",
                 primary_key=True,
                 autoincrement=False,
                 foreign_key=Operation.use('id').options(ondelete='cascade'))
    """Primary key."""
    goods_type = Many2One(model='Model.Wms.Goods.Type')
    """Expected :class:`Goods Type
    <anyblok_wms_base.bloks.wms_core.goods.Type>`.
    """
    goods_properties = Jsonb(label="Properties of arrived Goods")
    """Expected :class:`Properties
    <anyblok_wms_base.bloks.wms_core.goods.Properties>`.

    They are copied over to the newly created :class:`Goods
    <anyblok_wms_base.bloks.wms_core.goods.Goods>` as soon as the Arrival
    is planned, and aren't updated by :meth:`execute`. Matching them with
    reality is the concern of separate validation processes, and this
    field can serve for later assessments after the fact.
    """
    goods_code = String(label="Code to set on arrived Goods")
    """Expected :attr:`Goods code
    <anyblok_wms_base.bloks.wms_core.goods.Goods.code>`.

    Can be ``None`` in case the arrival process issues the code only
    at the time of actual arrival.
    """
    location = Many2One(model='Model.Wms.Location')
    """Will be the location of the initial Avatar."""

    inputs_number = 0
    """This Operation is a purely creative one."""

    def specific_repr(self):
        return ("goods_type={self.goods_type!r}, "
                "location={self.location!r}").format(self=self)

    def after_insert(self):
        Goods = self.registry.Wms.Goods
        self_props = self.goods_properties
        if self_props is None:
            props = None
        else:
            props = Goods.Properties.create(**self_props)

        goods = Goods.insert(type=self.goods_type,
                             properties=props,
                             code=self.goods_code)
        Goods.Avatar.insert(
            goods=goods,
            location=self.location,
            reason=self,
            state='present' if self.state == 'done' else 'future',
            dt_from=self.dt_execution,
        )

    def execute_planned(self):
        Avatar = self.registry.Wms.Goods.Avatar
        Avatar.query().filter(Avatar.reason == self).one().update(
            state='present', dt_from=self.dt_execution)
예제 #25
0
class Order(Mixin.UuidColumn, Mixin.TrackModel, Mixin.WorkFlow):
    """Sale.Order model
    """
    SCHEMA = OrderBaseSchema

    @classmethod
    def get_schema_definition(cls, **kwargs):
        return cls.SCHEMA(**kwargs)

    @classmethod
    def get_workflow_definition(cls):

        return {
            'draft': {
                'default': True,
                'allowed_to': ['quotation', 'cancelled']
            },
            'quotation': {
                'allowed_to': ['order', 'cancelled'],
                'validators':
                SchemaValidator(
                    cls.get_schema_definition(exclude=['price_list']))
            },
            'order': {
                'validators':
                SchemaValidator(
                    cls.get_schema_definition(exclude=['price_list']))
            },
            'cancelled': {},
        }

    code = String(label="Code", nullable=False)
    channel = String(label="Sale Channel", nullable=False)
    price_list = Many2One(label="Price list",
                          model=Declarations.Model.Sale.PriceList)
    delivery_method = String(label="Delivery Method")

    amount_untaxed = Decimal(label="Amount Untaxed", default=D(0))
    amount_tax = Decimal(label="Tax amount", default=D(0))
    amount_total = Decimal(label="Total", default=D(0))

    def __str__(self):
        return "{self.uuid} {self.channel} {self.code} {self.state}".format(
            self=self)

    def __repr__(self):
        return "<Sale(id={self.uuid}, code={self.code}," \
               " amount_untaxed={self.amount_untaxed},"\
               " amount_tax={self.amount_tax},"\
               " amount_total={self.amount_total},"\
               " channel={self.channel} state={self.state})>".format(
                    self=self)

    @classmethod
    def create(cls, price_list=None, **kwargs):
        data = kwargs.copy()
        if cls.get_schema_definition:
            sch = cls.get_schema_definition(registry=cls.registry,
                                            exclude=['lines'])
            if price_list:
                data["price_list"] = price_list.to_primary_keys()
            data = sch.load(data)
            data['price_list'] = price_list

        return cls.insert(**data)

    def compute(self):
        """Compute order total amount"""
        amount_untaxed = D(0)
        amount_tax = D(0)
        amount_total = D(0)

        for line in self.lines:
            amount_untaxed += line.amount_untaxed
            amount_tax += line.amount_tax
            amount_total += line.amount_total

        self.amount_untaxed = amount_untaxed
        self.amount_tax = amount_tax
        self.amount_total = amount_total
예제 #26
0
class Task:
    """Main Task, define the main table"""
    TASK_TYPE = None

    id = Integer(primary_key=True)
    label = String(nullable=False)
    create_at = DateTime(default=datetime.now, nullable=False)
    update_at = DateTime(default=datetime.now,
                         nullable=False,
                         auto_update=True)
    task_type = Selection(selections="get_task_type", nullable=False)
    order = Integer(nullable=False, default=100)
    main_task = Many2One(model='Model.Dramatiq.Task', one2many="sub_tasks")

    @classmethod
    def get_task_type(cls):
        """List the task type possible"""
        return {
            'call_method': 'Call classmethod',
            'stepbystep': 'Step by Step',
            'parallel': 'Parallel steps',
        }

    @classmethod
    def define_mapper_args(cls):
        """Polymorphism configuration"""
        mapper_args = super(Task, cls).define_mapper_args()
        if cls.__registry_name__ == Model.Dramatiq.Task.__registry_name__:
            mapper_args.update({
                'polymorphic_identity': cls.TASK_TYPE,
                'polymorphic_on': cls.task_type,
            })
        else:
            mapper_args.update({
                'polymorphic_identity': cls.TASK_TYPE,
            })

        return mapper_args

    def do_the_job(self,
                   main_job=None,
                   run_at=None,
                   with_args=None,
                   with_kwargs=None):
        """Create a job for this tash and add send it to dramatiq

        :param main_job: parent job if exist
        :param run_at: datetime to execute the job
        :param with_args: tuple of the argument to pass at the job
        :param with_kwargs: dict of the argument to pass at the job
        """
        values = dict(run_at=run_at,
                      data=dict(with_args=with_args or tuple(),
                                with_kwargs=with_kwargs or dict()),
                      task=self,
                      main_job=main_job)
        job = self.registry.Dramatiq.Job.insert(**values)
        # FIXME dramatiq don t accept uuid, waiting the next version
        self.registry.Dramatiq.Job.run(job_uuid=str(job.uuid), run_at=run_at)

    def run(self, job):
        """Execute the task for one job

        :param job: job executed
        """
        raise Exception("No task definition for job %r" % job)

    def run_next(self, job):
        """next action to execute when a sub job finish this task for one job

        :param job: job executed
        """
        raise Exception("No next action define for this task for job %r" % job)
예제 #27
0
            class Address:

                id = Integer(primary_key=True)
                street = String()
                zip = String()
                city = String()
예제 #28
0
 class Room:
     id = Integer(primary_key=True)
     name = String()
예제 #29
0
    class Person:

        name = String(primary_key=True)
        addresses = Many2Many(model=Model.Address)
예제 #30
0
 class T1:
     id = Integer(primary_key=True)
     code = String()
     val = Integer()
     rs_id = Integer(foreign_key=Model.Rs.use('id'))
     rs = Many2One(model=Model.Rs, column_names='rs_id')