Exemplo n.º 1
0
class TestExpressions(object):
    def test_conditional_update(self):
        SimpleMoneyModel.objects.bulk_create((
            SimpleMoneyModel(amount=Money(1)),
            SimpleMoneyModel(amount=Money(2)),
        ))
        SimpleMoneyModel.objects.update(
            amount=Case(When(amount=1, then=Value(10)), default=Value(0)))
        assert SimpleMoneyModel.objects.all()[:1].get().amount == Money(
            10, 'EUR')
        assert SimpleMoneyModel.objects.all()[1:2].get().amount == Money(
            0, 'EUR')

    @pytest.mark.skipif(VERSION < (1, 9),
                        reason='Only Django 1.9+ supports this')
    def test_create_func(self):
        instance = SimpleMoneyModel.objects.create(
            amount=Func(Value(-10), function='ABS'))
        instance.refresh_from_db()
        assert instance.amount.amount == 10

    @pytest.mark.parametrize('value, expected', (
        (None, None),
        (10, Money(10, 'EUR')),
        (Money(10, 'USD'), Money(10, 'USD')),
    ))
    def test_value_create(self, value, expected):
        instance = NullMoneyFieldModel.objects.create(amount=Value(value))
        instance.refresh_from_db()
        assert instance.amount == expected

    def test_value_create_invalid(self):
        with pytest.raises(ValidationError):
            SimpleMoneyModel.objects.create(amount=Value('string'))
Exemplo n.º 2
0
    def test_currency_querying(self, model_class):
        model_class.objects.create(amount=Money('100.0', 'GBP'))

        assert model_class.objects.filter(
            amount__lt=Money('1000', 'USD')).count() == 0
        assert model_class.objects.filter(
            amount__lt=Money('1000', 'GBP')).count() == 1
Exemplo n.º 3
0
 def test_fields(self, model_class):
     first_value = Money('100.0', 'GBP')
     second_value = Money('200.0', 'USD')
     instance = model_class.objects.create(amount=first_value,
                                           amount2=second_value)
     assert instance.amount == first_value
     assert instance.amount2 == second_value
Exemplo n.º 4
0
def test_find_models_related_to_money_models():
    money_model = SimpleMoneyModel.objects.create(amount=Money('100.0', 'USD'))
    ModelRelatedToModelWithMoney.objects.create(money_model=money_model)

    ModelRelatedToModelWithMoney.objects.get(
        money_model__amount=Money('100.0', 'USD'))
    ModelRelatedToModelWithMoney.objects.get(
        money_model__amount__lt=Money('1000.0', 'USD'))
Exemplo n.º 5
0
    def test_range_search(self):
        money = Money('3')

        instance = SimpleMoneyModel.objects.create(amount=Money('100.0'))
        retrieved = SimpleMoneyModel.objects.get(amount__gt=money)

        assert instance.pk == retrieved.pk
        assert SimpleMoneyModel.objects.filter(amount__lt=money).count() == 0
Exemplo n.º 6
0
 def test_default_currency(self):
     klass = self.create_class(default_currency=None,
                               default=Money(10, 'EUR'),
                               max_digits=10,
                               decimal_places=2)
     assert str(klass._meta.fields[2].default_currency) == 'EUR'
     instance = klass()
     assert instance.field == Money(10, 'EUR')
Exemplo n.º 7
0
    def test_save_new_value(self):
        instance = SimpleMoneyModel.objects.create(amount=Money('100.0'))

        # Try setting the value directly
        setattr(instance, 'amount', Money(1, 'GBP'))
        instance.save()
        instance.refresh_from_db()

        assert getattr(instance, 'amount') == Money(1, 'GBP')
Exemplo n.º 8
0
 def test_conditional_update(self):
     SimpleMoneyModel.objects.bulk_create((
         SimpleMoneyModel(amount=Money(1)),
         SimpleMoneyModel(amount=Money(2)),
     ))
     SimpleMoneyModel.objects.update(
         amount=Case(When(amount=1, then=Value(10)), default=Value(0)))
     assert SimpleMoneyModel.objects.all()[:1].get().amount == Money(
         10, 'EUR')
     assert SimpleMoneyModel.objects.all()[1:2].get().amount == Money(
         0, 'EUR')
Exemplo n.º 9
0
    def test_exact_match(self):
        money = Money('100.0')

        instance = SimpleMoneyModel.objects.create(amount=money)
        retrieved = SimpleMoneyModel.objects.get(amount=money)

        assert instance.pk == retrieved.pk
