Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should be possible to change and save money back to default currency #227

Merged
merged 7 commits into from
Sep 21, 2016
Merged
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- id: end-of-file-fixer
- id: fix-encoding-pragma
- repo: git://github.com/FalconSocial/pre-commit-python-sorter
sha: d044ff27300a6dc8b1a56cd22552e3a810dc6f49
sha: 1.0.1
hooks:
- id: python-import-sorter
args:
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Changes in 0.10

- Fixed ``understands_money`` behaviour. Now it can be used as a decorator `#215`_ (`Stranger6667`_)
- Do not fail comparisons because of different currency. Just return ``False`` `#225`_ (`benjaoming`_ and `ivirabyan`_)
- Fixed: Not possible to revert MoneyField currency back to default `#221`_ (`benjaoming`_)

Changes in 0.9.1
----------------
Expand Down Expand Up @@ -219,4 +220,7 @@ Changes in 0.3
.. _tsouvarev: https://github.com/tsouvarev
.. _w00kie: https://github.com/w00kie
.. _willhcr: https://github.com/willhcr
<<<<<<< e6efad2071e1281609732cc5c9d5c1cbf5c17c18
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its probably should not be there :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No indeed :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just force-pushed the fix, wonder who made it first

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You did ;)

.. _ivirabyan: https://github.com/ivirabyan
=======
>>>>>>> Add release note
2 changes: 1 addition & 1 deletion djmoney/apps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
from django.apps import AppConfig


Expand Down
2 changes: 1 addition & 1 deletion djmoney/contrib/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# coding: utf-8
# -*- coding: utf-8 -*-
2 changes: 1 addition & 1 deletion djmoney/contrib/django_rest_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# coding: utf-8
# -*- coding: utf-8 -*-
from .fields import MoneyField, register_money_field # noqa
from .helpers import VERSION # noqa
4 changes: 2 additions & 2 deletions djmoney/contrib/django_rest_framework/fields.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# coding: utf-8
from moneyed import Money
# -*- coding: utf-8 -*-
from rest_framework.serializers import DecimalField, ModelSerializer

from djmoney.models.fields import MoneyField as ModelField
from moneyed import Money

from .helpers import IS_DRF_3

Expand Down
2 changes: 1 addition & 1 deletion djmoney/contrib/django_rest_framework/helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
from rest_framework import VERSION


Expand Down
11 changes: 7 additions & 4 deletions djmoney/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
from django.db.models.signals import class_prepared
from django.utils import translation

from djmoney import forms
from moneyed import Currency, Money
from moneyed.localization import _FORMATTER, format_money

from djmoney import forms

