예제 #1
0
def test_get_installments_12x_with_simples_intereset():
    """
        Max 12 installs with PRICE intereset
        interest_rate = 2.30%
        min_installment_amount = 30.00
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    cielo_config = CieloConfig.objects.create(shop=shop,
                                              max_installments=12,
                                              installments_without_interest=2,
                                              interest_type=InterestType.Price,
                                              interest_rate=Decimal(2.3),
                                              min_installment_amount=Decimal(30))

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE)
    installment_choices = InstallmentContext(order_total, cielo_config).get_intallments_choices()

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == len(installment_choices)

    for installment in range(len(installment_choices)):
        total = format_money(shop.create_price(installment_choices[installment][2]))
        installment_amount = format_money(shop.create_price(installment_choices[installment][1]))

        assert json_content['installments'][installment]['number'] == installment+1
        assert installment_amount in json_content['installments'][installment]['name']
        assert total in json_content['installments'][installment]['name']
예제 #2
0
def test_order_creator_customer_details(rf, admin_user):
    shop = get_default_shop()
    contact = create_random_person(locale="en_US", minimum_name_comp_len=5)
    company = create_random_company()
    group = get_default_customer_group()
    contact.groups.add(group)
    contact.company_memberships.add(company)
    contact.save()
    product = create_product(sku=printable_gibberish(), supplier=get_default_supplier(), shop=shop)
    order = create_random_order(contact, products=[product])
    request = apply_request_middleware(rf.get("/", {"command": "customer_details", "id": contact.id}), user=admin_user)
    response = OrderEditView.as_view()(request)
    data = json.loads(response.content.decode("utf8"))

    assert "customer_info" in data
    assert "order_summary" in data
    assert "recent_orders" in data
    assert data["customer_info"]["name"] == contact.full_name
    assert data["customer_info"]["phone_no"] == contact.phone
    assert data["customer_info"]["email"] == contact.email
    assert company.full_name in data["customer_info"]["companies"]
    assert group.name in data["customer_info"]["groups"]
    assert data["customer_info"]["merchant_notes"] == contact.merchant_notes
    assert len(data["order_summary"]) == 1
    assert data["order_summary"][0]["year"] == order.order_date.year
    assert data["order_summary"][0]["total"] == format_money(order.taxful_total_price)
    assert len(data["recent_orders"]) == 1
    assert data["recent_orders"][0]["status"] == order.get_status_display()
    assert data["recent_orders"][0]["total"] == format_money(order.taxful_total_price)
    assert data["recent_orders"][0]["payment_status"] == force_text(order.payment_status.label)
    assert data["recent_orders"][0]["shipment_status"] == force_text(order.shipping_status.label)
예제 #3
0
파일: edit.py 프로젝트: vishalforcode/shuup
def encode_line(line):
    if line.base_unit_price.amount.value != 0:
        discount_percent = (
            line.discount_amount.amount.value /
            (line.base_unit_price.amount.value * line.quantity))
    else:
        discount_percent = 0
    return {
        "sku":
        line.sku,
        "text":
        line.text,
        "quantity":
        format_decimal(line.quantity, locale=get_current_babel_locale()),
        "unitPrice":
        format_money(line.base_unit_price.amount),
        "discountedUnitPrice":
        format_money(line.discounted_unit_price.amount),
        "discountAmount":
        format_money(line.discount_amount.amount),
        "discountPercent":
        format_percent(discount_percent, 2),
        "taxlessTotal":
        format_money(line.taxless_price.amount),
        "taxPercentage":
        format_percent(line.tax_rate, 2),
        "taxfulTotal":
        format_money(line.taxful_price.amount)
    }
예제 #4
0
def get_price_ranges(shop, min_price, max_price, range_step):
    if range_step == 0:
        return

    ranges = []
    min_price_value = format_money(shop.create_price(min_price))
    ranges.append(("-%s" % min_price, _("Under %(min_limit)s") % {
        "min_limit": min_price_value
    }))

    for range_min in range(min_price, max_price, range_step):
        range_min_price = format_money(shop.create_price(range_min))
        range_max = range_min + range_step
        if range_max < max_price:
            range_max_price = format_money(shop.create_price(range_max))
            ranges.append((
                "%s-%s" % (range_min, range_max),
                _("%(min)s to %(max)s") %
                dict(min=range_min_price, max=range_max_price),
            ))

    max_price_value = format_money(shop.create_price(max_price))
    ranges.append(("%s-" % max_price, _("%(max_limit)s & Above") % {
        "max_limit": max_price_value
    }))
    return ranges
예제 #5
0
파일: edit.py 프로젝트: wsmoyer/shuup
 def _handle_source_data(self, request):
     self.object = self.get_object()
     state = json.loads(self.get_request_body(request))["state"]
     source = create_source_from_state(
         state,
         creator=request.user,
         ip_address=request.META.get("REMOTE_ADDR"),
         order_to_update=self.object if self.object.pk else None)
     # Calculate final lines for confirmation
     source.calculate_taxes(force_recalculate=True)
     return {
         "taxfulTotal":
         format_money(source.taxful_total_price.amount),
         "taxlessTotal":
         format_money(source.taxless_total_price.amount),
         "totalDiscountAmount":
         format_money(source.total_discount.amount),
         "orderLines": [
             encode_line(line)
             for line in source.get_final_lines(with_taxes=True)
         ],
         "billingAddress":
         source.billing_address.as_string_list()
         if source.billing_address else None,
         "shippingAddress":
         source.shipping_address.as_string_list()
         if source.shipping_address else None,
     }
예제 #6
0
def test_get_installments_3x_no_intereset():
    """
        Max 3 installs with no intereset
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    CieloConfig.objects.create(shop=shop,
                               max_installments=3,
                               installments_without_interest=3)

    order_total = PRODUCT_QTNTY * PRODUCT_PRICE
    total_price_str = "{0}".format(format_money(shop.create_price(order_total)))

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 3

    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']

    total_2x_no_interest = format_money(shop.create_price(order_total / Decimal(2)))
    assert json_content['installments'][1]['number'] == 2
    assert total_price_str in json_content['installments'][1]['name']
    assert total_2x_no_interest in json_content['installments'][1]['name']

    total_3x_no_interest = format_money(shop.create_price(order_total / Decimal(3)))
    assert json_content['installments'][2]['number'] == 3
    assert total_price_str in json_content['installments'][2]['name']
    assert total_3x_no_interest in json_content['installments'][2]['name']
예제 #7
0
파일: edit.py 프로젝트: yukimiyagi/shuup
def encode_line(line):
    return {
        "sku": line.sku,
        "text": line.text,
        "quantity": format_decimal(line.quantity, locale=get_current_babel_locale()),
        "unitPrice": format_money(line.base_unit_price.amount),
        "discountAmount": format_money(line.discount_amount.amount),
        "taxlessTotal": format_money(line.taxless_price.amount),
        "taxPercentage": format_percent(line.tax_rate, 2),
        "taxfulTotal": format_money(line.taxful_price.amount)
    }
