Skip to main content

A currency field and support for ``z3c.form``.

Project description

https://github.com/zopefoundation/z3c.currency/actions/workflows/tests.yml/badge.svg https://coveralls.io/repos/github/zopefoundation/z3c.currency/badge.svg?branch=master https://img.shields.io/pypi/v/z3c.currency.svg https://img.shields.io/pypi/pyversions/z3c.currency.svg

A package implementing a currency field for zope.schema and support for using the field with z3c.form.

Detailed Documentation

The Currency Field

The currency field is a numerical field, specifically designed to manage monetary values.

>>> from z3c.currency import field, interfaces
>>> price = field.Currency(
...    title='Price',
...    description='The price of the item.')

Besides the common attributes, the currency field also provides two additional attributes, the precision and unit. The precision is intended to allow for specifying whether the value is provided whole units or 1/100th of the whole unit – in the US dollar and cents. By default this field is set to cents:

>>> price.precision is interfaces.CENTS
True

It can be set to be dollars:

>>> price.precision = interfaces.DOLLARS
>>> price.precision is interfaces.DOLLARS
True

For financial applications, we also sometimes needsub-cents:

>>> price.precision = interfaces.SUBCENTS
>>> price.precision is interfaces.SUBCENTS
True

Note: Is there a more “internationalized” word for the whole unit of a currency?

The unit specifies the symbol of the currency used. It is also used for formatting the numerical value to a string.

>>> price.unit
'$'
>>> price.unit = 'SEK'
>>> price.unit
'SEK'

Of course, both of those attributes are available as constructor arguments:

>>> price = field.Currency(
...    title='Price',
...    description='The price of the item.',
...    precision=interfaces.DOLLARS,
...    unit='SEK')
>>> price.precision is interfaces.DOLLARS
True
>>> price.unit
'SEK'

Let’s now have a look at the validation. First of all, the value must always be a decimal:

>>> import decimal
>>> price.validate(decimal.Decimal('12'))
>>> price.validate(12)
Traceback (most recent call last):
...
z3c.currency.interfaces.WrongCurrencyType: int
>>> price.validate(12.0)
Traceback (most recent call last):
...
z3c.currency.interfaces.WrongCurrencyType: float

Also, when the precision is set to DOLLARS as it is the case here, the value must be a whole number:

>>> price.validate(decimal.Decimal('12'))
>>> price.validate(decimal.Decimal('12.01'))
Traceback (most recent call last):
...
z3c.currency.interfaces.IncorrectValuePrecision: 0
>>> price.validate(decimal.Decimal('12.00'))
Traceback (most recent call last):
...
z3c.currency.interfaces.IncorrectValuePrecision: 0

When the precision is set to cents,

>>> price.precision = interfaces.CENTS

then values only with two decimal places are accepted:

>>> price.validate(decimal.Decimal('12.00'))
>>> price.validate(decimal.Decimal('12'))
Traceback (most recent call last):
...
z3c.currency.interfaces.IncorrectValuePrecision: 1
>>> price.validate(decimal.Decimal('12.0'))
Traceback (most recent call last):
...
z3c.currency.interfaces.IncorrectValuePrecision: 1

If we allow sub-cents,

>>> price.precision = interfaces.SUBCENTS

any precision is allowed:

>>> price.validate(decimal.Decimal('12.0'))
>>> price.validate(decimal.Decimal('12'))
>>> price.validate(decimal.Decimal('12.00001'))

If the field is not required, …

>>> price.required = False

let’s make sure that the validation still passes.

>>> price.validate(None)

Note that the IFromUnicode interface is purposefully not supported:

>>> price.fromUnicode
Traceback (most recent call last):
...
AttributeError: 'Currency' object has no attribute 'fromUnicode'

z3c.form Support

This package also provides support for integration with the z3c.form package. In particular it implements a data converter from the Currency field to any widget accepting a unicode string.

>>> from z3c.currency import converter
>>> conv = converter.CurrencyConverter(price, None)
>>> conv
<DataConverter from Currency to NoneType>

The converter easily produces a string from any value:

>>> conv.toWidgetValue(decimal.Decimal(12))
'12'
>>> conv.toWidgetValue(decimal.Decimal(1200))
'1,200'
>>> conv.toWidgetValue(decimal.Decimal(-12))
'-12'
>>> conv.toWidgetValue(decimal.Decimal('-12.0'))
'-12.00'
>>> conv.toWidgetValue(decimal.Decimal('-12.00'))
'-12.00'

