def setUp(self): self.ten_btc = Price(10, currency='BTC') self.twenty_btc = Price(20, currency='BTC') self.thirty_btc = Price(30, currency='BTC') self.forty_btc = Price(40, currency='BTC') self.range_ten_twenty = PriceRange(self.ten_btc, self.twenty_btc) self.range_thirty_forty = PriceRange(self.thirty_btc, self.forty_btc)
def test_quantize(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range = PriceRange(price1, price2) result = price_range.quantize() assert str(result.min_price.net.value) == '10.00' assert str(result.max_price.net.value) == '30.00'
def test_discounted_product_price(self): another_discount = models.Discount.objects.create( name='Flying Sale', rate=50) another_hat = models.Hat.objects.create(name='Silly Hat', slug='silly-hat', price=10, discount=another_discount) another_hat_simple_variant = another_hat.variants.create( price_offset=0, sku='silly-hat-simple') another_hat_offset_variant = another_hat.variants.create( price_offset=10, sku='silly-hat-offset') self.assertEqual(another_hat_simple_variant.get_price(), Price(5, currency='EUR')) self.assertEqual(another_hat_offset_variant.get_price(), Price(10, currency='EUR')) self.assertEqual(another_hat.get_price_range(), PriceRange(Price(5, currency='EUR'), Price(10, currency='EUR'))) self.assertEqual(another_hat_simple_variant.get_price(discount=False), Price(10, currency='EUR')) self.assertEqual(another_hat_offset_variant.get_price(discount=False), Price(20, currency='EUR')) self.assertEqual(another_hat.get_price_range(discount=False), PriceRange(Price(10, currency='EUR'), Price(20, currency='EUR')))
def test_equality(self): pr1 = PriceRange(self.ten_btc, self.twenty_btc) pr2 = PriceRange(self.ten_btc, self.twenty_btc) pr3 = PriceRange(self.ten_btc, self.ten_btc) pr4 = PriceRange(self.twenty_btc, self.twenty_btc) self.assertEqual(pr1, pr2) self.assertNotEqual(pr1, pr3) self.assertNotEqual(pr1, pr4) self.assertNotEqual(pr1, self.ten_btc)
def get_price_range(self, discounts=None): if self.variants.exists(): prices = [ self.get_price_per_item(variant, discounts=discounts) for variant in self ] return PriceRange(min(prices), max(prices)) price = calculate_discounted_price(self, self.price, discounts) return PriceRange(price, price)
def test_construction(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range = PriceRange(price1, price2) assert price_range.min_price == price1 assert price_range.max_price == price2 with pytest.raises(ValueError): PriceRange(price1, Price(Amount(20, 'PLN'), Amount(20, 'PLN'))) with pytest.raises(ValueError): PriceRange(price2, price1)
def test_replace(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price3 = Price(Amount(20, 'EUR'), Amount(30, 'EUR')) price_range = PriceRange(price1, price2) result = price_range.replace(max_price=price3) assert result.min_price == price1 assert result.max_price == price3 result = price_range.replace(min_price=price3) assert result.min_price == price3 assert result.max_price == price2
def test_comparison(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range1 = PriceRange(price1, price2) price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR')) price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR')) price_range2 = PriceRange(price3, price4) assert price_range1 == PriceRange(price1, price2) assert price_range1 != price_range2 assert price_range1 != PriceRange(price1, price1) assert price_range1 != PriceRange( Price(Amount(10, 'USD'), Amount(15, 'USD')), Price(Amount(30, 'USD'), Amount(45, 'USD'))) assert price_range1 != price1
def test_repr(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range = PriceRange(price1, price2) assert repr(price_range) == ( "PriceRange(Price(net=Amount('10', 'EUR'), gross=Amount('15', 'EUR')), Price(net=Amount('30', 'EUR'), gross=Amount('45', 'EUR')))" )
def test_repr(self): pr1 = self.range_thirty_forty pr2 = PriceRange(self.ten_btc, self.ten_btc) self.assertEqual( repr(pr1), "PriceRange(Price('30', currency='BTC')," " Price('40', currency='BTC'))") self.assertEqual(repr(pr2), "PriceRange(Price('10', currency='BTC'))")
def get_price_range(self, discounts=None, **kwargs): if not self.variants.exists(): price = calculate_discounted_price(self, self.price, discounts, **kwargs) return PriceRange(price, price) else: return super().get_price_range(discounts=discounts, **kwargs)
def test_non_taxed_product_price(self): # no tax group - tax should be zero self.assertEqual(self.cockatoo_variant.get_price(currency='PLN'), Price(5, currency='PLN')) pr = self.cockatoo.get_price_range(currency='PLN') self.assertEqual(pr, PriceRange(min_price=Price(5, currency='PLN'), max_price=Price(5, currency='PLN')))
def get_product_costs_data(product): zero_price = Price(0, 0, currency=settings.DEFAULT_CURRENCY) zero_price_range = PriceRange(zero_price, zero_price) purchase_costs_range = zero_price_range gross_margin = (0, 0) if not product.variants.exists(): return purchase_costs_range, gross_margin variants = product.variants.all() costs, margins = get_cost_data_from_variants(variants) if costs: purchase_costs_range = PriceRange(min(costs), max(costs)) if margins: gross_margin = (margins[0], margins[-1]) return purchase_costs_range, gross_margin
def exchange_currency(price, to_currency): if isinstance(price, PriceRange): return PriceRange(exchange_currency(price.min_price, to_currency), exchange_currency(price.max_price, to_currency)) if price.currency != BASE_CURRENCY: # Convert to default currency price = convert_price(price, BASE_CURRENCY) return convert_price(price, to_currency)
def test_pricerange(): tax_name = '2x Tax' tax = LinearTax(1, name=tax_name) price_range = PriceRange( Price(Amount(10, 'BTC'), Amount(10, 'BTC')), Price(Amount(20, 'BTC'), Amount(20, 'BTC'))) result = tax.apply(price_range) assert result.min_price == Price(Amount(10, 'BTC'), Amount(20, 'BTC')) assert result.max_price == Price(Amount(20, 'BTC'), Amount(40, 'BTC'))
def test_taxed_product_price(self): # 8% VAT self.assertEqual(self.macaw_variant.get_price(currency='PLN'), Price(5, Decimal('5.40'), currency='PLN')) pr = self.macaw.get_price_range(currency='PLN') self.assertEqual(pr, PriceRange(min_price=Price(5, Decimal('5.40'), currency='PLN'), max_price=Price(5, Decimal('5.40'), currency='PLN')))
def get_gross_price_range(self, discounts=None): grosses = [ self.get_price_per_item(variant, discounts=discounts) for variant in self ] if not grosses: return None grosses = sorted(grosses, key=lambda x: x.tax) return PriceRange(min(grosses), max(grosses))
def test_discount(): price = Price(Amount(100, 'BTC'), Amount(100, 'BTC')) discount = FractionalDiscount(factor='0.25') result = discount.apply(price) assert result.net == Amount(75, 'BTC') assert result.gross == Amount(75, 'BTC') price_range = PriceRange(price, price) result = discount.apply(price_range) assert result.min_price == Price(Amount(75, 'BTC'), Amount(75, 'BTC')) assert result.max_price == Price(Amount(75, 'BTC'), Amount(75, 'BTC'))
def test_discount(): price = Price(Amount(100, 'BTC'), Amount(100, 'BTC')) discount = percentage_discount(value=10, name='Ten percent off') result = discount.apply(price) assert result.net == Amount(90, 'BTC') assert result.gross == Amount(90, 'BTC') price_range = PriceRange(price, price) result = discount.apply(price_range) assert result.min_price == Price(Amount(90, 'BTC'), Amount(90, 'BTC')) assert result.max_price == Price(Amount(90, 'BTC'), Amount(90, 'BTC'))
def get_shipment_options(country_code): shipping_methods_qs = ShippingMethodCountry.objects.select_related( 'shipping_method') shipping_methods = shipping_methods_qs.filter(country_code=country_code) if not shipping_methods.exists(): shipping_methods = shipping_methods_qs.filter(country_code='') if shipping_methods: shipping_methods = shipping_methods.values_list('price', flat=True) return PriceRange(min_price=min(shipping_methods), max_price=max(shipping_methods))
def test_membership(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range = PriceRange(price1, price2) assert price1 in price_range assert price2 in price_range assert (price1 + price2) / 2 in price_range assert price1 + price2 not in price_range with pytest.raises(TypeError): 15 in price_range
def test_subtraction(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range1 = PriceRange(price1, price2) price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR')) price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR')) price_range2 = PriceRange(price3, price4) result = price_range2 - price_range1 assert result.min_price == price3 - price1 assert result.max_price == price4 - price2 result = price_range2 - price1 assert result.min_price == price3 - price1 assert result.max_price == price4 - price1 with pytest.raises(ValueError): price_range2 - PriceRange(Price(Amount(1, 'BTC'), Amount(1, 'BTC')), Price(Amount(2, 'BTC'), Amount(2, 'BTC'))) with pytest.raises(ValueError): price_range2 - Price(Amount(1, 'BTC'), Amount(1, 'BTC')) with pytest.raises(TypeError): price_range2 - 1
def test_addition(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range1 = PriceRange(price1, price2) price3 = Price(Amount(40, 'EUR'), Amount(60, 'EUR')) price4 = Price(Amount(80, 'EUR'), Amount(120, 'EUR')) price_range2 = PriceRange(price3, price4) result = price_range1 + price_range2 assert result.min_price == price1 + price3 assert result.max_price == price2 + price4 result = price_range1 + price3 assert result.min_price == price1 + price3 assert result.max_price == price2 + price3 with pytest.raises(ValueError): price_range1 + PriceRange(Price(Amount(1, 'BTC'), Amount(1, 'BTC')), Price(Amount(2, 'BTC'), Amount(2, 'BTC'))) with pytest.raises(ValueError): price_range1 + Price(Amount(1, 'BTC'), Amount(1, 'BTC')) with pytest.raises(TypeError): price_range1 + 1
def test_application(): price = Price(Amount(30, 'BTC'), Amount(30, 'BTC')) discount = FixedDiscount(Amount(10, 'BTC'), name='Ten off') result = discount.apply(price) assert result.net == Amount(20, 'BTC') assert result.gross == Amount(20, 'BTC') price_range = PriceRange(price, price) result = discount.apply(price_range) assert result.min_price == Price(Amount(20, 'BTC'), Amount(20, 'BTC')) assert result.max_price == Price(Amount(20, 'BTC'), Amount(20, 'BTC')) with pytest.raises(TypeError): discount.apply(1)
def get_cart_data(cart, shipping_range, currency, discounts): cart_total = None local_cart_total = None shipping_required = False total_with_shipping = None local_total_with_shipping = None if cart: cart_total = cart.get_total(discounts=discounts) local_cart_total = to_local_currency(cart_total, currency) shipping_required = cart.is_shipping_required() total_with_shipping = PriceRange(cart_total) if shipping_required and shipping_range: total_with_shipping = shipping_range + cart_total local_total_with_shipping = to_local_currency( total_with_shipping, currency) return { 'cart_total': cart_total, 'local_cart_total': local_cart_total, 'shipping_required': shipping_required, 'total_with_shipping': total_with_shipping, 'local_total_with_shipping': local_total_with_shipping}
def get_cart_data(cart, shipping_range, currency, discounts): """Return a JSON-serializable representation of the cart.""" cart_total = None local_cart_total = None shipping_required = False total_with_shipping = None local_total_with_shipping = None if cart: cart_total = cart.get_total(discounts=discounts) local_cart_total = to_local_currency(cart_total, currency) shipping_required = cart.is_shipping_required() total_with_shipping = PriceRange(cart_total) if shipping_required and shipping_range: total_with_shipping = shipping_range + cart_total local_total_with_shipping = to_local_currency( total_with_shipping, currency) return { 'cart_total': cart_total, 'local_cart_total': local_cart_total, 'shipping_required': shipping_required, 'total_with_shipping': total_with_shipping, 'taxed_total_with_shipping': price_range_get_taxed(total_with_shipping), 'local_total_with_shipping': local_total_with_shipping}
def price_range(self): prices = [country.price for country in self.price_per_country.all()] if prices: return PriceRange(min(prices), max(prices))
def get_gross_price_range(self, **kwargs): grosses = [self.get_price_per_item(item, **kwargs) for item in self] if not grosses: return None grosses = sorted(grosses, key=lambda x: x.tax) return PriceRange(min(grosses), max(grosses))
def get_price_range(self, **kwargs): prices = [self.get_price_per_item(item, **kwargs) for item in self] if not prices: raise AttributeError( 'Calling get_price_range() on an empty item range') return PriceRange(min(prices), max(prices))
class PriceRangeTest(unittest.TestCase): def setUp(self): self.ten_btc = Price(10, currency='BTC') self.twenty_btc = Price(20, currency='BTC') self.thirty_btc = Price(30, currency='BTC') self.forty_btc = Price(40, currency='BTC') self.range_ten_twenty = PriceRange(self.ten_btc, self.twenty_btc) self.range_thirty_forty = PriceRange(self.thirty_btc, self.forty_btc) def test_basics(self): self.assertEqual(self.range_ten_twenty.min_price, self.ten_btc) self.assertEqual(self.range_ten_twenty.max_price, self.twenty_btc) def test_valid_addition(self): pr1 = self.range_ten_twenty + self.range_thirty_forty self.assertEqual(pr1.min_price, self.ten_btc + self.thirty_btc) self.assertEqual(pr1.max_price, self.twenty_btc + self.forty_btc) pr2 = self.range_ten_twenty + self.ten_btc self.assertEqual(pr2.min_price, self.ten_btc + self.ten_btc) self.assertEqual(pr2.max_price, self.twenty_btc + self.ten_btc) def test_invalid_addition(self): self.assertRaises(TypeError, lambda: self.range_ten_twenty + 10) def test_subtraction(self): pr1 = self.range_thirty_forty - self.range_ten_twenty self.assertEqual(pr1.min_price, self.thirty_btc - self.ten_btc) self.assertEqual(pr1.max_price, self.forty_btc - self.twenty_btc) def test_valid_membership(self): ''' Prices can fit in a pricerange. ''' self.assertTrue(self.ten_btc in self.range_ten_twenty) self.assertTrue(self.twenty_btc in self.range_ten_twenty) self.assertFalse(self.thirty_btc in self.range_ten_twenty) def test_invalid_membership(self): ''' Non-prices can't fit in a pricerange. ''' self.assertRaises(TypeError, lambda: 15 in self.range_ten_twenty) def test_replacement(self): pr1 = self.range_ten_twenty.replace(max_price=self.thirty_btc) self.assertEqual(pr1.min_price, self.ten_btc) self.assertEqual(pr1.max_price, self.thirty_btc) pr2 = self.range_thirty_forty.replace(min_price=self.twenty_btc) self.assertEqual(pr2.min_price, self.twenty_btc) self.assertEqual(pr2.max_price, self.forty_btc) def test_tax(self): tax_name = '2x Tax' tax = LinearTax(1, name=tax_name) pr = self.range_ten_twenty + tax self.assertEqual(pr.min_price.net, self.ten_btc.net) self.assertEqual(pr.min_price.gross, self.ten_btc.gross * 2) self.assertEqual(pr.min_price.currency, self.ten_btc.currency) self.assertEqual(pr.max_price.net, self.twenty_btc.net) self.assertEqual(pr.max_price.gross, self.twenty_btc.gross * 2) self.assertEqual(pr.max_price.currency, self.twenty_btc.currency)
class PriceRangeTest(unittest.TestCase): def setUp(self): self.ten_btc = Price(10, currency='BTC') self.twenty_btc = Price(20, currency='BTC') self.thirty_btc = Price(30, currency='BTC') self.forty_btc = Price(40, currency='BTC') self.range_ten_twenty = PriceRange(self.ten_btc, self.twenty_btc) self.range_thirty_forty = PriceRange(self.thirty_btc, self.forty_btc) def test_basics(self): self.assertEqual(self.range_ten_twenty.min_price, self.ten_btc) self.assertEqual(self.range_ten_twenty.max_price, self.twenty_btc) def test_construction(self): pr = PriceRange(self.ten_btc) self.assertEqual(pr.min_price, self.ten_btc) self.assertEqual(pr.max_price, self.ten_btc) def test_invalid_construction(self): p = Price(10, currency='USD') self.assertRaises(ValueError, lambda: PriceRange(self.ten_btc, p)) self.assertRaises(ValueError, lambda: PriceRange(self.twenty_btc, self.ten_btc)) def test_addition(self): pr1 = self.range_ten_twenty + self.range_thirty_forty self.assertEqual(pr1.min_price, self.ten_btc + self.thirty_btc) self.assertEqual(pr1.max_price, self.twenty_btc + self.forty_btc) pr2 = self.range_ten_twenty + self.ten_btc self.assertEqual(pr2.min_price, self.ten_btc + self.ten_btc) self.assertEqual(pr2.max_price, self.twenty_btc + self.ten_btc) def test_invalid_addition(self): p = Price(10, currency='USD') pr = PriceRange(p) self.assertRaises(ValueError, lambda: self.range_ten_twenty + pr) self.assertRaises(ValueError, lambda: self.range_ten_twenty + p) self.assertRaises(TypeError, lambda: self.range_ten_twenty + 10) def test_subtraction(self): pr1 = self.range_thirty_forty - self.range_ten_twenty pr2 = self.range_thirty_forty - self.ten_btc self.assertEqual(pr1.min_price, self.thirty_btc - self.ten_btc) self.assertEqual(pr1.max_price, self.forty_btc - self.twenty_btc) self.assertEqual(pr2.min_price, self.thirty_btc - self.ten_btc) self.assertEqual(pr2.max_price, self.forty_btc - self.ten_btc) def test_invalid_subtraction(self): p = Price(10, currency='USD') pr = PriceRange(p) self.assertRaises(ValueError, lambda: self.range_thirty_forty - pr) self.assertRaises(ValueError, lambda: self.range_thirty_forty - p) self.assertRaises(TypeError, lambda: self.range_thirty_forty - 1) def test_equality(self): pr1 = PriceRange(self.ten_btc, self.twenty_btc) pr2 = PriceRange(self.ten_btc, self.twenty_btc) pr3 = PriceRange(self.ten_btc, self.ten_btc) pr4 = PriceRange(self.twenty_btc, self.twenty_btc) self.assertEqual(pr1, pr2) self.assertNotEqual(pr1, pr3) self.assertNotEqual(pr1, pr4) self.assertNotEqual(pr1, self.ten_btc) def test_membership(self): self.assertTrue(self.ten_btc in self.range_ten_twenty) self.assertTrue(self.twenty_btc in self.range_ten_twenty) self.assertFalse(self.thirty_btc in self.range_ten_twenty) def test_invalid_membership(self): self.assertRaises(TypeError, lambda: 15 in self.range_ten_twenty) def test_replacement(self): pr1 = self.range_ten_twenty.replace(max_price=self.thirty_btc) self.assertEqual(pr1.min_price, self.ten_btc) self.assertEqual(pr1.max_price, self.thirty_btc) pr2 = self.range_thirty_forty.replace(min_price=self.twenty_btc) self.assertEqual(pr2.min_price, self.twenty_btc) self.assertEqual(pr2.max_price, self.forty_btc) def test_repr(self): pr1 = self.range_thirty_forty pr2 = PriceRange(self.ten_btc, self.ten_btc) self.assertEqual( repr(pr1), "PriceRange(Price('30', currency='BTC')," " Price('40', currency='BTC'))") self.assertEqual( repr(pr2), "PriceRange(Price('10', currency='BTC'))")
def test_currency(): price1 = Price(Amount(10, 'EUR'), Amount(15, 'EUR')) price2 = Price(Amount(30, 'EUR'), Amount(45, 'EUR')) price_range = PriceRange(price1, price2) assert price_range.currency == 'EUR'