예제 #8
0
def _test_create_full_refund(browser, live_server, order):
    url = reverse("shuup_admin:order.create-refund", kwargs={"pk": order.pk})
    browser.visit("%s%s" % (live_server, url))
    wait_until_condition(browser, lambda x: x.is_text_present("Refunded: %s" % format_money(order.shop.create_price("0.00"))))
    wait_until_condition(browser, lambda x: x.is_text_present("Remaining: %s" % format_money(order.taxful_total_price)))
    url = reverse("shuup_admin:order.create-full-refund", kwargs={"pk": order.pk})
    click_element(browser, "a[href='%s']" % url)
    wait_until_condition(browser, lambda x: x.is_text_present("Refund Amount: %s" % format_money(order.taxful_total_price)))
    click_element(browser, "#create-full-refund")
    _check_create_refund_link(browser, order, False)
    _check_order_details_visible(browser)
    order.refresh_from_db()
    assert not order.taxful_total_price
    assert order.is_paid()
    assert order.is_fully_shipped()
예제 #9
0
def _test_create_full_refund(browser, live_server, order):
    url = reverse("shuup_admin:order.create-refund", kwargs={"pk": order.pk})
    browser.visit("%s%s" % (live_server, url))
    wait_until_condition(browser, lambda x: x.is_text_present("Refunded: %s" % format_money(order.shop.create_price("0.00"))))
    wait_until_condition(browser, lambda x: x.is_text_present("Remaining: %s" % format_money(order.taxful_total_price)))
    url = reverse("shuup_admin:order.create-full-refund", kwargs={"pk": order.pk})
    click_element(browser, "a[href='%s']" % url)
    wait_until_condition(browser, lambda x: x.is_text_present("Refund Amount: %s" % format_money(order.taxful_total_price)))
    click_element(browser, "#create-full-refund")
    wait_until_appeared(browser, "#order_details")
    _check_create_refund_link(browser, order, False)
    order.refresh_from_db()
    assert not order.taxful_total_price
    assert order.is_paid()
    assert order.is_fully_shipped()
예제 #10
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())
예제 #11
0
def _test_refund_view(browser, live_server, order):
    url = reverse("shuup_admin:order.create-refund", kwargs={"pk": order.pk})
    browser.visit("%s%s" % (live_server, url))
    wait_until_condition(browser, lambda x: x.is_text_present("Refunded: %s" % format_money(order.shop.create_price("0.00"))))
    assert len(browser.find_by_css("#id_form-0-line_number option")) == 12 # blank + arbitrary amount + num lines
    click_element(browser, "#select2-id_form-0-line_number-container")
    wait_until_appeared(browser, "input.select2-search__field")
    wait_until_appeared(browser, ".select2-results__option[aria-selected='false']")
    browser.execute_script('$($(".select2-results__option")[1]).trigger({type: "mouseup"})') # select arbitrary amount
    wait_until_condition(browser, lambda x: len(x.find_by_css("#id_form-0-text")))
    wait_until_condition(browser, lambda x: len(x.find_by_css("#id_form-0-amount")))
    browser.find_by_css("#id_form-0-text").first.value = "test"
    browser.find_by_css("#id_form-0-amount").first.value = "900"
    move_to_element(browser, "#add-refund")
    click_element(browser, "#add-refund")

    # New line starts here...
    move_to_element(browser, "#add-refund")
    click_element(browser, "#select2-id_form-1-line_number-container")
    wait_until_appeared(browser, "input.select2-search__field")

    elem = browser.find_by_css("input.select2-search__field").first
    elem._element.send_keys("line 1")
    elem._element.send_keys(Keys.RETURN)

    assert decimal.Decimal(browser.find_by_css("#id_form-1-amount").first.value) == decimal.Decimal("100.00")
    assert int(decimal.Decimal(browser.find_by_css("#id_form-1-quantity").first.value)) == 10
    click_element(browser, "button[form='create_refund']")
    _check_create_refund_link(browser, order, True) # can still refund quantity
    _check_order_details_visible(browser)
    order.refresh_from_db()
    assert not order.taxful_total_price
    assert order.is_paid()
    assert not order.is_fully_shipped()
예제 #12
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())
예제 #13
0
def test_get_installments_cc_does_not_allow_installments():
    """
        Max 9 installs with SIMPLE intereset
        interest_rate = 4.00%
        Credit card does not allow installments
    """
    patch_cielo_request()

    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    CieloConfig.objects.create(shop=shop,
                               max_installments=9,
                               installments_without_interest=3,
                               interest_type=InterestType.Simple,
                               interest_rate=Decimal(4.0))

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE)
    total_price_str = "{0}".format(format_money(
        shop.create_price(order_total)))

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Discover})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 1
    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']
예제 #14
0
    def get_display_value(self, context, object):
        display_callable = maybe_callable(self.display, context=context)
        if display_callable:
            return display_callable(object)

        value = object
        for bit in self.display.split("__"):
            value = getattr(value, bit, None)

        if isinstance(value, ProductMedia):
            return "<img src='/media/%s'>" % value.get_thumbnail()

        if isinstance(value, Image):
            thumbnailer = get_thumbnailer(value)
            options = {"size": (64, 64)}
            thumbnail = thumbnailer.get_thumbnail(options, generate=True)
            return "<img src='%s'>" % thumbnail.url

        if isinstance(value, bool):
            value = yesno(value)

        if isinstance(value, Manager):
            value = ", ".join("%s" % x for x in value.all())

        if isinstance(value, datetime.datetime):
            return get_locally_formatted_datetime(value)

        if isinstance(value, Money):
            return escape(format_money(value))

        if not value:
            value = ""

        return force_text(value)
예제 #15
0
파일: _source.py 프로젝트: gurch101/shuup
    def get_validation_errors(self):
        # check for the minimum sum of order total
        min_total = configuration.get(self.shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0))
        total = (self.taxful_total_price.value if self.shop.prices_include_tax else self.taxless_total_price.value)
        if total < min_total:
            min_total_price = format_money(self.shop.create_price(min_total))
            yield ValidationError(_("The total should be greater than {} to be ordered.").format(min_total_price),
                                  code="order_total_too_low")

        shipping_method = self.shipping_method
        payment_method = self.payment_method

        if shipping_method:
            for error in shipping_method.get_unavailability_reasons(source=self):
                yield error

        if payment_method:
            for error in payment_method.get_unavailability_reasons(source=self):
                yield error

        for supplier in self._get_suppliers():
            for product, quantity in iteritems(self._get_products_and_quantities(supplier)):
                shop_product = product.get_shop_instance(shop=self.shop)
                if not shop_product:
                    yield ValidationError(
                        _("%s not available in this shop") % product.name,
                        code="product_not_available_in_shop"
                    )
                for error in shop_product.get_orderability_errors(
                        supplier=supplier, quantity=quantity, customer=self.customer):
                    error.message = "%s: %s" % (product.name, error.message)
                    yield error
