Exemple #1
0
 def test_elements(self):
     p1 = ((self.ten_btc + self.twenty_btc) * 5).quantize('0.01')
     self.assertEqual(
         list(p1.elements()),
         [self.ten_btc, self.twenty_btc, 5, decimal.Decimal('0.01')])
     p2 = Price(3, history=History(1, operator.__add__, 2))
     self.assertEqual(list(p2.elements()), [1, 2])
Exemple #2
0
 def get_fixed_discount_for(self, amount):
     if self.discount_value_type == self.DISCOUNT_VALUE_FIXED:
         discount_price = Price(net=self.discount_value,
                                currency=settings.DEFAULT_CURRENCY)
         discount = FixedDiscount(amount=discount_price,
                                  name=smart_text(self))
     elif self.discount_value_type == self.DISCOUNT_VALUE_PERCENTAGE:
         discount = percentage_discount(value=self.discount_value,
                                        name=smart_text(self))
         fixed_discount_value = amount - discount.apply(amount)
         discount = FixedDiscount(amount=fixed_discount_value,
                                  name=smart_text(self))
     else:
         raise NotImplementedError('Unknown discount value type')
     if discount.amount > amount:
         return FixedDiscount(amount, name=smart_text(self))
     else:
         return discount
Exemple #3
0
def test_shipping_voucher_checkout_discountnot_applicable(settings,
                                                          is_shipping_required,
                                                          shipping_method,
                                                          discount_value,
                                                          discount_type,
                                                          apply_to, limit,
                                                          error_msg):
    settings.DEFAULT_CURRENCY = 'USD'
    checkout = Mock(is_shipping_required=is_shipping_required,
                    shipping_method=shipping_method)
    voucher = Voucher(
        code='unique', type=Voucher.SHIPPING_TYPE,
        discount_value_type=discount_type,
        discount_value=discount_value,
        limit=Price(limit, currency='USD') if limit is not None else None,
        apply_to=apply_to)
    with pytest.raises(NotApplicable) as e:
        voucher.get_discount_for_checkout(checkout)
    assert str(e.value) == error_msg
Exemple #4
0
def test_comparison():
    price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR'))
    price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR'))
    price_range1 = PriceRange(price1, price2)
    price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR'))
    price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR'))
    price_range2 = PriceRange(price3, price4)
    assert price_range1 == PriceRange(price1, price2)
    assert price_range1 != price_range2
    assert price_range1 != PriceRange(price1, price1)
    assert price_range1 != PriceRange(
        Price(Amount(10, 'USD'), Amount(15, 'USD')),
        Price(Amount(30, 'USD'), Amount(45, 'USD')))
    assert price_range1 != price1
Exemple #5
0
def order_details(request, order_pk):
    qs = (Order.objects.select_related('user', 'shipping_address',
                                       'billing_address').prefetch_related(
                                           'notes', 'payments', 'history',
                                           'groups__lines'))
    order = get_object_or_404(qs, pk=order_pk)
    notes = order.notes.all()
    all_payments = order.payments.exclude(status=PaymentStatus.INPUT)
    payment = order.payments.last()
    groups = list(order)
    captured = preauthorized = Price(0, currency=order.total.currency)
    balance = captured - order.total
    if payment:
        can_capture = (payment.status == PaymentStatus.PREAUTH and any([
            group.status != GroupStatus.CANCELLED
            for group in order.groups.all()
        ]))
        can_release = payment.status == PaymentStatus.PREAUTH
        can_refund = payment.status == PaymentStatus.CONFIRMED
        preauthorized = payment.get_total_price()
        if payment.status == PaymentStatus.CONFIRMED:
            captured = payment.get_captured_price()
            balance = captured - order.total
    else:
        can_capture = can_release = can_refund = False

    is_many_stock_locations = StockLocation.objects.count() > 1
    ctx = {
        'order': order,
        'all_payments': all_payments,
        'payment': payment,
        'notes': notes,
        'groups': groups,
        'captured': captured,
        'preauthorized': preauthorized,
        'can_capture': can_capture,
        'can_release': can_release,
        'can_refund': can_refund,
        'is_many_stock_locations': is_many_stock_locations,
        'balance': balance
    }
    return TemplateResponse(request, 'dashboard/order/detail.html', ctx)
