Exemple #1
0
class ProductType(ModelWithMetadata):
    name = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True, allow_unicode=True)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    is_digital = models.BooleanField(default=False)
    weight = MeasurementField(
        measurement=Weight, unit_choices=WeightUnits.CHOICES, default=zero_weight
    )

    class Meta(ModelWithMetadata.Meta):
        ordering = ("slug",)
        app_label = "product"
        permissions = (
            (
                ProductTypePermissions.MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES.codename,
                "Manage product types and attributes.",
            ),
        )

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )
Exemple #2
0
class ProductType(models.Model):
    name = models.CharField(max_length=128)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    tax_rate = models.CharField(max_length=128,
                                default=DEFAULT_TAX_RATE_NAME,
                                choices=TaxRateType.CHOICES)
    store = models.ForeignKey(Store,
                              null=True,
                              blank=True,
                              related_name='product_types',
                              on_delete=models.CASCADE)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              default=zero_weight)

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)
Exemple #3
0
class ProductType(ModelWithMetadata):
    name = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True, allow_unicode=True)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    is_digital = models.BooleanField(default=False)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              default=zero_weight)

    class Meta:
        ordering = ("slug", )
        app_label = "product"

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )
Exemple #4
0
class ShippingMethod(ModelWithMetadata):
    store = models.ForeignKey(
        Store,
        related_name="shipping_methods",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
    )
    tenant_id = 'store_id'
    name = models.CharField(max_length=100)
    type = models.CharField(max_length=30, choices=ShippingMethodType.CHOICES)
    shipping_zone = models.ForeignKey(ShippingZone,
                                      related_name="shipping_methods",
                                      on_delete=models.CASCADE)
    minimum_order_weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,
        default=zero_weight,
        blank=True,
        null=True,
    )
    maximum_order_weight = MeasurementField(measurement=Weight,
                                            unit_choices=WeightUnits.CHOICES,
                                            blank=True,
                                            null=True)
    excluded_products = models.ManyToManyField("product.Product",
                                               blank=True)  # type: ignore
    maximum_delivery_days = models.PositiveIntegerField(null=True, blank=True)
    minimum_delivery_days = models.PositiveIntegerField(null=True, blank=True)

    objects = ShippingMethodQueryset.as_manager()
    translated = TranslationProxy()

    class Meta(ModelWithMetadata.Meta):
        ordering = ("pk", )

    def __str__(self):
        return self.name

    def __repr__(self):
        if self.type == ShippingMethodType.PRICE_BASED:
            return "ShippingMethod(type=%s)" % (self.type, )
        return "ShippingMethod(type=%s weight_range=(%s)" % (
            self.type,
            _get_weight_type_display(self.minimum_order_weight,
                                     self.maximum_order_weight),
        )
Exemple #5
0
class ShippingMethod(BaseModel):
    class ShippingMethodType(models.TextChoices):
        PRICE_BASED = "price", _("Price")
        WEIGHT_BASED = "weight", _("Weight")

    name = models.CharField(max_length=100)
    type = models.CharField(max_length=30, choices=ShippingMethodType.choices)
    price_amount = models.DecimalField(
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        default=0,
    )
    shipping_zone = models.ForeignKey(ShippingZone,
                                      related_name="shipping_methods",
                                      on_delete=models.CASCADE)
    minimum_order_price = MoneyField(
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        default_currency=settings.DEFAULT_CURRENCY,
    )
    maximum_order_price = MoneyField(
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        default_currency=settings.DEFAULT_CURRENCY,
    )

    minimum_order_weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,
        default=0,
    )
    maximum_order_weight = MeasurementField(measurement=Weight,
                                            unit_choices=WeightUnits.CHOICES,
                                            blank=True,
                                            null=True)

    meta = models.JSONField(blank=True, default=dict)

    class Meta:
        verbose_name = _("Shipping Method")
        verbose_name_plural = _("Shipping Methods")

    def __str__(self):
        return self.name

    def get_total(self):
        return self.price_amount
