def get_order_overview_for_date_range(currency, start_date, end_date): orders = get_orders_by_currency(currency).complete() orders_in_range = orders.in_date_range(start_date, end_date) q = orders_in_range.aggregate(num_orders=Count("id"), num_customers=Count("customer", distinct=True), sales=Sum("taxful_total_price_value")) anon_orders = orders_in_range.filter(customer__isnull=True).aggregate( num_orders=Count("id")) q["num_customers"] += anon_orders["num_orders"] q["sales"] = TaxfulPrice(q["sales"] or 0, currency) return q
def test_create_order(admin_user, settings, target_customer): configure(settings) shop = factories.get_default_shop() basket = factories.get_basket() factories.create_default_order_statuses() shop_product = factories.get_default_shop_product() shop_product.default_price = TaxfulPrice(1, shop.currency) shop_product.save() client = _get_client(admin_user) # add shop product payload = {'shop_product': shop_product.id} if target_customer == "other": target = factories.create_random_person() payload["customer_id"] = target.pk else: target = get_person_contact(admin_user) response = client.post( '/api/shuup/basket/{}-{}/add/'.format(shop.pk, basket.key), payload) assert response.status_code == status.HTTP_200_OK response_data = json.loads(response.content.decode("utf-8")) assert len(response_data["items"]) == 1 response = client.post( '/api/shuup/basket/{}-{}/create_order/'.format(shop.pk, basket.key), payload) assert response.status_code == status.HTTP_400_BAD_REQUEST response_data = json.loads(response.content.decode("utf-8")) assert "errors" in response_data factories.get_default_payment_method() factories.get_default_shipping_method() response = client.post( '/api/shuup/basket/{}-{}/create_order/'.format(shop.pk, basket.key), payload) assert response.status_code == status.HTTP_201_CREATED response_data = json.loads(response.content.decode("utf-8")) basket.refresh_from_db() assert basket.finished order = Order.objects.get( reference_number=response_data["reference_number"]) assert order.status == OrderStatus.objects.get_default_initial() assert order.payment_status == PaymentStatus.NOT_PAID assert order.shipping_status == ShippingStatus.NOT_SHIPPED assert not order.payment_method assert not order.shipping_method assert float(order.taxful_total_price_value) == 1 assert order.customer == target assert order.orderer == get_person_contact(admin_user) assert order.creator == admin_user assert not order.billing_address assert not order.shipping_address
def test_basic_order(): PRODUCTS_TO_SEND = 10 product = get_default_product() supplier = get_default_supplier() order = create_order_with_product(product, supplier=supplier, quantity=PRODUCTS_TO_SEND, taxless_base_unit_price=10, tax_rate=Decimal("0.5")) assert order.shop.prices_include_tax is False price = order.shop.create_price currency = order.currency discount_order_line = OrderLine(order=order, quantity=1, type=OrderLineType.OTHER) discount_order_line.discount_amount = price(30) assert discount_order_line.price == price(-30) discount_order_line.save() order.cache_prices() order.check_all_verified() order.save() assert order.taxful_total_price == TaxfulPrice( PRODUCTS_TO_SEND * (10 + 5) - 30, currency) shipment = order.create_shipment_of_all_products(supplier=supplier) assert shipment.total_products == PRODUCTS_TO_SEND, "All products were shipped" assert shipment.weight == product.gross_weight * PRODUCTS_TO_SEND, "Gravity works" assert not order.get_unshipped_products( ), "Nothing was left in the warehouse" order.shipping_status = ShippingStatus.FULLY_SHIPPED order.create_payment(order.taxful_total_price) assert order.payments.exists(), "A payment was created" with pytest.raises(NoPaymentToCreateException): order.create_payment(Money(6, currency)) assert order.is_paid(), "Order got paid" assert order.can_set_complete(), "Finalization is possible" order.change_status(next_status=OrderStatus.objects.get_default_complete(), save=False) assert order.is_complete(), "Finalization done" summary = order.get_tax_summary() assert len(summary) == 2 assert summary[0].tax_rate * 100 == 50 assert summary[0].based_on == Money(100, currency) assert summary[0].tax_amount == Money(50, currency) assert summary[0].taxful == summary[0].based_on + summary[0].tax_amount assert summary[1].tax_id is None assert summary[1].tax_code == "" assert summary[1].tax_amount == Money(0, currency) assert summary[1].tax_rate == 0 assert order.get_total_tax_amount() == Money(50, currency)
def test_line_discount(): order = create_empty_order(prices_include_tax=False) order.save() currency = order.shop.currency ol = OrderLine( order=order, type=OrderLineType.OTHER, quantity=5, text="Thing" ) ol.discount_amount = order.shop.create_price(50) ol.base_unit_price = order.shop.create_price(40) ol.save() ol.taxes.add(OrderLineTax.from_tax( get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == order.shop.create_price(50) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == order.shop.create_price(150) assert ol.taxful_price == TaxfulPrice(150 + 75, currency) assert ol.taxless_base_unit_price == order.shop.create_price(40) assert ol.taxful_base_unit_price == TaxfulPrice(60, currency) assert "Thing" in six.text_type(ol)
def test_line_discount_more(): order = create_empty_order() order.save() ol = OrderLine(order=order, type=OrderLineType.OTHER) ol.quantity = 5 ol.base_unit_price = order.shop.create_price(30) ol.discount_amount = order.shop.create_price(50) ol.save() currency = order.shop.currency assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxless_price == TaxlessPrice(5 * 30 - 50, currency) ol.taxes.add( OrderLineTax.from_tax(get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == TaxlessPrice(100, currency) assert ol.taxful_price == TaxfulPrice(150, currency) assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxful_base_unit_price == TaxfulPrice(45, currency)
def stacked_value_added_taxes(price, taxes): """ Stack added taxes on the given price without compounding. Note that this will not take compound taxation (Quebec) into account. :param price: Taxful or taxless price to calculate taxes for :type price: shuup.core.pricing.Price :param taxes: List of Tax objects :type taxes: list[shuup.core.models.Tax] :return: TaxedPrice with the calculated taxes. :rtype: TaxedPrice """ def money_sum(iterable): return sum(iterable, Money(0, price.currency)) if not taxes: return TaxedPrice(TaxfulPrice(price), TaxlessPrice(price), []) if price.includes_tax: taxful = price rate_sum = sum(tax.rate for tax in taxes if tax.rate) amount_sum = money_sum(tax.amount for tax in taxes if tax.amount) taxless = TaxlessPrice((taxful.amount - amount_sum) / (1 + rate_sum)) else: taxful = None # will be calculated below taxless = price line_taxes = [ SourceLineTax.from_tax(tax=tax, base_amount=taxless.amount) for tax in taxes ] if taxful is None: total_tax_amount = money_sum(x.amount for x in line_taxes) taxful = TaxfulPrice(taxless.amount + total_tax_amount) return TaxedPrice(taxful, taxless, line_taxes)
def get_taxed_price(self, context, price, tax_class): if price.includes_tax: taxful = price taxless = TaxlessPrice(price.amount / Decimal('1.2')) else: taxful = TaxfulPrice(price.amount * Decimal('1.2')) taxless = price tax_amount = taxful.amount - taxless.amount base_amount = taxless.amount taxes = [ SourceLineTax(Tax(), 'fifth', tax_amount, base_amount), ] DummyTaxModule.calculations_done += 1 return TaxedPrice(taxful, taxless, taxes)
def create_price(self, value): """ Create a price with given value and settings of this shop. Takes the ``prices_include_tax`` and ``currency`` settings of this Shop into account. :type value: decimal.Decimal|int|str :rtype: shuup.core.pricing.Price """ if self.prices_include_tax: return TaxfulPrice(value, self.currency) else: return TaxlessPrice(value, self.currency)
def test_abandoned_baskets(admin_user, settings): configure(settings) shop = factories.get_default_shop() factories.get_default_payment_method() factories.get_default_shipping_method() basket1 = factories.get_basket() shop_product = factories.get_default_shop_product() shop_product.default_price = TaxfulPrice(1, shop.currency) shop_product.save() client = _get_client(admin_user) # add shop product payload = {'shop_product': shop_product.id} response = client.post('/api/shuup/basket/{}-{}/add/'.format(shop.pk, basket1.key), payload) assert response.status_code == status.HTTP_200_OK response_data = json.loads(response.content.decode("utf-8")) assert len(response_data["items"]) == 1 assert response_data["items"][0]["shop_product"] == shop_product.pk assert not response_data["validation_errors"] assert float(response_data["total_price"]) == 1 assert Basket.objects.count() == 1 response = client.get("/api/shuup/basket/abandoned/?shop={}&days_ago=0¬_updated_in_hours=0".format(shop.pk)) response_data = json.loads(response.content.decode("utf-8")) assert len(response_data) == 1 basket_data = response_data[0] assert basket_data["id"] == basket1.id basket2 = factories.get_basket() response = client.post('/api/shuup/basket/{}-{}/add/'.format(shop.pk, basket2.key), payload) assert response.status_code == status.HTTP_200_OK response_data = json.loads(response.content.decode("utf-8")) assert len(response_data["items"]) == 1 assert response_data["items"][0]["shop_product"] == shop_product.pk assert not response_data["validation_errors"] assert float(response_data["total_price"]) == 1 assert Basket.objects.count() == 2 response = client.get("/api/shuup/basket/abandoned/?shop={}&days_ago=0¬_updated_in_hours=0".format(shop.pk)) response_data = json.loads(response.content.decode("utf-8")) assert len(response_data) == 2 basket_data = response_data[1] assert basket_data["id"] == basket2.id # there is no shop with this id thus it should return 404 response = client.get("/api/shuup/basket/abandoned/?shop=2&days_ago=0¬_updated_in_hours=0") assert response.status_code == status.HTTP_404_NOT_FOUND
def get_open_orders_block(request, currency): orders = get_orders_by_currency(currency) # Open orders / open orders value open_order_data = (orders.incomplete().aggregate( count=Count("id"), sum=Sum("taxful_total_price_value"))) return DashboardMoneyBlock( id="open_orders_sum", color="orange", title=_("Open Orders Value"), value=TaxfulPrice((open_order_data.get("sum") or 0), currency), currency=currency, icon="fa fa-inbox", subtitle=get_subtitle(open_order_data.get("count")))
def get_data(self): orders = self.get_objects().order_by("-order_date") data = [] # TODO: maybe make raw sql query in future for order_date, orders_group in itertools.groupby(orders, key=self.extract_date): taxless_total = TaxlessPrice(0, currency=self.shop.currency) taxful_total = TaxfulPrice(0, currency=self.shop.currency) product_count = 0 order_count = 0 for order in orders_group: taxless_total += order.taxless_total_price taxful_total += order.taxful_total_price product_count += sum(order.get_product_ids_and_quantities().values()) order_count += 1 data.append({ "date": format_date(order_date, locale=get_current_babel_locale()), "order_count": order_count, "product_count": int(product_count), "taxless_total": taxless_total.as_rounded().value, "taxful_total": taxful_total.as_rounded().value, }) return self.get_return_data(data)
def _get_order_and_order_line(request): order = Order( shop=request.shop, currency=request.shop.currency, prices_include_tax=request.shop.prices_include_tax, ) order.taxful_total_price = TaxfulPrice("100", request.shop.currency) order.taxless_total_price = TaxlessPrice("50", request.shop.currency) pi = _get_price_info(request.shop, Product(sku='6.0745'), quantity=2) return (order, OrderLine( order=order, base_unit_price=pi.base_unit_price, discount_amount=pi.discount_amount, quantity=pi.quantity, ))
def test_get_totals_return_correct_totals(): expected_taxful_total, expected_taxless_total, shop, order = initialize_report_test( 10, 1, 0, 1) report_data = { "report": SalesTestReport.get_name(), "shop": shop.pk, "date_range": DateRangeChoices.THIS_YEAR, "writer": "html", "force_download": 1, } data = [ { "date": "", "order_count": None, "product_count": 10, "taxless_total": TaxlessPrice("10", "EUR"), "taxful_total": TaxfulPrice("5", "EUR"), }, { "date": "", "order_count": 12, "product_count": None, "taxless_total": TaxlessPrice("20", "EUR"), "taxful_total": None, }, ] report = SalesTestReport(**report_data) totals = report.get_totals(data) expected = { "date": None, "order_count": 12, "product_count": 10, "taxless_total": TaxlessPrice("30", "EUR"), "taxful_total": TaxfulPrice("5", "EUR"), } assert totals == expected
def test_payment_processor(rf): shop = get_default_shop() product = get_default_product() supplier = get_default_supplier() choice_identifier = "checkoutfi" processor = CheckoutFiPaymentProcessor.objects.create(merchant_id="1", merchant_secret="2") payment_method = PaymentMethod.objects.create( shop=shop, payment_processor=processor, choice_identifier=choice_identifier, tax_class=get_default_tax_class()) order = create_order_with_product(product=product, supplier=supplier, quantity=1, taxless_base_unit_price=Decimal('5.55'), shop=shop) order.taxful_total_price = TaxfulPrice(Decimal('5.55'), 'EUR') order.payment_method = payment_method order.save() request = rf.get("/", data={ "VERSION": "1", "STAMP": "2", "REFERENCE": "3", "PAYMENT": "4", "STATUS": "5", "ALGORITHM": "6", "MAC": "7" }) assert order.payment_status == PaymentStatus.NOT_PAID with mock.patch.object(Checkout, "validate_payment_return", return_value=True): processor.process_payment_return_request(choice_identifier, order, request) order.refresh_from_db() assert order.payment_status == PaymentStatus.FULLY_PAID processor.process_payment_return_request(choice_identifier, order, request) order.refresh_from_db() assert order.payment_status == PaymentStatus.FULLY_PAID
def get_open_orders_block(request, currency=None): orders = get_orders_for_shop(request) if not currency: shop = request.shop currency = shop.currency # Open orders / open orders value open_order_data = orders.incomplete().aggregate(count=Count("id"), sum=Sum("taxful_total_price_value")) return DashboardMoneyBlock( id="open_orders_sum", color="orange", title=_("Open Orders Value"), value=TaxfulPrice((open_order_data.get("sum") or 0), currency), currency=currency, icon="fa fa-inbox", subtitle=get_subtitle(open_order_data.get("count")), sort_order=1, )
def test_add_product_to_basket_with_custom_shop_product_fields(admin_user, settings): product_name = "Product Name" shop_product_name = "SHOP Product Name" configure(settings) shop = factories.get_default_shop() basket = factories.get_basket() factories.get_default_payment_method() factories.get_default_shipping_method() shop_product = factories.get_default_shop_product() shop_product.default_price = TaxfulPrice(1, shop.currency) shop_product.save() shop_product.product.name = product_name shop_product.product.save() client = _get_client(admin_user) payload = { 'product': shop_product.product.pk, 'shop': shop.pk } response = client.post('/api/shuup/basket/{}-{}/add/'.format(shop.pk, basket.key), payload) assert response.status_code == status.HTTP_200_OK response_data = json.loads(response.content.decode("utf-8")) assert len(response_data["items"]) == 1 assert response_data["items"][0]["shop_product"] == shop_product.pk assert response_data["items"][0]["text"] == product_name # set shop product name shop_product.product.name = shop_product_name shop_product.product.save() # add product payload = { 'product': shop_product.product.pk, 'shop': shop.pk } response = client.post('/api/shuup/basket/{}-{}/add/'.format(shop.pk, basket.key), payload) assert response.status_code == status.HTTP_200_OK response_data = json.loads(response.content.decode("utf-8")) assert len(response_data["items"]) == 1 assert response_data["items"][0]["text"] == shop_product_name
def get_shop_overview_block(request, currency, for_date=None): end = to_aware(for_date, time=time.max) if for_date else local_now() start_of_day = to_aware(end.date(), time=time.min) start_of_month = start_of_day.replace(day=1) start_of_year = start_of_day.replace(month=1, day=1) shop = request.shop if not currency: currency = shop.currency daily = get_order_overview_for_date_range(currency, start_of_day, end, shop=shop) mtd = get_order_overview_for_date_range(currency, start_of_month, end, shop=shop) ytd = get_order_overview_for_date_range(currency, start_of_year, end, shop=shop) totals = get_orders_by_currency(currency).complete().filter( shop=shop).aggregate(num_orders=Count("id"), num_customers=Count("customer", distinct=True), sales=Sum("taxful_total_price_value")) anon_orders = get_orders_by_currency(currency).complete().filter( customer__isnull=True, shop=shop).aggregate(num_orders=Count("id")) totals["num_customers"] += anon_orders["num_orders"] totals["sales"] = TaxfulPrice(totals["sales"] or 0, currency) block = DashboardContentBlock.by_rendering_template( "store_overview", request, "shuup/admin/sales_dashboard/_store_overview_dashboard_block.jinja", { "daily": daily, "mtd": mtd, "ytd": ytd, "totals": totals }) block.size = "medium" block.sort_order = 0 return block
def _refund_amount(self, context, order, index, text, amount, tax_proportions, supplier=None): taxes = list( chain.from_iterable( self.get_taxed_price(context, TaxfulPrice(amount * factor), tax_class).taxes for (tax_class, factor) in tax_proportions)) base_amount = amount if not order.prices_include_tax: base_amount /= 1 + sum([tax.tax.rate for tax in taxes]) from shuup.core.models import OrderLine, OrderLineType refund_line = OrderLine.objects.create( text=text, order=order, type=OrderLineType.REFUND, ordering=index, base_unit_price_value=-base_amount, quantity=1, supplier=supplier, ) for line_tax in taxes: refund_line.taxes.create( tax=line_tax.tax, name=_("Refund for %s" % line_tax.name), amount_value=-line_tax.amount, base_amount_value=-line_tax.base_amount, ordering=1, ) return refund_line
def test_refunds_for_discounted_order_lines(): shop = get_default_shop() supplier = get_default_supplier() product = create_product( "test-sku", shop=get_default_shop(), default_price=10, ) order = create_order_with_product(product, supplier, 2, 200, shop=shop) discount_line = OrderLine(order_id=order.id, type=OrderLineType.DISCOUNT, quantity=1, discount_amount_value=Decimal("0.54321")) discount_line.save() order.lines.add(discount_line) # Lines without quantity shouldn't affect refunds other_line = OrderLine(order=order, type=OrderLineType.OTHER, text="This random line for textual information", quantity=0) other_line.save() order.lines.add(other_line) product_line = order.lines.filter(type=OrderLineType.PRODUCT).first() product_line.discount_amount = TaxfulPrice(100, order.currency) product_line.save() taxful_price_with_discount = product_line.taxful_price order.cache_prices() order.save() assert product_line.base_price == TaxfulPrice(400, order.currency) assert taxful_price_with_discount == TaxfulPrice(300, order.currency) # try to refund only the product line - should fail since this would result in a negative total with pytest.raises(RefundExceedsAmountException): order.create_refund([{ "line": product_line, "quantity": 2, "amount": taxful_price_with_discount.amount }]) # try to refund the product line with a negative amount with pytest.raises(InvalidRefundAmountException): order.create_refund([{ "line": product_line, "quantity": 1, "amount": -taxful_price_with_discount.amount }]) # try to refund the discount line with a positive amount with pytest.raises(InvalidRefundAmountException): order.create_refund([{ "line": discount_line, "quantity": 1, "amount": -discount_line.taxful_price.amount }]) order.create_refund([{ "line": discount_line, "quantity": 1, "amount": discount_line.taxful_price.amount }, { "line": product_line, "quantity": 2, "amount": taxful_price_with_discount.amount }]) assert product_line.max_refundable_amount.value == 0 assert discount_line.max_refundable_amount.value == 0 assert order.taxful_total_price.value == 0 order = create_order_with_product(product, supplier, 2, 200, shop=shop) discount_line = OrderLine(order_id=order.id, type=OrderLineType.DISCOUNT, quantity=1, discount_amount_value=Decimal("0.54321")) discount_line.save() order.lines.add(discount_line) product_line = order.lines.filter(type=OrderLineType.PRODUCT).first() product_line.discount_amount = TaxfulPrice(100, order.currency) product_line.save() # Lines without quantity shouldn't affect refunds other_line = OrderLine(order=order, type=OrderLineType.OTHER, text="This random line for textual information", quantity=0) other_line.save() order.lines.add(other_line) order.cache_prices() order.save() order.create_full_refund(restock_products=False) assert order.taxful_total_price.value == 0
def test_taxed_discounted_unit_prices(): assert_almost_equal(line.taxless_discounted_unit_price, TaxlessPrice(33, "EUR") / Decimal("1.1") / 9) assert line.taxful_discounted_unit_price == TaxfulPrice(33, "EUR") / 9
def test_taxed_discount_amounts(): assert_almost_equal(line.taxless_discount_amount, TaxlessPrice(12, "EUR") / Decimal("1.1")) assert line.taxful_discount_amount == TaxfulPrice(12, "EUR")
def test_unit_discount_amount(): assert line.unit_discount_amount == TaxfulPrice(12, "EUR") / 9
def test_taxed_base_unit_prices(): assert_almost_equal(line.taxless_base_unit_price, TaxlessPrice(5, "EUR") / Decimal("1.1")) assert line.taxful_base_unit_price == TaxfulPrice(5, "EUR")
def test_price(): assert line.price == TaxfulPrice(33, "EUR") # 5 * 9 - 12
def test_discounted_unit_price(): assert line.discounted_unit_price == TaxfulPrice(33, "EUR") / 9
def test_tax_special_cases3(): taxless_line = Line( base_unit_price=TaxfulPrice(0, "EUR"), quantity=0, discount_amount=TaxfulPrice(0, "EUR"), tax_amount=Money(0, "EUR"), ) assert taxless_line.taxful_price == TaxfulPrice(0, "EUR") assert taxless_line.taxless_price == TaxlessPrice(0, "EUR") assert taxless_line.base_unit_price == TaxfulPrice(0, "EUR") assert taxless_line.taxful_base_unit_price == TaxfulPrice(0, "EUR") assert taxless_line.taxless_base_unit_price == TaxlessPrice(0, "EUR") assert taxless_line.discount_amount == TaxfulPrice(0, "EUR") assert taxless_line.taxful_discount_amount == TaxfulPrice(0, "EUR") assert taxless_line.taxless_discount_amount == TaxlessPrice(0, "EUR") assert taxless_line.price == TaxfulPrice(0, "EUR") assert taxless_line.taxful_price == TaxfulPrice(0, "EUR") assert taxless_line.taxless_price == TaxlessPrice(0, "EUR") assert taxless_line.base_price == TaxfulPrice(0, "EUR") assert taxless_line.taxful_base_price == TaxfulPrice(0, "EUR") assert taxless_line.taxless_base_price == TaxlessPrice(0, "EUR") assert taxless_line.unit_discount_amount == TaxfulPrice(0, "EUR") assert taxless_line.taxful_unit_discount_amount == TaxfulPrice(0, "EUR") assert taxless_line.taxless_unit_discount_amount == TaxlessPrice(0, "EUR") assert taxless_line.discount_rate == 0 assert taxless_line.tax_rate == 0
class Line(Priceful): base_unit_price = None quantity = None discount_amount = None tax_amount = None def __init__(self, base_unit_price, quantity, discount_amount, tax_amount): self.base_unit_price = base_unit_price self.quantity = quantity self.discount_amount = discount_amount self.tax_amount = tax_amount line = Line( base_unit_price=TaxfulPrice(5, "EUR"), quantity=9, discount_amount=TaxfulPrice(12, "EUR"), tax_amount=Money(3, "EUR"), ) line2 = Line( base_unit_price=TaxfulPrice(10, "EUR"), quantity=123, discount_amount=TaxfulPrice(0, "EUR"), tax_amount=Money(123, "EUR"), ) def setup_module(module): # uses the get_precision to avoiding db hits set_precision_provider(babel_precision_provider.get_precision)
def test_money_propped_type_checking_currency(): foo = Foo(currency='EUR', includes_tax=True) with pytest.raises(TypeError): FooItem(foo=foo, price=TaxfulPrice(42, 'USD'))
def test_price_property_get(): m = get_market() assert m.price == TaxfulPrice(123, 'GBP')
def test_price_property_set_invalid_unit(): m = get_market() with pytest.raises(UnitMixupError): m.price = TaxlessPrice(3, 'GBP') with pytest.raises(UnitMixupError): m.price = TaxfulPrice(3, 'USD')