Exemple #1
0
def test_units_match():
    class XxxMoney(int):
        currency = 'XXX'

    m1 = Money(1, 'EUR')
    m2 = Money(2, 'EUR')
    m3 = Money(3, 'XXX')
    m4 = XxxMoney(4)

    assert m1.unit_matches_with(m2)
    assert not m1.unit_matches_with(m3)
    assert m3.unit_matches_with(m4)
Exemple #2
0
def test_tax_special_cases1():
    all_tax_line1 = Line(base_unit_price=TaxfulPrice(25, 'EUR'),
                         quantity=5,
                         discount_amount=TaxfulPrice(25, 'EUR'),
                         tax_amount=Money(100, 'EUR'))
    assert all_tax_line1.taxful_price == TaxfulPrice(100, 'EUR')
    assert all_tax_line1.taxless_price == TaxlessPrice(0, 'EUR')
    assert all_tax_line1.taxful_discount_amount == TaxfulPrice(25, 'EUR')
    assert all_tax_line1.taxless_discount_amount == TaxlessPrice(0, 'EUR')
    assert all_tax_line1.tax_rate == 0
    assert all_tax_line1.taxful_base_unit_price == TaxfulPrice(25, 'EUR')
    assert all_tax_line1.taxless_base_unit_price == TaxlessPrice(0, 'EUR')
Exemple #3
0
    def get_data(self, **kwargs):
        orders = super(RefundedSalesReport, self).get_objects().filter(
            lines__type=OrderLineType.REFUND).distinct()
        total_refunded = Money(0, self.shop.currency)

        for order in orders:
            total_refunded += order.get_total_refunded_amount()

        data = [{
            "refunded_orders": len(orders),
            "total_refunded": total_refunded.value
        }]
        return self.get_return_data(data, has_totals=False)
Exemple #4
0
def test_can_create_refund():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    assert order.can_create_payment()

    # Partially refunded orders can create refunds
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert order.can_create_refund()

    # But fully refunded orders can't
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert not order.can_create_refund()
Exemple #5
0
def test_max_refundable_amount():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    assert len(order.lines.all()) == 1

    line = order.lines.first()
    assert line.max_refundable_amount == line.taxful_price.amount

    partial_refund_amount = Money(10, order.currency)
    assert partial_refund_amount.value > 0

    order.create_refund([{"line": line, "quantity": 1, "amount": partial_refund_amount}])
    assert line.max_refundable_amount == line.taxful_price.amount - partial_refund_amount
    assert order.get_total_tax_amount() == Money(
        order.taxful_total_price_value - order.taxless_total_price_value,
        order.currency)
Exemple #6
0
def test_convert_taxness_taxless_to_taxful():
    request = get_request()
    tax_class = TaxClass()
    item = Product(tax_class=tax_class)
    priceful = _get_price_info(TaxlessPrice)
    calcs_done_before = DummyTaxModule.calculations_done
    result = convert_taxness(request, item, priceful, with_taxes=True)
    calcs_done_after = DummyTaxModule.calculations_done
    assert result != priceful
    assert result.price == TaxfulPrice(576, 'USD')
    assert result.base_price == TaxfulPrice(792, 'USD')
    assert result.quantity == 2
    assert result.tax_amount == Money(96, 'USD')
    assert result.taxful_price == result.price
    assert result.taxless_price == priceful.price
    assert calcs_done_after == calcs_done_before + 2
Exemple #7
0
 def form_valid(self, form):
     order = self.object
     amount = Money(form.cleaned_data["amount"], order.currency)
     if amount.value == 0:
         messages.error(self.request, _("Payment amount cannot be 0"))
         return self.form_invalid(form)
     try:
         payment = order.create_payment(amount,
                                        description="Manual payment")
         messages.success(
             self.request,
             _("Payment %s created.") % payment.payment_identifier)
     except NoPaymentToCreateException:
         messages.error(self.request, _("Order has already been paid"))
         return self.form_invalid(form)
     else:
         return HttpResponseRedirect(get_model_url(order))
