Ejemplo n.º 1
0
class ModelWithDefaultAsOldMoney(models.Model):
    money = MoneyField(default=OldMoney('0.01', 'RUB'),
                       max_digits=10,
                       decimal_places=2)
Ejemplo n.º 2
0
class TestFExpressions:

    parametrize_f_objects = pytest.mark.parametrize('f_obj, expected', (
        (F('money') + Money(100, 'USD'), Money(200, 'USD')),
        (F('money') + OldMoney(100, 'USD'), Money(200, 'USD')),
        (Money(100, 'USD') + F('money'), Money(200, 'USD')),
        (F('money') - Money(100, 'USD'), Money(0, 'USD')),
        (Money(100, 'USD') - F('money'), Money(0, 'USD')),
        (F('money') * 2, Money(200, 'USD')),
        (F('money') * F('integer'), Money(200, 'USD')),
        (Money(50, 'USD') * F('integer'), Money(100, 'USD')),
        (F('integer') * Money(50, 'USD'), Money(100, 'USD')),
        (Money(50, 'USD') / F('integer'), Money(25, 'USD')),
        (Money(51, 'USD') % F('integer'), Money(1, 'USD')),
        (F('money') / 2, Money(50, 'USD')),
        (F('money') % 98, Money(2, 'USD')),
        (F('money') / F('integer'), Money(50, 'USD')),
        (F('money') + F('money'), Money(200, 'USD')),
        (F('money') - F('money'), Money(0, 'USD')),
    ))

    @parametrize_f_objects
    def test_save(self, f_obj, expected):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, 'USD'),
                                                             integer=2)
        instance.money = f_obj
        instance.save()
        instance.refresh_from_db()
        assert instance.money == expected

    @parametrize_f_objects
    def test_f_update(self, f_obj, expected):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, 'USD'),
                                                             integer=2)
        ModelWithVanillaMoneyField.objects.update(money=f_obj)
        instance.refresh_from_db()
        assert instance.money == expected

    def test_default_update(self):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, 'USD'),
                                                             integer=2)
        second_money = Money(100, 'USD')
        ModelWithVanillaMoneyField.objects.update(second_money=second_money)
        instance.refresh_from_db()
        assert instance.second_money == second_money

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

    def test_update_fields_save(self):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, 'USD'),
                                                             integer=2)
        instance.money = F('money') + Money(100, 'USD')
        instance.save(update_fields=['money'])
        instance.refresh_from_db()
        assert instance.money == Money(200, 'USD')

    INVALID_EXPRESSIONS = [
        F('money') + Money(100, 'EUR'),
        F('money') * F('money'),
        F('money') / F('money'),
        F('money') % F('money'),
        F('money') + F('integer'),
        F('money') + F('second_money'),
        F('money')**F('money'),
        F('money')**F('integer'),
        F('money')**2,
    ]

    @pytest.mark.parametrize('f_obj', INVALID_EXPRESSIONS)
    def test_invalid_expressions_access(self, f_obj):
        instance = ModelWithVanillaMoneyField.objects.create(
            money=Money(100, 'USD'))
        with pytest.raises(ValidationError):
            instance.money = f_obj