Exemple #6
0
class delivery_product(models.Model):
    to_location = models.CharField(max_length=100)
    from_location = models.CharField(max_length=100)
    product_type = models.ForeignKey(types_of_product,
                                     on_delete=models.CASCADE)
    weight = MeasurementField(measurement=Weight)
    Date = models.DateTimeField(default=timezone.now)
    image = models.ImageField(upload_to='images/')
class ParentsHeight(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    fathers_height = MeasurementField(measurement=Distance,
                                      unit_choices=[("cm", "cm")])
    mothers_height = MeasurementField(measurement=Distance,
                                      unit_choices=[("cm", "cm")])

    def __str__(self):
        return self.player.user.username

    def value_club_unit(self):
        measurement_system = self.player.club.measurement_system
        if measurement_system == 'SI':
            return round(self.fathers_height.cm,
                         1), round(self.mothers_height.cm, 0), 'cm'
        elif measurement_system == 'Imp':
            return round(self.fathers_height.inch,
                         1), round(self.mothers_height.inch, 0), 'inch'
class ProductMeasurements(models.Model):
    product_measurements = models.ForeignKey(
        Product,
        related_name="product_measurements_id",
        on_delete=models.CASCADE)
    product_volume = MeasurementField(measurement=Volume,
                                      null=True,
                                      blank=True)
    product_area = MeasurementField(measurement=Area, null=True, blank=True)
    product_mass = MeasurementField(measurement=Mass, null=True, blank=True)
    product_weight = MeasurementField(measurement=Weight,
                                      null=True,
                                      blank=True)
    product_time = MeasurementField(measurement=Time, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "product_measurements"
class DnaHeight(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    date = models.DateTimeField()  # Date in DNA file
    predicted_height = MeasurementField(measurement=Distance,
                                        unit_choices=[("cm", "cm")])
    meta = JSONField(default=dict())
    original_filename = models.CharField(max_length=2000)

    def __str__(self):
        return self.player.user.username
Exemple #10
0
class Log(DateTimeFields, SafeDeleteModel):
    """
    - Date
    - Weight
    - Calories In
    - Calories Out
    - Activity LVL
    - progress pic
    """
    class Meta:
        unique_together = ("user", "date")

    user = models.ForeignKey(
        get_user_model(),
        blank=False,
        null=False,
        on_delete=models.CASCADE,
    )

    date = models.DateField(blank=False)  # Log the date

    weight = MeasurementField(measurement=Weight, null=True, blank=False)

    calories_in = models.IntegerField(
        blank=False,
        help_text="Total calories consumed",
    )  # Calories consumed in kcal

    calories_out = models.IntegerField(
        blank=True,
        null=True,
        help_text="If you have a fitness tracker, total calories burned",
    )  # From fitness tracker e.g. apple watch, fitbit etc.

    choices = [
        ("L", "Low"),
        ("M", "Moderate"),
        ("H", "High"),
    ]

    activity_lvl = models.CharField(
        max_length=1,
        choices=choices,
        blank=True,
        null=True,
        help_text="Estimate your relative activity level",
    )

    front_progress_pic = CloudinaryField("image", null=True, blank=True)
    side_progress_pic = CloudinaryField("image", null=True, blank=True)
    back_progress_pic = CloudinaryField("image", null=True, blank=True)

    def __str__(self):
        return f"Log from {self.user}"
class delivery_product(models.Model):
    from_location = models.CharField(max_length=100)
    to_location = models.CharField(max_length=100)
    product_type = models.ForeignKey(types_of_product,
                                     on_delete=models.CASCADE)
    weight = MeasurementField(measurement=Weight, null=True, blank=True)
    Date = models.DateTimeField(default=timezone.now)
    image = models.ImageField(upload_to='images/', null=True, blank=True)

    def __str__(self):
        return self.from_location
class ProductMeasurements(models.Model):
    product_measurements = models.ForeignKey(Product, on_delete=models.CASCADE)
    selection_details = MultiSelectField(choices=PRODUCT_MEASUREMENTS_CHOICES,
                                         max_choices=4,
                                         max_length=255,
                                         null=True,
                                         blank=True)
    product_volume = MeasurementField(measurement=Volume,
                                      null=True,
                                      blank=True)
    product_area = MeasurementField(measurement=Area, null=True, blank=True)
    product_mass = MeasurementField(measurement=Mass, null=True, blank=True)
    product_weight = MeasurementField(measurement=Weight,
                                      null=True,
                                      blank=True)
    product_time = MeasurementField(measurement=Time, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "db_measurements"
Exemple #13
0
class Stock(models.Model):
    ingredient = models.ForeignKey('Ingredient',
                                   on_delete=models.CASCADE,
                                   blank=True,
                                   null=True,
                                   verbose_name=_('Название ингредиента'))
    weight = MeasurementField(blank=True,
                              null=True,
                              measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              verbose_name=_('Вес'))
    volume = MeasurementField(blank=True,
                              null=True,
                              measurement=Volume,
                              unit_choices=VolumeUnits.CHOICES,
                              verbose_name=_('Обьем'))
    quantity = SmallIntegerField(blank=True,
                                 null=True,
                                 verbose_name=_('Количество'))

    class Meta:
        verbose_name_plural = _('Склад')
        verbose_name = _('Ингредиент')

    def __str__(self):
        value = 0
        unit = ''
        if self.volume and self.volume.value:
            value, unit = self.volume.value, self.volume.unit
        if self.weight and self.weight.value:
            value, unit = self.weight.value, self.weight.unit
        if self.quantity:
            value, unit = self.quantity, 'шт'
        return f'{self.ingredient.name} - {value} {unit}'

    def save(self, *args, **kwargs):
        qs = Stock.objects.filter(ingredient=self.ingredient)
        if not qs:
            super().save(*args, **kwargs)
class KhamisRoche(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    date = models.DateField()  # Median Date between Height and Weight record
    predicted_height = MeasurementField(measurement=Distance,
                                        unit_choices=[("cm", "cm")])
    current_height = models.ForeignKey('profile.Height',
                                       on_delete=models.CASCADE)
    current_weight = models.ForeignKey('profile.Weight',
                                       on_delete=models.CASCADE)
    parents_height = models.ForeignKey('profile.ParentsHeight',
                                       on_delete=models.CASCADE)
    meta = JSONField(default=dict())
Exemple #15
0
class Product(SeoModel, ModelWithMetadata, PublishableModel):
    product_type = models.ForeignKey(ProductType,
                                     related_name="products",
                                     on_delete=models.CASCADE)
    name = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True, allow_unicode=True)
    description = models.TextField(blank=True)
    description_json = SanitizedJSONField(blank=True,
                                          default=dict,
                                          sanitizer=clean_draft_js)
    category = models.ForeignKey(
        Category,
        related_name="products",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
    )

    currency = models.CharField(
        max_length=settings.DEFAULT_CURRENCY_CODE_LENGTH,
        default=settings.DEFAULT_CURRENCY,
    )

    minimal_variant_price_amount = models.DecimalField(
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        blank=True,
        null=True,
    )
    minimal_variant_price = MoneyField(
        amount_field="minimal_variant_price_amount", currency_field="currency")
    updated_at = models.DateTimeField(auto_now=True, null=True)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              blank=True,
                              null=True)
    objects = ProductsQueryset.as_manager()
    translated = TranslationProxy()

    class Meta:
        app_label = "product"
        ordering = ("slug", )
        permissions = ((ProductPermissions.MANAGE_PRODUCTS.codename,
                        "Manage products."), )

    def __str__(self) -> str:
        return self.name

    @staticmethod
    def sort_by_attribute_fields() -> list:
        return ["concatenated_values_order", "concatenated_values", "name"]
class MeasurementTestModel(models.Model):
    measurement_distance = MeasurementField(
        measurement=measures.Distance,
        validators=[
            MinValueValidator(measures.Distance(mi=1.0)),
            MaxValueValidator(measures.Distance(mi=3.0))
        ],
        blank=True, null=True,
    )
    measurement_distance_km = MeasurementField(
        measurement=measures.Distance,
        unit_choices=(('km', 'km'),),
        validators=[
            MinValueValidator(measures.Distance(km=1.0)),
            MaxValueValidator(measures.Distance(km=3.0))
        ],
        blank=True, null=True,
    )

    measurement_weight = MeasurementField(
        measurement=measures.Weight,
        validators=[
            MinValueValidator(measures.Weight(kg=1.0)),
            MaxValueValidator(measures.Weight(kg=3.0))
        ],
        blank=True, null=True,
    )

    measurement_speed = MeasurementField(
        measurement=measures.Speed,
        validators=[
            MinValueValidator(measures.Speed(mph=1.0)),
            MaxValueValidator(measures.Speed(mph=3.0))
        ],
        blank=True, null=True,
    )

    measurement_temperature = MeasurementField(
        measurement=measures.Temperature,
        validators=[
            MinValueValidator(measures.Temperature(1.0)),
            MaxValueValidator(measures.Temperature(3.0))
        ],
        blank=True, null=True,
    )

    measurement_speed_mph = MeasurementField(
        measurement=measures.Speed,
        unit_choices=(('mi__hr', 'mph'),),
        validators=[
            MinValueValidator(measures.Speed(mph=1.0)),
            MaxValueValidator(measures.Speed(mph=3.0))
        ],
        blank=True, null=True,
    )

    def __unicode__(self):
        return self.measurement
class Weight(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    date = models.DateField()
    weight = MeasurementField(measurement=WeightMeasurement,
                              unit_choices=[("kg", "kg")])

    def __str__(self):
        return self.player.user.username

    def value_club_unit(self):
        measurement_system = self.player.club.measurement_system
        if measurement_system == 'SI':
            return round(self.weight.kg, 1), 'kg'
        elif measurement_system == 'Imp':
            return round(self.weight.lb, 1), 'lb'
Exemple #18
0
class ProductType(models.Model):
    name = models.CharField(max_length=128)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    tax_rate = models.CharField(max_length=128, choices=TaxRateType.CHOICES)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              default=zero_weight)

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)
Exemple #19
0
class ProductType(ModelWithMetadata):
    name = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True, allow_unicode=True)
    kind = models.CharField(max_length=32, choices=ProductTypeKind.CHOICES)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    is_digital = models.BooleanField(default=False)
    weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,  # type: ignore
        default=zero_weight,
    )

    class Meta(ModelWithMetadata.Meta):
        ordering = ("slug",)
        app_label = "product"
        permissions = (
            (
                ProductTypePermissions.MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES.codename,
                "Manage product types and attributes.",
            ),
        )
        indexes = [
            *ModelWithMetadata.Meta.indexes,
            GinIndex(
                name="product_type_search_gin",
                # `opclasses` and `fields` should be the same length
                fields=["name", "slug"],
                opclasses=["gin_trgm_ops"] * 2,
            ),
        ]

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )
class DeliveryProduct(models.Model):
    # order_id = models.AutoField(primary_key=True)
    from_location = models.ForeignKey(Industry,
                                      on_delete=models.CASCADE,
                                      related_name='from_location')
    to_location = models.ForeignKey(Industry,
                                    on_delete=models.CASCADE,
                                    related_name='to_location')
    PresentAddress = models.CharField(max_length=255, choices=OPTIONS3)
    product_type = models.ForeignKey(TypesOfProduct, on_delete=models.CASCADE)
    weight = MeasurementField(measurement=Weight, null=True, blank=True)
    Date = models.DateTimeField(default=timezone.now)
    image = models.ImageField(upload_to='images/', null=True, blank=True)
    phone = models.CharField(max_length=20)
    Bill = models.IntegerField(null=True, blank=True)
    order_status = models.CharField(max_length=100,
                                    choices=OPTIONS2,
                                    default="0")

    def __str__(self):
        return f"From Location :{self.from_location} and To location : {self.to_location} and Phone Number :{self.phone} and Product Type :{self.product_type}"