Exemple #8
0
def test_mixed_chart():
    labels = ["One", "Two", "Three"]
    locale = "pt_br"
    currency = "BRL"
    chart = MixedChart("ma biultiful xart",
                       labels,
                       data_type=ChartDataType.CURRENCY,
                       locale=locale,
                       currency=currency)

    dataset1 = OrderedDict({
        "type": ChartType.BAR,
        "label": "some bars #1",
        "data": [1, 2, 3]
    })
    dataset2 = OrderedDict({
        "type": ChartType.BAR,
        "label": "some bars #2",
        "data": [2, 3, 4]
    })
    dataset3 = OrderedDict({
        "type": ChartType.LINE,
        "label": "some lines #1",
        "data": [5, 6, 7]
    })
    dataset4 = OrderedDict({
        "type": ChartType.LINE,
        "label": "some lines #2",
        "data": [8, 9, 10]
    })
    datasets = [dataset1, dataset2, dataset3, dataset4]

    for dataset in datasets:
        chart.add_data(dataset["label"], dataset["data"], dataset["type"])

    chart_config = chart.get_config()
    assert chart_config["type"] == "mixed"
    assert chart_config["labels"] == labels

    for i in range(len(chart_config["data"])):
        for j in range(len(chart_config["data"][i]["data"])):
            assert chart_config["data"][i]["data"][j] == datasets[i]["data"][j]

            formatted_data = chart_config["data"][i]["formatted_data"][j]
            assert formatted_data == format_money(
                Money(datasets[i]["data"][j], currency=currency).as_rounded())
Exemple #9
0
def _get_order(prices_include_tax=False, include_basket_campaign=False, include_catalog_campaign=False):
    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if include_basket_campaign:
        _add_basket_campaign(shop)

    if include_catalog_campaign:
        _add_catalog_campaign(shop)
    _add_taxes()

    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact())
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(
            sku=product_data.pop("sku"),
            shop=shop,
            supplier=supplier,
            stock_behavior=StockBehavior.STOCKED,
            tax_class=get_default_tax_class(),
            **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=product,
            supplier=supplier,
            quantity=quantity,
            base_unit_price=pi.base_unit_price,
            discount_amount=pi.discount_amount
        )
    oc = OrderCreator()
    order = oc.create_order(source)
    order.create_payment(Money("1", "EUR"))
    assert not order.has_refunds()
    assert order.can_create_refund()
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.payment_status == PaymentStatus.PARTIALLY_PAID
    return order
Exemple #10
0
 def post(self, request, *args, **kwargs):
     order = self.object = self.get_object()
     error = False
     if order.payment_status not in (PaymentStatus.DEFERRED,
                                     PaymentStatus.NOT_PAID):
         error = True
         messages.error(
             self.request,
             _("Only orders which are not paid or deferred can be set as paid."
               ))
     if order.taxful_total_price:
         error = True
         messages.error(
             self.request,
             _("Only zero price orders can be set as paid without creating a payment."
               ))
     if not error:
         amount = Money(0, order.shop.currency)
         order.create_payment(amount, description=_("Zero amount payment"))
         messages.success(self.request, _("Order marked as paid."))
     return HttpResponseRedirect(get_model_url(self.get_object()))
Exemple #11
0
    def _get_refund_line_info(self, order, data):
        refund_line_info = {}
        amount_value = data.get("amount", 0) or 0
        line_number = data.get("line_number")
        quantity = data.get("quantity", 0) or 1
        restock_products = data.get("restock_products")

        if line_number != "amount":
            line = order.lines.filter(ordering=line_number).first()

            if not line:
                return None
            refund_line_info["line"] = line
            refund_line_info["quantity"] = quantity
            refund_line_info["restock_products"] = bool(restock_products)
        else:
            refund_line_info["line"] = "amount"
            refund_line_info["text"] = data.get("text")
            refund_line_info["quantity"] = 1
        refund_line_info["amount"] = Money(amount_value, order.currency)
        return refund_line_info
