Package: z3c.currency
A package implementing a currency field forzope.schemaand support for
using the field withz3c.form.Detailed DocumentationThe Currency FieldThe 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
TrueIt can be set to be dollars:>>> price.precision = interfaces.DOLLARS
>>> price.precision is interfaces.DOLLARS
TrueFor financial applications, we also sometimes needsub-cents:>>> price.precision = interfaces.SUBCENTS
>>> price.precision is interfaces.SUBCENTS
TrueNote: 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: floatAlso, 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: 0When the precision is set to cents,>>> price.precision = interfaces.CENTSthen 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: 1If we allow sub-cents,>>> price.precision = interfaces.SUBCENTSany 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 = Falselet’s make sure that the validation still passes.>>> price.validate(None)Note that theIFromUnicodeinterface is purposefully not supported:>>> price.fromUnicode
Traceback (most recent call last):
...
AttributeError: 'Currency' object has no attribute 'fromUnicode'z3c.formSupportThis package also provides support for integration with thez3c.formpackage. In particular it implements a data converter from theCurrencyfield 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('')CHANGES2.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 usingpython setup.py test.1.2.0 (2018-11-14)Python 3.6 and 3.7 support. Drop Python 2.6.Tests now run withpython 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 toEnsure proper precision of decimal after initial parsing.Format the value to the proper precision.Changed “precision” field inICurrencyinterface to be a choice, so that
UIs generate nicely.Cleaned up code a little bit.0.1.0 (2007-09-12)Initial ReleaseImplementation ofCurrencyfield supporting precision and a unit.Implementation of data converter.