def get_data(self): data = [] # group products by id - que queryset must be ordered by id to make this work for key, groups in itertools.groupby(self.get_objects(), lambda pl: pl.product_id): quantity = 0 taxful_total = TaxfulPrice(0, self.shop.currency) taxless_total = TaxlessPrice(0, self.shop.currency) product = None for order_line in groups: quantity += order_line.quantity taxful_total += order_line.taxful_price taxless_total += order_line.taxless_price if not product: product = order_line.product data.append({ "product": product.name, "sku": product.sku, "quantity": quantity, "taxful_total": taxful_total.as_rounded().value, "taxless_total": taxless_total.as_rounded().value, }) order_by = self.options.get("order_by") if order_by: data = sorted(data, key=itemgetter(order_by), reverse=True) return self.get_return_data(data)
def test_taxless_and_taxful_price_properties(): class Foo(object): taxful_value = 110 taxless_value = 100 currency = 'USD' taxful_price = TaxfulPriceProperty('taxful_value', 'currency') taxless_price = TaxlessPriceProperty('taxless_value', 'currency') foo = Foo() assert foo.taxful_price == TaxfulPrice(110, 'USD') foo.taxful_price = TaxfulPrice(220, 'USD') assert foo.taxful_price == TaxfulPrice(220, 'USD') assert foo.taxful_value == 220 assert foo.taxless_price == TaxlessPrice(100, 'USD') foo.taxless_price = TaxlessPrice(200, 'USD') assert foo.taxless_price == TaxlessPrice(200, 'USD') assert foo.taxless_value == 200 with pytest.raises(UnitMixupError): foo.taxful_price = TaxlessPrice(220, 'USD') with pytest.raises(UnitMixupError): foo.taxful_price = TaxfulPrice(220, 'EUR') with pytest.raises(UnitMixupError): foo.taxless_price = TaxfulPrice(220, 'USD') with pytest.raises(UnitMixupError): foo.taxless_price = TaxlessPrice(220, 'EUR')
def test_init_with_currency(): m42eur = TaxlessPrice(42, 'EUR') assert m42eur.amount == Money(42, 'EUR') assert m42eur.value == 42 assert m42eur.currency == 'EUR' assert TaxlessPrice(1, 'USD').currency == 'USD'
def _calc_compounded_added_taxes_from_taxless(amount, tax_groups): base_price = TaxlessPrice(amount) line_taxes = [] for taxes in tax_groups: taxed_price = stacked_value_added_taxes(base_price, taxes) base_price = TaxlessPrice(taxed_price.taxful) line_taxes.extend(taxed_price.taxes) return TaxedPrice(taxful=TaxfulPrice(base_price), taxless=TaxlessPrice(amount), taxes=line_taxes)
def test_init(): TaxfulPrice(42, 'EUR') TaxlessPrice(42, 'EUR') assert TaxfulPrice(currency='EUR').value == 0 assert TaxlessPrice(currency='EUR').value == 0 with pytest.raises(TypeError): Price() with pytest.raises(TypeError): Price(10) with pytest.raises(TypeError): Price(10, 'EUR')
def test_tax_special_cases1(): all_tax_line1 = Line(base_unit_price=TaxfulPrice(25, 'EUR'), quantity=5, discount_amount=TaxfulPrice(25, 'EUR'), tax_amount=Money(100, 'EUR')) assert all_tax_line1.taxful_price == TaxfulPrice(100, 'EUR') assert all_tax_line1.taxless_price == TaxlessPrice(0, 'EUR') assert all_tax_line1.taxful_discount_amount == TaxfulPrice(25, 'EUR') assert all_tax_line1.taxless_discount_amount == TaxlessPrice(0, 'EUR') assert all_tax_line1.tax_rate == 0 assert all_tax_line1.taxful_base_unit_price == TaxfulPrice(25, 'EUR') assert all_tax_line1.taxless_base_unit_price == TaxlessPrice(0, 'EUR')
def get_data(self): orders = self.get_objects().order_by("-order_date") data = [] 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) paid_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 if order.payment_date: paid_total += order.taxful_total_price data.append({ "date": format_date(order_date, format="short", locale=get_current_babel_locale()), "order_count": order_count, "product_count": int(product_count), "taxless_total": taxless_total, "taxful_total": taxful_total, }) return self.get_return_data(data)
def test_stacked_tax_taxful_price(): shop = get_shop(prices_include_tax=True, currency='EUR') source = OrderSource(shop) assert source.prices_include_tax source.add_line(type=OrderLineType.OTHER, quantity=1, base_unit_price=source.create_price(20)) with override_provides("tax_module", TAX_MODULE_SPEC): with override_settings(WSHOP_TAX_MODULE="irvine"): source.shipping_address = MutableAddress( street="16215 Alton Pkwy", postal_code="92602", ) line = source.get_final_lines(with_taxes=True)[0] assert isinstance(line, SourceLine) assert line.taxes assert line.taxful_price == TaxfulPrice(20, 'EUR') assert_almost_equal(line.taxless_price, TaxlessPrice("18.52", 'EUR')) source.uncache() # Let's move out to a taxless location. source.shipping_address.postal_code = "11111" line = source.get_final_lines(with_taxes=True)[0] assert isinstance(line, SourceLine) assert not line.taxes assert line.taxful_price == TaxfulPrice(20, source.currency) assert line.taxless_price.value == Decimal("20")
def test_convert_taxness_taxful_to_taxless(): request = get_request() tax_class = TaxClass() item = Product(tax_class=tax_class) priceful = _get_price_info(TaxfulPrice) calcs_done_before = DummyTaxModule.calculations_done result = convert_taxness(request, item, priceful, with_taxes=False) calcs_done_after = DummyTaxModule.calculations_done assert result != priceful assert (result.price - TaxlessPrice(400, 'USD')).value < 0.00001 assert result.base_price == TaxlessPrice(550, 'USD') assert result.quantity == 2 assert result.tax_amount == Money(80, 'USD') assert result.taxless_price == result.price assert result.taxful_price == priceful.price assert calcs_done_after == calcs_done_before + 2
def get_tax_summary(self): """ :rtype: TaxSummary """ all_line_taxes = [] untaxed = TaxlessPrice(self.create_price(0).amount) for line in self.get_final_lines(): line_taxes = list(line.taxes) all_line_taxes.extend(line_taxes) if not line_taxes: untaxed += line.taxless_price return taxing.TaxSummary.from_line_taxes(all_line_taxes, untaxed)
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
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: wshop.core.pricing.Price :param taxes: List of Tax objects :type taxes: list[wshop.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 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: wshop.core.pricing.Price """ if self.prices_include_tax: return TaxfulPrice(value, self.currency) else: return TaxlessPrice(value, self.currency)
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 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_tax_summary(source): """ Get tax summary of given source lines. :type source: OrderSource :type lines: list[SourceLine] :rtype: TaxSummary """ all_line_taxes = [] untaxed = TaxlessPrice(source.create_price(0).amount) for line in source.get_final_lines(): line_taxes = list(line.taxes) all_line_taxes.extend(line_taxes) if not line_taxes: untaxed += line.taxless_price return TaxSummary.from_line_taxes(all_line_taxes, untaxed)
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_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) order_line_tax = OrderLineTax.from_tax( get_default_tax(), ol.taxless_price.amount, order_line=ol) order_line_tax.save() ol.taxes.add(order_line_tax) 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 price(value): return TaxlessPrice(value, 'EUR')
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')
def test_money_propped_type_checking_taxness(): foo = Foo(currency='EUR', includes_tax=True) with pytest.raises(TypeError): FooItem(foo=foo, price=TaxlessPrice(42, 'EUR'))
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 tlprice(value): return TaxlessPrice(value, 'USD')
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_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_taxed_prices(): assert line.taxful_price == line.price assert line.taxless_price == TaxlessPrice(30, 'EUR') # 33 - 3
def test_tax_mixup(): with pytest.raises(TypeError): TaxfulPrice(42, 'EUR') - TaxlessPrice(2, 'EUR')
def test_new(): assert TaxfulPrice(currency='EUR').new(42) == TaxfulPrice(42, 'EUR') assert TaxlessPrice(currency='EUR').new(-10) == TaxlessPrice(-10, 'EUR') assert TaxfulPrice(10, 'GBP').new(5) == TaxfulPrice(5, 'GBP')