예제 #16
0
파일: _source.py 프로젝트: yashodhank/shuup
    def get_validation_errors(self):  # noqa (C901)
        # check for the minimum sum of order total
        min_total = configuration.get(self.shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0))
        total = (self.taxful_total_price.value if self.shop.prices_include_tax else self.taxless_total_price.value)
        if total < min_total:
            min_total_price = format_money(self.shop.create_price(min_total))
            yield ValidationError(_("The total should be greater than {} to be ordered.").format(min_total_price),
                                  code="order_total_too_low")

        shipping_method = self.shipping_method
        payment_method = self.payment_method

        if shipping_method:
            for error in shipping_method.get_unavailability_reasons(source=self):
                yield error

        if payment_method:
            for error in payment_method.get_unavailability_reasons(source=self):
                yield error

        for supplier in self._get_suppliers():
            for product, quantity in iteritems(self._get_products_and_quantities(supplier)):
                try:
                    shop_product = product.get_shop_instance(shop=self.shop)
                except ShopProduct.DoesNotExist:
                    yield ValidationError(
                        _("%s not available in this shop") % product.name,
                        code="product_not_available_in_shop"
                    )
                    continue
                for error in shop_product.get_orderability_errors(
                        supplier=supplier, quantity=quantity, customer=self.customer):
                    error.message = "%s: %s" % (product.name, error.message)
                    yield error
예제 #17
0
파일: charts.py 프로젝트: gurch101/shuup
    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})
예제 #18
0
def format_data(data, format_iso_dates=False, format_money_values=False):
    if data is None:
        return ""

    elif isinstance(data, Money):
        if format_money_values:
            return format_money(data)
        return float(data.as_rounded().value)

    elif isinstance(data, Decimal):
        exponent = abs(data.normalize().as_tuple().exponent)
        # Limit the amount of decimals to 10
        return floatformat(data, min(exponent, 10))

    elif callable(data):
        return force_text(data())

    elif isinstance(data, Promise):
        return force_text(data)

    elif isinstance(data, models.Model):
        return force_text(data)

    elif isinstance(data, datetime):
        if format_iso_dates:
            return data.isoformat()
        return get_locally_formatted_datetime(data)

    return data
예제 #19
0
    def get_display_value(self, context, object):
        display_callable = maybe_callable(self.display, context=context)
        if display_callable:
            return display_callable(object)

        value = object
        for bit in self.display.split("__"):
            value = getattr(value, bit, None)

        if isinstance(value, ProductMedia):
            return "<img src='/media/%s'>" % value.get_thumbnail()

        if isinstance(value, Image):
            thumbnailer = get_thumbnailer(value)
            options = {"size": (64, 64)}
            thumbnail = thumbnailer.get_thumbnail(options, generate=True)
            return "<img src='%s'>" % thumbnail.url

        if isinstance(value, bool):
            value = yesno(value)

        if isinstance(value, Manager):
            value = ", ".join("%s" % x for x in value.all())

        if isinstance(value, datetime.datetime):
            return get_locally_formatted_datetime(value)

        if isinstance(value, Money):
            return escape(format_money(value))

        if not value:
            value = ""

        return force_text(value)
예제 #20
0
파일: _taxes.py 프로젝트: zarlant/shuup
 def __str__(self):
     text = super(Tax, self).__str__()
     if self.rate is not None:
         text += " ({})".format(format_percent(self.rate, digits=3))
     if self.amount is not None:
         text += " ({})".format(format_money(self.amount))
     return text
예제 #21
0
def test_get_installments_cc_does_not_allow_installments():
    """
        Max 9 installs with SIMPLE intereset
        interest_rate = 4.00%
        Credit card does not allow installments
    """
    patch_cielo_request()

    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    CieloConfig.objects.create(shop=shop,
                               max_installments=9,
                               installments_without_interest=3,
                               interest_type=InterestType.Simple,
                               interest_rate=Decimal(4.0))

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE)
    total_price_str = "{0}".format(format_money(shop.create_price(order_total)))

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Discover})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 1
    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']
예제 #22
0
def _test_refund_view(browser, live_server, order):
    url = reverse("shuup_admin:order.create-refund", kwargs={"pk": order.pk})
    browser.visit("%s%s" % (live_server, url))
    wait_until_condition(browser, lambda x: x.is_text_present("Refunded: %s" % format_money(order.shop.create_price("0.00"))))
    assert len(browser.find_by_css("#id_form-0-line_number option")) == 12 # blank + arbitrary amount + num lines
    click_element(browser, "#select2-id_form-0-line_number-container")
    wait_until_appeared(browser, "input.select2-search__field")
    browser.execute_script('$($(".select2-results__option")[1]).trigger({type: "mouseup"})') # select arbitrary amount
    wait_until_condition(browser, lambda x: len(x.find_by_css("#id_form-0-text")))
    wait_until_condition(browser, lambda x: len(x.find_by_css("#id_form-0-amount")))
    browser.find_by_css("#id_form-0-text").first.value = "test"
    browser.find_by_css("#id_form-0-amount").first.value = "900"
    click_element(browser, "#add-refund")
    click_element(browser, "#select2-id_form-1-line_number-container")
    wait_until_appeared(browser, "input.select2-search__field")
    browser.execute_script('$($(".select2-results__option")[2]).trigger({type: "mouseup"})') # select first line
    assert decimal.Decimal(browser.find_by_css("#id_form-1-amount").first.value) == decimal.Decimal("100.00")
    assert int(decimal.Decimal(browser.find_by_css("#id_form-1-quantity").first.value)) == 10
    click_element(browser, "button[form='create_refund']")
    _check_create_refund_link(browser, order, True) # can still refund quantity
    _check_order_details_visible(browser)
    order.refresh_from_db()
    assert not order.taxful_total_price
    assert order.is_paid()
    assert not order.is_fully_shipped()
예제 #23
0
파일: edit.py 프로젝트: zorkhax/shuup
    def handle_customer_details(self, request):
        customer_id = request.GET["id"]
        customer = Contact.objects.get(pk=customer_id)
        companies = []
        if isinstance(customer, PersonContact):
            companies = sorted(customer.company_memberships.all(),
                               key=(lambda x: force_text(x)))
        recent_orders = customer.customer_orders.valid().order_by('-id')[:10]

        order_summary = []
        for dt in customer.customer_orders.valid().datetimes(
                'order_date', 'year'):
            summary = customer.customer_orders.filter(
                order_date__year=dt.year).aggregate(
                    total=Sum('taxful_total_price_value'))
            order_summary.append({
                'year':
                dt.year,
                'total':
                format_currency(summary['total'],
                                currency=recent_orders[0].currency,
                                locale=get_current_babel_locale())
            })

        return {
            "customer_info": {
                "name":
                customer.full_name,
                "phone_no":
                customer.phone,
                "email":
                customer.email,
                "tax_number":
                getattr(customer, "tax_number", ""),
                "companies":
                [force_text(company)
                 for company in companies] if len(companies) else None,
                "groups":
                [force_text(group) for group in customer.groups.all()],
                "merchant_notes":
                customer.merchant_notes
            },
            "order_summary":
            order_summary,
            "recent_orders": [{
                "order_date":
                get_locally_formatted_datetime(order.order_date),
                "total":
                format_money(order.taxful_total_price),
                "status":
                order.get_status_display(),
                "payment_status":
                force_text(order.payment_status.label),
                "shipment_status":
                force_text(order.shipping_status.label)
            } for order in recent_orders]
        }