Exemple #21
0
class ProductType(index.Indexed, BaseModel):
    """Think about product types as templates for your products. Multiple products can use the same product type."""

    name = models.CharField(
        verbose_name=_("Name"),
        max_length=255,
        help_text=_("Required, Maximum of 255 characters."),
    )
    slug = models.SlugField(max_length=255, unique=True, allow_unicode=True)
    weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,
        blank=True,
        null=True,
    )

    class Meta:
        verbose_name = _("Product Type")
        verbose_name_plural = _("Products Types")

    def __str__(self) -> str:
        return f"{self.name}"
Exemple #22
0
class ShipmentPiece(BaseModel):
    """Represents the physical shipped item as box or envelope etc..."""

    shipment = ParentalKey(Shipment,
                           related_name="pieces",
                           on_delete=models.CASCADE)
    weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,
        default=0,
    )
    height = models.DecimalField(verbose_name=_("Height"),
                                 max_digits=20,
                                 decimal_places=4,
                                 null=True,
                                 blank=True)
    depth = models.DecimalField(verbose_name=_("Depth"),
                                max_digits=20,
                                decimal_places=4,
                                null=True,
                                blank=True)
    width = models.DecimalField(verbose_name=_("Width"),
                                max_digits=20,
                                decimal_places=4,
                                null=True,
                                blank=True)
    declared_value = models.DecimalField(verbose_name=_("Declared Value"),
                                         max_digits=20,
                                         decimal_places=4,
                                         null=True,
                                         blank=True)

    class Meta:
        verbose_name = _("Shipment Piece")
        verbose_name_plural = _("Shipments Pieces")

    def __str__(self):
        return f"{self.order.number}"
