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 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 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 _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_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 _test_create_full_refund(browser, live_server, order): url = reverse("wshop_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("wshop_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 money(amount, digits=None, widen=0): """ Format money amount according to current locale settings. :param amount: Money or Price object to format :type amount: wshop.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_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 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 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 _test_refund_view(browser, live_server, order): url = reverse("wshop_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 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 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 format_taxful_total_price(self, instance, *args, **kwargs): return escape(format_money(instance.taxful_total_price))