Ejemplo n.º 3
0
class TestVanillaMoneyField:
    @pytest.mark.parametrize(
        "model_class, kwargs, expected",
        (
            (ModelWithVanillaMoneyField, {
                "money": Money("100.0")
            }, Money("100.0")),
            (ModelWithVanillaMoneyField, {
                "money": OldMoney("100.0")
            }, Money("100.0")),
            (BaseModel, {}, Money(0, "USD")),
            (BaseModel, {
                "money": "111.2"
            }, Money("111.2", "USD")),
            (BaseModel, {
                "money": Money("123", "PLN")
            }, Money("123", "PLN")),
            (BaseModel, {
                "money": OldMoney("123", "PLN")
            }, Money("123", "PLN")),
            (BaseModel, {
                "money": ("123", "PLN")
            }, Money("123", "PLN")),
            (BaseModel, {
                "money": (123.0, "PLN")
            }, Money("123", "PLN")),
            (ModelWithDefaultAsMoney, {}, Money("0.01", "RUB")),
            (ModelWithDefaultAsFloat, {}, Money("12.05", "PLN")),
            (ModelWithDefaultAsStringWithCurrency, {}, Money("123", "USD")),
            (ModelWithDefaultAsString, {}, Money("123", "PLN")),
            (ModelWithDefaultAsInt, {}, Money("123", "GHS")),
            (ModelWithDefaultAsDecimal, {}, Money("0.01", "CHF")),
            (CryptoModel, {
                "money": Money(10, "USDT")
            }, Money(10, "USDT")),
        ),
    )
    def test_create_defaults(self, model_class, kwargs, expected):
        instance = model_class.objects.create(**kwargs)
        assert instance.money == expected

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

    def test_old_money_defaults(self):
        instance = ModelWithDefaultAsOldMoney.objects.create()
        assert instance.money == Money(".01", "RUB")

    @pytest.mark.parametrize(
        "model_class, other_value",
        (
            (ModelWithVanillaMoneyField, Money("100.0")),
            (BaseModel, Money(0, "USD")),
            (ModelWithDefaultAsMoney, Money("0.01", "RUB")),
            (ModelWithDefaultAsFloat, OldMoney("12.05", "PLN")),
            (ModelWithDefaultAsFloat, Money("12.05", "PLN")),
        ),
    )
    def test_revert_to_default(self, model_class, other_value):
        if hasattr(model_class._meta, "get_field"):
            default_instance = model_class._meta.get_field(
                "money").get_default()
        else:
            default_instance = model_class._meta.get_field_by_name(
                "money").default
        instance1 = model_class.objects.create()
        pk = instance1.pk
        # Grab a fresh instance, change the currency to something non-default
        # and unexpected
        instance2 = model_class.objects.get(id=pk)
        instance2.money = Money(other_value.amount, "DKK")
        instance2.save()
        instance3 = model_class.objects.get(id=pk)
        assert instance3.money == Money(other_value.amount, "DKK")
        # Now change the field back to the default currency
        instance3.money = copy(default_instance)
        instance3.save()
        instance4 = model_class.objects.get(id=pk)
        assert instance4.money == default_instance

    @pytest.mark.parametrize("value",
                             ((1, "USD", "extra_string"), (1, None), (1, )))
    def test_invalid_values(self, value):
        with pytest.raises(ValidationError):
            BaseModel.objects.create(money=value)

    @pytest.mark.parametrize("money_class", (Money, OldMoney))
    @pytest.mark.parametrize("field_name", ("money", "second_money"))
    def test_save_new_value(self, field_name, money_class):
        ModelWithVanillaMoneyField.objects.create(
            **{field_name: money_class("100.0")})

        # Try setting the value directly
        retrieved = ModelWithVanillaMoneyField.objects.get()
        setattr(retrieved, field_name, Money(1, "DKK"))
        retrieved.save()
        retrieved = ModelWithVanillaMoneyField.objects.get()

        assert getattr(retrieved, field_name) == Money(1, "DKK")

    def test_rounding(self):
        money = Money("100.0623456781123219")

        instance = ModelWithVanillaMoneyField.objects.create(money=money)
        # TODO. Should instance.money be rounded too?

        retrieved = ModelWithVanillaMoneyField.objects.get(pk=instance.pk)

        assert retrieved.money == Money("100.06")

    @pytest.fixture(params=[Money, OldMoney])
    def objects_setup(self, request):
        Money = request.param
        ModelWithTwoMoneyFields.objects.bulk_create((
            ModelWithTwoMoneyFields(amount1=Money(1, "USD"),
                                    amount2=Money(2, "USD")),
            ModelWithTwoMoneyFields(amount1=Money(2, "USD"),
                                    amount2=Money(0, "USD")),
            ModelWithTwoMoneyFields(amount1=Money(3, "USD"),
                                    amount2=Money(0, "USD")),
            ModelWithTwoMoneyFields(amount1=Money(4, "USD"),
                                    amount2=Money(0, "GHS")),
            ModelWithTwoMoneyFields(amount1=Money(5, "USD"),
                                    amount2=Money(5, "USD")),
            ModelWithTwoMoneyFields(amount1=Money(5, "EUR"),
                                    amount2=Money(5, "USD")),
        ))

    @pytest.mark.parametrize(
        "filters, expected_count",
        (
            (Q(amount1=F("amount2")), 1),
            (Q(amount1__gt=F("amount2")), 2),
            (Q(amount1__in=(Money(1, "USD"), Money(5, "EUR"))), 2),
            (Q(id__in=(-1, -2)), 0),
            (Q(amount1=Money(1, "USD")) | Q(amount2=Money(0, "USD")), 3),
            (Q(amount1=Money(1, "USD")) | Q(amount1=Money(4, "USD"))
             | Q(amount2=Money(0, "GHS")), 2),
            (Q(amount1=OldMoney(1, "USD")) | Q(amount1=OldMoney(4, "USD"))
             | Q(amount2=OldMoney(0, "GHS")), 2),
            (Q(amount1=Money(1, "USD")) | Q(amount1=Money(5, "USD"))
             | Q(amount2=Money(0, "GHS")), 3),
            (Q(amount1=Money(1, "USD"))
             | Q(amount1=Money(4, "USD"), amount2=Money(0, "GHS")), 2),
            (Q(amount1=Money(1, "USD"))
             | Q(amount1__gt=Money(4, "USD"), amount2=Money(0, "GHS")), 1),
            (Q(amount1=Money(1, "USD"))
             | Q(amount1__gte=Money(4, "USD"), 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

    def test_date_lookup(self):
        DateTimeModel.objects.create(field=Money(1, "USD"),
                                     created="2016-12-05")
        assert DateTimeModel.objects.filter(
            created__date="2016-12-01").count() == 0
        assert DateTimeModel.objects.filter(
            created__date="2016-12-05").count() == 1

    @pytest.mark.parametrize(
        "lookup, rhs, expected",
        (
            ("startswith", 2, 1),
            ("regex", "^[134]", 3),
            ("iregex", "^[134]", 3),
            ("istartswith", 2, 1),
            ("contains", 5, 2),
            ("lt", 5, 4),
            ("endswith", 5, 2),
            ("iendswith", 5, 2),
            ("gte", 4, 3),
            ("iexact", 3, 1),
            ("exact", 3, 1),
            ("isnull", True, 0),
            ("range", (3, 5), 4),
            ("lte", 2, 2),
            ("gt", 3, 3),
            ("icontains", 5, 2),
            ("in", (1, 0), 1),
        ),
    )
    @pytest.mark.usefixtures("objects_setup")
    def test_all_lookups(self, lookup, rhs, expected):
        kwargs = {"amount1__" + lookup: rhs}
        assert ModelWithTwoMoneyFields.objects.filter(
            **kwargs).count() == expected

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

        instance = ModelWithVanillaMoneyField.objects.create(money=money)
        retrieved = ModelWithVanillaMoneyField.objects.get(money=money)

        assert instance.pk == retrieved.pk

    def test_issue_300_regression(self):
        date = datetime.datetime(year=2017, month=2, day=1)
        ModelIssue300.objects.filter(money__created=date)
        ModelIssue300.objects.filter(money__created__gt=date)

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

        instance = ModelWithVanillaMoneyField.objects.create(
            money=Money("100.0"))
        retrieved = ModelWithVanillaMoneyField.objects.get(money__gt=money)

        assert instance.pk == retrieved.pk

        assert ModelWithVanillaMoneyField.objects.filter(
            money__lt=money).count() == 0

    def test_filter_chaining(self):
        usd_instance = ModelWithVanillaMoneyField.objects.create(
            money=Money(100, "USD"))
        ModelWithVanillaMoneyField.objects.create(money=Money(100, "EUR"))
        query = ModelWithVanillaMoneyField.objects.filter().filter(
            money=Money(100, "USD"))
        assert usd_instance in query
        assert query.count() == 1

    @pytest.mark.parametrize(
        "model_class",
        (ModelWithVanillaMoneyField, ModelWithChoicesMoneyField))
    def test_currency_querying(self, model_class):
        model_class.objects.create(money=Money("100.0", "ZWN"))

        assert model_class.objects.filter(
            money__lt=Money("1000", "USD")).count() == 0
        assert model_class.objects.filter(
            money__lt=Money("1000", "ZWN")).count() == 1

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

    @pytest.mark.usefixtures("objects_setup")
    def test_in_lookup_f_expression(self):
        assert ModelWithTwoMoneyFields.objects.filter(
            amount1__in=(Money(4, "USD"), F("amount2"))).count() == 2

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

        queryset = NullMoneyFieldModel.objects.filter(field=None)
        assert queryset.count() == 1

    def test_null_default(self):
        instance = NullMoneyFieldModel.objects.create()
        assert instance.field is None
Ejemplo n.º 4
0
class TestFExpressions:

    parametrize_f_objects = pytest.mark.parametrize(
        "f_obj, expected",
        (
            (F("money") + Money(100, "USD"), Money(200, "USD")),
            (F("money") + OldMoney(100, "USD"), Money(200, "USD")),
            (Money(100, "USD") + F("money"), Money(200, "USD")),
            (F("money") - Money(100, "USD"), Money(0, "USD")),
            (Money(100, "USD") - F("money"), Money(0, "USD")),
            (F("money") * 2, Money(200, "USD")),
            (F("money") * F("integer"), Money(200, "USD")),
            (Money(50, "USD") * F("integer"), Money(100, "USD")),
            (F("integer") * Money(50, "USD"), Money(100, "USD")),
            (Money(50, "USD") / F("integer"), Money(25, "USD")),
            (Money(51, "USD") % F("integer"), Money(1, "USD")),
            (F("money") / 2, Money(50, "USD")),
            (F("money") % 98, Money(2, "USD")),
            (F("money") / F("integer"), Money(50, "USD")),
            (F("money") + F("money"), Money(200, "USD")),
            (F("money") - F("money"), Money(0, "USD")),
        ),
    )

    @parametrize_f_objects
    def test_save(self, f_obj, expected):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, "USD"),
                                                             integer=2)
        instance.money = f_obj
        instance.save()
        instance.refresh_from_db()
        assert instance.money == expected

    @parametrize_f_objects
    def test_f_update(self, f_obj, expected):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, "USD"),
                                                             integer=2)
        ModelWithVanillaMoneyField.objects.update(money=f_obj)
        instance.refresh_from_db()
        assert instance.money == expected

    def test_default_update(self):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, "USD"),
                                                             integer=2)
        second_money = Money(100, "USD")
        ModelWithVanillaMoneyField.objects.update(second_money=second_money)
        instance.refresh_from_db()
        assert instance.second_money == second_money

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

    def test_update_fields_save(self):
        instance = ModelWithVanillaMoneyField.objects.create(money=Money(
            100, "USD"),
                                                             integer=2)
        instance.money = F("money") + Money(100, "USD")
        instance.save(update_fields=["money"])
        instance.refresh_from_db()
        assert instance.money == Money(200, "USD")

    INVALID_EXPRESSIONS = [
        F("money") + Money(100, "EUR"),
        F("money") * F("money"),
        F("money") / F("money"),
        F("money") % F("money"),
        F("money") + F("integer"),
        F("money") + F("second_money"),
        F("money")**F("money"),
        F("money")**F("integer"),
        F("money")**2,
    ]

    @pytest.mark.parametrize("f_obj", INVALID_EXPRESSIONS)
    def test_invalid_expressions_access(self, f_obj):
        instance = ModelWithVanillaMoneyField.objects.create(
            money=Money(100, "USD"))
        with pytest.raises(ValidationError):
            instance.money = f_obj