예제 #24
0
def _test_refund_view(browser, live_server, order):
    url = reverse("shuup_admin:order.create-refund", kwargs={"pk": order.pk})
    browser.visit("%s%s" % (live_server, url))
    wait_until_condition(
        browser, lambda x: x.is_text_present("Refunded: %s" % format_money(
            order.shop.create_price("0.00"))))
    assert len(browser.find_by_css("#id_form-0-line_number option")
               ) == 12  # blank + arbitrary amount + num lines

    try:
        click_element(browser, "#select2-id_form-0-line_number-container")
        wait_until_appeared(browser, "input.select2-search__field")
    except selenium.common.exceptions.TimeoutException as e:
        # For some reason first click happen before the element is not ready so
        # let's re-click when timeout happens. The actual functionality seem
        # to work nicely.
        click_element(browser, "#select2-id_form-0-line_number-container")
        wait_until_appeared(browser, "input.select2-search__field")

    wait_until_appeared(browser,
                        ".select2-results__option[aria-selected='false']")
    browser.execute_script(
        '$($(".select2-results__option")[1]).trigger({type: "mouseup"})'
    )  # select arbitrary amount
    wait_until_condition(browser,
                         lambda x: len(x.find_by_css("#id_form-0-text")))
    wait_until_condition(browser,
                         lambda x: len(x.find_by_css("#id_form-0-amount")))
    browser.find_by_css("#id_form-0-text").first.value = "test"
    browser.find_by_css("#id_form-0-amount").first.value = "900"
    move_to_element(browser, "#add-refund")
    click_element(browser, "#add-refund")

    # New line starts here...
    move_to_element(browser, "#add-refund")
    click_element(browser, "#select2-id_form-1-line_number-container")
    wait_until_appeared(browser, "input.select2-search__field")

    elem = browser.find_by_css("input.select2-search__field").first
    elem._element.send_keys("line 1")
    elem._element.send_keys(Keys.RETURN)

    assert decimal.Decimal(
        browser.find_by_css(
            "#id_form-1-amount").first.value) == decimal.Decimal("100.00")
    assert int(
        decimal.Decimal(
            browser.find_by_css("#id_form-1-quantity").first.value)) == 10
    click_element(browser, "button[form='create_refund']")
    _check_create_refund_link(browser, order,
                              True)  # can still refund quantity
    _check_order_details_visible(browser)
    order.refresh_from_db()
    assert not order.taxful_total_price
    assert order.is_paid()
    assert not order.is_fully_shipped()
예제 #25
0
 def _handle_source_data(self, request):
     self.object = self.get_object()
     state = json.loads(request.body.decode("utf-8"))["state"]
     source = create_source_from_state(
         state,
         creator=request.user,
         ip_address=request.META.get("REMOTE_ADDR"),
         order_to_update=self.object if self.object.pk else None
     )
     # Calculate final lines for confirmation
     source.calculate_taxes(force_recalculate=True)
     return {
         "taxfulTotal": format_money(source.taxful_total_price.amount),
         "taxlessTotal": format_money(source.taxless_total_price.amount),
         "totalDiscountAmount": format_money(source.total_discount.amount),
         "orderLines": [encode_line(line) for line in source.get_final_lines(with_taxes=True)],
         "billingAddress": source.billing_address.as_string_list() if source.billing_address else None,
         "shippingAddress": source.shipping_address.as_string_list() if source.shipping_address else None,
     }
예제 #26
0
def get_price_ranges(shop, min_price, max_price, range_step):
    if range_step == 0:
        return

    ranges = []
    min_price_value = format_money(shop.create_price(min_price))
    ranges.append(("-%s" % min_price, _("Under %(min_limit)s") % {"min_limit": min_price_value}))

    for range_min in range(min_price, max_price, range_step):
        range_min_price = format_money(shop.create_price(range_min))
        range_max = range_min + range_step
        if range_max < max_price:
            range_max_price = format_money(shop.create_price(range_max))
            ranges.append(
                ("%s-%s" % (range_min, range_max), "%s to %s" % (range_min_price, range_max_price)))

    max_price_value = format_money(shop.create_price(max_price))
    ranges.append(("%s-" % max_price, _("%(max_limit)s & Above") % {"max_limit": max_price_value}))
    return ranges