Exemple #12
0
    def add_data(self, name, data, chart_type):
        """
        Add data to this chart
        :param name: the name of the dataset
        :type name: str
        :param data: the list of data
        :type data: list[int|float|Decimal]
        :param chart_type: the chart type - tells how data should be rendered.
            This data type must be available in the `supported_chart_type` attribute of this instance
        :type chart_type: ChartType
        """
        assert chart_type in self.supported_chart_types
        formatted_data = []

        # format value for each data point
        if self.data_type == ChartDataType.CURRENCY:
            for value in data:
                formatted_data.append(
                    format_money(
                        Money(value, currency=self.currency).as_rounded()))

        elif self.data_type == ChartDataType.PERCENT:
            for value in data:
                formatted_data.append(format_percent(value,
                                                     locale=self.locale))

        # self.data_type == ChartDataType.NUMBER
        else:
            for value in data:
                formatted_data.append(format_decimal(value,
                                                     locale=self.locale))

        self.datasets.append({
            "type": chart_type,
            "label": name,
            "data": data,
            "formatted_data": formatted_data
        })
Exemple #13
0
def test_money_without_currency():
    with pytest.raises(TypeError):
        Money(42)
Exemple #14
0
 def money_round(value):
     return Money(value, shop.currency).as_rounded(2)
Exemple #15
0
def test_repr():
    assert repr(Money(42, 'EUR')) == "Money('42', 'EUR')"
    assert repr(Money('42.123', 'EUR')) == "Money('42.123', 'EUR')"
    assert repr(Money('42.0', 'EUR')) == "Money('42.0', 'EUR')"
    assert repr(Money('42.123', 'EUR')) == "Money('42.123', 'EUR')"
    assert repr(Money('42.123', 'USD')) == "Money('42.123', 'USD')"
Exemple #16
0
def usd(value):
    """
    Get Money with USD currency for given value.
    """
    return Money(value, "USD")