class PredictedHeight(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    date = models.DateField()
    predicted_height = MeasurementField(measurement=Distance,
                                        unit_choices=[("cm", "cm")])
    METHOD_CHOICES = (
        ('dna', 'DNA Test'),  # DNA Test has always priority
        ('khr', 'Khamis Roche'),
    )
    method = models.CharField(max_length=10, choices=METHOD_CHOICES)
    khamis_roche = models.ForeignKey(KhamisRoche, blank=True, null=True)
    dna_height = models.ForeignKey(DnaHeight, blank=True, null=True)

    def __str__(self):
        return self.player.user.username

    def value_club_unit(self):
        measurement_system = self.player.club.measurement_system
        if measurement_system == 'SI':
            return round(self.predicted_height.cm, 1), 'cm'
        elif measurement_system == 'Imp':
            return round(self.predicted_height.inch, 1), 'inch'
Exemple #24
0
class Profile(models.Model):
    """Profile model.

    Proxy model that extends the base data with other
    information.
    """
    class UnitMeasurement(models.TextChoices):
        """
        Class to deal with enum unit measures
        Two posibles values: 0: METRIC, 1:IMPERIAL
        """

        METRIC = "METRIC"
        IMPERIAL = "IMPERIAL"

    user = models.OneToOneField(User, on_delete=models.CASCADE)

    picture = models.ImageField(upload_to='users/pictures',
                                blank=True,
                                null=True)

    height = MeasurementField(measurement=Distance,
                              unit_choices=(('ft', 'ft'), ('m', 'm')))
    measurement_system = models.CharField(blank=True,
                                          choices=[(tag, tag.value)
                                                   for tag in UnitMeasurement],
                                          default=UnitMeasurement.METRIC,
                                          max_length=8)
    country_code = models.CharField(blank=True, max_length=2)

    active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        """Return username."""
        return self.user.username
Exemple #25
0
class ProductType(models.Model):
    name = models.CharField(max_length=128)
    has_variants = models.BooleanField(default=True)
    product_attributes = models.ManyToManyField(
        'ProductAttribute', related_name='product_types', blank=True)
    variant_attributes = models.ManyToManyField(
        'ProductAttribute', related_name='product_variant_types', blank=True)
    is_shipping_required = models.BooleanField(default=False)
    tax_rate = models.CharField(
        max_length=128, default=DEFAULT_TAX_RATE_NAME, blank=True)
    weight = MeasurementField(
        measurement=Weight, unit_choices=WeightUnits.CHOICES,
        default=zero_weight)

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (
            class_.__module__, class_.__name__, self.pk, self.name)
Exemple #26
0
class ProductType(models.Model):
    name = models.CharField(max_length=128)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    is_digital = models.BooleanField(default=False)
    weight = MeasurementField(
        measurement=Weight, unit_choices=WeightUnits.CHOICES, default=zero_weight
    )
    meta = JSONField(blank=True, null=True, default=dict, encoder=CustomJsonEncoder)

    class Meta:
        app_label = "product"

    def __str__(self):
        return self.name

    def __repr__(self):
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )
Exemple #27
0
class ProductType(ModelWithMetadata):
    name = models.CharField(max_length=128)
    has_variants = models.BooleanField(default=True)
    is_shipping_required = models.BooleanField(default=True)
    is_digital = models.BooleanField(default=False)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              default=zero_weight)
    objects = models.Manager()

    class Meta:
        app_label = "product"

    def __str__(self):
        return self.name

    def __repr__(self):
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )
Exemple #28
0
class ProductVariant(ModelWithMetadata):
    sku = models.CharField(max_length=32, unique=True)
    name = models.CharField(max_length=255, blank=True)
    price_override = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        blank=True,
        null=True,
    )
    product = models.ForeignKey(Product,
                                related_name="variants",
                                on_delete=models.CASCADE)
    attributes = FilterableJSONBField(default=dict,
                                      blank=True,
                                      validators=[validate_attribute_json])
    images = models.ManyToManyField("ProductImage", through="VariantImage")
    track_inventory = models.BooleanField(default=True)
    quantity = models.IntegerField(validators=[MinValueValidator(0)],
                                   default=Decimal(1))
    quantity_allocated = models.IntegerField(validators=[MinValueValidator(0)],
                                             default=Decimal(0))
    cost_price = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        blank=True,
        null=True,
    )
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              blank=True,
                              null=True)

    objects = ProductVariantQueryset.as_manager()
    translated = TranslationProxy()

    class Meta:
        app_label = "product"

    def __str__(self):
        return self.name or self.sku

    @property
    def quantity_available(self):
        return max(self.quantity - self.quantity_allocated, 0)

    @property
    def is_visible(self):
        return self.product.is_visible

    @property
    def is_available(self):
        return self.product.is_available

    def check_quantity(self, quantity):
        """Check if there is at least the given quantity in stock.

        If stock handling is disabled, it simply run no check.
        """
        if self.track_inventory and quantity > self.quantity_available:
            raise InsufficientStock(self)

    @property
    def base_price(self):
        return (self.price_override
                if self.price_override is not None else self.product.price)

    def get_price(self, discounts: Iterable[DiscountInfo] = None):
        return calculate_discounted_price(self.product, self.base_price,
                                          discounts)

    def get_weight(self):
        return self.weight or self.product.weight or self.product.product_type.weight

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse("product:details",
                       kwargs={
                           "slug": slug,
                           "product_id": product_id
                       })

    def is_shipping_required(self):
        return self.product.product_type.is_shipping_required

    def is_digital(self):
        is_digital = self.product.product_type.is_digital
        return not self.is_shipping_required() and is_digital

    def is_in_stock(self):
        return self.quantity_available > 0

    def display_product(self, translated=False):
        if translated:
            product = self.product.translated
            variant_display = str(self.translated)
        else:
            variant_display = str(self)
            product = self.product
        product_display = ("%s (%s)" % (product, variant_display)
                           if variant_display else str(product))
        return smart_text(product_display)

    def get_first_image(self):
        images = list(self.images.all())
        return images[0] if images else self.product.get_first_image()

    def get_ajax_label(self, discounts=None):
        price = self.get_price(discounts)
        return "%s, %s, %s" % (
            self.sku,
            self.display_product(),
            prices_i18n.amount(price),
        )
Exemple #29
0
class Product(SeoModel, ModelWithMetadata, PublishableModel):
    product_type = models.ForeignKey(ProductType,
                                     related_name="products",
                                     on_delete=models.CASCADE)
    name = models.CharField(max_length=128)
    description = models.TextField(blank=True)
    description_json = SanitizedJSONField(blank=True,
                                          default=dict,
                                          sanitizer=clean_draft_js)
    category = models.ForeignKey(Category,
                                 related_name="products",
                                 on_delete=models.CASCADE)
    price = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
    )
    minimal_variant_price = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
    )
    attributes = FilterableJSONBField(default=dict,
                                      blank=True,
                                      validators=[validate_attribute_json])
    updated_at = models.DateTimeField(auto_now=True, null=True)
    charge_taxes = models.BooleanField(default=True)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              blank=True,
                              null=True)
    objects = ProductsQueryset.as_manager()
    translated = TranslationProxy()

    class Meta:
        app_label = "product"
        ordering = ("name", )
        permissions = ((
            "manage_products",
            pgettext_lazy("Permission description", "Manage products."),
        ), )

    def __iter__(self):
        if not hasattr(self, "__variants"):
            setattr(self, "__variants", self.variants.all())
        return iter(getattr(self, "__variants"))

    def __repr__(self):
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )

    def __str__(self):
        return self.name

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        # Make sure the "minimal_variant_price" is set
        if self.minimal_variant_price is None:
            self.minimal_variant_price = self.price
        return super().save(force_insert, force_update, using, update_fields)

    @property
    def plain_text_description(self):
        if settings.USE_JSON_CONTENT:
            return json_content_to_raw_text(self.description_json)
        return strip_tags(self.description)

    @property
    def is_available(self):
        return self.is_visible and self.is_in_stock()

    def get_absolute_url(self):
        return reverse("product:details",
                       kwargs={
                           "slug": self.get_slug(),
                           "product_id": self.id
                       })

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def is_in_stock(self):
        return any(variant.is_in_stock() for variant in self)

    def get_first_image(self):
        images = list(self.images.all())
        return images[0] if images else None

    def get_price_range(self, discounts: Iterable[DiscountInfo] = None):
        if self.variants.all():
            prices = [variant.get_price(discounts) for variant in self]
            return MoneyRange(min(prices), max(prices))
        price = calculate_discounted_price(self, self.price, discounts)
        return MoneyRange(start=price, stop=price)