예제 #27
0
def test_get_installments_9x_with_simples_intereset():
    """
        Max 9 installs with SIMPLE intereset
        interest_rate = 4.00%
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    cielo_config = CieloConfig.objects.create(
        shop=shop,
        max_installments=9,
        installments_without_interest=3,
        interest_type=InterestType.Simple,
        interest_rate=Decimal(4.0))
    SHIP_AMOUNT = Decimal(19.0)
    shipping_method = get_default_shipping_method()
    shipping_method.behavior_components.add(
        FixedCostBehaviorComponent.objects.create(price_value=SHIP_AMOUNT))

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE) + SHIP_AMOUNT
    installment_choices = InstallmentContext(
        order_total, cielo_config).get_intallments_choices()

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == len(installment_choices)

    for installment in range(len(installment_choices)):
        total = format_money(
            shop.create_price(installment_choices[installment][2]))
        installment_amount = format_money(
            shop.create_price(installment_choices[installment][1]))

        assert json_content['installments'][installment][
            'number'] == installment + 1
        assert installment_amount in json_content['installments'][installment][
            'name']
        assert total in json_content['installments'][installment]['name']
예제 #28
0
def test_order_creator_customer_details(rf, admin_user):
    shop = get_default_shop()
    contact = create_random_person(locale="en_US", minimum_name_comp_len=5)
    company = create_random_company()
    group = get_default_customer_group()
    contact.groups.add(group)
    contact.company_memberships.add(company)
    contact.save()
    product = create_product(sku=printable_gibberish(),
                             supplier=get_default_supplier(),
                             shop=shop)
    order = create_random_order(contact, products=[product])
    request = apply_request_middleware(rf.get(
        "/", {
            "command": "customer_details",
            "id": contact.id
        }),
                                       user=admin_user)
    response = OrderEditView.as_view()(request)
    data = json.loads(response.content.decode("utf8"))

    assert "customer_info" in data
    assert "order_summary" in data
    assert "recent_orders" in data
    assert data["customer_info"]["name"] == contact.full_name
    assert data["customer_info"]["phone_no"] == contact.phone
    assert data["customer_info"]["email"] == contact.email
    assert company.full_name in data["customer_info"]["companies"]
    assert group.name in data["customer_info"]["groups"]
    assert data["customer_info"]["merchant_notes"] == contact.merchant_notes
    assert len(data["order_summary"]) == 1
    assert data["order_summary"][0]["year"] == order.order_date.year
    assert data["order_summary"][0]["total"] == format_money(
        order.taxful_total_price)
    assert len(data["recent_orders"]) == 1
    assert data["recent_orders"][0]["status"] == order.get_status_display()
    assert data["recent_orders"][0]["total"] == format_money(
        order.taxful_total_price)
    assert data["recent_orders"][0]["payment_status"] == force_text(
        order.payment_status.label)
    assert data["recent_orders"][0]["shipment_status"] == force_text(
        order.shipping_status.label)
예제 #29
0
    def get_discount_effect(self, instance):
        if not (instance.discount_amount_value or instance.discounted_price_value or instance.discount_percentage):
            return "-"

        effects = []
        shop = get_shop(self.request)
        if instance.discount_amount_value:
            effects.append(
                "- %s" % format_money(shop.create_price(instance.discount_amount_value))
                if shop else format_number(instance.discount_amount_value))

        if instance.discounted_price_value:
            effects.append(
                format_money(shop.create_price(instance.discounted_price_value))
                if shop else format_number(instance.discounted_price_value))

        if instance.discount_percentage:
            effects.append(format_percent(instance.discount_percentage))

        return ','.join(effects)
예제 #30
0
def test_get_installments_12x_with_simples_intereset():
    """
        Max 12 installs with PRICE intereset
        interest_rate = 2.30%
        min_installment_amount = 30.00
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    cielo_config = CieloConfig.objects.create(
        shop=shop,
        max_installments=12,
        installments_without_interest=2,
        interest_type=InterestType.Price,
        interest_rate=Decimal(2.3),
        min_installment_amount=Decimal(30))

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE)
    installment_choices = InstallmentContext(
        order_total, cielo_config).get_intallments_choices()

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == len(installment_choices)

    for installment in range(len(installment_choices)):
        total = format_money(
            shop.create_price(installment_choices[installment][2]))
        installment_amount = format_money(
            shop.create_price(installment_choices[installment][1]))

        assert json_content['installments'][installment][
            'number'] == installment + 1
        assert installment_amount in json_content['installments'][installment][
            'name']
        assert total in json_content['installments'][installment]['name']
예제 #31
0
    def get_validation_errors(cls, order_source):
        # check for the minimum sum of order total
        min_total = configuration.get(order_source.shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0))

        if order_source.shop.prices_include_tax:
            total = order_source.taxful_total_price.value
        else:
            total = order_source.taxless_total_price.value

        if total < min_total:
            min_total_price = format_money(order_source.shop.create_price(min_total))
            msg = _("The total should be greater than {} to be ordered.").format(min_total_price)
            yield ValidationError(msg, code="order_total_too_low")
예제 #32
0
    def get_validation_errors(cls, order_source):
        # check for the minimum sum of order total
        min_total = configuration.get(order_source.shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0))

        if order_source.shop.prices_include_tax:
            total = order_source.taxful_total_price.value
        else:
            total = order_source.taxless_total_price.value

        if total < min_total:
            min_total_price = format_money(order_source.shop.create_price(min_total))
            msg = _("The total price should be greater than {} to be ordered.").format(min_total_price)
            yield ValidationError(msg, code="order_total_too_low")
예제 #33
0
 def get_data(self):
     data = []
     order_lines = self.get_objects()[:self.queryset_row_limit]
     for line in order_lines:
         data.append({
             "order_line_sku":
             line.sku,
             "order_line_text":
             line.text,
             "order_line_quantity":
             line.quantity,
             "taxless_unit_price":
             format_money(line.taxless_base_unit_price),
             "taxful_unit_price":
             format_money(line.taxful_base_unit_price),
             "taxful_price":
             format_money(line.taxful_price),
             "type":
             line.type.name.capitalize(),
             "created_on":
             get_locally_formatted_datetime(line.created_on),
         })
     return self.get_return_data(data, has_totals=False)