Ejemplo n.º 5
0
class TestGetOrCreate:
    @pytest.mark.parametrize(
        "model, field_name, kwargs, currency",
        (
            (ModelWithVanillaMoneyField, "money", {
                "money_currency": "PLN"
            }, "PLN"),
            (ModelWithVanillaMoneyField, "money", {
                "money": Money(0, "EUR")
            }, "EUR"),
            (ModelWithVanillaMoneyField, "money", {
                "money": OldMoney(0, "EUR")
            }, "EUR"),
            (ModelWithSharedCurrency, "first", {
                "first": 10,
                "second": 15,
                "currency": "CZK"
            }, "CZK"),
        ),
    )
    def test_get_or_create_respects_currency(self, model, field_name, kwargs,
                                             currency):
        instance, created = model.objects.get_or_create(**kwargs)
        field = getattr(instance, field_name)
        assert str(
            field.currency
        ) == currency, "currency should be taken into account in get_or_create"

    def test_get_or_create_respects_defaults(self):
        value = Money(10, "SEK")
        instance = ModelWithUniqueIdAndCurrency.objects.create(money=value)
        instance, created = ModelWithUniqueIdAndCurrency.objects.get_or_create(
            id=instance.id, money_currency=instance.money_currency)
        assert not created
        assert instance.money == value

    def test_defaults(self):
        money = Money(10, "EUR")
        instance, _ = ModelWithVanillaMoneyField.objects.get_or_create(
            integer=1, defaults={"money": money})
        assert instance.money == money

    def test_currency_field_lookup(self):
        value = Money(10, "EUR")
        ModelWithVanillaMoneyField.objects.create(money=value)
        instance, created = ModelWithVanillaMoneyField.objects.get_or_create(
            money_currency__iexact="eur")
        assert not created
        assert instance.money == value

    @pytest.mark.parametrize(
        "model, create_kwargs, get_kwargs",
        (
            (NullMoneyFieldModel, {
                "field": Money(100, "USD")
            }, {
                "field": 100,
                "field_currency": "USD"
            }),
            (ModelWithSharedCurrency, {
                "first": 10,
                "second": 15,
                "currency": "USD"
            }, {
                "first": 10,
                "currency": "USD"
            }),
        ),
    )
    def test_no_default_model(self, model, create_kwargs, get_kwargs):
        model.objects.create(**create_kwargs)
        instance, created = model.objects.get_or_create(**get_kwargs)
        assert not created

    def test_shared_currency(self):
        instance, created = ModelWithSharedCurrency.objects.get_or_create(
            first=10, second=15, currency="USD")
        assert instance.first == Money(10, "USD")
        assert instance.second == Money(15, "USD")
