Example #1
0
    def _set_numeric_value(self, new_value):
        if self.attribute.type == AttributeType.BOOLEAN and new_value is None:
            """
            Wshop uses `django.forms.fields.NullBooleanField` in admin.
            Which can read in the `None` value.

            Note: This is being handled separately due backwards compatibility.
            TODO (2.0): Boolean should not be a special case and handling `None` should be
            same for every "numeric" value.
            """
            self.numeric_value = None
            self.datetime_value = None
            self.untranslated_string_value = ""
            return

        if isinstance(new_value, datetime.timedelta):
            value = new_value.total_seconds()
            if value == int(value):
                value = int(value)
        else:
            value = parse_decimal_string(new_value or 0)

        if self.attribute.type == AttributeType.INTEGER:
            value = int(value)

        if self.attribute.type == AttributeType.BOOLEAN:
            value = int(bool(value))

        self.numeric_value = value
        self.datetime_value = None
        self.untranslated_string_value = str(self.numeric_value)
        return
Example #2
0
def test_parse_decimal_string_with_dirty_input():
    assert parse_decimal_string('1e12') == Decimal(112)
    assert parse_decimal_string('foo1bar 1x2') == Decimal(112)
    assert parse_decimal_string('4a bc2def 8g.h5') == Decimal('428.5')
    assert parse_decimal_string(float('inf')) == Decimal('inf')
    assert parse_decimal_string(float('-inf')) == Decimal('-inf')
    assert str(parse_decimal_string(float('nan'))) == str(Decimal('nan'))
    assert parse_decimal_string('') == Decimal(0)
    assert parse_decimal_string(' ') == Decimal(0)
Example #3
0
    def _initialize_product_line_data(self, product, supplier, shop, quantity=0):
        if product.variation_children.count():
            raise ValueError("Attempting to add variation parent to basket")

        return {
            # TODO: FIXME: Make sure line_id's are unique (not random)
            "line_id": str(random.randint(0, 0x7FFFFFFF)),
            "product": product,
            "supplier": supplier,
            "shop": shop,
            "quantity": parse_decimal_string(quantity),
        }
Example #4
0
 def update_display_quantity(self, line, value, **kwargs):
     if not line:
         return False
     new_display_quantity = parse_decimal_string(value)
     if new_display_quantity is None:
         return False
     basket_line = self.basket.get_basket_line(line['line_id'])
     if basket_line and basket_line.product:
         unit = basket_line.shop_product.unit
         new_quantity = unit.from_display(new_display_quantity)
     else:
         new_quantity = new_display_quantity
     return self._update_quantity(line, new_quantity)
Example #5
0
    def _process_line_quantity_and_price(self, source, sline, sl_kwargs):
        quantity_val = sline.pop("quantity", None)
        try:
            sl_kwargs["quantity"] = parse_decimal_string(quantity_val)
        except Exception as exc:
            msg = _("The quantity '%(quantity)s' (for line %(text)s) is invalid (%(error)s)") % {
                "text": sl_kwargs["text"],
                "quantity": quantity_val,
                "error": exc,
            }
            self.add_error(ValidationError(msg, code="invalid_quantity"))
            return False

        is_product = bool(sline.get("type") == "product")
        price_val = sline.pop("baseUnitPrice", None) if is_product else sline.pop("unitPrice", None)
        try:
            sl_kwargs["base_unit_price"] = source.create_price(parse_decimal_string(price_val))
        except Exception as exc:
            msg = _("The price '%(price)s' (for line %(text)s) is invalid (%(error)s)") % {
                "text": sl_kwargs["text"],
                "price": price_val,
                "error": exc
            }
            self.add_error(ValidationError(msg, code="invalid_price"))
            return False

        discount_val = sline.pop("discountAmount", parse_decimal_string(str("0.00")))
        try:
            sl_kwargs["discount_amount"] = source.create_price(parse_decimal_string(discount_val))
        except Exception as exc:
            msg = _("The discount '%(discount)s' (for line %(text)s is invalid (%(error)s)") % {
                "discount": discount_val,
                "text": sl_kwargs["text"],
                "error": exc
            }
            self.add_error(ValidationError(msg, code="invalid_discount"))

        return True
Example #6
0
 def update_quantity(self, line, value, **kwargs):
     new_quantity = parse_decimal_string(value)
     if new_quantity is None:
         return False
     return self._update_quantity(line, new_quantity)
Example #7
0
def test_parse_decimal_string_with_unaccepted_input(value):
    with pytest.raises(decimal.InvalidOperation):
        parse_decimal_string(value)