Exemple #17
0
def test_refunds():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    tax_rate = Decimal("0.1")
    taxless_base_unit_price = shop.create_price(200)
    order = create_order_with_product(product, supplier, 3, taxless_base_unit_price, tax_rate, shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    assert order.get_total_refunded_amount().value == 0
    assert order.get_total_unrefunded_amount().value == order.taxful_total_price.value
    assert not order.can_edit()

    assert len(order.lines.all()) == 1

    product_line = order.lines.first()
    assert product_line.ordering == 0
    assert order.can_create_refund()
    assert not order.has_refunds()

    order.create_refund([{"line": product_line, "quantity": 1, "amount": (product_line.taxful_price.amount / 3)}])
    assert len(order.lines.all()) == 2
    assert order.lines.last().ordering == 1
    assert order.has_refunds()

    # Confirm the value of the refund
    assert order.lines.last().taxful_price == -product_line.base_unit_price
    assert order.lines.last().tax_amount == -(product_line.taxless_base_unit_price * tax_rate).amount

    # Create a refund with a parent line and amount
    order.create_refund([{"line": product_line, "quantity": 1, "amount": product_line.taxful_price.amount / 3}])
    assert len(order.lines.all()) == 3
    assert order.lines.last().ordering == 2

    assert order.lines.last().taxful_price.amount == -taxless_base_unit_price.amount * (1 + tax_rate)
    assert order.lines.last().tax_amount == -taxless_base_unit_price.amount * tax_rate

    assert order.taxless_total_price.amount == taxless_base_unit_price.amount
    assert order.taxful_total_price.amount == taxless_base_unit_price.amount * (1 + tax_rate)
    assert order.can_create_refund()
    assert order.get_total_tax_amount() == Money(
        (order.taxful_total_price_value - order.taxless_total_price_value),
        order.currency)

    # Try to refunding remaining amount without a parent line
    with pytest.raises(AssertionError):
        order.create_refund([{"amount": taxless_base_unit_price}])

    # refund remaining amount
    order.create_refund([{"line": product_line, "quantity": 1, "amount": product_line.taxful_price.amount / 3}])
    assert len(order.lines.all()) == 4
    assert order.lines.last().ordering == 3
    assert order.lines.last().taxful_price.amount == -taxless_base_unit_price.amount * (1 + tax_rate)

    assert not order.taxful_total_price.amount
    assert not order.can_create_refund()
    assert order.get_total_tax_amount() == Money(
        (order.taxful_total_price_value - order.taxless_total_price_value),
        order.currency)

    with pytest.raises(RefundExceedsAmountException):
        order.create_refund([{"line": product_line, "quantity": 1, "amount": taxless_base_unit_price.amount}])
Exemple #18
0
 def create_refund():
     order.create_refund([
         {"line": product_line, "quantity": 1, "amount": Money(1, order.currency), "restock_products": restock}])
Exemple #19
0
def test_money_init_does_not_call_settings():
    def guarded_getattr(self, name):
        assert False, 'nobody should read settings yet'

    with patch.object(type(settings), '__getattr__', guarded_getattr):
        Money(42, 'EUR')
Exemple #20
0
    base_unit_price = None
    quantity = None
    discount_amount = None
    tax_amount = None

    def __init__(self, base_unit_price, quantity, discount_amount, tax_amount):
        self.base_unit_price = base_unit_price
        self.quantity = quantity
        self.discount_amount = discount_amount
        self.tax_amount = tax_amount


line = Line(base_unit_price=TaxfulPrice(5, 'EUR'),
            quantity=9,
            discount_amount=TaxfulPrice(12, 'EUR'),
            tax_amount=Money(3, 'EUR'))
line2 = Line(base_unit_price=TaxfulPrice(10, 'EUR'),
             quantity=123,
             discount_amount=TaxfulPrice(0, 'EUR'),
             tax_amount=Money(123, 'EUR'))


def setup_module(module):
    # uses the get_precision to avoiding db hits
    set_precision_provider(babel_precision_provider.get_precision)


def test_price():
    assert line.price == TaxfulPrice(33, 'EUR')  # 5 * 9 - 12

Exemple #21
0
def test_money_property_set_invalid_unit():
    w = get_wallet()
    with pytest.raises(UnitMixupError):
        w.amount = Money(3, 'USD')
Exemple #22
0
def test_money_property_get():
    w = get_wallet()
    assert w.amount == Money(42, 'EUR')
Exemple #23
0
def test_str():
    assert str(Money('42.25', 'EUR')) == '42.25 EUR'
    assert str(Money('100', 'USD')) == '100 USD'

    assert str(Money(42, 'EUR')) == '42 EUR'
    assert str(Money('12.345', 'EUR')) == '12.345 EUR'
Exemple #24
0
 def tax_amount(self):
     """
     :rtype: wshop.utils.money.Money
     """
     zero = Money(0, self.order.currency)
     return sum((x.amount for x in self.taxes.all()), zero)
Exemple #25
0
def test_format_money():
    assert format_money(Money("3.6", "EUR"), locale="fi") == "3,60\xa0\u20ac"
    assert format_money(Money("3.6", "EUR"), widen=2,
                        locale="fi") == "3,6000\xa0\u20ac"
    assert format_money(Money("3.6", "EUR"), digits=0,
                        locale="fi") == "4\xa0\u20ac"
Exemple #26
0
def test_money_init_from_value_with_currency():
    class Dollar(int):
        currency = 'USD'

    assert Money(Dollar(42)) == Money(42, 'USD')
Exemple #27
0
def test_refunds(admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    tax_rate = Decimal("0.1")
    taxless_base_unit_price = shop.create_price(200)
    order = create_order_with_product(product,
                                      supplier,
                                      3,
                                      taxless_base_unit_price,
                                      tax_rate,
                                      shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    assert len(order.lines.all()) == 1
    assert order.can_create_refund()
    assert not order.has_refunds()

    client = _get_client(admin_user)

    # Refund first and the only order line in 3 parts
    refund_url = "/api/wshop/order/%s/create_refund/" % order.id
    product_line = order.lines.first()
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1,
            "amount": (product_line.taxful_price.amount.value / 3),
            "restock_products": False
        }]
    }

    # First refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 2
    assert order.has_refunds()

    # Second refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 3
    assert order.can_create_refund()

    # Third refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 4
    assert not order.can_create_refund()
    assert not order.taxful_total_price.amount
    assert order.get_total_tax_amount() == Money(
        (order.taxful_total_price_value - order.taxless_total_price_value),
        order.currency)

    # Test error message
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    error_msg = json.loads(response.content.decode("utf-8"))["error"]
    assert error_msg == "Order can not be refunded at the moment."