Exemplo n.º 10
0
    def test_isnull_lookup(self):
        NullMoneyFieldModel.objects.create(amount=None)
        NullMoneyFieldModel.objects.create(amount=Money(100, 'USD'))

        queryset = NullMoneyFieldModel.objects.filter(amount=None)

        assert queryset.count() == 1
Exemplo n.º 11
0
 def test_in_lookup(self):
     assert ModelWithTwoMoneyFields.objects.filter(
         amount1__in=(Money(1, 'EUR'), Money(5, 'USD'))).count() == 2
     assert ModelWithTwoMoneyFields.objects.filter(
         Q(amount1__lte=Money(2, 'EUR')),
         amount1__in=(Money(1, 'EUR'), Money(3, 'EUR'))).count() == 1
     assert ModelWithTwoMoneyFields.objects.exclude(
         amount1__in=(Money(1, 'EUR'), Money(5, 'USD'))).count() == 4
Exemplo n.º 12
0
 def test_money_field_serializer(self):
     model = SimpleMoneyModel.objects.create(
         amount=Money(amount='100.00', currency='EUR'))
     serializer = SimpleMoneyModelSerializer(model)
     expected = {
         'id': model.pk,
         'amount': model.amount.amount_rounded,
         'amount_currency': model.amount.currency,
     }
     assert serializer.data == expected
Exemplo n.º 13
0
class TestGetOrCreate(object):
    @pytest.mark.parametrize('kwargs, currency', (({
        'amount_currency': 'PLN'
    }, 'PLN'), ({
        'amount': Money(0, 'EUR')
    }, 'EUR')))
    def test_get_or_create_respects_currency(self, kwargs, currency):
        instance, created = SimpleMoneyModel.objects.get_or_create(**kwargs)
        assert str(
            instance.amount.currency
        ) == currency, 'currency should be taken into account in get_or_create'

    def test_defaults(self):
        money = Money(10, 'GBP')
        instance, _ = SimpleMoneyModel.objects.get_or_create(
            defaults={'amount': money})
        assert instance.amount == money
Exemplo n.º 14
0
 def test_patching(self):
     ProxyMoneyModel.objects.create(amount=Money('100.0', 'USD'))
     # This will fail if ProxyMoneyModel.objects doesn't have the patched manager
     assert ProxyMoneyModel.objects.filter(
         amount__gt=Money('50.00', 'GBP')).count() == 0
Exemplo n.º 15
0
 def test_defaults(self):
     money = Money(10, 'GBP')
     instance, _ = SimpleMoneyModel.objects.get_or_create(
         defaults={'amount': money})
     assert instance.amount == money
Exemplo n.º 16
0
 def test_objects_creation(self):
     SimpleMoneyModel.objects.create(amount=Money('100.0', 'USD'))
     assert SimpleMoneyModel.objects.count() == 1
Exemplo n.º 17
0
 def test_instances(self):
     ProxyMoneyModel.objects.create(amount=Money('100.0', 'USD'))
     assert isinstance(ProxyMoneyModel.objects.all()[:1].get(),
                       ProxyMoneyModel)
Exemplo n.º 18
0
 def test_string_parse(self):
     value = Money.from_string('100.0 GBP')
     assert value.amount == Decimal('100.0')
     assert value.currency == 'GBP'
     assert value.currency == CURRENCIES['GBP']
Exemplo n.º 19
0
 def test_mutation_of_currency_attribute(self):
     money = Money('2', 'EUR')
     with pytest.raises(AttributeError):
         money.currency = 'USD'