Example #8
0
def test_parse_decimal_string_with_normal_input():
    assert parse_decimal_string('42') == Decimal(42)
    assert parse_decimal_string('0') == Decimal(0)
    assert parse_decimal_string(3.5) == Decimal('3.5')
    assert parse_decimal_string(-5) == Decimal(-5)
    assert parse_decimal_string('-5') == Decimal(-5)
Example #9
0
def test_parse_decimal_string_with_float_input(input_val, expected_val):
    result = parse_decimal_string(input_val)
    assert result == expected_val
Example #10
0
 def __init__(self, id, value, title, currency, **kwargs):
     self.currency = currency
     value = parse_decimal_string(value)
     value = format_currency(value, currency=self.currency, locale=get_current_babel_locale())
     super(DashboardMoneyBlock, self).__init__(id, value, title, **kwargs)
Example #11
0
 def __init__(self, id, value, title, **kwargs):
     value = parse_decimal_string(value)
     if int(value) == value:
         value = int(value)
     value = format_number(value, locale=get_current_babel_locale())
     super(DashboardNumberBlock, self).__init__(id, value, title, **kwargs)
Example #12
0
def handle_add(  # noqa (C901)
        request, basket, product_id,
        quantity=1, unit_type='internal',
        supplier_id=None, **kwargs):
    """
    Handle adding a product to the basket.

    :param product_id: product ID to add (or if `child_product_id` is truey, the parent ID)
    :param quantity: quantity of products to add
    :param child_product_id: child product ID to add (if truey)
    :param supplier_id: The supplier ID for the new line. If None, the first supplier is used.
    """
    product_id = int(product_id)

    product = get_object_or_404(Product, pk=product_id)

    if product.mode in (ProductMode.SIMPLE_VARIATION_PARENT, ProductMode.VARIABLE_VARIATION_PARENT):
        raise ValidationError("Invalid product", code="invalid_product")

    try:
        shop_product = product.get_shop_instance(shop=request.shop)
    except ShopProduct.DoesNotExist:
        raise ValidationError("Product not available in this shop", code="product_not_available_in_shop")

    if supplier_id:
        supplier = shop_product.suppliers.filter(pk=supplier_id).first()
    else:
        supplier = shop_product.get_supplier(basket.customer, quantity, basket.shipping_address)

    if not supplier:
        raise ValidationError("Invalid supplier", code="invalid_supplier")

    try:
        quantity = parse_decimal_string(quantity)
        if unit_type == 'display':
            quantity = shop_product.unit.from_display(quantity)
        if not product.sales_unit.allow_fractions:
            if quantity % 1 != 0:
                msg = _(
                    "The quantity %f is not allowed. "
                    "Please use an integer value.") % quantity
                raise ValidationError(msg, code="invalid_quantity")
            quantity = int(quantity)
    except (ValueError, decimal.InvalidOperation):
        raise ValidationError(_(u"The quantity %s is not valid.") % quantity, code="invalid_quantity")

    if quantity <= 0:
        raise ValidationError(_(u"The quantity %s is not valid.") % quantity, code="invalid_quantity")

    product_ids_and_quantities = basket.get_product_ids_and_quantities()
    already_in_basket_qty = product_ids_and_quantities.get(product.id, 0)
    shop_product.raise_if_not_orderable(
        supplier=supplier,
        quantity=(already_in_basket_qty + quantity),
        customer=basket.customer
    )

    # If the product is a package parent, also check child products
    if product.is_package_parent():
        for child_product, child_quantity in six.iteritems(product.get_package_child_to_quantity_map()):
            already_in_basket_qty = product_ids_and_quantities.get(child_product.id, 0)
            total_child_quantity = (quantity * child_quantity)
            try:
                sp = child_product.get_shop_instance(shop=request.shop)
            except ShopProduct.DoesNotExist:
                raise ProductNotOrderableProblem("%s not available in %s" % (child_product, request.shop))

            sp.raise_if_not_orderable(
                supplier=supplier,
                quantity=(already_in_basket_qty + total_child_quantity),
                customer=basket.customer
            )

    # TODO: Hook/extension point
    # if product.form:
    #     return {
    #         "error": u"Form required",
    #         "return": reverse_GET("product-form", kwargs={"pk": product.pk}, GET={"n": quantity})
    #     }

    add_product_kwargs = {
        "product": product,
        "quantity": quantity,
        "supplier": supplier,
        "shop": request.shop,
        "force_new_line": kwargs.get("force_new_line", False),
        "extra": kwargs.get("extra"),
        "parent_line": kwargs.get("parent_line")
    }
    line = basket.add_product(**add_product_kwargs)

    return {
        'ok': basket.smart_product_count,
        'line_id': line.line_id,
        'added': quantity
    }
Example #13
0
 def round(self, value):
     return bankers_round(parse_decimal_string(value), self.decimals)