Exemple #6
0
def test_sale_applies_to_correct_products():
    product = Product.objects.create(name='Test Product',
                                     price=10,
                                     weight=1,
                                     description='',
                                     pk=10)
    variant = ProductVariant.objects.create(product=product, sku='firstvar')
    product2 = Product.objects.create(name='Second product',
                                      price=15,
                                      weight=1,
                                      description='')
    sec_variant = ProductVariant.objects.create(product=product2,
                                                sku='secvar',
                                                pk=10)
    sale = Sale.objects.create(name='Test sale', value=5, type=Sale.FIXED)
    sale.products.add(product)
    assert product2 not in sale.products.all()
    assert sale.modifier_for_variant(variant).amount == Price(net=5,
                                                              currency='USD')
    with pytest.raises(NotApplicable):
        sale.modifier_for_variant(sec_variant)
Exemple #7
0
def test_addition():
    price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR'))
    price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR'))
    price_range1 = PriceRange(price1, price2)
    price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR'))
    price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR'))
    price_range2 = PriceRange(price3, price4)
    result = price_range1 + price_range2
    assert result.min_price == price1 + price3
    assert result.max_price == price2 + price4
    result = price_range1 + price3
    assert result.min_price == price1 + price3
    assert result.max_price == price2 + price3
    with pytest.raises(ValueError):
        price_range1 + PriceRange(Price(Amount(1, 'BTC'), Amount(1, 'BTC')),
                                  Price(Amount(2, 'BTC'), Amount(2, 'BTC')))
    with pytest.raises(ValueError):
        price_range1 + Price(Amount(1, 'BTC'), Amount(1, 'BTC'))
    with pytest.raises(TypeError):
        price_range1 + 1
Exemple #8
0
def get_tax_country_code(code, price: Union[Price,
                                            float]) -> Tuple[Price, float]:
    rate = RATES.get(code, None)
    if not rate:
        rate = RATES.get(settings.DEFAULT_TAX_RATE_COUNTRY,
                         settings.FALLBACK_TAX_RATE)

    if isinstance(rate, CountryTax):
        rate = rate.rate

    if type(price) is Price:
        gross = price.gross
        currency = price.currency
    else:
        gross = price
        currency = settings.DEFAULT_CURRENCY

    taxed = _get_taxed(rate, gross)

    p = Price(gross=Decimal(taxed), net=gross, currency=currency)

    return p, rate
Exemple #9
0
def test_subtraction():
    price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR'))
    price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR'))
    price_range1 = PriceRange(price1, price2)
    price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR'))
    price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR'))
    price_range2 = PriceRange(price3, price4)
    result = price_range2 - price_range1
    assert result.min_price == price3 - price1
    assert result.max_price == price4 - price2
    result = price_range2 - price1
    assert result.min_price == price3 - price1
    assert result.max_price == price4 - price1
    with pytest.raises(ValueError):
        price_range2 - PriceRange(Price(Amount(1, 'BTC'), Amount(1, 'BTC')),
                                  Price(Amount(2, 'BTC'), Amount(2, 'BTC')))
    with pytest.raises(ValueError):
        price_range2 - Price(Amount(1, 'BTC'), Amount(1, 'BTC'))
    with pytest.raises(TypeError):
        price_range2 - 1