예제 #34
0
def test_get_installments_3x_no_intereset():
    """
        Max 3 installs with no intereset
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    CieloConfig.objects.create(shop=shop,
                               max_installments=3,
                               installments_without_interest=3)

    order_total = PRODUCT_QTNTY * PRODUCT_PRICE
    total_price_str = "{0}".format(format_money(
        shop.create_price(order_total)))

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 3

    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']

    total_2x_no_interest = format_money(
        shop.create_price(order_total / Decimal(2)))
    assert json_content['installments'][1]['number'] == 2
    assert total_price_str in json_content['installments'][1]['name']
    assert total_2x_no_interest in json_content['installments'][1]['name']

    total_3x_no_interest = format_money(
        shop.create_price(order_total / Decimal(3)))
    assert json_content['installments'][2]['number'] == 3
    assert total_price_str in json_content['installments'][2]['name']
    assert total_3x_no_interest in json_content['installments'][2]['name']
예제 #35
0
def test_get_installments_9x_with_simples_intereset():
    """
        Max 9 installs with SIMPLE intereset
        interest_rate = 4.00%
    """
    patch_cielo_request()
    shop = get_default_shop()
    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')
    c = SmartClient()
    _configure_basket(c)
    cielo_config = CieloConfig.objects.create(shop=shop,
                                              max_installments=9,
                                              installments_without_interest=3,
                                              interest_type=InterestType.Simple,
                                              interest_rate=Decimal(4.0))
    SHIP_AMOUNT = Decimal(19.0)
    shipping_method = get_default_shipping_method()
    shipping_method.behavior_components.add(
        FixedCostBehaviorComponent.objects.create(price_value=SHIP_AMOUNT)
    )

    order_total = (PRODUCT_QTNTY * PRODUCT_PRICE) + SHIP_AMOUNT
    installment_choices = InstallmentContext(order_total, cielo_config).get_intallments_choices()

    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == len(installment_choices)

    for installment in range(len(installment_choices)):
        total = format_money(shop.create_price(installment_choices[installment][2]))
        installment_amount = format_money(shop.create_price(installment_choices[installment][1]))

        assert json_content['installments'][installment]['number'] == installment+1
        assert installment_amount in json_content['installments'][installment]['name']
        assert total in json_content['installments'][installment]['name']
예제 #36
0
    def get_discount_effect(self, instance):
        if not (instance.discount_amount_value
                or instance.discounted_price_value
                or instance.discount_percentage):
            return "-"

        effects = []
        shop = get_shop(self.request)
        if instance.discount_amount_value:
            effects.append(
                "- %s" %
                format_money(shop.create_price(instance.discount_amount_value))
                if shop else format_number(instance.discount_amount_value))

        if instance.discounted_price_value:
            effects.append(
                format_money(shop.create_price(instance.discounted_price_value)
                             )
                if shop else format_number(instance.discounted_price_value))

        if instance.discount_percentage:
            effects.append(format_percent(instance.discount_percentage))

        return ','.join(effects)
예제 #37
0
def money(amount, digits=None, widen=0):
    """
    Format money amount according to the current locale settings.

    :param amount: Money or Price object to format.
    :type amount: shuup.utils.money.Money
    :param digits: Number of digits to use, by default use locale's default.
    :type digits: int|None
    :param widen:
      Number of extra digits to add; for formatting with additional
      precision, e.g. ``widen=3`` will use 5 digits instead of the default 2.
    :type widen: int
    :return: Formatted string representing the given amount
    :rtype: str
    """
    return format_money(amount, digits, widen)
예제 #38
0
def money(amount, digits=None, widen=0):
    """
    Format money amount according to current locale settings.

    :param amount: Money or Price object to format
    :type amount: shuup.utils.money.Money
    :param digits: Number of digits to use, by default use locale's default
    :type digits: int|None
    :param widen:
      Number of extra digits to add; for formatting with additional
      precision, e.g. ``widen=3`` will use 5 digits instead of 2
    :type widen: int
    :return: Formatted string representing the given amount
    :rtype: str
    """
    return format_money(amount, digits, widen)
예제 #39
0
def test_get_installments_options_rest():
    patch_cielo_request()
    shop = get_default_shop()
    c = SmartClient()

    # method not allowed
    response = c.post(INSTALLMENTS_PATH)
    assert response.status_code == 405

    # missing parameters
    response = c.get(INSTALLMENTS_PATH)
    assert response.status_code == 400

    # no CieloConfig for shop
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 400

    CieloConfig.objects.create(shop=shop)

    # basket not valid (no products and not payment/shipping methods)
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 400

    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')

    # configures the user basket
    _configure_basket(c)

    # only 1 installment, because no configurations were set on CieloConfig
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 200

    # should be the order total
    order_total = PRODUCT_QTNTY * PRODUCT_PRICE
    total_price_str = "{0}".format(format_money(
        shop.create_price(order_total)))

    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 1
    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']
예제 #40
0
def test_get_installments_options_rest():
    patch_cielo_request()
    shop = get_default_shop()
    c = SmartClient()

    # method not allowed
    response = c.post(INSTALLMENTS_PATH)
    assert response.status_code == 405

    # missing parameters
    response = c.get(INSTALLMENTS_PATH)
    assert response.status_code == 400

    # no CieloConfig for shop
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 400

    CieloConfig.objects.create(shop=shop)

    # basket not valid (no products and not payment/shipping methods)
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 400

    create_default_order_statuses()
    populate_if_required()
    set_current_theme('shuup.themes.classic_gray')

    # configures the user basket
    _configure_basket(c)

    # only 1 installment, because no configurations were set on CieloConfig
    response = c.get(INSTALLMENTS_PATH, {"cc_brand": CieloCardBrand.Visa})
    assert response.status_code == 200

    # should be the order total
    order_total = PRODUCT_QTNTY * PRODUCT_PRICE
    total_price_str = "{0}".format(format_money(shop.create_price(order_total)))

    json_content = json.loads(response.content.decode("utf-8"))
    assert len(json_content['installments']) == 1
    assert json_content['installments'][0]['number'] == 1
    assert total_price_str in json_content['installments'][0]['name']
예제 #41
0
    def handle_customer_details(self, request):
        customer_id = request.GET["id"]
        customer = Contact.objects.get(pk=customer_id)
        companies = []
        if isinstance(customer, PersonContact):
            companies = sorted(customer.company_memberships.all(), key=(lambda x: force_text(x)))
        recent_orders = customer.customer_orders.valid().order_by('-id')[:10]

        order_summary = []
        for dt in customer.customer_orders.valid().datetimes('order_date', 'year'):
            summary = customer.customer_orders.filter(order_date__year=dt.year).aggregate(
                total=Sum('taxful_total_price_value')
            )
            order_summary.append({
                'year': dt.year,
                'total': format_currency(
                    summary['total'], currency=recent_orders[0].currency, locale=get_current_babel_locale()
                )
            })

        return {
            "customer_info": {
                "name": customer.full_name,
                "phone_no": customer.phone,
                "email": customer.email,
                "tax_number": getattr(customer, "tax_number", ""),
                "companies": [force_text(company) for company in companies] if len(companies) else None,
                "groups": [force_text(group) for group in customer.groups.all()],
                "merchant_notes": customer.merchant_notes
            },
            "order_summary": order_summary,
            "recent_orders": [
                {
                    "order_date": get_locally_formatted_datetime(order.order_date),
                    "total": format_money(order.taxful_total_price),
                    "status": order.get_status_display(),
                    "payment_status": force_text(order.payment_status.label),
                    "shipment_status": force_text(order.shipping_status.label)
                } for order in recent_orders
            ]
        }
예제 #42
0
    def check_different_types(self, value):
        if isinstance(value, ProductMedia):
            return "<img src='/media/%s'>" % value.get_thumbnail()

        if isinstance(value, Image):
            thumbnailer = get_thumbnailer(value)
            options = {"size": (64, 64)}
            thumbnail = thumbnailer.get_thumbnail(options, generate=True)
            return "<img src='%s'>" % thumbnail.url

        if isinstance(value, bool):
            value = yesno(value)

        if isinstance(value, Manager):
            value = ", ".join("%s" % x for x in value.all())

        if isinstance(value, datetime.datetime):
            return get_locally_formatted_datetime(value)

        if isinstance(value, Money):
            return escape(format_money(value))
예제 #43
0
파일: picotable.py 프로젝트: ruqaiya/shuup
    def check_different_types(self, value):
        if isinstance(value, ProductMedia):
            return "<img src='/media/%s'>" % value.get_thumbnail()

        if isinstance(value, Image):
            thumbnailer = get_thumbnailer(value)
            options = {"size": (64, 64)}
            thumbnail = thumbnailer.get_thumbnail(options, generate=True)
            return "<img src='%s'>" % thumbnail.url

        if isinstance(value, bool):
            value = yesno(value)

        if isinstance(value, Manager):
            value = ", ".join("%s" % x for x in value.all())
            return value

        if isinstance(value, datetime.datetime):
            return get_locally_formatted_datetime(value)

        if isinstance(value, Money):
            return escape(format_money(value))
예제 #44
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
        })
예제 #45
0
    def get_data(self):
        data = []
        orders = self.get_objects(paid=False)

        for order in orders:
            data.append({
                "order_num":
                order.identifier,
                "order_date":
                get_locally_formatted_datetime(order.order_date),
                "status":
                order.status,
                "order_line_quantity":
                order.lines.filter(type=OrderLineType.PRODUCT).count(),
                "order_total_amount":
                format_money(order.taxful_total_price),
                "payment_status":
                order.get_payment_status_display(),
                "shipment_status":
                order.get_shipping_status_display(),
                "customer":
                order.get_customer_name()
            })
        return self.get_return_data(data, has_totals=False)
예제 #46
0
def test_happy_hour_prices_expiration(rf):
    with override_settings(
            CACHES={
                'default': {
                    'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                    'LOCATION': 'test_happy_hour_prices_bump',
                }
            }):
        happy_hour = init_test()

        # it is now: 2018-01-01 09:00 AM
        before_happy_hour = datetime.datetime(2018,
                                              1,
                                              1,
                                              9,
                                              0,
                                              tzinfo=pytz.UTC)  # 09:00 AM
        inside_happy_hour = datetime.datetime(2018,
                                              1,
                                              1,
                                              10,
                                              30,
                                              tzinfo=pytz.UTC)  # 10:30 AM
        after_happy_hours = datetime.datetime(2018,
                                              1,
                                              1,
                                              11,
                                              20,
                                              tzinfo=pytz.UTC)  # 11:30 AM

        # Create condition from 10am to 11am
        hour_start = datetime.datetime(2018, 1, 1, 10, 0,
                                       tzinfo=pytz.UTC).time()  # 10:00 AM
        hour_end = datetime.datetime(2018, 1, 1, 11, 0,
                                     tzinfo=pytz.UTC).time()  # 11:00 AM
        set_valid_times_condition(happy_hour, hour_start, hour_end,
                                  str(before_happy_hour.weekday()))

        shop = happy_hour.shops.first()
        discount = happy_hour.discounts.first()
        product = discount.product
        shop_product = product.get_shop_instance(shop)
        assert shop_product.default_price_value == 10
        assert discount.discounted_price_value == 6

        def get_request():
            return apply_request_middleware(rf.get("/"))

        price_template = engines["jinja2"].from_string("{{ product|price }}")
        is_discounted_template = engines["jinja2"].from_string(
            "{{ product|is_discounted }}")
        discount_percent_template = engines["jinja2"].from_string(
            "{{ product|discount_percent }}")

        # we start with time being before happy hour
        with patch("django.utils.timezone.now", new=lambda: before_happy_hour):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time",
                       new=lambda: to_timestamp(before_happy_hour)):
                # check that product price is still the orignal (€10.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop_product.default_price)
                    assert is_discounted_template.render(context) == "False"
                    assert discount_percent_template.render(context) == "0%"

                    if cache_test == 1:
                        assert get_cached_price_info(
                            get_request(),
                            product,
                            1,
                            supplier=shop_product.get_supplier())

        # now we are inside happy hour range
        with patch("django.utils.timezone.now", new=lambda: inside_happy_hour):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time",
                       new=lambda: to_timestamp(inside_happy_hour)):
                # check that product price is the discounted one (€6.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop.create_price(discount.discounted_price_value))
                    assert is_discounted_template.render(context) == "True"
                    assert discount_percent_template.render(context) == "40%"

                    if cache_test == 1:
                        assert get_cached_price_info(
                            get_request(),
                            product,
                            1,
                            supplier=shop_product.get_supplier())

                # we change the discounted price from $6 to $7
                # cached should be bumped
                discount.discounted_price_value = 7
                discount.save()
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop.create_price(discount.discounted_price_value))
                    assert is_discounted_template.render(context) == "True"
                    assert discount_percent_template.render(context) == "30%"

                    if cache_test == 1:
                        assert get_cached_price_info(
                            get_request(),
                            product,
                            1,
                            supplier=shop_product.get_supplier())

        # now we are inside happy hour range
        with patch("django.utils.timezone.now", new=lambda: after_happy_hours):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time",
                       new=lambda: to_timestamp(after_happy_hours)):
                # check that product price is the orignal (€10.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop_product.default_price)
                    assert is_discounted_template.render(context) == "False"
                    assert discount_percent_template.render(context) == "0%"

                    if cache_test == 1:
                        assert get_cached_price_info(
                            get_request(),
                            product,
                            1,
                            supplier=shop_product.get_supplier())
예제 #47
0
def test_happy_hour_prices_expiration(rf):
    with override_settings(
        CACHES={
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'test_happy_hour_prices_bump',
            }
        }
    ):
        happy_hour = init_test()

        # it is now: 2018-01-01 09:00 AM
        before_happy_hour = datetime.datetime(2018, 1, 1, 9, 0, tzinfo=pytz.UTC)    # 09:00 AM
        inside_happy_hour = datetime.datetime(2018, 1, 1, 10, 30, tzinfo=pytz.UTC)  # 10:30 AM
        after_happy_hours = datetime.datetime(2018, 1, 1, 11, 20, tzinfo=pytz.UTC)  # 11:30 AM

        # Create condition from 10am to 11am
        hour_start = datetime.datetime(2018, 1, 1, 10, 0, tzinfo=pytz.UTC).time()  # 10:00 AM
        hour_end = datetime.datetime(2018, 1, 1, 11, 0, tzinfo=pytz.UTC).time()  # 11:00 AM
        set_valid_times_condition(happy_hour, hour_start, hour_end, str(before_happy_hour.weekday()))

        shop = happy_hour.shops.first()
        discount = happy_hour.discounts.first()
        product = discount.product
        shop_product = product.get_shop_instance(shop)
        assert shop_product.default_price_value == 10
        assert discount.discounted_price_value == 6

        def get_request():
            return apply_request_middleware(rf.get("/"))

        price_template = engines["jinja2"].from_string("{{ product|price }}")
        is_discounted_template = engines["jinja2"].from_string("{{ product|is_discounted }}")
        discount_percent_template = engines["jinja2"].from_string("{{ product|discount_percent }}")

        # we start with time being before happy hour
        with patch("django.utils.timezone.now", new=lambda: before_happy_hour):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time", new=lambda: to_timestamp(before_happy_hour)):
                # check that product price is still the orignal (€10.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(shop_product.default_price)
                    assert is_discounted_template.render(context) == "False"
                    assert discount_percent_template.render(context) == "0%"

                    if cache_test == 1:
                        assert get_cached_price_info(get_request(), product, 1, supplier=shop_product.get_supplier())

        # now we are inside happy hour range
        with patch("django.utils.timezone.now", new=lambda: inside_happy_hour):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time", new=lambda: to_timestamp(inside_happy_hour)):
                # check that product price is the discounted one (€6.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop.create_price(discount.discounted_price_value)
                    )
                    assert is_discounted_template.render(context) == "True"
                    assert discount_percent_template.render(context) == "40%"

                    if cache_test == 1:
                        assert get_cached_price_info(get_request(), product, 1, supplier=shop_product.get_supplier())

                # we change the discounted price from $6 to $7
                # cached should be bumped
                discount.discounted_price_value = 7
                discount.save()
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(
                        shop.create_price(discount.discounted_price_value)
                    )
                    assert is_discounted_template.render(context) == "True"
                    assert discount_percent_template.render(context) == "30%"

                    if cache_test == 1:
                        assert get_cached_price_info(get_request(), product, 1, supplier=shop_product.get_supplier())

        # now we are inside happy hour range
        with patch("django.utils.timezone.now", new=lambda: after_happy_hours):
            # mock also time.time so the cache timeout will be calculated correctly
            with patch("time.time", new=lambda: to_timestamp(after_happy_hours)):
                # check that product price is the orignal (€10.00)
                # run twice to make sure caches are being used
                for cache_test in range(2):
                    context = dict(product=product, request=get_request())
                    assert price_template.render(context) == format_money(shop_product.default_price)
                    assert is_discounted_template.render(context) == "False"
                    assert discount_percent_template.render(context) == "0%"

                    if cache_test == 1:
                        assert get_cached_price_info(get_request(), product, 1, supplier=shop_product.get_supplier())
예제 #48
0
파일: _list.py 프로젝트: stjordanis/shuup
 def format_taxful_total_price(self, instance, *args, **kwargs):
     if not instance.taxful_total_price:
         return ""
     return escape(format_money(instance.taxful_total_price))
예제 #49
0
    def get(self, request, *args, **kwargs):
        cc_brand = request.GET.get("cc_brand", "").lower()

        if not cc_brand:
            return HttpResponseBadRequest()

        if not hasattr(request.shop, "cielo_config"):
            logger.error("CieloConfig not configured for {0} shop".format(request.shop))
            return HttpResponseBadRequest()

        try:
            # populate the basket with all the checkout stuff
            _configure_basket(request)

            basket_total = request.basket.taxful_total_price.value
        except:
            logger.exception("Basket total is not valid")
            return HttpResponseBadRequest()

        installments = []

        FALLBACK_INSTALLMENT = {
            "number": 1,
            "name": INSTALLMENT_CHOICE_WITHOUT_INTEREST_STRING.format(
                1,
                format_money(request.basket.create_price(basket_total)),
                format_money(request.basket.create_price(basket_total)),
                localize(Decimal())
            )
        }

        # if it is a credit card service and the brand allows installments..
        if CieloProductMatrix.get(cc_brand, {}).get(CieloProduct.InstallmentCredit):

            try:
                context = InstallmentContext(basket_total, request.shop.cielo_config)
                interest_rate = request.shop.cielo_config.interest_rate

                for choice in context.get_intallments_choices():

                    # if installment has interest
                    if choice[3] > 0:
                        name = INSTALLMENT_CHOICE_WITH_INTEREST_STRING.format(
                            choice[0],
                            format_money(request.basket.create_price(choice[1])),
                            format_money(request.basket.create_price(choice[2])),
                            localize(interest_rate)
                        )
                    else:
                        name = INSTALLMENT_CHOICE_WITHOUT_INTEREST_STRING.format(
                            choice[0],
                            format_money(request.basket.create_price(choice[1])),
                            format_money(request.basket.create_price(choice[2]))
                        )

                    installments.append({"number": choice[0], "name": name})

            except:
                logger.exception("Failed to calculate installments for basket {0}".format(request.basket))

        if len(installments) == 0:
            installments.append(FALLBACK_INSTALLMENT)

        return JsonResponse({"installments": installments})
예제 #50
0
파일: list.py 프로젝트: gurch101/shuup
 def format_taxful_total_price(self, instance, *args, **kwargs):
     return escape(format_money(instance.taxful_total_price))
예제 #51
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"
예제 #52
0
def test_postalcodeshipping(class_spec):

    with override_settings(SHIPPING_SIMULATOR_CLASS_SPEC=class_spec):
        get_default_shop()
        product = get_default_product()

        clear_load_cache()

        carrier = CustomCarrier.objects.create(name="Kustom Karrier")
        service = carrier.create_service(None, enabled=True,
                               shop=get_default_shop(),
                               tax_class=get_default_tax_class(),
                               name="A Kustom Cervise",
                               description="Nice!")

        path = reverse("shuup:simulate-product-shipping")
        client = Client()

        data = {
            "product_id": product.id,
            "command": "add",
            "quantity": "1",
        }

        if class_spec.endswith("PostalCodeShippingSimulator"):
            data["postal_code"] = "37128482"

        elif class_spec.endswith("CityStateCountryShippingSimulator"):
            data["city"] = "Plumenau"
            data["region"] = "SC"
            data["country"] = "BR"

        # First, the method does not return any price. it must be free
        cost = get_default_shop().create_price(0.00)
        response = client.post(path, data)
        json_response = json.loads(response.content.decode("utf-8"))
        method = json_response["methods"][0]
        assert method["name"] == service.name
        assert method["description"] == service.description
        assert method["cost"] == cost.value
        assert method["formatted_cost"] == format_money(cost)
        assert method.get("time") is None

        # now lets add some extra price and time behavior
        service.behavior_components.add(ExpensiveSwedenBehaviorComponent.objects.create())

        cost = get_default_shop().create_price(1.00)
        duration = DurationRange(timedelta(days=5))

        with patch.object(ExpensiveSwedenBehaviorComponent, 'get_costs', return_value=[ServiceCost(cost)]):
            with patch.object(ExpensiveSwedenBehaviorComponent, 'get_delivery_time', return_value=duration):
                response = client.post(path, data)
                json_response = json.loads(response.content.decode("utf-8"))
                method = json_response["methods"][0]

                assert method["name"] == service.name
                assert method["description"] == service.description
                assert method["cost"] == cost.value
                assert method["formatted_cost"] == format_money(cost)
                assert method["time"]["min"] == duration.min_duration.days
                assert not method["time"]["formatted"] is None
                assert method["time"].get("max") is None

        # now with duration range time
        cost = get_default_shop().create_price(3.0)
        duration = DurationRange(timedelta(days=2), timedelta(days=8))

        with patch.object(ExpensiveSwedenBehaviorComponent, 'get_delivery_time', return_value=duration):
            with patch.object(ExpensiveSwedenBehaviorComponent, 'get_costs', return_value=[ServiceCost(cost)]):
                response = client.post(path, data)
                json_response = json.loads(response.content.decode("utf-8"))
                method = json_response["methods"][0]

                assert method["name"] == service.name
                assert method["description"] == service.description
                assert method["cost"] == cost.value
                assert method["formatted_cost"] == format_money(cost)

                assert method["time"]["min"] == duration.min_duration.days
                assert method["time"]["max"] == duration.max_duration.days


        # with suppier id
        data["supplier_id"] = get_default_supplier().pk
        response = client.post(path, data)
        json_response = json.loads(response.content.decode("utf-8"))
        method = json_response["methods"][0]
        assert method["name"] == service.name

        # with fractional quantity - internal error
        data["quantity"] = "1.321"
        response = client.post(path, data)
        assert response.status_code == 400

        # invalid quantity - internal error
        data["quantity"] = "1.,32.,1"
        response = client.post(path, data)
        assert response.status_code == 400

        # negative quantity - internal error
        data["quantity"] = "-1"
        response = client.post(path, data)
        assert response.status_code == 400

        # invalid form
        data = {"produt_id": product.id}
        response = client.post(path, data)
        assert json.loads(response.content.decode("utf-8")) == {}
예제 #53
0
 def format_taxless_total_price(self, instance, *args, **kwargs):
     return escape(format_money(instance.taxless_total_price))
예제 #54
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"