from .._compat import (
BaseExpression,
Expression,
Expand Down Expand Up @@ -258,9 +257,13 @@ def set_currency(self, obj, value):
# then the currency is already set up, before this code hits
# __set__ of MoneyField. This is because the currency field
# has less creation counter than money field.
#
# Gotcha:
# But we should also allow setting a field back to its original default
# value!
# https://github.com/django-money/django-money/issues/221
object_currency = obj.__dict__[self.currency_field_name]
default_currency = str(self.field.default_currency)
if object_currency != value and (object_currency == default_currency or value != default_currency):
if object_currency != value:
# in other words, update the currency only if it wasn't
# changed before.
setattr(obj, self.currency_field_name, value)
Expand Down
29 changes: 19 additions & 10 deletions djmoney/models/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .._compat import LOOKUP_SEP, BaseExpression, smart_unicode, wraps
from ..utils import get_currency_field_name, prepare_expression
from .fields import MoneyField
from .fields import CurrencyField, MoneyField


def _get_clean_name(name):
Expand Down Expand Up @@ -124,22 +124,31 @@ def _expand_money_kwargs(model, args=(), kwargs=None, exclusions=()):
"""
Augments kwargs so that they contain _currency lookups.
"""
involved_fields = [_get_clean_name(name) for name in kwargs]
for name, value in list(kwargs.items()):
if name in exclusions:
continue
if isinstance(value, Money):
clean_name = _get_clean_name(name)
kwargs[name] = value.amount
kwargs[get_currency_field_name(clean_name)] = smart_unicode(value.currency)
elif isinstance(_get_field(model, name), MoneyField):
if isinstance(value, (BaseExpression, F)):
clean_name = _get_clean_name(name)
if not isinstance(value, F):
value = prepare_expression(value)
kwargs[get_currency_field_name(clean_name)] = F(get_currency_field_name(value.name))
if is_in_lookup(name, value):
args += (_convert_in_lookup(model, name, value), )
del kwargs[name]
else:
field = _get_field(model, name)
if isinstance(field, MoneyField):
if isinstance(value, (BaseExpression, F)):
clean_name = _get_clean_name(name)
if not isinstance(value, F):
value = prepare_expression(value)
kwargs[get_currency_field_name(clean_name)] = F(get_currency_field_name(value.name))
if is_in_lookup(name, value):
args += (_convert_in_lookup(model, name, value), )
del kwargs[name]
elif isinstance(field, CurrencyField):
money_field_name = name[:-9] # Remove '_currency'
if money_field_name not in involved_fields:
money_field = _get_field(model, money_field_name)
kwargs[money_field_name] = money_field.default.amount

return args, kwargs


Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ universal = 1
line_length = 79
combine_as_imports = true
known_django = django
known_first_party = tests, djmoney
known_first_party = tests, djmoney, moneyed
known_third_party = pytest, rest_framework
sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
include_trailing_comma = true
Expand Down
2 changes: 1 addition & 1 deletion tests/contrib/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# coding: utf-8
# -*- coding: utf-8 -*-
2 changes: 1 addition & 1 deletion tests/contrib/test_django_rest_framework.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
import pytest
from moneyed import Money

Expand Down
3 changes: 2 additions & 1 deletion tests/test_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

from django import VERSION

import moneyed
import pytest

import moneyed
from moneyed import Money

from .testapp.forms import (
Expand Down
2 changes: 1 addition & 1 deletion tests/test_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from django.db.models import F, Q

import pytest
from moneyed import Money

from djmoney._compat import split_expression
from djmoney.models.managers import _expand_money_args, _expand_money_kwargs
from djmoney.utils import get_amount
from moneyed import Money

from .testapp.models import ModelWithNonMoneyField

Expand Down
2 changes: 1 addition & 1 deletion tests/test_migrations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
from textwrap import dedent

from django import VERSION
Expand Down
34 changes: 32 additions & 2 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

@author: jake
"""
from copy import copy
from decimal import Decimal

from django import VERSION
Expand All @@ -12,12 +13,12 @@
from django.db.models import F, Q
from django.utils.six import PY2

import moneyed
import pytest
from moneyed import Money

import moneyed
from djmoney._compat import Case, Func, Value, When
from djmoney.models.fields import MoneyField, MoneyPatched, NotSupportedLookup
from moneyed import Money

from .testapp.models import (
AbstractModel,
Expand Down Expand Up @@ -75,6 +76,35 @@ def test_create_defaults(self, model_class, kwargs, expected):
retrieved = model_class.objects.get(pk=instance.pk)
assert retrieved.money == expected

@pytest.mark.parametrize(
'model_class, other_value',
(
(ModelWithVanillaMoneyField, Money('100.0')),
(BaseModel, Money(0, 'USD')),
(ModelWithDefaultAsMoney, Money('0.01', 'RUB')),
(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

def test_not_supported_lookup(self):
with pytest.raises(NotSupportedLookup) as exc:
ModelWithVanillaMoneyField.objects.filter(money__regex='\d+').count()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_serialization.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
import pytest

from djmoney.serializers import Deserializer, Serializer
Expand Down
2 changes: 1 addition & 1 deletion tests/test_settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
import pytest


Expand Down
2 changes: 1 addition & 1 deletion tests/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from django.utils.translation import override

import pytest
from moneyed import Money

from djmoney.models.fields import MoneyPatched
from moneyed import Money


def assert_template(string, result, context=None):
Expand Down