Exemple #10
0
def order_details(request, order_pk):
    qs = (Order.objects.select_related('user', 'shipping_address',
                                       'billing_address').prefetch_related(
                                           'notes', 'payments', 'history',
                                           'groups', 'groups__items'))
    order = get_object_or_404(qs, pk=order_pk)
    notes = order.notes.all()
    all_payments = order.payments.all()
    payment = order.payments.last()
    groups = list(order)
    captured = preauthorized = Price(0, currency=order.get_total().currency)
    balance = captured - order.get_total()
    if payment:
        can_capture = (payment.status == 'preauth'
                       and order.status != 'cancelled')
        can_release = payment.status == 'preauth'
        can_refund = payment.status == 'confirmed'
        preauthorized = payment.get_total_price()
        if payment.status == 'confirmed':
            captured = payment.get_captured_price()
            balance = captured - order.get_total()
    else:
        can_capture = can_release = can_refund = False

    ctx = {
        'order': order,
        'all_payments': all_payments,
        'payment': payment,
        'notes': notes,
        'groups': groups,
        'captured': captured,
        'preauthorized': preauthorized,
        'can_capture': can_capture,
        'can_release': can_release,
        'can_refund': can_refund,
        'balance': balance
    }
    return TemplateResponse(request, 'dashboard/order/detail.html', ctx)
Exemple #11
0
    def test_undiscounted_variant_price_tag_without_asvar(self):
        token = mock.Mock()
        token.split_contents.return_value = ('variant_price', 'product',
                                             'currency=PLN', 'discount=0')
        parser = mock.Mock()

        def side_effect(arg):
            return template.Variable(arg)

        parser.compile_filter = mock.Mock(side_effect=side_effect)

        node = product_prices.variant_price(parser, token)

        #testing simple expresion
        self.assertEqual(node.item.var, 'product')
        self.assertEqual(node.kwargs['currency'].var, 'PLN')
        self.assertEqual(node.kwargs['discount'].var, '0')

        context = {'product': MockProduct(), 'PLN': 'PLN', '0': 0}
        result = node.render(context)
        self.assertEqual(
            result,
            Price(net=5, gross=5 * decimal.Decimal('1.9'), currency=u'PLN'))
Exemple #12
0
    def test_variant_price_tag_with_asvar(self):
        token = mock.Mock()
        token.split_contents.return_value = ('variant_price', 'product',
                                             'currency=PLN', 'as', 'price')
        parser = mock.Mock()

        def side_effect(arg):
            return template.Variable(arg)

        parser.compile_filter = mock.Mock(side_effect=side_effect)

        node = product_prices.variant_price(parser, token)
        self.assertEqual(node.item.var, 'product')
        self.assertEqual(node.kwargs['currency'].var, 'PLN')
        self.assertEqual(node.asvar, 'price')

        context = {'product': MockProduct(), 'PLN': 'PLN'}
        node.render(context)
        self.assertEqual(
            context['price'],
            Price(net=5 * decimal.Decimal('0.9'),
                  gross=(5 * decimal.Decimal('1.9') * decimal.Decimal('0.9')),
                  currency=u'PLN'))
Exemple #13
0
    def deliveries(self):
        """Return the cart split into delivery groups.

        Generates tuples consisting of a partition, its shipping cost and its
        total cost.

        Each partition is a list of tuples containing the cart line, its unit
        price and the line total.
        """
        for partition in self.cart.partition():
            if self.shipping_method and partition.is_shipping_required():
                shipping_cost = self.shipping_method.get_total()
            else:
                shipping_cost = Price(0, currency=settings.DEFAULT_CURRENCY)
            total_with_shipping = partition.get_total(
                discounts=self.cart.discounts) + shipping_cost

            partition = [
                (item, item.get_price_per_item(discounts=self.cart.discounts),
                 item.get_total(discounts=self.cart.discounts))
                for item in partition
            ]

            yield partition, shipping_cost, total_with_shipping
