• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

samdobson / monzoh / 17649463783

11 Sep 2025 03:27PM UTC coverage: 89.902% (-0.07%) from 89.975%
17649463783

push

github

web-flow
Merge pull request #23 from samdobson/feat/amounts

Use major units

41 of 46 new or added lines in 5 files covered. (89.13%)

1 existing line in 1 file now uncovered.

1469 of 1634 relevant lines covered (89.9%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.88
/src/monzoh/models/base.py
1
"""Base models and common types."""
2

3
from datetime import datetime
1✔
4
from decimal import Decimal
1✔
5

6
from pydantic import BaseModel, Field
1✔
7

8

9
class OAuthToken(BaseModel):
1✔
10
    """OAuth token response."""
11

12
    access_token: str = Field(..., description="Access token for API authentication")
1✔
13
    client_id: str = Field(..., description="Client identifier")
1✔
14
    expires_in: int = Field(..., description="Token expiry time in seconds")
1✔
15
    refresh_token: str | None = Field(
1✔
16
        None, description="Refresh token (only for confidential clients)"
17
    )
18
    token_type: str = Field("Bearer", description="Token type (always 'Bearer')")
1✔
19
    user_id: str = Field(..., description="User identifier")
1✔
20

21

22
class WhoAmI(BaseModel):
1✔
23
    """Who am I response."""
24

25
    authenticated: bool = Field(..., description="Whether the request is authenticated")
1✔
26
    client_id: str = Field(..., description="Client identifier")
1✔
27
    user_id: str = Field(..., description="User identifier")
1✔
28

29

30
class PaginationParams(BaseModel):
1✔
31
    """Pagination parameters."""
32

33
    limit: int | None = Field(
1✔
34
        None, ge=1, le=100, description="Number of results per page (1-100, default 30)"
35
    )
36
    since: datetime | str | None = Field(
1✔
37
        None, description="Start time (RFC3339 timestamp) or object ID"
38
    )
39
    before: datetime | None = Field(None, description="End time (RFC3339 timestamp)")
1✔
40

41

42
class ExpandParams(BaseModel):
1✔
43
    """Expand parameters."""
44

45
    expand: list[str] | None = Field(
1✔
46
        None, description="List of related objects to expand inline"
47
    )
48

49

50
def convert_amount_to_minor_units(amount: int | float | Decimal | str) -> int:
1✔
51
    """Convert amount from major units to minor units.
52

53
    Args:
54
        amount: Amount in major units (e.g., pounds, euros, dollars)
55

56
    Returns:
57
        Amount in minor units (e.g., pennies, cents)
58

59
    Raises:
60
        ValueError: If amount is negative or invalid
61

62
    Examples:
63
        >>> convert_amount_to_minor_units(1.50)
64
        150
65
        >>> convert_amount_to_minor_units("10.99")
66
        1099
67
        >>> convert_amount_to_minor_units(5)
68
        500
69
    """
70
    try:
1✔
71
        if isinstance(amount, str):
1✔
NEW
72
            amount = Decimal(amount)
×
73
        elif isinstance(amount, int | float):
1✔
74
            amount = Decimal(str(amount))
1✔
75

76
        if amount < 0:
1✔
NEW
77
            raise ValueError("Amount cannot be negative")
×
78

79
        # All supported currencies (GBP, EUR, USD) use 2 decimal places
80
        return int(amount * 100)
1✔
81

NEW
82
    except (ValueError, TypeError, ArithmeticError) as e:
×
NEW
83
        raise ValueError(f"Invalid amount '{amount}': {e}") from e
×
84

85

86
def convert_amount_from_minor_units(amount: int) -> Decimal:
1✔
87
    """Convert amount from minor units to major units.
88

89
    Args:
90
        amount: Amount in minor units (e.g., pennies, cents)
91

92
    Returns:
93
        Amount in major units as Decimal
94

95
    Examples:
96
        >>> convert_amount_from_minor_units(150)
97
        Decimal('1.50')
98
        >>> convert_amount_from_minor_units(1099)
99
        Decimal('10.99')
100
    """
101
    return Decimal(amount) / 100
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc