def test_analog(): PseudoPaymentProcessorLogEntry = define_log_model(PseudoPaymentProcessor) assert PseudoPaymentProcessorLogEntry.__module__ == PseudoPaymentProcessor.__module__ assert PseudoPaymentProcessorLogEntry._meta.get_field("target").rel.to is PseudoPaymentProcessor assert PseudoPaymentProcessor.log_entries.rel.model is PseudoPaymentProcessor assert PseudoPaymentProcessor.log_entries.rel.related_model is PseudoPaymentProcessorLogEntry assert issubclass(PseudoPaymentProcessorLogEntry, BaseLogEntry) assert isinstance(PseudoPaymentProcessorLogEntry(), BaseLogEntry)
def test_analog(): FakeModelLogEntry = define_log_model(FakeModel) assert FakeModelLogEntry.__module__ == FakeModel.__module__ assert FakeModelLogEntry._meta.get_field("target").rel.to is FakeModel assert FakeModel.log_entries.related.model is FakeModel assert FakeModel.log_entries.related.related_model is FakeModelLogEntry assert issubclass(FakeModelLogEntry, BaseLogEntry) assert isinstance(FakeModelLogEntry(), BaseLogEntry)
def test_analog(): PseudoPaymentProcessorLogEntry = define_log_model(PseudoPaymentProcessor) assert PseudoPaymentProcessorLogEntry.__module__ == PseudoPaymentProcessor.__module__ related_field_name = "related" # Behavior changs in Django 1.9 if VERSION >= (1, 9): related_field_name = "rel" relation_manager = getattr(PseudoPaymentProcessorLogEntry._meta.get_field("target"), related_field_name) assert relation_manager.to is PseudoPaymentProcessor relation_manager = getattr(PseudoPaymentProcessor.log_entries, related_field_name) assert relation_manager.model is PseudoPaymentProcessor assert relation_manager.related_model is PseudoPaymentProcessorLogEntry assert issubclass(PseudoPaymentProcessorLogEntry, BaseLogEntry) assert isinstance(PseudoPaymentProcessorLogEntry(), BaseLogEntry)
service_model = ShippingMethod def delete(self, *args, **kwargs): ShippingMethod.objects.filter(carrier=self).update( **{"enabled": False}) super(Carrier, self).delete(*args, **kwargs) def _create_service(self, choice_identifier, **kwargs): labels = kwargs.pop("labels", None) service = ShippingMethod.objects.create( carrier=self, choice_identifier=choice_identifier, **kwargs) if labels: service.labels = labels return service class CustomCarrier(Carrier): """ Carrier without any integration or special processing. """ class Meta: verbose_name = _("custom carrier") verbose_name_plural = _("custom carriers") def get_service_choices(self): return [ServiceChoice('manual', _("Manually processed shipment"))] ShippingMethodLogEntry = define_log_model(ShippingMethod) CarrierLogEntry = define_log_model(Carrier)
# LICENSE file in the root directory of this source tree. from __future__ import unicode_literals from django.db import models from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from shuup.core.fields import InternalIdentifierField from shuup.utils.analog import define_log_model __all__ = ("Manufacturer",) @python_2_unicode_compatible class Manufacturer(models.Model): created_on = models.DateTimeField(auto_now_add=True, verbose_name=_('added')) identifier = InternalIdentifierField(unique=True) name = models.CharField(max_length=128, verbose_name=_('name')) url = models.CharField(null=True, blank=True, max_length=128, verbose_name=_('URL')) class Meta: verbose_name = _('manufacturer') verbose_name_plural = _('manufacturers') def __str__(self): # pragma: no cover return u'%s' % (self.name) ManufacturerLogEntry = define_log_model(Manufacturer)
objects = ShopManager() class Meta: verbose_name = _('shop') verbose_name_plural = _('shops') def __str__(self): return force_text(self.safe_translation_getter("name", default="Shop %d" % self.pk)) def create_price(self, value): """ Create a price with given value and settings of this shop. Takes the ``prices_include_tax`` and ``currency`` settings of this Shop into account. :type value: decimal.Decimal|int|str :rtype: shuup.core.pricing.Price """ if self.prices_include_tax: return TaxfulPrice(value, self.currency) else: return TaxlessPrice(value, self.currency) def _are_changes_protected(self): return Order.objects.filter(shop=self).exists() ShopLogEntry = define_log_model(Shop)
shop_product.categories.remove(self) shop_product.primary_category = None shop_product.save() for shop_product in self.shop_products.all(): shop_product.categories.remove(self) shop_product.primary_category = None shop_product.save() for child in self.children.all(): child.parent = None child.save() self.status = CategoryStatus.DELETED self.add_log_entry("Success! Deleted (soft).", kind=LogEntryKind.DELETION, user=user) self.save() category_deleted.send(sender=type(self), category=self) def save(self, *args, **kwargs): rv = super(Category, self).save(*args, **kwargs) generate_multilanguage_slugs(self, self._get_slug_name) # bump children cache from shuup.core import cache cache.bump_version("category_cached_children") return rv CategoryLogEntry = define_log_model(Category)
from shuup.core.fields import CurrencyField, MoneyValueField from shuup.utils.analog import define_log_model from shuup.utils.properties import MoneyProperty, MoneyPropped __all__ = ("Payment",) class Payment(MoneyPropped, models.Model): # TODO: Revise!!! order = models.ForeignKey("Order", related_name='payments', on_delete=models.PROTECT, verbose_name=_('order')) created_on = models.DateTimeField(auto_now_add=True, verbose_name=_('created on')) gateway_id = models.CharField(max_length=32, verbose_name=_('gateway ID')) # TODO: do we need this? payment_identifier = models.CharField(max_length=96, unique=True, verbose_name=_('identifier')) amount = MoneyProperty('amount_value', 'order.currency') foreign_amount = MoneyProperty('foreign_amount_value', 'foreign_currency') amount_value = MoneyValueField(verbose_name=_('amount')) foreign_amount_value = MoneyValueField(default=None, blank=True, null=True, verbose_name=_('foreign amount')) foreign_currency = CurrencyField(default=None, blank=True, null=True, verbose_name=_('foreign amount currency')) description = models.CharField(max_length=256, blank=True, verbose_name=_('description')) class Meta: verbose_name = _('payment') verbose_name_plural = _('payments') PaymentLogEntry = define_log_model(Payment)
class CustomerTaxGroup(TranslatableShuupModel): identifier = InternalIdentifierField(unique=True) translations = TranslatedFields( name=models.CharField(max_length=100, verbose_name=_('name')), ) enabled = models.BooleanField(default=True, verbose_name=_('enabled')) class Meta: verbose_name = _('customer tax group') verbose_name_plural = _('customer tax groups') @classmethod def get_default_person_group(cls): obj, c = CustomerTaxGroup.objects.get_or_create(identifier="default_person_customers", defaults={ "name": _("Retail Customers") }) return obj @classmethod def get_default_company_group(cls): obj, c = CustomerTaxGroup.objects.get_or_create(identifier="default_company_customers", defaults={ "name": _("Company Customers") }) return obj TaxLogEntry = define_log_model(Tax) TaxClassLogEntry = define_log_model(TaxClass) CustomerTaxGroupLogEntry = define_log_model(CustomerTaxGroup)
@python_2_unicode_compatible class OrderLineTax(MoneyPropped, ShuupModel, LineTax): order_line = models.ForeignKey( OrderLine, related_name='taxes', on_delete=models.PROTECT, verbose_name=_('order line')) tax = models.ForeignKey( "Tax", related_name="order_line_taxes", on_delete=models.PROTECT, verbose_name=_('tax')) name = models.CharField(max_length=200, verbose_name=_('tax name')) amount = MoneyProperty('amount_value', 'order_line.order.currency') base_amount = MoneyProperty('base_amount_value', 'order_line.order.currency') amount_value = MoneyValueField(verbose_name=_('tax amount')) base_amount_value = MoneyValueField( verbose_name=_('base amount'), help_text=_('Amount that this tax is calculated from')) ordering = models.IntegerField(default=0, verbose_name=_('ordering')) class Meta: ordering = ["ordering"] def __str__(self): return "%s: %s on %s" % (self.name, self.amount, self.base_amount) OrderLineLogEntry = define_log_model(OrderLine) OrderLineTaxLogEntry = define_log_model(OrderLineTax)
def use(self, order): return CouponUsage.add_usage(order=order, coupon=self) def increase_customer_usage_limit_by(self, amount): if self.usage_limit_customer: new_limit = self.usage_limit_customer + amount else: new_limit = self.usages.count() + amount self.usage_limit_customer = new_limit def increase_usage_limit_by(self, amount): self.usage_limit = self.usage_limit + amount if self.usage_limit else (self.usages.count() + amount) def has_been_used(self, usage_count=1): """ See if code is used the times given """ return CouponUsage.objects.filter(coupon=self).count() >= usage_count def save(self, **kwargs): if Coupon.objects.filter(code__iexact=self.code, active=True).exclude(pk=self.pk).exists(): raise ValidationError(_("Cannot have two same codes active at the same time.")) return super(Coupon, self).save(**kwargs) def __str__(self): return self.code CatalogCampaignLogEntry = define_log_model(CatalogCampaign) BasketCampaignLogEntry = define_log_model(BasketCampaign) CouponLogEntry = define_log_model(Coupon) CouponUsageLogEntry = define_log_model(CouponUsage)
if self.kind != ProductMediaKind.IMAGE: return None return get_thumbnailer(self.file) def get_thumbnail(self, **kwargs): """ Get thumbnail for image This will return `None` if there is no file or kind is not `ProductMediaKind.IMAGE` :rtype: easy_thumbnails.files.ThumbnailFile|None """ kwargs.setdefault("size", (64, 64)) kwargs.setdefault("crop", True) # sane defaults kwargs.setdefault("upscale", True) # sane defaults if kwargs["size"] is (0, 0): return None thumbnailer = self.easy_thumbnails_thumbnailer if not thumbnailer: return None return thumbnailer.get_thumbnail(thumbnail_options=kwargs) ProductMediaLogEntry = define_log_model(ProductMedia)
def __str__(self): return self.code def get_currency_precision(currency): """ Get precision by currency code. Precision values will be populated from the ``decimal_places`` fields of the `Currency` objects in the database. :type currency: str :param currency: Currency code as 3-letter string (ISO-4217) :rtype: decimal.Decimal|None :return: Precision value for given currency code or None for unknown """ cache_key = 'currency_precision:' + currency precision = cache.get(cache_key) if precision is None: currency_obj = Currency.objects.filter(code=currency).first() precision = ( decimal.Decimal('0.1') ** currency_obj.decimal_places if currency_obj else None) cache.set(cache_key, precision) return precision CurrencyLogEntry = define_log_model(Currency)
created_on = models.DateTimeField(auto_now_add=True, editable=False, db_index=True, verbose_name=_("created on")) modified_on = models.DateTimeField(auto_now=True, editable=False, db_index=True, verbose_name=_("modified on")) objects = TaskCommentQuerySet.as_manager() def reply(self, contact, body): comment = TaskComment(task=self.task, comment_author=contact, body=body) comment.full_clean() comment.save() return comment def as_html(self): return mark_safe(force_text(self.body)) def can_see(self, user): is_admin = user.is_superuser is_staff = bool(user.is_staff and user in self.task.shop.staff_members.all()) if not (is_admin or is_staff): return (self.visibility == TaskCommentVisibility.PUBLIC) elif not is_admin: return ( self.visibility == TaskCommentVisibility.PUBLIC or self.visibility == TaskCommentVisibility.STAFF_ONLY ) return True TaskLogEntry = define_log_model(Task)
from django.utils.translation import ugettext_lazy as _ from shuup.core.fields import QuantityField from shuup.utils.analog import define_log_model class SuppliedProduct(models.Model): supplier = models.ForeignKey("Supplier", on_delete=models.CASCADE, verbose_name=_("supplier")) product = models.ForeignKey("Product", on_delete=models.CASCADE, verbose_name=_("product")) sku = models.CharField(db_index=True, max_length=128, verbose_name=_('SKU')) alert_limit = models.IntegerField(default=0, verbose_name=_('alert limit')) physical_count = QuantityField(editable=False, verbose_name=_('physical stock count')) logical_count = QuantityField(editable=False, verbose_name=_('logical stock count')) class Meta: unique_together = (( "supplier", "product", ), ) SuppliedProductLogEntry = define_log_model(SuppliedProduct)
""" owner = models.ForeignKey("Contact", on_delete=models.CASCADE, verbose_name=_("owner")) address = models.ForeignKey( MutableAddress, verbose_name=_('address'), related_name="saved_addresses", on_delete=models.CASCADE) role = EnumIntegerField(SavedAddressRole, verbose_name=_('role'), default=SavedAddressRole.SHIPPING) status = EnumIntegerField(SavedAddressStatus, default=SavedAddressStatus.ENABLED, verbose_name=_('status')) title = models.CharField(max_length=255, blank=True, verbose_name=_('title')) objects = SavedAddressManager() class Meta: verbose_name = _('saved address') verbose_name_plural = _('saved addresses') ordering = ("owner_id", "role", "title") def __str__(self): return u"%s" % self.get_title() def get_title(self): """ Returns the display title for this `SavedAddress` instance. Defaults to a short representation of the address. This method should be used instead of accessing the `title` field directly when displaying `SavedAddress` objects. """ return self.title.strip() if self.title else six.text_type(self.address) SavedAddressLogEntry = define_log_model(SavedAddress)
default=SavedAddressRole.SHIPPING) status = EnumIntegerField(SavedAddressStatus, default=SavedAddressStatus.ENABLED, verbose_name=_('status')) title = models.CharField(max_length=255, blank=True, verbose_name=_('title')) objects = SavedAddressManager() class Meta: verbose_name = _('saved address') verbose_name_plural = _('saved addresses') ordering = ("owner_id", "role", "title") def __str__(self): return u"%s" % self.get_title() def get_title(self): """ Returns the display title for this `SavedAddress` instance. Defaults to a short representation of the address. This method should be used instead of accessing the `title` field directly when displaying `SavedAddress` objects. """ return self.title.strip() if self.title else six.text_type( self.address) SavedAddressLogEntry = define_log_model(SavedAddress)
class Meta: verbose_name = _("custom payment processor") verbose_name_plural = _("custom payment processors") def get_service_choices(self): return [ ServiceChoice('manual', _("Manually processed payment")), ServiceChoice('cash', _("Cash payment")) ] def _create_service(self, choice_identifier, **kwargs): service = super(CustomPaymentProcessor, self)._create_service( choice_identifier, **kwargs) if choice_identifier == 'cash': service.behavior_components.add( StaffOnlyBehaviorComponent.objects.create()) return service def process_payment_return_request(self, service, order, request): if service == 'cash': if not order.is_paid(): order.create_payment( order.taxful_total_price, payment_identifier="Cash-%s" % now().isoformat(), description="Cash Payment" ) PaymentMethodLogEntry = define_log_model(PaymentMethod) PaymentProcessorLogEntry = define_log_model(PaymentProcessor)
return products def get_unshipped_products(self): return dict( (product, summary_datum) for product, summary_datum in self.get_product_summary().items() if summary_datum['unshipped'] ) def get_status_display(self): return force_text(self.status) def get_tracking_codes(self): return [shipment.tracking_code for shipment in self.shipments.all() if shipment.tracking_code] def can_edit(self): return ( not self.has_refunds() and not self.is_canceled() and not self.is_complete() and self.shipping_status == ShippingStatus.NOT_SHIPPED and self.payment_status == PaymentStatus.NOT_PAID ) OrderLogEntry = define_log_model(Order) def _round_price(value): return bankers_round(value, 2) # TODO: To be fixed in SHUUP-1912
return self.module.get_stock_status(product_id) def get_suppliable_products(self, shop, customer): """ :param shop: Shop to check for suppliability :type shop: shuup.core.models.Shop :param customer: Customer contact to check for suppliability :type customer: shuup.core.models.Contact :rtype: list[int] """ return [ shop_product.pk for shop_product in self.shop_products.filter(shop=shop) if shop_product.is_orderable(self, customer, shop_product.minimum_purchase_quantity) ] def adjust_stock(self, product_id, delta, created_by=None, type=None): from shuup.core.suppliers.base import StockAdjustmentType adjustment_type = type or StockAdjustmentType.INVENTORY return self.module.adjust_stock(product_id, delta, created_by=created_by, type=adjustment_type) def update_stock(self, product_id): return self.module.update_stock(product_id) def update_stocks(self, product_ids): return self.module.update_stocks(product_ids) SupplierLogEntry = define_log_model(Supplier)
Note: `Carrier` objects should never be created on their own but rather through a concrete subclass. """ service_model = ShippingMethod def delete(self, *args, **kwargs): ShippingMethod.objects.filter(carrier=self).update(**{"enabled": False}) super(Carrier, self).delete(*args, **kwargs) def _create_service(self, choice_identifier, **kwargs): return ShippingMethod.objects.create( carrier=self, choice_identifier=choice_identifier, **kwargs) class CustomCarrier(Carrier): """ Carrier without any integration or special processing. """ class Meta: verbose_name = _("custom carrier") verbose_name_plural = _("custom carriers") def get_service_choices(self): return [ServiceChoice('manual', _("Manually processed shipment"))] ShippingMethodLogEntry = define_log_model(ShippingMethod) CarrierLogEntry = define_log_model(Carrier)
attr = self.get_available_attribute_queryset().get(identifier=identifier) applied_attr = self.attributes.filter(attribute=attr).first() if not applied_attr: applied_attr = self.attributes.model(attribute=attr) setattr(applied_attr, applied_attr._applied_fk_field, self) else: self.clear_attribute_cache() if attr.is_translated: if not language: raise ValueError("`language` must be set for translated attribute %s" % attr) applied_attr.set_current_language(language) if not attr.is_translated and attr.is_null_value(value): # Trying to set a null value for an untranslated attribute, # so we can just get rid of the applied object altogether. # TODO: Do the same sort of cleanup for translated attributes. if applied_attr.pk: applied_attr.delete() return # Set the value and save the attribute (possibly new) applied_attr.value = value applied_attr.save() return applied_attr AttributeLogEntry = define_log_model(Attribute)
Shipment, related_name='products', on_delete=models.PROTECT, verbose_name=_("shipment") ) product = models.ForeignKey( "Product", related_name='shipments', on_delete=models.CASCADE, verbose_name=_("product") ) quantity = QuantityField(verbose_name=_("quantity")) # volume is m^3, not mm^3, because mm^3 are tiny. like ants. unit_volume = MeasurementField(unit="m3", verbose_name=_("unit volume")) unit_weight = MeasurementField(unit="g", verbose_name=_("unit weight")) class Meta: verbose_name = _('sent product') verbose_name_plural = _('sent products') def __str__(self): # pragma: no cover return "%(quantity)s of '%(product)s' in Shipment #%(shipment_pk)s" % { 'product': self.product, 'quantity': self.quantity, 'shipment_pk': self.shipment_id, } def cache_values(self): prod = self.product self.unit_volume = (prod.width * prod.height * prod.depth) / CUBIC_MM_TO_CUBIC_METERS_DIVISOR self.unit_weight = prod.gross_weight ShipmentLogEntry = define_log_model(Shipment) ShipmentProductLogEntry = define_log_model(ShipmentProduct)
return get_thumbnailer(self.file) def get_thumbnail(self, **kwargs): """ Get thumbnail for image. This will return `None` if there is no file or kind is not `ProductMediaKind.IMAGE` :rtype: easy_thumbnails.files.ThumbnailFile|None """ kwargs.setdefault("size", (64, 64)) kwargs.setdefault("crop", True) # sane defaults kwargs.setdefault("upscale", True) # sane defaults if kwargs["size"] == (0, 0): return None thumbnailer = self.easy_thumbnails_thumbnailer if not thumbnailer: return None try: return thumbnailer.get_thumbnail(thumbnail_options=kwargs) except InvalidImageFormatError: return None ProductMediaLogEntry = define_log_model(ProductMedia)
shop__isnull=True, group__identifier__in=PROTECTED_CONTACT_GROUP_IDENTIFIERS).exclude( group__identifier__in=identifiers).exclude(pk__in=ids).values_list( "id", flat=True) return ContactGroupPriceDisplay.objects.filter(pk__in=list(ids) + list(defaults)) def get_groups_for_price_display_create(shop): default_groups = ContactGroup.objects.filter( shop__isnull=True, identifier__in=PROTECTED_CONTACT_GROUP_IDENTIFIERS) used_in_shop = ContactGroupPriceDisplay.objects.filter(shop=shop) if not used_in_shop.exists(): return default_groups used_groups = [pd.group for pd in used_in_shop] used_ids = [g.id for g in used_groups] used_identifiers = [g.identifier for g in used_groups] available = ContactGroup.objects.filter(shop=shop).exclude( id__in=used_ids).values_list("id", flat=True) defaults = default_groups.exclude(identifier__in=used_identifiers).exclude( pk__in=used_ids).values_list("id", flat=True) return ContactGroup.objects.filter(pk__in=list(available) + list(defaults)) CompanyContactLogEntry = define_log_model(CompanyContact) PersonContactLogEntry = define_log_model(PersonContact) ContactGroupLogEntry = define_log_model(ContactGroup)
""" :param shop: Shop to check for suppliability :type shop: shuup.core.models.Shop :param customer: Customer contact to check for suppliability :type customer: shuup.core.models.Contact :rtype: list[int] """ return [ shop_product.pk for shop_product in self.shop_products.filter(shop=shop) if shop_product.is_orderable( self, customer, shop_product.minimum_purchase_quantity) ] def adjust_stock(self, product_id, delta, created_by=None, type=None): from shuup.core.suppliers.base import StockAdjustmentType adjustment_type = type or StockAdjustmentType.INVENTORY return self.module.adjust_stock(product_id, delta, created_by=created_by, type=adjustment_type) def update_stock(self, product_id): return self.module.update_stock(product_id) def update_stocks(self, product_ids): return self.module.update_stocks(product_ids) SupplierLogEntry = define_log_model(Supplier)
def soft_delete(self, user=None): if not self.status == CategoryStatus.DELETED: for shop_product in self.primary_shop_products.all(): shop_product.categories.remove(self) shop_product.primary_category = None shop_product.save() for shop_product in self.shop_products.all(): shop_product.categories.remove(self) shop_product.primary_category = None shop_product.save() for child in self.children.all(): child.parent = None child.save() self.status = CategoryStatus.DELETED self.add_log_entry("Deleted.", kind=LogEntryKind.DELETION, user=user) self.save() category_deleted.send(sender=type(self), category=self) def save(self, *args, **kwargs): rv = super(Category, self).save(*args, **kwargs) generate_multilanguage_slugs(self, self._get_slug_name) # bump children cache from shuup.core import cache cache.bump_version("category_cached_children") return rv CategoryLogEntry = define_log_model(Category)
from shuup.core.models import Contact, Shop from shuup.utils.analog import define_log_model class MailchimpBaseModel(models.Model): shop = models.ForeignKey(Shop, related_name="+", on_delete=models.CASCADE, verbose_name=_("shop")) updated = models.DateTimeField(auto_now=True, verbose_name=_("updated")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("created")) sent_to_mailchimp = models.DateTimeField(null=True, verbose_name=_("sent to mailchimp")) class Meta: abstract = True class MailchimpContact(MailchimpBaseModel): contact = models.ForeignKey( Contact, related_name="+", on_delete=models.CASCADE, verbose_name=_("contact"), blank=True, null=True, ) email = models.EmailField(max_length=254, verbose_name=_('email'), unique=True) class Meta: abstract = False MailchimpLogEntry = define_log_model(MailchimpContact)
image = FilerImageField( verbose_name=_("Image"), blank=True, null=True, on_delete=models.SET_NULL, help_text=_("The image of your object."), related_name="blog_meta_image" ) og_type = EnumField(PageOpenGraphType, verbose_name=_("type"), default=PageOpenGraphType.Website) translations = TranslatedFields( title=models.CharField(max_length=100, blank=True, verbose_name=_("Title"), help_text=_( 'The title of your object as it should appear within the graph, e.g. The Rock.' )), description=models.TextField(max_length=160, blank=True, verbose_name=_("Description"), help_text=_( "A one to two sentence description of your object." )), section=models.CharField(max_length=256, blank=True, verbose_name=_("Section"), help_text=_( "A high-level section name, e.g. Technology. Only applicable when type is Article." )), tags=models.CharField(max_length=256, blank=True, verbose_name=_("Tags"), help_text=_( "Tag words associated with this article. Only applicable when type is Article." )), article_author=models.CharField(max_length=100, blank=True, verbose_name=_("Article author"), help_text=_( 'The name of the author for the article. Only applicable when type is Article.' )) ) def __str__(self): return force_text(self.page) PageLogEntry = define_log_model(Page)
identifier = InternalIdentifierField(unique=True) shops = models.ManyToManyField("shuup.Shop", blank=True, verbose_name=_("shops")) name = models.CharField( max_length=128, verbose_name=_('name'), help_text=_( "Enter the manufacturer’s name. " "Products can be filtered by the manufacturer and can be useful for inventory and stock management." )) url = models.CharField( null=True, blank=True, max_length=128, verbose_name=_('URL'), help_text=_( "Enter the URL of the product manufacturer if you would like customers to be able to visit the manufacturer's " "website.")) class Meta: verbose_name = _('manufacturer') verbose_name_plural = _('manufacturers') def __str__(self): # pragma: no cover return u'%s' % (self.name) ManufacturerLogEntry = define_log_model(Manufacturer)
(product, summary_datum) for product, summary_datum in self.get_product_summary().items() if summary_datum['unshipped']) def get_status_display(self): return force_text(self.status) def get_tracking_codes(self): return [ shipment.tracking_code for shipment in self.shipments.all_except_deleted() if shipment.tracking_code ] def can_edit(self): return (not self.has_refunds() and not self.is_canceled() and not self.is_complete() and self.shipping_status == ShippingStatus.NOT_SHIPPED and self.payment_status == PaymentStatus.NOT_PAID) def get_customer_name(self): name_attrs = [ "customer", "billing_address", "orderer", "shipping_address" ] for attr in name_attrs: if getattr(self, "%s_id" % attr): return getattr(self, attr).name OrderLogEntry = define_log_model(Order)
# -*- coding: utf-8 -*- # This file is part of Shuup. # # Copyright (c) 2012-2016, Shoop Ltd. All rights reserved. # # This source code is licensed under the AGPLv3 license found in the # LICENSE file in the root directory of this source tree. from django.db import models from django.utils.translation import ugettext_lazy as _ from shuup.core.fields import QuantityField from shuup.utils.analog import define_log_model class SuppliedProduct(models.Model): supplier = models.ForeignKey("Supplier", on_delete=models.CASCADE, verbose_name=_("supplier")) product = models.ForeignKey("Product", on_delete=models.CASCADE, verbose_name=_("product")) sku = models.CharField(db_index=True, max_length=128, verbose_name=_('SKU')) alert_limit = models.IntegerField(default=0, verbose_name=_('alert limit')) physical_count = QuantityField(editable=False, verbose_name=_('physical stock count')) logical_count = QuantityField(editable=False, verbose_name=_('logical stock count')) class Meta: unique_together = (("supplier", "product", ), ) SuppliedProductLogEntry = define_log_model(SuppliedProduct)
verbose_name=_("modified on")) objects = TaskCommentQuerySet.as_manager() def reply(self, contact, body): comment = TaskComment(task=self.task, comment_author=contact, body=body) comment.full_clean() comment.save() return comment def as_html(self): return mark_safe(force_text(self.body)) def can_see(self, user): is_admin = user.is_superuser is_staff = bool(user.is_staff and user in self.task.shop.staff_members.all()) if not (is_admin or is_staff): return (self.visibility == TaskCommentVisibility.PUBLIC) elif not is_admin: return (self.visibility == TaskCommentVisibility.PUBLIC or self.visibility == TaskCommentVisibility.STAFF_ONLY) return True TaskLogEntry = define_log_model(Task)
foreign_currency = CurrencyField(default=None, blank=True, null=True, verbose_name=_('foreign amount currency')) description = models.CharField(max_length=256, blank=True, verbose_name=_('description')) class Meta: abstract = True # TODO (2.0): Rename this to OrderPayment class Payment(AbstractPayment): order = models.ForeignKey("Order", related_name='payments', on_delete=models.PROTECT, verbose_name=_('order')) class Meta: verbose_name = _('payment') verbose_name_plural = _('payments') @property def currency(self): return self.order.currency PaymentLogEntry = define_log_model(Payment)
def get_serialized_steps(self): return [step.serialize() for step in self.get_steps()] def set_serialized_steps(self, serialized_data): self._steps = None self._step_data = serialized_data # Poor man's validation for step in self.get_steps(): pass @property def event_class(self): return Event.class_for_identifier(self.event_identifier) def __str__(self): return self.name def execute(self, context): """ Execute the script in the given context. :param context: Script context :type context: shuup.notify.script.Context """ for step in self.get_steps(): if step.execute(context) == StepNext.STOP: break ScriptLogEntry = define_log_model(Script)
class Meta: verbose_name = _("custom payment processor") verbose_name_plural = _("custom payment processors") def get_service_choices(self): return [ ServiceChoice('manual', _("Manually processed payment")), ServiceChoice('cash', _("Cash payment")) ] def _create_service(self, choice_identifier, **kwargs): service = super(CustomPaymentProcessor, self)._create_service(choice_identifier, **kwargs) if choice_identifier == 'cash': service.behavior_components.add( StaffOnlyBehaviorComponent.objects.create()) return service def process_payment_return_request(self, service, order, request): if service == 'cash': if not order.is_paid(): order.create_payment(order.taxful_total_price, payment_identifier="Cash-%s" % now().isoformat(), description="Cash Payment") PaymentMethodLogEntry = define_log_model(PaymentMethod) PaymentProcessorLogEntry = define_log_model(PaymentProcessor)
quantity=None, shipping_address=None): supplier_strategy = cached_load( "SHUUP_SHOP_PRODUCT_SUPPLIERS_STRATEGY") kwargs = { "shop_product": self, "customer": customer, "quantity": quantity, "shipping_address": shipping_address } return supplier_strategy().get_supplier(**kwargs) def __str__(self): return self.get_name() def get_name(self): return self._safe_get_string("name") def get_description(self): return self._safe_get_string("description") def get_short_description(self): return self._safe_get_string("short_description") def _safe_get_string(self, key): return (self.safe_translation_getter(key, any_language=True) or self.product.safe_translation_getter(key, any_language=True)) ShopProductLogEntry = define_log_model(ShopProduct)
applied_attr.set_current_language(language) if not attr.is_translated and attr.is_null_value(value): # Trying to set a null value for an untranslated attribute, # so we can just get rid of the applied object altogether. # TODO: Do the same sort of cleanup for translated attributes. if applied_attr.pk: applied_attr.delete() return # Set the value and save the attribute (possibly new) applied_attr.value = value applied_attr.save() return applied_attr def clear_attribute_value(self, identifier, language=None): avail_attrs = self.get_available_attribute_queryset() attr = avail_attrs.get(identifier=identifier) attr_val = self.attributes.filter(attribute=attr).first() if not attr_val: return if language is None: # Delete all translations attr_val.delete() return trans = attr_val.translations.filter(language_code=language).first() if trans: trans.delete() AttributeLogEntry = define_log_model(Attribute)
translations = TranslatedFields( name=models.CharField(max_length=64, verbose_name=_("name")), public_name=models.CharField(max_length=64, verbose_name=_("public name")), maintenance_message=models.CharField(max_length=300, blank=True, verbose_name=_("maintenance message")) ) def __str__(self): return self.safe_translation_getter("name", default="Shop %d" % self.pk) def create_price(self, value): """ Create a price with given value and settings of this shop. Takes the ``prices_include_tax`` and ``currency`` settings of this Shop into account. :type value: decimal.Decimal|int|str :rtype: shuup.core.pricing.Price """ if self.prices_include_tax: return TaxfulPrice(value, self.currency) else: return TaxlessPrice(value, self.currency) def _are_changes_protected(self): return Order.objects.filter(shop=self).exists() ShopLogEntry = define_log_model(Shop)
verbose_name_plural = _("currencies") def __str__(self): return self.code def get_currency_precision(currency): """ Get precision by currency code. Precision values will be populated from the ``decimal_places`` fields of the `Currency` objects in the database. :type currency: str :param currency: Currency code as 3-letter string (ISO-4217). :rtype: decimal.Decimal|None :return: Precision value for a given currency code or None for unknown. """ cache_key = "currency_precision:" + currency precision = cache.get(cache_key) if precision is None: currency_obj = Currency.objects.filter(code=currency).first() precision = decimal.Decimal( "0.1")**currency_obj.decimal_places if currency_obj else None cache.set(cache_key, precision) return precision CurrencyLogEntry = define_log_model(Currency)
ProductPackageLink.objects.filter(child=self).values_list("parent", flat=True) )) def get_all_package_children(self): return Product.objects.filter(pk__in=( ProductPackageLink.objects.filter(parent=self).values_list("child", flat=True) )) def get_public_media(self): return self.media.filter(enabled=True, public=True) def is_stocked(self): return (self.stock_behavior == StockBehavior.STOCKED) ProductLogEntry = define_log_model(Product) class ProductCrossSell(models.Model): product1 = models.ForeignKey( Product, related_name="cross_sell_1", on_delete=models.CASCADE, verbose_name=_("primary product")) product2 = models.ForeignKey( Product, related_name="cross_sell_2", on_delete=models.CASCADE, verbose_name=_("secondary product")) weight = models.IntegerField(default=0, verbose_name=_("weight")) type = EnumIntegerField(ProductCrossSellType, verbose_name=_("type")) class Meta: verbose_name = _('cross sell link') verbose_name_plural = _('cross sell links')
on_delete=models.CASCADE, verbose_name=_("product")) quantity = QuantityField(verbose_name=_("quantity")) unit_volume = MeasurementField(unit=get_shuup_volume_unit(), verbose_name=_("unit volume ({})".format( get_shuup_volume_unit()))) unit_weight = MeasurementField(unit=settings.SHUUP_MASS_UNIT, verbose_name=_("unit weight ({})".format( settings.SHUUP_MASS_UNIT))) class Meta: verbose_name = _('sent product') verbose_name_plural = _('sent products') def __str__(self): # pragma: no cover return "%(quantity)s of '%(product)s' in Shipment #%(shipment_pk)s" % { 'product': self.product, 'quantity': self.quantity, 'shipment_pk': self.shipment_id, } def cache_values(self): prod = self.product self.unit_volume = prod.width * prod.height * prod.depth self.unit_weight = prod.gross_weight ShipmentLogEntry = define_log_model(Shipment) ShipmentProductLogEntry = define_log_model(ShipmentProduct)
if self.usages.filter(order__customer=customer, coupon=self).count() >= self.usage_limit_customer: return False return not self.exhausted def use(self, order): return CouponUsage.add_usage(order=order, coupon=self) def increase_customer_usage_limit_by(self, amount): if self.usage_limit_customer: new_limit = self.usage_limit_customer + amount else: new_limit = self.usages.count() + amount self.usage_limit_customer = new_limit def increase_usage_limit_by(self, amount): self.usage_limit = self.usage_limit + amount if self.usage_limit else (self.usages.count() + amount) def has_been_used(self, usage_count=1): """ See if code was already used the number of maximum times given """ return CouponUsage.objects.filter(coupon=self).count() >= usage_count def __str__(self): return self.code CatalogCampaignLogEntry = define_log_model(CatalogCampaign) BasketCampaignLogEntry = define_log_model(BasketCampaign) CouponLogEntry = define_log_model(Coupon) CouponUsageLogEntry = define_log_model(CouponUsage)
name=models.CharField(max_length=100, verbose_name=_('name'), help_text=_( "The customer tax group name. " "Customer tax groups can be used to control how taxes are applied to a set of customers. " ) ), ) enabled = models.BooleanField(default=True, verbose_name=_('enabled')) class Meta: verbose_name = _('customer tax group') verbose_name_plural = _('customer tax groups') @classmethod def get_default_person_group(cls): obj, c = CustomerTaxGroup.objects.get_or_create(identifier="default_person_customers", defaults={ "name": _("Retail Customers") }) return obj @classmethod def get_default_company_group(cls): obj, c = CustomerTaxGroup.objects.get_or_create(identifier="default_company_customers", defaults={ "name": _("Company Customers") }) return obj TaxLogEntry = define_log_model(Tax) TaxClassLogEntry = define_log_model(TaxClass) CustomerTaxGroupLogEntry = define_log_model(CustomerTaxGroup)
'is_active': user.is_active, 'first_name': getattr(user, 'first_name', ''), 'last_name': getattr(user, 'last_name', ''), 'email': getattr(user, 'email', ''), } return PersonContact.objects.get_or_create(user=user, defaults=defaults)[0] def get_company_contact(user): """ Get preferred CompanyContact of given user. If user has associated PersonContact which is member of CompanyContact, return CompanyContact. Otherwise, return None. :param user: User object (or None) to get contact for :type user: django.contrib.auth.models.User|None :return: CompanyContact (or none) of which user's PersonContact is a member :rtype: CompanyContact|None """ contact = get_person_contact(user) if not contact: return None return contact.company_memberships.filter(is_active=True).first() CompanyContactLogEntry = define_log_model(CompanyContact) PersonContactLogEntry = define_log_model(PersonContact) ContactGroupLogEntry = define_log_model(ContactGroup)