예제 #1
0
class BaseEntityRelatedDataMart(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: Entity related data marts.
    RUS: Сущность связанных витрин данных.
    """
    entity = deferred.ForeignKey('BaseEntity',
                                 verbose_name=_('Entity'),
                                 related_name='+')
    data_mart = deferred.ForeignKey('BaseDataMart',
                                    verbose_name=_('Data mart'),
                                    related_name='+')

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("Related data mart")
        verbose_name_plural = _("Entity related data marts")

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        return "{} → {}".format(self.entity.get_real_instance().entity_name,
                                self.data_mart.name)
예제 #2
0
class BaseEntityRelation(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: Allows to be attached related entities.
    RUS: Позволяет присоединять связанные сущности.
    """
    from_entity = deferred.ForeignKey('BaseEntity',
                                      related_name='forward_relations',
                                      verbose_name=_('From Entity'))
    to_entity = deferred.ForeignKey('BaseEntity',
                                    related_name='backward_relations',
                                    verbose_name=_('To Entity'))
    term = deferred.ForeignKey('BaseTerm',
                               verbose_name=_('Term'),
                               related_name='+',
                               db_index=True)

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("Entity Relation")
        verbose_name_plural = _("Entity Relations")
        unique_together = (('term', 'from_entity', 'to_entity'), )

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        return "{} → {} → {}".format(
            self.from_entity.get_real_instance().entity_name, self.term.name,
            self.to_entity.get_real_instance().entity_name)
예제 #3
0
class BaseDataMartRelation(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: Entity related data marts.
    RUS: Сущность связанных витрин данных.
    """
    RELATION_BIDIRECTIONAL = "b"
    RELATION_FORWARD = "f"
    RELATION_REVERSE = "r"

    RELATION_DIRECTIONS = (
        (RELATION_BIDIRECTIONAL, _('Bidirectional')),
        (RELATION_FORWARD, _('Forward')),
        (RELATION_REVERSE, _('Reverse')),
    )

    data_mart = deferred.ForeignKey('BaseDataMart',
                                    verbose_name=_('Data mart'),
                                    related_name='relations')
    term = deferred.ForeignKey('BaseTerm',
                               verbose_name=_('Term'),
                               related_name='+')
    direction = models.CharField(
        _("Relation direction"),
        max_length=1,
        choices=RELATION_DIRECTIONS,
        default=RELATION_BIDIRECTIONAL,
        help_text=
        _('Defines the direction of relation on which selection is carried out'
          ))
    subjects = deferred.ManyToManyField('BaseEntity',
                                        related_name='+',
                                        verbose_name=_('Subjects'),
                                        blank=True)

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("Data mart relation")
        verbose_name_plural = _("Data mart relations")
        unique_together = (('data_mart', 'term'), )

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        relation_directions = dict(self.RELATION_DIRECTIONS)
        return "{} `{}{}` ← {}: {}".format(self.data_mart.name, self.term_id,
                                           self.direction,
                                           relation_directions[self.direction],
                                           self.term.name)
예제 #4
0
class BaseEntityFile(with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: ManyToMany relation from the polymorphic Entity to a set of files.
    RUS: Связь многие-ко многим от полиморфной Сущности к файлам.
    """
    file = FilerFileField(verbose_name=_('File'))
    entity = deferred.ForeignKey('BaseEntity', verbose_name=_('Entity'))
    order = models.SmallIntegerField(default=0,
                                     blank=False,
                                     null=False,
                                     db_index=True)

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("Entity File")
        verbose_name_plural = _("Entity Files")
        ordering = ('order', )
        unique_together = (('file', 'entity'), )

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        return "{}".format(self.file)
예제 #5
0
class BaseAddress(models.Model):
    customer = deferred.ForeignKey('BaseCustomer')

    priority = models.SmallIntegerField(
        default=0,
        db_index=True,
        help_text=_("Priority for using this address"),
    )

    class Meta:
        abstract = True

    objects = AddressManager()

    def as_text(self):
        """
        Return the address as plain text to be used for printing, etc.
        """
        template_names = [
            '{}/{}-address.txt'.format(app_settings.APP_LABEL,
                                       self.address_type),
            '{}/address.txt'.format(app_settings.APP_LABEL),
            'shop/address.txt',
        ]
        template = select_template(template_names)
        context = {'address': self}
        return template.render(context)

    as_text.short_description = _("Address")
예제 #6
0
class BaseDataMartImage(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: ManyToMany relation from the polymorphic Datamart to a set of images.
    RUS: Связь многие-ко многим от полиморфной Витрины данных к изображениям.
    """
    image = image.FilerImageField(verbose_name=_('Image'))
    data_mart = deferred.ForeignKey('BaseDataMart', verbose_name=_('DataMart'))
    order = models.SmallIntegerField(default=0,
                                     blank=False,
                                     null=False,
                                     db_index=True)

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("DataMart Image")
        verbose_name_plural = _("DataMart Images")
        ordering = ('order', )

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        return "{}".format(self.image)
예제 #7
0
class BaseAdditionalEntityCharacteristicOrMark(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    ENG: ManyToMany relation from the polymorphic Entity to a set of Terms.
    RUS: Связь многие-ко многим от полиморфной Сущности к Терминам.
    """
    term = deferred.ForeignKey('BaseTerm',
                               verbose_name=_('Term'),
                               related_name='+',
                               db_index=True)
    entity = deferred.ForeignKey('BaseEntity',
                                 verbose_name=_('Entity'),
                                 related_name='+')
    value = models.CharField(_("Value"), max_length=255)
    view_class = models.CharField(
        verbose_name=_('View Class'),
        max_length=255,
        null=True,
        blank=True,
        help_text=
        _('Space delimited class attribute, specifies one or more classnames for an entity.'
          ))

    class Meta:
        """
        RUS: Метаданные класса.
        """
        abstract = True
        verbose_name = _("Additional Entity Characteristic or Mark")
        verbose_name_plural = _("Additional Entity Characteristics or Marks")

    def __str__(self):
        """
        RUS: Строковое представление данных.
        """
        return "{}: {}".format(self.term.name, self.value)

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        """
        RUS: Сохраняет объект в базе данных.
        """
        if not force_update:
            self.view_class = ' '.join([
                x.lower() for x in self.view_class.split()
            ]) if self.view_class else None
        return super(BaseAdditionalEntityCharacteristicOrMark,
                     self).save(force_insert, force_update, *args, **kwargs)
예제 #8
0
class Cart(BaseCart):
    """
    Default materialized model for BaseCart containing common fields
    """
    shipping_address = deferred.ForeignKey(
        BaseShippingAddress,
        null=True,
        default=None,
        related_name='+',
        on_delete=SET_DEFAULT,
    )

    billing_address = deferred.ForeignKey(
        BaseBillingAddress,
        null=True,
        default=None,
        related_name='+',
        on_delete=SET_DEFAULT,
    )
예제 #9
0
class BaseDataMartPermission(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    Data marts permissions per customer
    """
    data_mart = deferred.ForeignKey('BaseDataMart',
                                    verbose_name=_('Data mart'),
                                    related_name='permissions')
    customer = deferred.ForeignKey('BaseCustomer',
                                   verbose_name=_('Customer'),
                                   related_name='+')
    can_add = models.BooleanField(
        default=True,
        verbose_name=_("Can add"),
        db_index=True,
        help_text=_("Has this customer add entity to data mart permission."))
    can_change = models.BooleanField(
        default=True,
        verbose_name=_("Can change"),
        db_index=True,
        help_text=_(
            "Has this customer change entity from data mart permission."))
    can_delete = models.BooleanField(
        default=True,
        verbose_name=_("Can delete"),
        db_index=True,
        help_text=_(
            "Has this customer delete entity from data mart permission."))

    class Meta:
        abstract = True
        verbose_name = _("Data mart permission")
        verbose_name_plural = _("Data mart permissions")
        unique_together = (('data_mart', 'customer'), )

    def __str__(self):
        return "{} | {} {} {} | {}".format(self.data_mart.name,
                                           '⦿' if self.can_add else '⦾',
                                           '⦿' if self.can_change else '⦾',
                                           '⦿' if self.can_delete else '⦾',
                                           self.customer.get_username())
예제 #10
0
class BaseEntityComment(
        with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    Comment model
    """
    entity = deferred.ForeignKey('BaseEntity', verbose_name=_('Entity'))

    origin_name = models.CharField(
        verbose_name=_('Origin name'),
        help_text=_(
            'Comment owner name. You must indicate the source of comment (company name/full name '
            'and position of the company representative)'),
        blank=False,
        null=False,
        max_length=255)
    text = models.TextField(
        verbose_name=_('Text'),
        help_text=
        _('Text of comment, contains a quote with a rebuttal (maximum 300 symbols).'
          ),
        blank=False,
        null=False,
        max_length=300)
    origin_url = models.CharField(
        verbose_name=_('Origin url'),
        help_text=
        _('Comment owner link, refers to materials containing a denial on the media website.'
          ),
        blank=True,
        null=True,
        max_length=255)
    logo = FilerImageField(
        verbose_name=_('Origin logo'),
        help_text=_('Comment owner logo'),
        blank=True,
        null=True,
    )
    bind_to = models.TextField(
        verbose_name=_('Bind to'),
        help_text=
        _('Refers to a news item that has been commented on. If the news has been published by several '
          'media outlets, you can post links to each source. Including yourself. Separate by newline'
          ),
        blank=True,
        null=True)

    class Meta:
        abstract = True
        verbose_name = _("Publication comment")
        verbose_name_plural = _("Publication comments")

    def __str__(self):
        return "{} ({})".format(self.origin_name, self.origin_url)
예제 #11
0
class BaseDeliveryItem(with_metaclass(deferred.ForeignKeyBuilder,
                                      models.Model)):
    """
    Abstract base class to keep track on the delivered quantity for each ordered item. Since the
    quantity can be any numerical value, it has to be defined by the class implementing this model.
    """
    delivery = deferred.ForeignKey(
        BaseDelivery,
        verbose_name=_("Delivery"),
        help_text=_("Refer to the shipping provider used to ship this item"),
    )

    item = deferred.ForeignKey(
        BaseOrderItem,
        verbose_name=_("Ordered item"),
    )

    class Meta:
        abstract = True
        verbose_name = _("Deliver item")
        verbose_name_plural = _("Deliver items")

    @classmethod
    def perform_model_checks(cls):
        try:
            order_field = [
                f for f in OrderItemModel._meta.fields
                if f.attname == 'quantity'
            ][0]
            deliver_field = [
                f for f in cls._meta.fields if f.attname == 'quantity'
            ][0]
            if order_field.get_internal_type(
            ) != deliver_field.get_internal_type():
                msg = "Field `{}.quantity` must be of one same type `{}.quantity`."
                raise ImproperlyConfigured(
                    msg.format(cls.__name__, OrderItemModel.__name__))
        except IndexError:
            msg = "Class `{}` must implement a field named `quantity`."
            raise ImproperlyConfigured(msg.format(cls.__name__))
예제 #12
0
class BaseDelivery(with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    Shipping provider to keep track on each delivery.
    """
    order = deferred.ForeignKey(BaseOrder)

    shipping_id = models.CharField(
        _("Shipping ID"),
        max_length=255,
        null=True,
        blank=True,
        help_text=_("The transaction processor's reference"),
    )

    fulfilled_at = models.DateTimeField(
        _("Fulfilled at"),
        null=True,
        blank=True,
    )

    shipped_at = models.DateTimeField(
        _("Shipped at"),
        null=True,
        blank=True,
    )

    shipping_method = models.CharField(
        _("Shipping method"),
        max_length=50,
        help_text=_(
            "The shipping backend used to deliver the items for this order"),
    )

    class Meta:
        abstract = True
        verbose_name = _("Delivery")
        verbose_name_plural = _("Deliveries")

    def __str__(self):
        return _("Delivery ID: {}").format(self.id)

    @classmethod
    def perform_model_checks(cls):
        canceled_field = [
            f for f in OrderItemModel._meta.fields if f.attname == 'canceled'
        ]
        if not canceled_field or canceled_field[0].get_internal_type(
        ) != 'BooleanField':
            msg = (
                "Class `{}` must implement a `BooleanField` named `canceled`, "
                + "if used in combination with a Delivery model.")
            raise ImproperlyConfigured(msg.format(OrderItemModel.__name__))
예제 #13
0
class OrderPayment(with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    A model to hold received payments for a given order.
    """
    order = deferred.ForeignKey(
        BaseOrder,
        verbose_name=_("Order"),
    )

    amount = MoneyField(
        _("Amount paid"),
        help_text=_("How much was paid with this particular transfer."),
    )

    transaction_id = models.CharField(
        _("Transaction ID"),
        max_length=255,
        help_text=_("The transaction processor's reference"),
    )

    created_at = models.DateTimeField(
        _("Received at"),
        auto_now_add=True,
    )

    payment_method = models.CharField(
        _("Payment method"),
        max_length=50,
        help_text=_("The payment backend used to process the purchase"),
    )

    class Meta(EntityModel.RESTMeta):
        verbose_name = pgettext_lazy('order_models', "Order payment")
        verbose_name_plural = pgettext_lazy('order_models', "Order payments")

    def __str__(self):
        return _("Payment ID: {}").format(self.id)
예제 #14
0
class BaseCartItem(with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    This is a holder for the quantity of items in the cart and, obviously, a
    pointer to the actual Product being purchased
    """
    cart = deferred.ForeignKey(
        'BaseCart',
        related_name='items',
    )

    product = deferred.ForeignKey(BaseProduct)

    product_code = models.CharField(
        _("Product code"),
        max_length=255,
        null=True,
        blank=True,
        help_text=_("Product code of added item."),
    )

    extra = JSONField(
        verbose_name=_("Arbitrary information for this cart item"))

    objects = CartItemManager()

    class Meta:
        abstract = True
        verbose_name = _("Cart item")
        verbose_name_plural = _("Cart items")

    @classmethod
    def perform_model_checks(cls):
        try:
            allowed_types = ('IntegerField', 'DecimalField', 'FloatField')
            field = [f for f in cls._meta.fields if f.attname == 'quantity'][0]
            if not field.get_internal_type() in allowed_types:
                msg = "Field `{}.quantity` must be of one of the types: {}."
                raise ImproperlyConfigured(
                    msg.format(cls.__name__, allowed_types))
        except IndexError:
            msg = "Class `{}` must implement a field named `quantity`."
            raise ImproperlyConfigured(msg.format(cls.__name__))

    def __init__(self, *args, **kwargs):
        # reduce the given fields to what the model actually can consume
        all_field_names = [
            field.name for field in self._meta.get_fields(include_parents=True)
        ]
        model_kwargs = {
            k: v
            for k, v in kwargs.items() if k in all_field_names
        }
        super(BaseCartItem, self).__init__(*args, **model_kwargs)
        self.extra_rows = OrderedDict()
        self._dirty = True

    def save(self, *args, **kwargs):
        super(BaseCartItem, self).save(*args, **kwargs)
        self._dirty = True
        self.cart._dirty = True

    def update(self, request):
        """
        Loop over all registered cart modifier, change the price per cart item and optionally add
        some extra rows.
        """
        if not self._dirty:
            return
        self.extra_rows = OrderedDict()  # reset the dictionary
        for modifier in cart_modifiers_pool.get_all_modifiers():
            modifier.process_cart_item(self, request)
        self._dirty = False
예제 #15
0
class BaseOrderItem(with_metaclass(deferred.ForeignKeyBuilder, models.Model)):
    """
    An item for an order.
    """
    order = deferred.ForeignKey(
        BaseOrder,
        related_name='items',
        verbose_name=_("Order"),
    )

    product_name = models.CharField(
        _("Product name"),
        max_length=255,
        null=True,
        blank=True,
        help_text=_("Product name at the moment of purchase."),
    )

    product_code = models.CharField(
        _("Product code"),
        max_length=255,
        null=True,
        blank=True,
        help_text=_("Product code at the moment of purchase."),
    )

    product = deferred.ForeignKey(
        'BaseProduct',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        verbose_name=_("Product"),
    )

    step = models.DecimalField(verbose_name=_('addition step'),
                               default=1,
                               max_digits=10,
                               decimal_places=3)

    _unit_price = models.DecimalField(
        _("Unit price"),
        null=True,  # may be NaN
        help_text=_("Products unit price at the moment of purchase."),
        **BaseOrder.decimalfield_kwargs)

    _line_total = models.DecimalField(
        _("Line Total"),
        null=True,  # may be NaN
        help_text=_("Line total on the invoice at the moment of purchase."),
        **BaseOrder.decimalfield_kwargs)

    extra = JSONField(
        verbose_name=_("Extra fields"),
        help_text=_("Arbitrary information for this order item"),
    )

    class Meta:
        abstract = True
        verbose_name = _("Order item")
        verbose_name_plural = _("Order items")

    def __str__(self):
        return self.product_name

    @classmethod
    def perform_model_checks(cls):
        try:
            cart_field = [
                f for f in CartItemModel._meta.fields
                if f.attname == 'quantity'
            ][0]
            order_field = [
                f for f in cls._meta.fields if f.attname == 'quantity'
            ][0]
            if order_field.get_internal_type() != cart_field.get_internal_type(
            ):
                msg = "Field `{}.quantity` must be of one same type `{}.quantity`."
                raise ImproperlyConfigured(
                    msg.format(cls.__name__, CartItemModel.__name__))
        except IndexError:
            msg = "Class `{}` must implement a field named `quantity`."
            raise ImproperlyConfigured(msg.format(cls.__name__))

    @property
    def unit_price(self):
        # MoneyMaker(self.order.currency)(self._unit_price)
        return self._unit_price

    @property
    def line_total(self):
        # MoneyMaker(self.order.currency)(self._line_total)
        return self._line_total

    @property
    def absolute_quantity(self):
        if self.step:
            return self.quantity * self.step
        return self.quantity

    def populate_from_cart_item(self, cart_item, request):
        """
        From a given cart item, populate the current order item.
        If the operation was successful, the given item shall be removed from the cart.
        If a CartItem.DoesNotExist exception is raised, discard the order item.
        """
        if cart_item.quantity == 0:
            raise CartItemModel.DoesNotExist("Cart Item is on the Wish List")

        self.product = cart_item.product
        self.product_name = cart_item.product.product_name
        self.product_code = cart_item.product_code
        self._unit_price = Decimal(cart_item.unit_price)
        self._line_total = Decimal(cart_item.line_total)
        self.quantity = cart_item.quantity
        self.step = cart_item.product.get_step
        self.extra = dict(cart_item.extra)
        extra_rows = [(modifier, extra_row.data)
                      for modifier, extra_row in cart_item.extra_rows.items()]
        self.extra.update(rows=extra_rows)

    def save(self, *args, **kwargs):
        """
        Before saving the OrderItem object to the database, round the amounts to the given decimal places
        """
        self._unit_price = BaseOrder.round_amount(self._unit_price)
        self._line_total = BaseOrder.round_amount(self._line_total)
        super(BaseOrderItem, self).save(*args, **kwargs)
예제 #16
0
class BaseOrder(FSMMixin, EntityModel.materialized):
    """
    An Order is the "in process" counterpart of the shopping cart, which freezes the state of the
    cart on the moment of purchase. It also holds stuff like the shipping and billing addresses,
    and keeps all the additional entities, as determined by the cart modifiers.
    """
    DATA_MART_NAME_PATTERN = '{}-dm'

    TRANSITION_TARGETS = {
        'new': _("New order"),
        'processed': _("Processed by manager"),
        'in_work': _("In work"),  # Проведен
        'shipped': _("Shipped"),  # Отгружен
        'completed': _("Completed"),
        'canceled': _("Canceled"),
    }

    VIEW_COMPONENT_LIST = 'order_list'

    VIEW_COMPONENTS = ((VIEW_COMPONENT_LIST, _('List')), )

    decimalfield_kwargs = {
        'max_digits': 30,
        'decimal_places': 2,
    }

    decimal_exp = Decimal('.' + '0' * decimalfield_kwargs['decimal_places'])

    customer = deferred.ForeignKey(
        'BaseCustomer',
        verbose_name=_("Customer"),
        related_name='orders',
    )

    status = FSMField(
        default='new',
        protected=True,
        verbose_name=_("Status"),
    )

    currency = models.CharField(
        max_length=7,
        editable=False,
        help_text=_("Currency in which this order was concluded"),
    )

    _subtotal = models.DecimalField(_("Subtotal"), **decimalfield_kwargs)

    _total = models.DecimalField(_("Total"), **decimalfield_kwargs)

    extra = JSONField(
        verbose_name=_("Extra fields"),
        help_text=
        _("Arbitrary information for this order object on the moment of purchase."
          ),
        blank=True,
        null=True)

    stored_request = JSONField(
        verbose_name=_("Stored request"),
        help_text=_("Parts of the Request objects on the moment of purchase."),
    )

    objects = OrderManager()

    class Meta:
        abstract = True
        verbose_name = pgettext_lazy('order_models', "Order")
        verbose_name_plural = pgettext_lazy('order_models', "Orders")

    def __str__(self):
        return self.get_number()

    def __repr__(self):
        return "<{}(pk={})>".format(self.__class__.__name__, self.pk)

    class RESTMeta:
        lookup_fields = ('id', )

        #validators = []

        exclude = [
            '_subtotal', '_total', 'stored_request', 'images', 'files',
            'status'
        ]  # todo: 'status readonly

        include = {
            'transition': ('rest_framework.serializers.CharField', {
                'write_only': True,
                'required': False
            }),
            'state': ('rest_framework.serializers.CharField', {
                'source': 'get_state',
                'read_only': True
            }),
            'subtotal': (
                'rest_framework.serializers.DecimalField',
                {
                    'max_digits': 10,
                    'decimal_places': 2,
                    'required': False
                    #'read_only': True
                }),
            'total': (
                'rest_framework.serializers.DecimalField',
                {
                    'max_digits': 10,
                    'decimal_places': 2,
                    'required': False
                    # 'read_only': True
                }),
            'amount_paid': ('rest_framework.serializers.DecimalField', {
                'max_digits': 10,
                'decimal_places': 2,
                'read_only': True
            }),
            'outstanding_amount': ('rest_framework.serializers.DecimalField', {
                'max_digits': 10,
                'decimal_places': 2,
                'read_only': True
            }),  #app_settings.ORDER_ITEM_SERIALIZER
            'items': ('edw_shop.serializers.defaults.OrderItemSerializer', {
                'read_only': True,
                'many': True
            }),
            'cancelable': ('rest_framework.serializers.BooleanField', {
                'read_only': True,
            }),
            'rels': ('rest_framework.serializers.ListField', {
                'child': ObjRelationSerializer(),
                'required': False,
                'write_only': True
            }),

            #todo: delete
            #'cancel': ('rest_framework.serializers.BooleanField', {
            #    'write_only': True,
            #    'default':False,
            #})
        }

        filters = {
            'order_status': ("edw_shop.rest.filters.order.stateFilter", {
                'name': 'status'
            }),
        }

    """
    'shipped': _("Shipped"), # Отгружен
            'completed': _("Completed"),
            'canceled': _("Canceled"),
    """

    def do_transition(self, transition_name):
        trans_func = getattr(self, transition_name)
        return trans_func()

    @transition(field=status,
                source='new',
                target='processed',
                custom=dict(admin=True, button_name=_("New to processed")))
    def new_to_processed(self):
        pass

    @transition(field=status,
                source='new',
                target='in_work',
                custom=dict(admin=True, button_name=_("New to in work")))
    def new_to_in_work(self):
        pass

    @transition(field=status,
                source='new',
                target='shipped',
                custom=dict(admin=True, button_name=_("New to shipped")))
    def new_to_shipped(self):
        pass

    @transition(field=status,
                source='new',
                target='completed',
                custom=dict(admin=True, button_name=_("New to completed")))
    def new_to_completed(self):
        pass

    @transition(field=status,
                source='new',
                target='canceled',
                custom=dict(admin=True, button_name=_("New to canceled")))
    def new_to_canceled(self):
        pass

    @transition(field=status,
                source='processed',
                target='canceled',
                custom=dict(admin=True,
                            button_name=_("Processed to canceled")))
    def processed_to_canceled(self):
        pass

    @transition(field=status,
                source='processed',
                target='in_work',
                custom=dict(admin=True, button_name=_("Processed to in_work")))
    def processed_to_in_work(self):
        pass

    @transition(field=status,
                source='processed',
                target='shipped',
                custom=dict(admin=True, button_name=_("Processed to in_work")))
    def processed_to_shipped(self):
        pass

    @transition(field=status,
                source='processed',
                target='completed',
                custom=dict(admin=True,
                            button_name=_("Processed to completed")))
    def processed_to_completed(self):
        pass

    @transition(field=status,
                source='in_work',
                target='shipped',
                custom=dict(admin=True, button_name=_("In work to shipped")))
    def in_work_to_shipped(self):
        pass

    @transition(field=status,
                source='in_work',
                target='completed',
                custom=dict(admin=True, button_name=_("In work to completed")))
    def in_work_to_completed(self):
        pass

    @transition(field=status,
                source='in_work',
                target='canceled',
                custom=dict(admin=True, button_name=_("In work to canceled")))
    def in_work_to_canceled(self):
        pass

    @transition(field=status,
                source='shipped',
                target='completed',
                custom=dict(admin=True, button_name=_("Shipped to completed")))
    def shipped_to_completed(self):
        pass

    @transition(field=status,
                source='shipped',
                target='canceled',
                custom=dict(admin=True, button_name=_("Shipped to canceled")))
    def shipped_to_canceled(self):
        pass

    @transition(field=status,
                source='canceled',
                target='new',
                custom=dict(admin=True, button_name=_("Canceled to new")))
    def canceled_to_new(self):
        pass

    def get_summary_extra(self, context):

        extra = {
            'url': self.get_detail_url(),
            'number': self.get_number(),
            'status': self.status_name(),
            'cancelable': self.cancelable(),
            'subtotal': self.subtotal,
            'total': self.total,
            'created_at': self.created_at,
            'updated_at': self.updated_at
        }

        return extra

    def get_state(self):

        return self.status

    @classmethod
    def validate_data_mart_model(cls):
        '''
        Создаем структуру витрин данных соответствующих тематической модели объектов. Модели потомки также используют
        этот метод для создания иерархии витрин данных
        :return:
        '''
        class_name = 'order'
        with transaction.atomic():
            root_cls_dm, is_created = DataMartModel.objects.get_or_create(
                slug=cls.DATA_MART_NAME_PATTERN.format(class_name),
                parent=None,
                defaults={'name': force_text(cls._meta.verbose_name_plural)})

        cls_dm = root_cls_dm

        if is_created:
            try:
                dm_term = cls.get_entities_types()[class_name]
            except KeyError:
                dm_term = cls.get_entities_types(from_cache=False)[class_name]
            cls_dm.terms.add(dm_term.id)
            cls_dm.system_flags = _shared_system_flags_datamart_restriction
            cls_dm.save()

    def get_or_assign_number(self):
        """
        Hook to get or to assign the order number. It shall be invoked, every time an Order
        object is created. If you prefer to use an order number which differs from the primary
        key, then override this method.
        """
        return self.get_number()

    def get_number(self):
        """
        Hook to get the order number.
        A class inheriting from Order may transform this into a string which is better readable.
        """
        return str(self.pk)

    @classmethod
    def resolve_number(cls, number):
        """
        Return a lookup pair used to filter down a queryset.
        It should revert the effect from the above method `get_number`.
        """
        return dict(pk=number)

    @property
    def subtotal(self):
        """
        The summed up amount for all ordered items excluding extra order lines.
        """
        # MoneyMaker(self.currency)(self._subtotal)
        return self._subtotal

    @property
    def total(self):
        """
        The final total to charge for this order.
        """
        # MoneyMaker(self.currency)(self._total)
        return self._total

    @classmethod
    def round_amount(cls, amount):
        if amount and amount.is_finite():
            return Decimal(amount).quantize(cls.decimal_exp)
        return Decimal('0').quantize(cls.decimal_exp)

    def get_detail_url(self, data_mart=None):

        return reverse('order_detail', args=[self.pk])

    #def get_absolute_url(self, request=None, format=None):
    #    """
    #    Returns the URL for the detail view of this order.
    #    """
    #    return urljoin(OrderModel.objects.get_summary_url(), self.get_number())

    def populate_dialog_forms(self, cart, request):
        dialog_forms = set(
            [import_string(fc) for fc in app_settings.DIALOG_FORMS])
        if dialog_forms:
            for form_class in dialog_forms:
                form_class.populate_from_cart(request, cart, self)

    @transaction.atomic
    def populate_from_cart(self, cart, request):
        """
        Populate the order object with the fields from the given cart.
        For each cart item a corresponding order item is created populating its fields and removing
        that cart item.

        Override this method, in case a customized cart has some fields which have to be transfered
        to the cart.
        """
        for cart_item in cart.items.active():
            cart_item.update(request)
            order_item = OrderItemModel(order=self)
            try:
                order_item.populate_from_cart_item(cart_item, request)
                order_item.save()
                cart_item.delete()
            except CartItemModel.DoesNotExist:
                pass

        self._subtotal = Decimal(cart.subtotal)
        self._total = Decimal(cart.total)
        self.extra = dict(cart.extra)
        self.extra.update(
            rows=[(modifier, extra_row.data)
                  for modifier, extra_row in cart.extra_rows.items()])
        self.save()

        self.populate_dialog_forms(cart, request)

    @transaction.atomic
    def readd_to_cart(self, cart):
        """
        Re-add the items of this order back to the cart.
        """
        for order_item in self.items.all():
            extra = dict(order_item.extra)
            extra.pop('rows', None)
            extra.update(product_code=order_item.product_code)
            cart_item = order_item.product.is_in_cart(cart, **extra)
            if cart_item:
                cart_item.quantity = max(cart_item.quantity,
                                         order_item.quantity)
            else:
                cart_item = CartItemModel(cart=cart,
                                          product=order_item.product,
                                          product_code=order_item.product_code,
                                          quantity=order_item.quantity,
                                          extra=extra)
            cart_item.save()

    def save(self, **kwargs):
        """
        The status of an Order object may change, if auto transistions are specified.
        """
        # round the total to the given decimal_places
        self._subtotal = BaseOrder.round_amount(self._subtotal)
        self._total = BaseOrder.round_amount(self._total)
        super(BaseOrder, self).save(**kwargs)

    @cached_property
    def amount_paid(self):
        """
        The amount paid is the sum of related orderpayments
        """
        amount = self.orderpayment_set.aggregate(
            amount=Sum('amount'))['amount']
        if amount is None:
            amount = Decimal(0.0)  #MoneyMaker(self.currency)()
        return amount

    @property
    def outstanding_amount(self):
        """
        Return the outstanding amount paid for this order
        """
        return self.total - self.amount_paid

    def is_fully_paid(self):
        return self.amount_paid >= self.total

    @transition(field='status',
                source='*',
                target='payment_confirmed',
                conditions=[is_fully_paid])
    def acknowledge_payment(self, by=None):
        """
        Change status to `payment_confirmed`. This status code is known globally and can be used
        by all external plugins to check, if an Order object has been fully paid.
        """

    def cancelable(self):
        """
        Returns True if the current Order is cancelable.

        This method is just a hook and must be overridden by a mixin class
        managing Order cancellations.
        """
        return False

    def refund_payment(self):
        """
        Hook to handle payment refunds.
        """

    @classmethod
    def get_all_transitions(cls):
        """
        Returns a generator over all transition objects for this Order model.
        """
        return cls.status.field.get_all_transitions(OrderModel)

    @classmethod
    def get_transition_name(cls, target):
        """Return the human readable name for a given transition target"""
        return cls.TRANSITION_TARGETS.get(target, target)

    def status_name(self):
        """Return the human readable name for the current transition state"""
        return self.TRANSITION_TARGETS.get(self.status, self.status)

    status_name.short_description = pgettext_lazy('order_models', "State")