Exemple #14
0
def order_details(request, pk):
    order = get_object_or_404(Order.objects.prefetch_related(
        'notes', 'payments', 'history', 'groups'), pk=pk)
    notes = order.notes.all()
    payment = order.payments.last()
    groups = list(order)
    for group in groups:
        group.can_ship = (payment and payment.status == 'confirmed' and
                          group.status == 'new')

    note = OrderNote(order=order, user=request.user)
    note_form = OrderNoteForm(request.POST or None, instance=note)
    if note_form.is_valid():
        note_form.save()
        msg = _('Added note')
        order.create_history_entry(comment=msg, user=request.user)
        messages.success(request, msg)
        return redirect('dashboard:order-details', pk=pk)

    captured = preauthorized = Price(0, currency=order.get_total().currency)
    if payment:
        can_capture = (payment.status == 'preauth' and
                       order.status != 'cancelled')
        can_release = payment.status == 'preauth'
        can_refund = payment.status == 'confirmed'
        preauthorized = payment.get_total_price()
        if payment.status == 'confirmed':
            captured = payment.get_captured_price()
    else:
        can_capture = can_release = can_refund = False

    ctx = {'order': order, 'payment': payment, 'notes': notes, 'groups': groups,
           'note_form': note_form, 'captured': captured,
           'preauthorized': preauthorized, 'can_capture': can_capture,
           'can_release': can_release, 'can_refund': can_refund}
    return TemplateResponse(request, 'dashboard/order/detail.html', ctx)
Exemple #15
0
def test_get_category_variants_and_prices_product_with_many_categories(
        cart, default_category, product_in_stock):
    # Test: don't duplicate percentage voucher
    # when product is in more than one category with discount
    category = Category.objects.create(
        name='Foobar', slug='foo', parent=default_category)
    product_in_stock.price = Decimal('10.00')
    product_in_stock.save()
    product_in_stock.categories.add(category)
    variant = product_in_stock.variants.first()
    cart.add(variant, check_quantity=False)

    discounted_products = list(
        get_category_variants_and_prices(cart, default_category))
    assert len(discounted_products) == 1

    voucher = Voucher.objects.create(
        category=default_category, type=Voucher.CATEGORY_TYPE,
        discount_value='10.0', code='foobar',
        discount_value_type=Voucher.DISCOUNT_VALUE_PERCENTAGE)
    checkout_mock = Mock(spec=Checkout, cart=cart)
    discount = voucher.get_discount_for_checkout(checkout_mock)
    # 10% of 10.00 is 1.00
    assert discount.amount == Price('1.00', currency=discount.amount.currency)
Exemple #16
0
 def price(self):
     return Price(fake.pydecimal(2, 2, positive=True),
                  currency=settings.DEFAULT_CURRENCY)
Exemple #17
0
def get_cost_price(stock):
    zero_price = Price(0, 0, currency=settings.DEFAULT_CURRENCY)
    if not stock.cost_price:
        return zero_price
    return stock.cost_price
Exemple #18
0
 def get_captured_price(self):
     return Price(self.captured_amount, currency=self.currency)
Exemple #19
0
 def get_total_price(self):
     net = self.total - self.tax
     return Price(net, gross=self.total, currency=self.currency)
Exemple #20
0
 def get_price_per_item(self, **kwargs):
     return Price(net=self.unit_price_net,
                  gross=self.unit_price_gross,
                  currency=settings.DEFAULT_CURRENCY)
Exemple #21
0
 def get_total_shipping(self):
     costs = [group.shipping_price for group in self]
     if costs:
         return sum(costs[1:], costs[0])
     return Price(net=0, currency=settings.DEFAULT_CURRENCY)
Exemple #22
0
 def get_subtotal_without_voucher(self):
     if self.get_items():
         return super(Order, self).get_total()
     return Price(net=0, currency=settings.DEFAULT_CURRENCY)
Exemple #23
0
 def total(self, price):
     self.total_net = price
     self.total_tax = Price(price.tax, currency=price.currency)