Exemple #28
0
 def money_sum(iterable):
     return sum(iterable, Money(0, price.currency))
Exemple #29
0
def test_broken_order(admin_user):
    """
    """
    quantities = [44, 23, 65]
    expected = sum(quantities) * 50
    expected_based_on = expected / 1.5

    # Wshop is calculating taxes per line so there will be some "errors"
    expected_based_on = ensure_decimal_places(
        Decimal("%s" % (expected_based_on + 0.01)))

    shop = get_default_shop()

    supplier = get_default_supplier()
    product1 = create_product("simple-test-product1", shop, supplier, 50)
    product2 = create_product("simple-test-product2", shop, supplier, 50)
    product3 = create_product("simple-test-product3", shop, supplier, 50)

    tax = get_default_tax()

    source = BasketishOrderSource(get_default_shop())
    billing_address = get_address(country="US")
    shipping_address = get_address(name="Test street", country="US")
    source.status = get_initial_order_status()
    source.billing_address = billing_address
    source.shipping_address = shipping_address
    source.customer = create_random_person()
    source.payment_method = get_default_payment_method()
    source.shipping_method = get_default_shipping_method()

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product1,
        supplier=get_default_supplier(),
        quantity=quantities[0],
        base_unit_price=source.create_price(50),
    )

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product2,
        supplier=get_default_supplier(),
        quantity=quantities[1],
        base_unit_price=source.create_price(50),
    )

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product3,
        supplier=get_default_supplier(),
        quantity=quantities[2],
        base_unit_price=source.create_price(50),
    )

    currency = "EUR"
    summary = source.get_tax_summary()

    assert len(summary) == 1
    summary = summary[0]

    assert summary.taxful == Money(expected, "EUR")
    assert summary.based_on == Money(expected_based_on, "EUR")

    # originally non-rounded value
    assert bankers_round(source.get_total_tax_amount()) == summary.tax_amount

    assert source.taxless_total_price.value == expected_based_on
    assert summary.taxful.value == source.taxful_total_price.value

    assert summary.tax_amount == Money(
        bankers_round(source.taxful_total_price.value -
                      source.taxless_total_price.value), currency)
    assert summary.taxful == summary.raw_based_on + summary.tax_amount

    assert summary.tax_rate == tax.rate
    assert summary.taxful.value == (
        summary.based_on + summary.tax_amount).value - Decimal("%s" % 0.01)

    # create order from basket
    creator = OrderCreator()
    order = creator.create_order(source)
    assert order.taxless_total_price.value == expected_based_on

    # originally non-rounded value
    assert bankers_round(order.get_total_tax_amount()) == summary.tax_amount
Exemple #30
0
def test_money_init_from_money():
    assert Money(Money(123, 'GBP')) == Money(123, 'GBP')