Note that always two decimal places are printed. You can also set the precision to DOLLARS:

>>> conv.field.precision = interfaces.DOLLARS
>>> conv.toWidgetValue(decimal.Decimal(12))
'12'
>>> conv.toWidgetValue(decimal.Decimal('12.00'))
'12'

Let’s try sub-cents as well:

>>> conv.field.precision = interfaces.SUBCENTS
>>> conv.toWidgetValue(decimal.Decimal('12.00'))
'12.00'
>>> conv.toWidgetValue(decimal.Decimal('12'))
'12'
>>> conv.toWidgetValue(decimal.Decimal('12.0001'))
'12.0001'

If the value is missing, then handle it gracefully.

>>> conv.toWidgetValue(None)
''

Let’s now parse a value. The parser is a little bit flexible, not only accepting the output values, …

>>> conv.field.precision = interfaces.CENTS
>>> conv.toFieldValue('12')
Decimal('12.00')
>>> conv.toFieldValue('1,200')
Decimal('1200.00')
>>> conv.toFieldValue('-12')
Decimal('-12.00')
>>> conv.toFieldValue('-12.00')
Decimal('-12.00')
>>> conv.field.precision = interfaces.DOLLARS
>>> conv.toFieldValue('12')
Decimal('12')
>>> conv.toFieldValue('12.00')
Decimal('12')
>>> conv.field.precision = interfaces.SUBCENTS
>>> conv.toFieldValue('12')
Decimal('12')
>>> conv.toFieldValue('12.00')
Decimal('12.00')
>>> conv.toFieldValue('12.0000')
Decimal('12.0000')
>>> conv.toFieldValue('12.0001')
Decimal('12.0001')

but also other input values:

>>> conv.toFieldValue('1200')
Decimal('1200')

If the browser sends an empty string, then handle it gracefully.

>>> conv.toFieldValue('')

CHANGES

2.0 (2023-02-08)

  • Drop support for Python 2.7, 3.5, 3.6.

  • Add support for Python 3.8, 3.9, 3.10, 3.11.

  • Drop deprecated support for running the tests using python setup.py test.

1.2.0 (2018-11-14)

  • Python 3.6 and 3.7 support. Drop Python 2.6.

  • Tests now run with python setup.py test.

1.1.1 (2015-11-09)

  • Standardize namespace __init__

1.1.0 (2013-09-27)

  • Added new precision value “sub-cents” (interfaces.SUBCENTS), which allows precision beyond pennies, which is needed for financial and other business applications.

1.0.0 (2013-08-16)

  • Updated Trove classifiers.

  • Moved code to GitHub.

  • Changed validation to raise custom validation errors, since the upstream code looks at the doc string of the exception instead of the first argument.

  • Improved converter to

    • Ensure proper precision of decimal after initial parsing.

    • Format the value to the proper precision.

  • Changed “precision” field in ICurrency interface to be a choice, so that UIs generate nicely.

  • Cleaned up code a little bit.

0.1.0 (2007-09-12)

  • Initial Release

    • Implementation of Currency field supporting precision and a unit.

    • Implementation of data converter.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

z3c.currency-2.0.tar.gz (10.3 kB view details)

Uploaded Source

Built Distribution

z3c.currency-2.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file z3c.currency-2.0.tar.gz.

File metadata

  • Download URL: z3c.currency-2.0.tar.gz
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for z3c.currency-2.0.tar.gz
Algorithm Hash digest
SHA256 38e11ee70ac5a441b086f40abf3af01ee8060fb46a255df59f368856493cf900
MD5 732bdd09a80d5cb116e61072aa59e953
BLAKE2b-256 429a1bd5701fb87f7b81c6792a47a5a849142aff78b20c1a066eb4058ed3d823

See more details on using hashes here.

File details

Details for the file z3c.currency-2.0-py3-none-any.whl.

File metadata

  • Download URL: z3c.currency-2.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for z3c.currency-2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 888b5c5866224ffbab1ff5beec501a80374dfc73aeab5d06c6a69db8132780ba
MD5 0368dd8a43640184ec37b4b09d6336e1
BLAKE2b-256 b8d5ce4f02eb9c5ebcf76280a1486935c112f8dcf372d3bc2d3b0c0fffb644fb

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page