aboutsummaryrefslogtreecommitdiff
path: root/jb/models/currency.py
blob: 3094e2aede7d3bbe212dcdb1a85d1e3aeab41c2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import warnings
from decimal import Decimal
from typing import Any

from pydantic import GetCoreSchemaHandler, NonNegativeInt
from pydantic_core import CoreSchema, core_schema


class USDCent(int):
    def __new__(cls, value, *args, **kwargs):

        if isinstance(value, float):
            warnings.warn(
                "USDCent init with a float. Rounding behavior may " "be unexpected"
            )

        if isinstance(value, Decimal):
            warnings.warn(
                "USDCent init with a Decimal. Rounding behavior may " "be unexpected"
            )

        if value < 0:
            raise ValueError("USDCent not be less than zero")

        return super(cls, cls).__new__(cls, value)

    def __add__(self, other):
        assert isinstance(other, USDCent)
        res = super(USDCent, self).__add__(other)
        return self.__class__(res)

    def __sub__(self, other):
        assert isinstance(other, USDCent)
        res = super(USDCent, self).__sub__(other)
        return self.__class__(res)

    def __mul__(self, other):
        assert isinstance(other, USDCent)
        res = super(USDCent, self).__mul__(other)
        return self.__class__(res)

    def __abs__(self):
        res = super(USDCent, self).__abs__()
        return self.__class__(res)

    def __truediv__(self, other):
        raise ValueError("Division not allowed for USDCent")

    def __str__(self):
        return "%d" % int(self)

    def __repr__(self):
        return "USDCent(%d)" % int(self)

    @classmethod
    def __get_pydantic_core_schema__(
        cls, source_type: Any, handler: GetCoreSchemaHandler
    ) -> CoreSchema:
        """
        https://docs.pydantic.dev/latest/concepts/types/#customizing-validation-with-__get_pydantic_core_schema__
        """
        return core_schema.no_info_after_validator_function(
            cls, handler(NonNegativeInt)
        )

    def to_usd(self) -> Decimal:
        return Decimal(int(self) / 100).quantize(Decimal(".01"))

    def to_usd_str(self) -> str:
        return "${:,.2f}".format(float(self.to_usd()))