Exemple #24
0
 def total(self):
     if self.total_net is not None:
         gross = self.total_net.net + self.total_tax.gross
         return Price(net=self.total_net.net,
                      gross=gross,
                      currency=settings.DEFAULT_CURRENCY)
Exemple #25
0
 def get_delivery_total(self):
     return sum([group.shipping_price for group in self.groups.all()],
                Price(0, currency=settings.DEFAULT_CURRENCY))
Exemple #26
0
 def get_total_shipping(self):
     zero = Price(0, currency=settings.DEFAULT_CURRENCY)
     cost_iterator = (shipping_cost
                      for shipment, shipping_cost, total in self.deliveries)
     total = sum(cost_iterator, zero)
     return total
Exemple #27
0
def test_total_with_discount(client, sale, request_cart, product_in_stock):
    sales = Sale.objects.all()
    variant = product_in_stock.variants.get()
    request_cart.add(variant, 1)
    line = request_cart.lines.first()
    assert line.get_total(discounts=sales) == Price(currency="USD", net=5)
Exemple #28
0
 def get_total(self):
     zero = Price(0, currency=settings.DEFAULT_CURRENCY)
     cost_iterator = (total
                      for shipment, shipping_cost, total in self.deliveries)
     total = sum(cost_iterator, zero)
     return total if self.discount is None else self.discount.apply(total)
Exemple #29
0
 def get_subtotal_without_voucher(self):
     if self.get_lines():
         return self.total
     return Price(net=0, currency=settings.DEFAULT_CURRENCY)
Exemple #30
0
 def get_price_per_item(self, **kwargs):
     gross = self.data['unit_price_gross']
     net = self.data['unit_price_net']
     return Price(net=net, gross=gross, currency=settings.DEFAULT_CURRENCY)
Exemple #31
0
    def create_order(self):
        """Create an order from the checkout session.

        Each order will get a private copy of both the billing and the shipping
        address (if shipping ).

        If any of the addresses is new and the user is logged in the address
        will also get saved to that user's address book.

        Current user's language is saved in the order so we can later determine
        which language to use when sending email.
        """
        # FIXME: save locale along with the language
        voucher = self._get_voucher(vouchers=Voucher.objects.active(
            date=date.today()).select_for_update())
        if self.voucher_code is not None and voucher is None:
            # Voucher expired in meantime, abort order placement
            return None

        if self.is_shipping_required:
            shipping_address = self._save_order_shipping_address()
            self._add_to_user_address_book(self.shipping_address,
                                           is_shipping=True)
        else:
            shipping_address = None
        billing_address = self._save_order_billing_address()
        self._add_to_user_address_book(self.billing_address, is_billing=True)

        shipping_price = (self.shipping_method.get_total()
                          if self.shipping_method else Price(
                              0, currency=settings.DEFAULT_CURRENCY))
        order_data = {
            'language_code': get_language(),
            'billing_address': billing_address,
            'shipping_address': shipping_address,
            'tracking_client_id': self.tracking_code,
            'shipping_price': shipping_price,
            'total': self.get_total()
        }

        if self.user.is_authenticated:
            order_data['user'] = self.user
            order_data['user_email'] = self.user.email
        else:
            order_data['user_email'] = self.email

        if voucher is not None:
            discount = self.discount
            order_data['voucher'] = voucher
            order_data['discount_amount'] = discount.amount
            order_data['discount_name'] = discount.name

        order = Order.objects.create(**order_data)

        for partition in self.cart.partition():
            shipping_required = partition.is_shipping_required()
            shipping_method_name = (smart_text(self.shipping_method)
                                    if shipping_required else None)
            group = order.groups.create(
                shipping_method_name=shipping_method_name)
            group.process(partition, self.cart.discounts)
            group.save()

        if voucher is not None:
            increase_voucher_usage(voucher)

        if self.note is not None and self.note:
            order.notes.create(user=order.user, content=self.note)

        return order