Exemple #30
0
class ProductVariant(SortableModel, ModelWithMetadata):
    sku = models.CharField(max_length=255, unique=True)
    name = models.CharField(max_length=255, blank=True)
    product = models.ForeignKey(
        Product, related_name="variants", on_delete=models.CASCADE
    )
    media = models.ManyToManyField("ProductMedia", through="VariantMedia")
    track_inventory = models.BooleanField(default=True)

    weight = MeasurementField(
        measurement=Weight,
        unit_choices=WeightUnits.CHOICES,  # type: ignore
        blank=True,
        null=True,
    )

    objects = models.Manager.from_queryset(ProductVariantQueryset)()
    translated = TranslationProxy()

    class Meta(ModelWithMetadata.Meta):
        ordering = ("sort_order", "sku")
        app_label = "product"

    def __str__(self) -> str:
        return self.name or self.sku

    def get_price(
        self,
        product: Product,
        collections: Iterable["Collection"],
        channel: Channel,
        channel_listing: "ProductVariantChannelListing",
        discounts: Optional[Iterable[DiscountInfo]] = None,
    ) -> "Money":
        return calculate_discounted_price(
            product=product,
            price=channel_listing.price,
            discounts=discounts,
            collections=collections,
            channel=channel,
        )

    def get_weight(self):
        return self.weight or self.product.weight or self.product.product_type.weight

    def is_shipping_required(self) -> bool:
        return self.product.product_type.is_shipping_required

    def is_digital(self) -> bool:
        is_digital = self.product.product_type.is_digital
        return not self.is_shipping_required() and is_digital

    def display_product(self, translated: bool = False) -> str:
        if translated:
            product = self.product.translated
            variant_display = str(self.translated)
        else:
            variant_display = str(self)
            product = self.product
        product_display = (
            f"{product} ({variant_display})" if variant_display else str(product)
        )
        return smart_text(product_display)

    def get_ordering_queryset(self):
        return self.product.variants.all()