Ejemplo n.º 6
0
class TestVanillaMoneyField:

    @pytest.mark.parametrize(
        'model_class, kwargs, expected',
        (
            (ModelWithVanillaMoneyField, {'money': Money('100.0')}, Money('100.0')),
            (ModelWithVanillaMoneyField, {'money': OldMoney('100.0')}, Money('100.0')),
            (BaseModel, {}, Money(0, 'USD')),
            (BaseModel, {'money': '111.2'}, Money('111.2', 'USD')),
            (BaseModel, {'money': Money('123', 'PLN')}, Money('123', 'PLN')),
            (BaseModel, {'money': OldMoney('123', 'PLN')}, Money('123', 'PLN')),
            (BaseModel, {'money': ('123', 'PLN')}, Money('123', 'PLN')),
            (BaseModel, {'money': (123.0, 'PLN')}, Money('123', 'PLN')),
            (ModelWithDefaultAsMoney, {}, Money('0.01', 'RUB')),
            (ModelWithDefaultAsFloat, {}, Money('12.05', 'PLN')),
            (ModelWithDefaultAsStringWithCurrency, {}, Money('123', 'USD')),
            (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.money == expected

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

    def test_old_money_defaults(self):
        instance = ModelWithDefaultAsOldMoney.objects.create()
        assert instance.money == Money('.01', 'RUB')

    @pytest.mark.parametrize(
        'model_class, other_value',
        (
            (ModelWithVanillaMoneyField, Money('100.0')),
            (BaseModel, Money(0, 'USD')),
            (ModelWithDefaultAsMoney, Money('0.01', 'RUB')),
            (ModelWithDefaultAsFloat, OldMoney('12.05', 'PLN')),
            (ModelWithDefaultAsFloat, Money('12.05', 'PLN')),
        )
    )
    def test_revert_to_default(self, model_class, other_value):
        if hasattr(model_class._meta, 'get_field'):
            default_instance = model_class._meta.get_field('money').get_default()
        else:
            default_instance = model_class._meta.get_field_by_name('money').default
        instance1 = model_class.objects.create()
        pk = instance1.pk
        # Grab a fresh instance, change the currency to something non-default
        # and unexpected
        instance2 = model_class.objects.get(id=pk)
        instance2.money = Money(other_value.amount, "DKK")
        instance2.save()
        instance3 = model_class.objects.get(id=pk)
        assert instance3.money == Money(other_value.amount, "DKK")
        # Now change the field back to the default currency
        instance3.money = copy(default_instance)
        instance3.save()
        instance4 = model_class.objects.get(id=pk)
        assert instance4.money == default_instance

    @pytest.mark.parametrize(
        'value',
        (
            (1, 'USD', 'extra_string'),
            (1, None),
            (1, ),
        )
    )
    def test_invalid_values(self, value):
        with pytest.raises(ValidationError):
            BaseModel.objects.create(money=value)

    @pytest.mark.parametrize('Money', (Money, OldMoney))
    @pytest.mark.parametrize('field_name', ('money', 'second_money'))
    def test_save_new_value(self, field_name, Money):
        ModelWithVanillaMoneyField.objects.create(**{field_name: Money('100.0')})

        # Try setting the value directly
        retrieved = ModelWithVanillaMoneyField.objects.get()
        setattr(retrieved, field_name, Money(1, 'DKK'))
        retrieved.save()
        retrieved = ModelWithVanillaMoneyField.objects.get()

        assert getattr(retrieved, field_name) == Money(1, 'DKK')

    def test_rounding(self):
        money = Money('100.0623456781123219')

        instance = ModelWithVanillaMoneyField.objects.create(money=money)
        # TODO. Should instance.money be rounded too?

        retrieved = ModelWithVanillaMoneyField.objects.get(pk=instance.pk)

        assert retrieved.money == Money('100.06')

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

    @pytest.mark.parametrize(
        'filters, expected_count',
        (
            (Q(amount1=F('amount2')), 1),
            (Q(amount1__gt=F('amount2')), 2),
            (Q(amount1__in=(Money(1, 'USD'), Money(5, 'EUR'))), 2),
            (Q(id__in=(-1, -2)), 0),
            (Q(amount1=Money(1, 'USD')) | Q(amount2=Money(0, 'USD')), 3),
            (Q(amount1=Money(1, 'USD')) | Q(amount1=Money(4, 'USD')) | Q(amount2=Money(0, 'GHS')), 2),
            (Q(amount1=OldMoney(1, 'USD')) | Q(amount1=OldMoney(4, 'USD')) | Q(amount2=OldMoney(0, 'GHS')), 2),
            (Q(amount1=Money(1, 'USD')) | Q(amount1=Money(5, 'USD')) | Q(amount2=Money(0, 'GHS')), 3),
            (Q(amount1=Money(1, 'USD')) | Q(amount1=Money(4, 'USD'), amount2=Money(0, 'GHS')), 2),
            (Q(amount1=Money(1, 'USD')) | Q(amount1__gt=Money(4, 'USD'), amount2=Money(0, 'GHS')), 1),
            (Q(amount1=Money(1, 'USD')) | Q(amount1__gte=Money(4, 'USD'), 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.skipif(VERSION[:2] == (1, 8), reason="Django 1.8 doesn't support __date lookup")
    def test_date_lookup(self):
        DateTimeModel.objects.create(field=Money(1, 'USD'), created='2016-12-05')
        assert DateTimeModel.objects.filter(created__date='2016-12-01').count() == 0
        assert DateTimeModel.objects.filter(created__date='2016-12-05').count() == 1

    @pytest.mark.parametrize('lookup, rhs, expected', (
        ('startswith', 2, 1),
        ('regex', '^[134]', 3),
        ('iregex', '^[134]', 3),
        ('istartswith', 2, 1),
        ('contains', 5, 2),
        ('lt', 5, 4),
        ('endswith', 5, 2),
        ('iendswith', 5, 2),
        ('gte', 4, 3),
        ('iexact', 3, 1),
        ('exact', 3, 1),
        ('isnull', True, 0),
        ('range', (3, 5), 4),
        ('lte', 2, 2),
        ('gt', 3, 3),
        ('icontains', 5, 2),
        ('in', (1, 0), 1)
    ))
    @pytest.mark.usefixtures('objects_setup')
    def test_all_lookups(self, lookup, rhs, expected):
        kwargs = {'amount1__' + lookup: rhs}
        assert ModelWithTwoMoneyFields.objects.filter(**kwargs).count() == expected

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

        instance = ModelWithVanillaMoneyField.objects.create(money=money)
        retrieved = ModelWithVanillaMoneyField.objects.get(money=money)

        assert instance.pk == retrieved.pk

    def test_issue_300_regression(self):
        date = datetime.datetime(year=2017, month=2, day=1)
        ModelIssue300.objects.filter(money__created=date)
        ModelIssue300.objects.filter(money__created__gt=date)

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

        instance = ModelWithVanillaMoneyField.objects.create(money=Money('100.0'))
        retrieved = ModelWithVanillaMoneyField.objects.get(money__gt=money)

        assert instance.pk == retrieved.pk

        assert ModelWithVanillaMoneyField.objects.filter(money__lt=money).count() == 0

    def test_filter_chaining(self):
        usd_instance = ModelWithVanillaMoneyField.objects.create(money=Money(100, 'USD'))
        ModelWithVanillaMoneyField.objects.create(money=Money(100, 'EUR'))
        query = ModelWithVanillaMoneyField.objects.filter().filter(money=Money(100, 'USD'))
        assert usd_instance in query
        assert query.count() == 1

    @pytest.mark.parametrize('model_class', (ModelWithVanillaMoneyField, ModelWithChoicesMoneyField))
    def test_currency_querying(self, model_class):
        model_class.objects.create(money=Money('100.0', 'ZWN'))

        assert model_class.objects.filter(money__lt=Money('1000', 'USD')).count() == 0
        assert model_class.objects.filter(money__lt=Money('1000', 'ZWN')).count() == 1

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

    @pytest.mark.usefixtures('objects_setup')
    def test_in_lookup_f_expression(self):
        assert ModelWithTwoMoneyFields.objects.filter(amount1__in=(Money(4, 'USD'), F('amount2'))).count() == 2

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

        queryset = NullMoneyFieldModel.objects.filter(field=None)
        assert queryset.count() == 1

    def test_null_default(self):
        instance = NullMoneyFieldModel.objects.create()
        assert instance.field is None
Ejemplo n.º 7
0
class TestGetOrCreate:
    @pytest.mark.parametrize('model, field_name, kwargs, currency',
                             ((ModelWithVanillaMoneyField, 'money', {
                                 'money_currency': 'PLN'
                             }, 'PLN'), (ModelWithVanillaMoneyField, 'money', {
                                 'money': Money(0, 'EUR')
                             }, 'EUR'), (ModelWithVanillaMoneyField, 'money', {
                                 'money': OldMoney(0, 'EUR')
                             }, 'EUR'), (ModelWithSharedCurrency, 'first', {
                                 'first': 10,
                                 'second': 15,
                                 'currency': 'CZK'
                             }, 'CZK')))
    def test_get_or_create_respects_currency(self, model, field_name, kwargs,
                                             currency):
        instance, created = model.objects.get_or_create(**kwargs)
        field = getattr(instance, field_name)
        assert str(
            field.currency
        ) == currency, 'currency should be taken into account in get_or_create'

    def test_get_or_create_respects_defaults(self):
        value = Money(10, 'SEK')
        instance = ModelWithUniqueIdAndCurrency.objects.create(money=value)
        instance, created = ModelWithUniqueIdAndCurrency.objects.get_or_create(
            id=instance.id, money_currency=instance.money_currency)
        assert not created
        assert instance.money == value

    def test_defaults(self):
        money = Money(10, 'EUR')
        instance, _ = ModelWithVanillaMoneyField.objects.get_or_create(
            integer=1, defaults={'money': money})
        assert instance.money == money

    def test_currency_field_lookup(self):
        value = Money(10, 'EUR')
        ModelWithVanillaMoneyField.objects.create(money=value)
        instance, created = ModelWithVanillaMoneyField.objects.get_or_create(
            money_currency__iexact='eur')
        assert not created
        assert instance.money == value

    @pytest.mark.parametrize('model, create_kwargs, get_kwargs', (
        (NullMoneyFieldModel, {
            'field': Money(100, 'USD')
        }, {
            'field': 100,
            'field_currency': 'USD'
        }),
        (ModelWithSharedCurrency, {
            'first': 10,
            'second': 15,
            'currency': 'USD'
        }, {
            'first': 10,
            'currency': 'USD'
        }),
    ))
    def test_no_default_model(self, model, create_kwargs, get_kwargs):
        model.objects.create(**create_kwargs)
        instance, created = model.objects.get_or_create(**get_kwargs)
        assert not created

    def test_shared_currency(self):
        instance, created = ModelWithSharedCurrency.objects.get_or_create(
            first=10, second=15, currency='USD')
        assert instance.first == Money(10, 'USD')
        assert instance.second == Money(15, 'USD')