Exemplo n.º 20
0
class TestMoney(object):
    """
    Tests of the Money class
    """

    MONEY_CREATION = [
        # Int values
        (Money(10, 'EUR'), Decimal(10), 'EUR'),
        (Money(-10, 'EUR'), Decimal(-10), 'EUR'),
        # Str values
        (Money('10', 'EUR'), Decimal(10), 'EUR'),
        (Money('-10', 'EUR'), Decimal(-10), 'EUR'),
        (Money(str('10.50'), str('EUR')), Decimal('10.50'), 'EUR'),
        (Money(str('-10.50'), str('EUR')), Decimal('-10.50'), 'EUR'),
        (Money('10.50', 'EUR'), Decimal('10.50'), 'EUR'),
        (Money('-10.50', 'EUR'), Decimal('-10.50'), 'EUR'),
        # Float values
        (Money(10.50, 'EUR'), Decimal('10.50'), 'EUR'),
        (Money(-10.50, 'EUR'), Decimal('-10.50'), 'EUR'),
        # Decimal values
        (Money(Decimal('10.50'), 'EUR'), Decimal('10.50'), 'EUR'),
        (Money(Decimal('-10.50'), 'EUR'), Decimal('-10.50'), 'EUR'),
        # Unspecified currency
        (Money(10), Decimal(10), settings.DEFAULT_CURRENCY),
        # Unspecified amount
        (Money(currency='EUR'), 0, 'EUR'),
        # Internal type
        (Money(1, Currency(code='AAA', name='My Currency')), 1, 'AAA'),
        # Parsed value
        (Money('10 EUR'), 10, 'EUR'),
    ]

    @pytest.mark.parametrize('value,expected_amount,expected_currency',
                             MONEY_CREATION)
    def test_creation(self, value, expected_amount, expected_currency):
        assert isinstance(value, Money)
        assert value.amount == expected_amount
        assert value.currency.code == expected_currency

    MONEY_CREATION_UNSUPPORTED = [
        (lambda: Money('10 EUR', 'USD')),
        (lambda: Money('EUR 10 EUR')),
    ]

    @pytest.mark.parametrize('value', MONEY_CREATION_UNSUPPORTED)
    def test_invalid_creation(self, value):
        with pytest.raises(IncorrectMoneyInputError):
            value()

    def test_amount_attribute(self):
        value = Money(101, 'USD')
        assert value.amount == 101

    def test_mutation_of_amount_attribute(self):
        money = Money('2', 'EUR')
        with pytest.raises(AttributeError):
            money.amount = 1

    MONEY_PRECISION = [(Money('10 EUR'), Decimal(10)),
                       (Money('10.2 EUR'), Decimal('10.2')),
                       (Money('10.225 EUR'), Decimal('10.23')),
                       (Money('10.226 EUR'), Decimal('10.23')),
                       (Money('10.2288 EUR'), Decimal('10.23'))]

    @pytest.mark.parametrize('value,expected', MONEY_PRECISION)
    def test_amount_rounded_attribute(self, value, expected):
        assert value.amount_rounded == expected

    def test_mutation_of_amount_rounded_attribute(self):
        money = Money('2', 'EUR')
        with pytest.raises(AttributeError):
            money.amount_rounded = 1

    def test_currency_attribute(self):
        value = Money(101, 'USD')
        assert value.currency == 'USD'

    def test_mutation_of_currency_attribute(self):
        money = Money('2', 'EUR')
        with pytest.raises(AttributeError):
            money.currency = 'USD'

    MONEY_STRINGS = [
        # Default currency:
        (
            Money(' 123'),
            f'123 {settings.DEFAULT_CURRENCY}',
        ),
        (
            Money('-123'),
            f'-123 {settings.DEFAULT_CURRENCY}',
        ),
        # Test a currency with decimals:
        (
            Money('123', 'EUR'),
            '123 EUR',
        ),
        (
            Money('-123', 'EUR'),
            '-123 EUR',
        ),
        (
            Money('123.0000', 'EUR'),
            '123.0000 EUR',
        ),
        (
            Money('-123.0000', 'EUR'),
            '-123.0000 EUR',
        ),
        (
            Money('123.25', 'EUR'),
            '123.25 EUR',
        ),
        (
            Money('-123.25', 'EUR'),
            '-123.25 EUR',
        ),
        # Test a currency that is normally written without decimals:
        (
            Money('123', 'JPY'),
            '123 JPY',
        ),
        (
            Money('-123', 'JPY'),
            '-123 JPY',
        ),
        (
            Money('123.0000', 'JPY'),
            '123.0000 JPY',
        ),
        (
            Money('-123.0000', 'JPY'),
            '-123.0000 JPY',
        ),
        (
            Money('123.25', 'JPY'),
            '123.25 JPY',
        ),
        (
            Money('-123.25', 'JPY'),
            '-123.25 JPY',
        ),
    ]

    @pytest.mark.parametrize('value,expected', MONEY_STRINGS)
    def test_str(self, value, expected):
        assert str(value) == expected

    @pytest.mark.parametrize('value,expected', MONEY_STRINGS)
    def test_repr(self, value, expected):
        assert repr(value) == expected

    MONEY_ARITHMETIC = [
        # Casting
        (lambda: Money('100') + 0.5, Money('100.5')),
        (lambda: float(Money('100')), float(100)),
        (lambda: int(Money('100')), 100),

        # Addition
        (lambda: Money('100') + Money('100'), Money('200')),
        (lambda: Money('100') + Money('-100'), Money('0')),
        (lambda: Money('100') + 100, Money('200')),
        (lambda: Money('100') + -100, Money('0')),
        (lambda: Money('100') + Decimal('100'), Money('200')),
        (lambda: Money('100') + Decimal('-100'), Money('0')),

        # Subtraction
        (lambda: Money('100') - Money('100'), Money('0')),
        (lambda: Money('100') - Money('-100'), Money('200')),
        (lambda: Money('100') - 100, Money('0')),
        (lambda: Money('100') - -100, Money('200')),
        (lambda: Money('100') - Decimal('100'), Money('0')),
        (lambda: Money('100') - Decimal('-100'), Money('200')),

        # Multiplication
        (lambda: Money('100') * 4, Money('400')),
        (lambda: Money('100') * Decimal('4'), Money('400')),

        # Division
        (lambda: Money('100') / 4, Money('25')),
        (lambda: Money('100') / Decimal('4'), Money('25')),

        # Negation
        (lambda: -Money('100'), Money('-100')),
        (lambda: -Money('100.12', 'EUR'), Money('-100.12', 'EUR')),
        (lambda: +Money('100'), Money('100')),

        # Absolute value
        (lambda: abs(Money('-100')), Money('100')),
        (lambda: abs(Money('-100.12', 'EUR')), Money('100.12', 'EUR')),
        (lambda: abs(Money('0')), Money('0')),
        (lambda: abs(Money('100')), Money('100')),
        (lambda: abs(Money('100.12', 'EUR')), Money('100.12', 'EUR')),
    ]

    @pytest.mark.parametrize('value,expected', MONEY_ARITHMETIC)
    def test_arithmetic(self, value, expected):
        result = value()
        assert result == expected

    MONEY_ARITHMETIC_UNSUPPORTED = [
        # Modulus
        (lambda: 4 % Money('100')),
        (lambda: Decimal('4') % Money('100')),
        (lambda: Money('100') % 4),
        (lambda: Money('100') % Decimal('4')),

        # Division: floor division (see future import above)
        (lambda: Money('100') // 4),
        (lambda: Money('100') // Decimal('4')),

        # Dividing a value by Money
        (lambda: 4 / Money('100')),
        (lambda: Decimal('4') / Money('100')),
        (lambda: Money('100') / Money('100')),

        # Multiplication of 2 Money objects
        (lambda: Money('100') * Money('100')),

        # Subtracting money from a digit
        (lambda: 100 - Money('100')),
        (lambda: -100 - Money('100')),
        (lambda: Decimal('100') - Money('100')),
        (lambda: Decimal('-100') - Money('100')),
    ]

    @pytest.mark.parametrize('value', MONEY_ARITHMETIC_UNSUPPORTED)
    def test_invalid_arithmetic(self, value):
        with pytest.raises(TypeError):
            value()

    MONEY_ARITHMETIC_MISMATCHED = [
        # Mismatched currencies
        (lambda: Money('100', 'JPY') + Money('100', 'EUR')),
        (lambda: Money('100', 'JPY') - Money('100', 'EUR')),
    ]

    @pytest.mark.parametrize('value', MONEY_ARITHMETIC_MISMATCHED)
    def test_invalid_currency(self, value):
        with pytest.raises(CurrencyMismatch):
            value()

    MONEY_EQUALITY = [
        # Bool
        (bool(Money('0')), False),
        (bool(Money('1')), True),
        (bool(Money('0', 'EUR')), False),
        (bool(Money('1', 'EUR')), True),
        (bool(Money('-1', 'EUR')), True),

        # Equality
        (Money('0') == Money('0'), True),
        (Money('100') == Money('100'), True),
        (Money('-100') == Money('-100'), True),
        (Money('100', 'EUR') == Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') == Money('100', 'EUR'), True),

        # Mismatched currencies
        (Money('0', 'EUR') == Money('0', 'JPY'), False),
        (Money('100', 'JPY') == Money('100'), False),
        (Money('100', 'EUR') == Money('100', 'JPY'), False),
        (Money('100.0', 'EUR') == Money('100', 'JPY'), False),

        # Other types
        (Money('100.0', 'EUR') == Decimal('100'), False),
        (Money('100.0', 'EUR') == 100, False),
        (Decimal('100') == Money('100.0', 'EUR'), False),
        (100 == Money('100.0', 'EUR'), False),

        # Inequality
        (Money('0') != Money('0'), False),
        (Money('100') != Money('100'), False),
        (Money('-100') != Money('-100'), False),
        (Money('100', 'EUR') != Money('100', 'EUR'), False),
        (Money('100.0', 'EUR') != Money('100', 'EUR'), False),

        # Mismatched currencies
        (Money('0', 'EUR') != Money('0', 'JPY'), True),
        (Money('100', 'JPY') != Money('100'), True),
        (Money('100', 'EUR') != Money('100', 'JPY'), True),
        (Money('100.0', 'EUR') != Money('100', 'JPY'), True),

        # Other types
        (Money('100.0', 'EUR') != Decimal('100'), True),
        (Money('100.0', 'EUR') != 100, True),
        (Decimal('100') != Money('100.0', 'EUR'), True),
        (100 != Money('100.0', 'EUR'), True),

        # LT/GT
        (0 < Money('0'), False),
        (100 < Money('100'), False),
        (-100 < Money('-100'), False),
        (100 < Money('100', 'EUR'), False),
        (100.0 < Money('100', 'EUR'), False),
        (0 > Money('1'), False),
        (1 > Money('0'), True),
        (-101 > Money('-100'), False),
        (-100 > Money('-101'), True),
        (100 > Money('100.01', 'EUR'), False),
        (100.01 > Money('100', 'EUR'), True),
        (Money('0') < Money('0'), False),
        (Money('100') < Money('100'), False),
        (Money('-100') < Money('-100'), False),
        (Money('100', 'EUR') < Money('100', 'EUR'), False),
        (Money('100.0', 'EUR') < Money('100', 'EUR'), False),
        (Money('0') > Money('0'), False),
        (Money('100') > Money('100'), False),
        (Money('-100') > Money('-100'), False),
        (Money('100', 'EUR') > Money('100', 'EUR'), False),
        (Money('0') < Money('1'), True),
        (Money('1') < Money('0'), False),
        (Money('-101') < Money('-100'), True),
        (Money('-100') < Money('-101'), False),
        (Money('100', 'EUR') < Money('100.01', 'EUR'), True),
        (Money('100.01', 'EUR') < Money('100', 'EUR'), False),
        (Money('0') > Money('1'), False),
        (Money('1') > Money('0'), True),
        (Money('-101') > Money('-100'), False),
        (Money('-100') > Money('-101'), True),
        (Money('100', 'EUR') > Money('100.01', 'EUR'), False),
        (Money('100.01', 'EUR') > Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') < Money('100', 'EUR'), False),
        (Money('100.0', 'EUR') > Money('100', 'EUR'), False),

        # GTE/LTE
        (Money('0') <= Money('0'), True),
        (Money('100') <= Money('100'), True),
        (Money('-100') <= Money('-100'), True),
        (Money('100', 'EUR') <= Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') <= Money('100', 'EUR'), True),
        (Money('0') >= Money('0'), True),
        (Money('100') >= Money('100'), True),
        (Money('-100') >= Money('-100'), True),
        (Money('100', 'EUR') >= Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') >= Money('100', 'EUR'), True),
        (Money('0') <= Money('1'), True),
        (Money('1') <= Money('0'), False),
        (Money('-101') <= Money('-100'), True),
        (Money('-100') <= Money('-101'), False),
        (Money('100', 'EUR') <= Money('100.01', 'EUR'), True),
        (Money('100.01', 'EUR') <= Money('100', 'EUR'), False),
        (Money('0') >= Money('1'), False),
        (Money('1') >= Money('0'), True),
        (Money('-101') >= Money('-100'), False),
        (Money('-100') >= Money('-101'), True),
        (Money('100', 'EUR') >= Money('100.01', 'EUR'), False),
        (Money('100.01', 'EUR') >= Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') <= Money('100', 'EUR'), True),
        (Money('100.0', 'EUR') >= Money('100', 'EUR'), True),
    ]

    @pytest.mark.parametrize('value,expected', MONEY_EQUALITY)
    def test_equality(self, value, expected):
        assert value == expected

    def test_string_parse(self):
        value = Money.from_string('100.0 GBP')
        assert value.amount == Decimal('100.0')
        assert value.currency == 'GBP'
        assert value.currency == CURRENCIES['GBP']

    def test_string_parse_default_currency(self):
        value = Money.from_string('100.35')
        assert value.amount == Decimal('100.35')
        assert value.currency == settings.DEFAULT_CURRENCY
        assert value.currency == CURRENCIES[settings.DEFAULT_CURRENCY]

    MONEY_ROUND = [
        (lambda: Money('123.001', 'EUR').round(), Money('123', 'EUR')),
        (lambda: Money('123.005', 'EUR').round(), Money('123.01', 'EUR')),
        (lambda: Money('123.006', 'EUR').round(), Money('123.01', 'EUR')),
        (lambda: Money('123.001', 'EUR').round(3), Money('123.001', 'EUR')),
        (lambda: Money('123.005', 'EUR').round(3), Money('123.005', 'EUR')),
        (lambda: Money('123.006', 'EUR').round(3), Money('123.006', 'EUR')),
    ]

    @pytest.mark.parametrize('value,expected', MONEY_ROUND)
    def test_round(self, value, expected):
        assert value() == expected
Exemplo n.º 21
0
 def test_string_parse_default_currency(self):
     value = Money.from_string('100.35')
     assert value.amount == Decimal('100.35')
     assert value.currency == settings.DEFAULT_CURRENCY
     assert value.currency == CURRENCIES[settings.DEFAULT_CURRENCY]
Exemplo n.º 22
0
 def test_f_update(self, f_obj, expected):
     instance = SimpleMoneyModel.objects.create(amount=Money(100, 'USD'))
     SimpleMoneyModel.objects.update(amount=f_obj)
     instance.refresh_from_db()
     assert instance.amount == expected
Exemplo n.º 23
0
 def test_update_fields_save(self):
     instance = SimpleMoneyModel.objects.create(amount=Money(100, 'USD'))
     instance.amount = F('amount') + Money(100, 'USD')
     instance.save(update_fields=['amount'])
     instance = SimpleMoneyModel.objects.get(pk=instance.pk)
     assert instance.amount == Money(200, 'USD')
Exemplo n.º 24
0
class TestMoneyField(object):
    @pytest.mark.parametrize('value', (
        (1, 'USD', 'extra_string'),
        (1, None),
        (1, ),
    ))
    def test_create_with_invalid_values(self, value):
        with pytest.raises(ValidationError):
            SimpleMoneyModel.objects.create(amount=value)

    @pytest.mark.parametrize('model_class, kwargs, expected', (
        (NullMoneyFieldModel, {}, None),
        (SimpleMoneyModel, {
            'amount': Money('100.0')
        }, Money('100.0')),
        (SimpleMoneyModel, {}, Money(0, 'EUR')),
        (SimpleMoneyModel, {
            'amount': '111.2'
        }, Money('111.2', 'EUR')),
        (SimpleMoneyModel, {
            'amount': Money('123', 'PLN')
        }, Money('123', 'PLN')),
        (SimpleMoneyModel, {
            'amount': ('123', 'PLN')
        }, Money('123', 'PLN')),
        (SimpleMoneyModel, {
            'amount': (123.0, 'PLN')
        }, Money('123', 'PLN')),
        (ModelWithDefaultAsMoney, {}, Money('0.01', 'RUB')),
        (ModelWithDefaultAsFloat, {}, Money('12.05', 'PLN')),
        (ModelWithDefaultAsStringWithCurrency, {}, Money('123', 'EUR')),
        (ModelWithDefaultAsString, {}, Money('123', 'PLN')),
        (ModelWithDefaultAsInt, {}, Money('123', 'GHS')),
        (ModelWithDefaultAsDecimal, {}, Money('0.01', 'CHF')),
    ))
    def test_create_defaults(self, model_class, kwargs, expected):
        instance = model_class.objects.create(**kwargs)
        assert instance.amount == expected

        retrieved = model_class.objects.get(pk=instance.pk)
        assert retrieved.amount == expected

    def test_save_new_value(self):
        instance = SimpleMoneyModel.objects.create(amount=Money('100.0'))

        # Try setting the value directly
        setattr(instance, 'amount', Money(1, 'GBP'))
        instance.save()
        instance.refresh_from_db()

        assert getattr(instance, 'amount') == Money(1, 'GBP')

    def test_not_supported_lookup(self):
        with pytest.raises(NotSupportedLookup) as exc:
            SimpleMoneyModel.objects.filter(amount__regex=r'\d+').count()
        assert str(
            exc.value) == 'Lookup "regex" is not supported for MoneyField'

    @pytest.fixture
    def objects_setup(self):
        ModelWithTwoMoneyFields.objects.bulk_create((
            ModelWithTwoMoneyFields(amount1=Money(1, 'EUR'),
                                    amount2=Money(2, 'EUR')),
            ModelWithTwoMoneyFields(amount1=Money(2, 'EUR'),
                                    amount2=Money(0, 'EUR')),
            ModelWithTwoMoneyFields(amount1=Money(3, 'EUR'),
                                    amount2=Money(0, 'EUR')),
            ModelWithTwoMoneyFields(amount1=Money(4, 'EUR'),
                                    amount2=Money(0, 'GHS')),
            ModelWithTwoMoneyFields(amount1=Money(5, 'EUR'),
                                    amount2=Money(5, 'EUR')),
            ModelWithTwoMoneyFields(amount1=Money(5, 'USD'),
                                    amount2=Money(5, 'EUR')),
        ))

    @pytest.mark.parametrize('filters, expected_count', (
        (Q(amount1=F('amount2')), 1),
        (Q(amount1__gt=F('amount2')), 2),
        (Q(amount1__in=(Money(1, 'EUR'), Money(5, 'USD'))), 2),
        (Q(id__in=(-1, -2)), 0),
        (Q(amount1=Money(1, 'EUR')) | Q(amount2=Money(0, 'EUR')), 3),
        (Q(amount1=Money(1, 'EUR')) | Q(amount1=Money(4, 'EUR'))
         | Q(amount2=Money(0, 'GHS')), 2),
        (Q(amount1=Money(1, 'EUR')) | Q(amount1=Money(5, 'EUR'))
         | Q(amount2=Money(0, 'GHS')), 3),
        (Q(amount1=Money(1, 'EUR'))
         | Q(amount1=Money(4, 'EUR'), amount2=Money(0, 'GHS')), 2),
        (Q(amount1=Money(1, 'EUR'))
         | Q(amount1__gt=Money(4, 'EUR'), amount2=Money(0, 'GHS')), 1),
        (Q(amount1=Money(1, 'EUR'))
         | Q(amount1__gte=Money(4, 'EUR'), amount2=Money(0, 'GHS')), 2),
    ))
    @pytest.mark.usefixtures('objects_setup')
    def test_comparison_lookup(self, filters, expected_count):
        assert ModelWithTwoMoneyFields.objects.filter(
            filters).count() == expected_count

    @pytest.mark.usefixtures('objects_setup')
    def test_in_lookup(self):
        assert ModelWithTwoMoneyFields.objects.filter(
            amount1__in=(Money(1, 'EUR'), Money(5, 'USD'))).count() == 2
        assert ModelWithTwoMoneyFields.objects.filter(
            Q(amount1__lte=Money(2, 'EUR')),
            amount1__in=(Money(1, 'EUR'), Money(3, 'EUR'))).count() == 1
        assert ModelWithTwoMoneyFields.objects.exclude(
            amount1__in=(Money(1, 'EUR'), Money(5, 'USD'))).count() == 4

    def test_isnull_lookup(self):
        NullMoneyFieldModel.objects.create(amount=None)
        NullMoneyFieldModel.objects.create(amount=Money(100, 'USD'))

        queryset = NullMoneyFieldModel.objects.filter(amount=None)

        assert queryset.count() == 1

    def test_rounding(self):
        instance = SimpleMoneyModel.objects.create(
            amount=Money('100.0623456781123219'))
        instance.refresh_from_db()
        assert instance.amount == Money('100.06')

    def test_exact_match(self):
        money = Money('100.0')

        instance = SimpleMoneyModel.objects.create(amount=money)
        retrieved = SimpleMoneyModel.objects.get(amount=money)

        assert instance.pk == retrieved.pk

    def test_range_search(self):
        money = Money('3')

        instance = SimpleMoneyModel.objects.create(amount=Money('100.0'))
        retrieved = SimpleMoneyModel.objects.get(amount__gt=money)

        assert instance.pk == retrieved.pk
        assert SimpleMoneyModel.objects.filter(amount__lt=money).count() == 0

    # @pytest.mark.parametrize('model_class', (SimpleMoneyModel, ModelWithChoicesMoneyField))
    @pytest.mark.parametrize('model_class', (SimpleMoneyModel, ))
    def test_currency_querying(self, model_class):
        model_class.objects.create(amount=Money('100.0', 'GBP'))

        assert model_class.objects.filter(
            amount__lt=Money('1000', 'USD')).count() == 0
        assert model_class.objects.filter(
            amount__lt=Money('1000', 'GBP')).count() == 1
Exemplo n.º 25
0
class TestFExpressions(object):
    parametrize_f_objects = pytest.mark.parametrize('f_obj, expected', (
        (F('amount') + Money(100, 'USD'), Money(200, 'USD')),
        (F('amount') - Money(100, 'USD'), Money(0, 'USD')),
        (F('amount') * 2, Money(200, 'USD')),
        (F('amount') * 2, Money(200, 'USD')),
        (F('amount') / 2, Money(50, 'USD')),
        (F('amount') % 98, Money(2, 'USD')),
        (F('amount') / 2, Money(50, 'USD')),
        (F('amount') + F('amount'), Money(200, 'USD')),
        (F('amount') - F('amount'), Money(0, 'USD')),
    ))

    @parametrize_f_objects
    def test_save(self, f_obj, expected):
        instance = SimpleMoneyModel.objects.create(amount=Money(100, 'USD'))
        instance.amount = f_obj
        instance.save()
        instance.refresh_from_db()
        assert instance.amount == expected

    @parametrize_f_objects
    def test_f_update(self, f_obj, expected):
        instance = SimpleMoneyModel.objects.create(amount=Money(100, 'USD'))
        SimpleMoneyModel.objects.update(amount=f_obj)
        instance.refresh_from_db()
        assert instance.amount == expected

    @pytest.mark.parametrize('create_kwargs, filter_value, in_result', (
        ({
            'amount1': Money(100, 'USD'),
            'amount2': Money(100, 'USD')
        }, {
            'amount1': F('amount1')
        }, True),
        ({
            'amount1': Money(100, 'USD'),
            'amount2': Money(100, 'USD')
        }, {
            'amount1': F('amount2')
        }, True),
        ({
            'amount1': Money(100, 'USD'),
            'amount2': Money(100, 'EUR')
        }, {
            'amount1': F('amount2')
        }, False),
        ({
            'amount1': Money(50, 'USD'),
            'amount2': Money(100, 'USD')
        }, {
            'amount2': F('amount1') * 2
        }, True),
        ({
            'amount1': Money(50, 'USD'),
            'amount2': Money(100, 'USD')
        }, {
            'amount2': F('amount1') + Money(50, 'USD')
        }, True),
        ({
            'amount1': Money(50, 'USD'),
            'amount2': Money(100, 'EUR')
        }, {
            'amount2': F('amount1') * 2
        }, False),
        ({
            'amount1': Money(50, 'USD'),
            'amount2': Money(100, 'EUR')
        }, {
            'amount2': F('amount1') + Money(50, 'USD')
        }, False),
    ))
    def test_filtration(self, create_kwargs, filter_value, in_result):
        instance = ModelWithTwoMoneyFields.objects.create(**create_kwargs)
        assert (instance in ModelWithTwoMoneyFields.objects.filter(
            **filter_value)) is in_result

    def test_update_fields_save(self):
        instance = SimpleMoneyModel.objects.create(amount=Money(100, 'USD'))
        instance.amount = F('amount') + Money(100, 'USD')
        instance.save(update_fields=['amount'])
        instance = SimpleMoneyModel.objects.get(pk=instance.pk)
        assert instance.amount == Money(200, 'USD')
Exemplo n.º 26
0
 def test_currency_attribute(self):
     value = Money(101, 'USD')
     assert value.currency == 'USD'
Exemplo n.º 27
0
class ModelWithDefaultAsMoney(models.Model):
    amount = MoneyField(default=Money('0.01', 'RUB'),
                        max_digits=10,
                        decimal_places=2)
Exemplo n.º 28
0
 def test_rounding(self):
     instance = SimpleMoneyModel.objects.create(
         amount=Money('100.0623456781123219'))
     instance.refresh_from_db()
     assert instance.amount == Money('100.06')
Exemplo n.º 29
0
 def objects_setup(self):
     ModelWithTwoMoneyFields.objects.bulk_create((
         ModelWithTwoMoneyFields(amount1=Money(1, 'EUR'),
                                 amount2=Money(2, 'EUR')),
         ModelWithTwoMoneyFields(amount1=Money(2, 'EUR'),
                                 amount2=Money(0, 'EUR')),
         ModelWithTwoMoneyFields(amount1=Money(3, 'EUR'),
                                 amount2=Money(0, 'EUR')),
         ModelWithTwoMoneyFields(amount1=Money(4, 'EUR'),
                                 amount2=Money(0, 'GHS')),
         ModelWithTwoMoneyFields(amount1=Money(5, 'EUR'),
                                 amount2=Money(5, 'EUR')),
         ModelWithTwoMoneyFields(amount1=Money(5, 'USD'),
                                 amount2=Money(5, 'EUR')),
     ))
Exemplo n.º 30
0
 def test_mutation_of_amount_rounded_attribute(self):
     money = Money('2', 'EUR')
     with pytest.raises(AttributeError):
         money.amount_rounded = 1