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']
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)
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) }
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
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, }
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']
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) }
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()
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()
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())
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()
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']
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)
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
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
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})
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
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
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']
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()
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] }
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()
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, }
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
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']
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)
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)
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']
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")
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")
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)
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']
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']
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)
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)
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)
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']
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']
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 ] }
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))
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))
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 })
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)
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())
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())
def format_taxful_total_price(self, instance, *args, **kwargs): if not instance.taxful_total_price: return "" return escape(format_money(instance.taxful_total_price))
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})
def format_taxful_total_price(self, instance, *args, **kwargs): return escape(format_money(instance.taxful_total_price))
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"
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")) == {}
def format_taxless_total_price(self, instance, *args, **kwargs): return escape(format_money(instance.taxless_total_price))