def add_extra_cart_row(self, cart, request): """ Add a field on cart.extra_price_fields: """ subtotal10 = (cart.items.filter(product__tax_switch=False).values( 'quantity', 'product__unit_price').aggregate(total=ExpressionWrapper( Sum(F('quantity') * F('product__unit_price')), DecimalField())) )['total'] # 10 percent tax subtotal20 = (cart.items.filter(product__tax_switch=True).values( 'quantity', 'product__unit_price').aggregate(total=ExpressionWrapper( Sum(F('quantity') * F('product__unit_price')), DecimalField())) )['total'] # 20 percent tax amount10 = (subtotal10 or 0) * self.taxes10 amount20 = (subtotal20 or 0) * self.taxes20 instance10 = { 'label': _("{}% VAT incl.").format(settings.SHOP_VALUE_ADDED_TAX10), 'amount': Money(amount10), } instance20 = { 'label': _("{}% VAT incl.").format(settings.SHOP_VALUE_ADDED_TAX), 'amount': Money(amount20), } cart.extra_rows[self.identifier + '10'] = ExtraCartRow(instance10) cart.extra_rows[self.identifier + '20'] = ExtraCartRow(instance20)
def create_products(self): manufacturer = Manufacturer.objects.create(name="SanDisk") sdhc_4gb = SmartCard.objects.create( product_name="SDHC Card 4GB", slug="sdhc-card-4gb", unit_price=Money('3.99'), caption="Dependability and solid performance", manufacturer=manufacturer, card_type="SDHC", storage=4, speed=4, product_code="sd1041", description="SanDisk SDHC and SDXC memory cards are great", order=1) ProductPage.objects.create(page=self.shop_page, product=sdhc_4gb) ProductPage.objects.create(page=self.smartcards_page, product=sdhc_4gb) xtr_sdhc_16gb = SmartCard.objects.create( product_name="EXTREME PLUS SDHC 16GB", slug="extreme-plus-sdhc-16gb", unit_price=Money('8.49'), caption="Up to 80/60MB/s read/write speed", manufacturer=manufacturer, card_type="SDHC", storage=16, speed=80, product_code="sd2016", description= "SanDisk Extreme memory cards offer speed, capacity, and durability", order=2, ) ProductPage.objects.create(page=self.shop_page, product=xtr_sdhc_16gb) ProductPage.objects.create(page=self.smartcards_page, product=xtr_sdhc_16gb)
def get_default_caption_data(cls): return { 'num_items': 0, 'total_quantity': 0, 'subtotal': Money(), 'total': Money() }
def get_price_steps(steps=5, products=None): """ Returns min and max price with the steps in between. {% get_price_steps 3 products as price_steps %} """ queryset = Product.objects.active().top_level() if products is not None: queryset = queryset.filter(id__in=[x.id for x in products]) if not queryset: return [] queryset = queryset.order_by('_unit_price') min_price, max_price = math.floor(queryset.first().unit_price), math.ceil( queryset.last().unit_price) if max_price == min_price: return [Money(min_price)] price_steps = [Money(min_price)] chunk = Money(int(max_price - min_price) / (steps + 1)) for i in range(steps): price_steps.append(price_steps[-1] + chunk) price_steps = sorted(list(set(price_steps))) price_steps.append(Money(max_price)) return price_steps
def get_default_caption_data(cls): warnings.warn("This method is deprecated") return { 'num_items': 0, 'total_quantity': 0, 'subtotal': Money(), 'total': Money() }
def add_extra_cart_row(self, cart, request): shipping_modifiers = cart_modifiers_pool.get_shipping_modifiers() if not self.is_active(cart.extra.get( 'shipping_modifier')) and len(shipping_modifiers) > 1: return # add a shipping flat fee amount = Money('5') if cart.total >= Money(100): amount = Money('0') instance = {'label': _("Shipping costs"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
def add_extra_cart_row(self, cart, request): if not self.is_active(cart.extra.get('payment_modifier')) and len(cart_modifiers_pool.get_payment_modifiers()) > 1: return False amount = Money('30') instance = {'label': _("Extra charge by post"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
def add_extra_cart_row(self, cart, request): if not self.is_active(cart.extra.get('shipping_modifier')) and len( cart_modifiers_pool.get_shipping_modifiers()) > 1: return amount = Money(settings.WELTLADEN_BIKING_PRICE) instance = {'label': _("Shipping costs"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
def create_modifier(self, name, amount=0, percent=None, **kwargs): attrs = { 'name': name, 'code': slugify(name), 'amount': Money(amount), 'percent': D(percent) if percent else None } attrs.update(kwargs) return Modifier.objects.language().create(**attrs)
def add_extra_cart_row(self, cart, request): for modifier in Modifier.get_cart_modifiers(): if modifier.can_be_applied(request, cart=cart): amount = modifier.get_added_amount(cart.total) instance = {'label': modifier.label, 'amount': amount, 'code': self.get_applied_code(modifier)} cart.extra_rows[modifier.code] = ExtraCartRow(instance) cart.total += amount if cart.total < 0: cart.total = Money(0)
def add_extra_cart_item_row(self, cart_item, request): for modifier in cart_item.product.get_modifiers(): if modifier.can_be_applied(request, cart_item=cart_item): amount = modifier.get_added_amount(cart_item.line_total, cart_item.quantity) instance = {'label': modifier.label, 'amount': amount, 'code': self.get_applied_code(modifier)} cart_item.extra_rows[modifier.code] = ExtraCartRow(instance) cart_item.line_total += amount if cart_item.line_total < 0: cart_item.line_total = Money(0)
def add_extra_cart_row(self, cart, request): if not self.is_active(cart) and len( cart_modifiers_pool.get_shipping_modifiers()) > 1: return # add a shipping flat fee amount = Money('3') instance = {'label': _("Courier shipping costs"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
class CartIconCaptionSerializer(serializers.ModelSerializer): """ The default serializer used to render the information nearby the cart icon symbol, normally located on the top right of e-commerce sites. """ num_items = serializers.IntegerField(read_only=True, default=0) total = MoneyField(default=Money()) class Meta: model = CartModel fields = ['num_items', 'total']
def empty_cart(rf, api_client): request = rf.get('/my-cart') request.session = api_client.session request.user = AnonymousUser() request.customer = Customer.objects.get_or_create_from_request(request) request.customer.email = '*****@*****.**' request.customer.save() cart = CartModel.objects.get_from_request(request) cart.update(request) assert cart.is_empty assert cart.subtotal == Money(0) return cart
def get_price(self, request): """ Return the starting price for instances of this smart phone model. """ if not hasattr(self, '_price'): if self.variants.exists(): currency = self.variants.first().unit_price.currency aggr = self.variants.aggregate(models.Min('unit_price')) self._price = MoneyMaker(currency)(aggr['unit_price__min']) else: self._price = Money() return self._price
def create_product(self, name, kind=Product.SINGLE, unit_price=0, **kwargs): attrs = { 'name': name, 'slug': slugify(name), 'code': slugify(name), 'kind': kind, 'unit_price': Money(unit_price) } attrs.update(kwargs) return Product.objects.language().create(**attrs)
class CommodityFactory(factory.django.DjangoModelFactory): class Meta: model = Commodity product_name = factory.fuzzy.FuzzyText(prefix='Product-') product_code = factory.Sequence(lambda n: 'article-{}'.format(n + 1)) unit_price = Money(factory.fuzzy.FuzzyDecimal(1, 100).fuzz()) slug = factory.fuzzy.FuzzyText(length=7) @classmethod def create(cls, **kwargs): product = super(CommodityFactory, cls).create(**kwargs) page = create_page("Catalog", 'page.html', 'en') ProductPageModel.objects.create(page=page, product=product) return product
def add_extra_cart_row(self, cart, request): if not self.is_active(cart.extra.get('shipping_modifier')) and len(cart_modifiers_pool.get_shipping_modifiers()) > 1: return # add a shipping flat fee amount = Money('5') if cart.total_weight<1: amount = Money('4') elif cart.total_weight >=1 and cart.total_weight < 3: amount = Money('7.5') elif cart.total_weight >=3 and cart.total_weight < 15: amount = Money('10') elif cart.total_weight >=15 and cart.total_weight < 30: amount = Money('20') elif cart.total_weight > 30: amount = Money('500') else: amount = Money('999') instance = {'label': _("Shipping costs"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
def setUp(self): self.create_request() self.mod1 = self.create_modifier('Mod1', percent=-10) self.cond1 = self.create_modifier_condition( self.mod1, 'shopit.modifier_conditions.QuantityGreaterThanCondition', 2) # noqa self.cond2 = self.create_modifier_condition( self.mod1, 'shopit.modifier_conditions.PriceGreaterThanCondition', 10) # noqa self.p1 = self.create_product('P1', unit_price=20) CartItem.objects.get_or_create(cart=self.cart, product=self.p1, quantity=1) self.cart_items = CartItem.objects.filter_cart_items( self.cart, self.request) self.cart.total = Money( sum([ x.product.get_price(self.request) * x.quantity for x in self.cart_items ]))
def add_extra_cart_row(self, cart, request): if not self.is_active(cart) and len( cart_modifiers_pool.get_shipping_modifiers()) > 1: return # postal tarifs by Siarhei if cart.total_weight < 1: amount = Money('6') elif cart.total_weight >= 1 and cart.total_weight < 3: amount = Money('9') elif cart.total_weight >= 3 and cart.total_weight < 15: amount = Money('12') elif cart.total_weight >= 15 and cart.total_weight < 30: amount = Money('23') elif cart.total_weight > 30: amount = Money('500') else: amount = Money('999') # add a shipping flat fee instance = {'label': _("Shipping costs to home"), 'amount': amount} cart.extra_rows[self.identifier] = ExtraCartRow(instance) cart.total += amount
def test_get_price(self): p = self.create_product('P', unit_price=300) self.assertEquals(self.admin.get_price(p), str(Money(300)))
def get_price(self, request): aggregate = self.variants.aggregate(models.Min('unit_price')) return Money(aggregate['unit_price__min'])
def test_get_value(self): m1 = self.create_modifier('M1', amount=-10) m2 = self.create_modifier('M2', percent=-10) self.assertEquals(self.admin.get_value(m1), str(Money(-10))) self.assertEquals(self.admin.get_value(m2), '{} %'.format(Decimal(-10)))
class Modifier(TranslatableModel): STANDARD = 'standard' DISCOUNT = 'discount' CART = 'cart' KINDS = ( (STANDARD, _('Standard')), (DISCOUNT, _('Discount')), (CART, _('Cart')), ) translations = TranslatedFields(name=models.CharField(_('Name'), max_length=128), ) code = models.SlugField( _('Code'), unique=True, help_text=_('Unique identifier for this modifier.')) amount = MoneyField( _('Amount'), default=Money(0), help_text=('Amount that should be added. Can be negative.')) percent = models.DecimalField( _('Percent'), blank=True, null=True, max_digits=4, decimal_places=2, help_text= _('Percent that should be added, overrides the amount. Can be negative.' )) kind = models.CharField( _('Kind'), max_length=16, choices=KINDS, default=STANDARD, help_text=_( 'Standard affects the product regardles, Discount checks for a "Discountable" flag on a product and should be ' 'negative, Cart will affect an entire cart.')) active = models.BooleanField( _('Active'), default=True, help_text=_('Is this modifier publicly visible.')) created_at = models.DateTimeField(_('Created at'), auto_now_add=True) updated_at = models.DateTimeField(_('Updated at'), auto_now=True) order = models.PositiveIntegerField(_('Sort'), default=0) objects = ModifierQuerySet.as_manager() class Meta: db_table = 'shopit_modifiers' verbose_name = _('Modifier') verbose_name_plural = _('Modifiers') ordering = ['order'] def __str__(self): return self.label def save(self, *args, **kwargs): self.clean() super(Modifier, self).save(*args, **kwargs) @property def label(self): return self.safe_translation_getter('name', any_language=True) @property def requires_code(self): return self.discount_codes.active().exists() @property def is_filtering_enabled(self): return Modifier.objects.filtering_enabled().active().filter( id=self.id).exists() def get_conditions(self): if not hasattr(self, '_conditions'): setattr(self, '_conditions', list(self.conditions.all())) return getattr(self, '_conditions') def get_discount_codes(self, include_added=False): key = '_discount_codes_added' if include_added else '_discount_codes' if not hasattr(self, key): setattr( self, key, list(self.discount_codes.valid(include_added=include_added))) return getattr(self, key) def get_added_amount(self, price, quantity=1): return self.percent * price / 100 if self.percent else self.amount * quantity def can_be_applied(self, request, cart_item=None, cart=None): """ Returns if a modifier can be applied to the given cart or cart item. Either `cart_item` or `cart` must be passed in. """ if cart_item is None and cart is None: return False if cart_item and not self.is_eligible_product(cart_item.product): return False for condition in self.get_conditions(): if not condition.is_met(request, cart_item, cart): return False if self.requires_code and not self.is_code_applied( cart_item.cart_id if cart_item else cart.id): return False return self.active # Should never happen to be False up to this point, but just in case. def is_eligible_product(self, product): """ Returns if modifier can be applied to the given product. """ if self.kind == self.DISCOUNT: return product.discountable return self.kind == self.STANDARD def is_code_applied(self, cart_id): """ Make sure that at least one code is applied to the given cart. """ cart_codes = CartDiscountCode.objects.filter( cart_id=cart_id).values_list('code', flat=True) for code in self.get_discount_codes(include_added=True): if code.code in cart_codes: return True return False def clean(self): if self.kind == self.DISCOUNT: if self.percent and self.percent >= 0 or not self.percent and self.amount >= 0: raise ValidationError(EM['discount_not_negative']) @classmethod def get_cart_modifiers(cls): return cls.objects.filter(kind=cls.CART)
def cart_item_condition(self, request, cart_item, value=0): return cart_item.line_total < Money(value)
def process_cart(self, cart, request): if not isinstance(cart.subtotal, AbstractMoney): # if we don't know the currency, use the default cart.subtotal = Money(cart.subtotal) cart.total = cart.subtotal return super().process_cart(cart, request)
def cart_condition(self, request, cart, value=0): return cart.total < Money(value)