money

package
v1.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 19, 2025 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package money provides functionality for handling monetary values.

It is a value object that represents a monetary value in a specific currency. Invariants:

  • Amount is always stored in the smallest currency unit (e.g., cents for USD).
  • Currency code must be valid ISO 4217 (3 uppercase letters).
  • All arithmetic operations require matching currencies.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrMismatchedCurrencies is returned when performing operations on money with
	// different currencies
	ErrMismatchedCurrencies = errors.New("mismatched currencies")

	// ErrNegativeAmount is returned when an operation would result in a negative amount
	ErrNegativeAmount = errors.New("resulting amount cannot be negative")
)

Common money package errors

View Source
var (
	// ErrInvalidAmount is returned when an invalid amount is provided.
	ErrInvalidAmount = fmt.Errorf("invalid amount float")

	// ErrAmountExceedsMaxSafeInt is returned when an amount exceeds the maximum safe integer value.
	ErrAmountExceedsMaxSafeInt = fmt.Errorf("amount exceeds maximum safe integer value")

	// ErrMismatchedCurrencies is returned when performing operations
	// on money with different currencies.
	ErrInvalidCurrency = fmt.Errorf("invalid currency code")
)
View Source
var (
	USDCurrency = Currency{Code: USD, Decimals: 2}
	EURCurrency = Currency{Code: EUR, Decimals: 2}
	GBPCurrency = Currency{Code: GBP, Decimals: 2}
	JPYCurrency = Currency{Code: JPY, Decimals: 0} // Japanese Yen has no decimal places
)

Common currency instances

View Source
var DefaultCode = USD

DefaultCode is the default currency code (USD)

View Source
var DefaultCurrency = USDCurrency

DefaultCurrency is the default currency (USD)

Functions

This section is empty.

Types

type Amount

type Amount = int64

Amount represents a monetary amount as an integer in the smallest currency unit (e.g., cents for USD).

type Code added in v1.3.0

type Code string

Code represents a currency code (e.g., "USD", "EUR").

const (
	USD Code = "USD" // US Dollar
	EUR Code = "EUR" // Euro
	JPY Code = "JPY" // Japanese Yen
	KWD Code = "KWD" // Kuwaiti Dinar
	GBP Code = "GBP" // British Pound
)

Common currency codes

func (Code) IsValid added in v1.3.0

func (c Code) IsValid() bool

IsValid checks if the currency code is valid

func (Code) String added in v1.3.0

func (c Code) String() string

String returns the string representation of the currency code.

func (Code) ToCurrency added in v1.3.0

func (c Code) ToCurrency() Currency

ToCurrency converts a Code to a Currency with default decimals

type Currency added in v1.3.0

type Currency struct {
	Code     Code // 3-letter ISO 4217 code (e.g., "USD")
	Decimals int  // Number of decimal places (0-8)
}

Currency represents a monetary unit with its standard decimal places

func (Currency) IsValid added in v1.3.0

func (c Currency) IsValid() bool

IsValid checks if the currency is valid.

func (Currency) String added in v1.3.0

func (c Currency) String() string

String returns the currency code as a string

type CurrencyConverter

type CurrencyConverter exchange.Exchange

Detracted: use exchange.Provider

type Money

type Money struct {
	// contains filtered or unexported fields
}

Money represents a monetary value in a specific currency. Invariants:

  • Amount is always stored in the smallest currency unit (e.g., cents for USD).
  • Currency must be valid (valid ISO 4217 code and valid decimal places).
  • All arithmetic operations require matching currencies.
Example (Comparison)

ExampleMoney_Comparison demonstrates comparing money values

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create two USD amounts
	money1, _ := money.New(100.50, money.USD)
	money2, _ := money.New(75.25, money.USD)

	// Compare them
	greater, _ := money1.GreaterThan(money2)
	equal := money1.Equals(money2)
	less, _ := money1.LessThan(money2)

	fmt.Printf("Greater than: %t\n", greater)
	fmt.Printf("Equal: %t\n", equal)
	fmt.Printf("Less than: %t\n", less)
}
Output:

Greater than: true
Equal: false
Less than: false

func Must

func Must(amount float64, currency Currency) *Money

Must creates a Money object from the given amount and currency. Invariants enforced:

  • Currency must be valid (valid ISO 4217 code and valid decimal places).
  • Amount must not have more decimal places than allowed by the currency.
  • Amount is converted to the smallest currency unit.

Panics if any invariant is violated.

func New

func New(amount float64, currency any) (*Money, error)

New creates a new Money value object with the given amount and currency. The currency parameter can be either a Code, Currency, or string (e.g., "USD"). Invariants enforced:

  • Currency must be valid (valid ISO 4217 code and valid decimal places).
  • Amount must not have more decimal places than allowed by the currency.
  • Amount is converted to the smallest currency unit.

Returns Money or an error if any invariant is violated.

Example

ExampleNew demonstrates how to create a new Money instance

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create money with USD
	usdMoney, err := money.New(100.50, money.USD)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("USD Money: %s\n", usdMoney.String())

	// Create money with EUR
	eurMoney, err := money.New(75.25, money.EUR)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("EUR Money: %s\n", eurMoney.String())

	// Create money with JPY (0 decimals)
	jpyMoney, err := money.New(1000, money.Code("JPY"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JPY Money: %s\n", jpyMoney.String())
}
Output:

USD Money: 100.50 USD
EUR Money: 75.25 EUR
JPY Money: 1000 JPY

func NewFromData

func NewFromData(amount int64, cc string) *Money

NewFromData creates a Money object from raw data (used for DB hydration). This bypasses invariants and should only be used for repository hydration or tests. Deprecated: use NewFromSmallestUnit instead.

func NewFromSmallestUnit

func NewFromSmallestUnit(amount int64, currency interface{}) (*Money, error)

NewFromSmallestUnit creates a new Money object from the smallest currency unit. The currency parameter can be either a Code or a Currency. Invariants enforced:

  • Currency must be valid (valid ISO 4217 code and valid decimal places).

Returns Money or an error if any invariant is violated.

Example

ExampleNewFromSmallestUnit demonstrates creating money from smallest unit

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create USD money from cents (smallest unit)
	usdMoney, err := money.NewFromSmallestUnit(10050, money.USD) // 100.50 USD
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("USD from cents: %s\n", usdMoney.String())

	// Create JPY money from yen (smallest unit)
	jpyMoney, err := money.NewFromSmallestUnit(1000, money.Code("JPY")) // 1000 JPY
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JPY from yen: %s\n", jpyMoney.String())
}
Output:

USD from cents: 100.50 USD
JPY from yen: 1000 JPY

func Zero

func Zero(currency interface{}) *Money

Zero creates a Money object with zero amount in the specified currency. The currency parameter can be either a Code or a Currency.

func (*Money) Abs

func (m *Money) Abs() *Money

Abs returns the absolute value of the Money amount.

func (*Money) Add

func (m *Money) Add(other *Money) (*Money, error)

Add returns a new Money object with the sum of amounts. Invariants enforced:

  • Currencies must match.
Example

ExampleMoney_Add demonstrates adding money values

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create two USD amounts
	money1, _ := money.New(100.50, money.USD)
	money2, _ := money.New(25.75, money.USD)

	// Add them together
	result, err := money1.Add(money2)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Result: %s\n", result.String())
}
Output:

Result: 126.25 USD

func (*Money) Amount

func (m *Money) Amount() Amount

Amount returns the amount of the Money object in the smallest currency unit.

Example

ExampleMoney_Amount demonstrates getting the amount

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create money with different amounts
	money1, _ := money.New(100.50, money.USD)
	money2, _ := money.New(1000, money.Code("JPY"))

	fmt.Printf("USD amount: %.2f\n", money1.AmountFloat())
	fmt.Printf("JPY amount: %.0f\n", money2.AmountFloat())
}
Output:

USD amount: 100.50
JPY amount: 1000

func (*Money) AmountFloat

func (m *Money) AmountFloat() float64

AmountFloat returns the amount as a float64 in the main currency unit (e.g., dollars for USD).

Example

ExampleMoney_AmountFloat demonstrates getting the amount as float64

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create money with different amounts
	money1, _ := money.New(100.50, money.USD)
	money2, _ := money.New(1000, money.Code("JPY"))

	fmt.Printf("USD amount float: %.2f\n", money1.AmountFloat())
	fmt.Printf("JPY amount float: %.0f\n", money2.AmountFloat())
}
Output:

USD amount float: 100.50
JPY amount float: 1000

func (*Money) Currency

func (m *Money) Currency() Currency

Currency returns the currency of the Money object.

Example

ExampleMoney_Currency demonstrates getting the currency

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create money with different currencies
	usdMoney, _ := money.New(100.50, money.USD)
	eurMoney, _ := money.New(75.25, money.EUR)
	jpyMoney, _ := money.New(1000, money.Code("JPY"))

	fmt.Printf("USD Money currency: %s\n", usdMoney.Currency())
	fmt.Printf("EUR Money currency: %s\n", eurMoney.Currency())
	fmt.Printf("JPY Money currency: %s\n", jpyMoney.Currency())
}
Output:

USD Money currency: USD
EUR Money currency: EUR
JPY Money currency: JPY

func (*Money) CurrencyCode added in v1.3.0

func (m *Money) CurrencyCode() Code

CurrencyCode returns the currency code of the Money object.

func (*Money) Divide

func (m *Money) Divide(divisor float64) (*Money, error)

Divide divides the Money amount by a scalar divisor. The result is rounded to the nearest integer. Invariants enforced:

  • Divisor must be positive.

Returns a new Money object or an error if the divisor is invalid.

Example

ExampleMoney_Divide demonstrates dividing money by a factor

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create USD amount
	money, _ := money.New(100.50, money.USD)

	// Divide by 2
	result, err := money.Divide(2)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Result: %s\n", result.String())
}
Output:

Result: 50.25 USD

func (*Money) Equals

func (m *Money) Equals(other *Money) bool

Equals checks if the current Money object is equal to another Money object. Invariants enforced:

  • Currencies must match.

func (*Money) GreaterThan

func (m *Money) GreaterThan(other *Money) (bool, error)

GreaterThan checks if the current Money object is greater than another Money object. Invariants enforced:

  • Currencies must match.

func (*Money) IsCurrency

func (m *Money) IsCurrency(currency Currency) bool

IsCurrency checks if the money object has the specified currency

func (*Money) IsNegative

func (m *Money) IsNegative() bool

IsNegative returns true if the Money is not nil and its amount is less than zero.

func (*Money) IsPositive

func (m *Money) IsPositive() bool

IsPositive returns true if the Money is not nil and its amount is greater than zero.

Example

ExampleMoney_IsPositive demonstrates checking if money is positive

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create positive and negative amounts
	positive, _ := money.New(100.50, money.USD)
	negative, _ := money.New(-25.75, money.USD)
	zero, _ := money.New(0, money.USD)

	fmt.Printf("Positive amount is positive: %t\n", positive.IsPositive())
	fmt.Printf("Negative amount is positive: %t\n", negative.IsPositive())
	fmt.Printf("Zero amount is positive: %t\n", zero.IsPositive())
}
Output:

Positive amount is positive: true
Negative amount is positive: false
Zero amount is positive: false

func (*Money) IsSameCurrency

func (m *Money) IsSameCurrency(other *Money) bool

IsSameCurrency checks if the current Money object has the same currency as another Money object.

func (*Money) IsZero

func (m *Money) IsZero() bool

IsZero returns true if the Money is nil or its amount is zero.

Example

ExampleMoney_IsZero demonstrates checking if money is zero

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create positive and zero amounts
	positive, _ := money.New(100.50, money.USD)
	zero, _ := money.New(0, money.USD)

	fmt.Printf("Positive amount is zero: %t\n", positive.IsZero())
	fmt.Printf("Zero amount is zero: %t\n", zero.IsZero())
}
Output:

Positive amount is zero: false
Zero amount is zero: true

func (*Money) LessThan

func (m *Money) LessThan(other *Money) (bool, error)

LessThan checks if the current Money object is less than another Money object. Invariants enforced:

  • Currencies must match.

Returns an error if currencies do not match.

func (Money) MarshalJSON

func (m Money) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface.

func (*Money) Multiply

func (m *Money) Multiply(factor float64) (*Money, error)

Multiply multiplies the Money amount by a scalar factor. The result is rounded to the nearest integer. Invariants enforced:

  • Factor must not be negative.
  • Result must not overflow int64.

Returns a new Money object or an error if the factor is invalid or would cause overflow.

Example

ExampleMoney_Multiply demonstrates multiplying money by a factor

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create USD amount
	money, _ := money.New(100.50, money.USD)

	// Multiply by 2.5
	result, err := money.Multiply(2.5)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Result: %s\n", result.String())
}
Output:

Result: 251.25 USD

func (*Money) Negate

func (m *Money) Negate() *Money

Negate negates the current Money object.

func (*Money) String

func (m *Money) String() string

String returns a string representation of the Money object.

Example

ExampleMoney_String demonstrates string representation

package main

import (
	"fmt"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create money with different currencies
	usdMoney, _ := money.New(100.50, money.USD)
	eurMoney, _ := money.New(75.25, money.EUR)
	jpyMoney, _ := money.New(1000, money.Code("JPY"))

	fmt.Printf("USD: %s\n", usdMoney.String())
	fmt.Printf("EUR: %s\n", eurMoney.String())
	fmt.Printf("JPY: %s\n", jpyMoney.String())
}
Output:

USD: 100.50 USD
EUR: 75.25 EUR
JPY: 1000 JPY

func (*Money) Subtract

func (m *Money) Subtract(other *Money) (*Money, error)

Subtract returns a new Money object with the difference of amounts. The result can be negative if the subtrahend is larger than the minuend. Invariants enforced:

  • Currencies must match.
Example

ExampleMoney_Subtract demonstrates subtracting money values

package main

import (
	"fmt"
	"log"

	"github.com/amirasaad/fintech/pkg/money"
)

func main() {
	// Create two USD amounts
	money1, _ := money.New(100.50, money.USD)
	money2, _ := money.New(25.75, money.USD)

	// Subtract the second from the first
	result, err := money1.Subtract(money2)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Result: %s\n", result.String())
}
Output:

Result: 74.75 USD

func (*Money) UnmarshalJSON

func (m *Money) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler interface.

Directories

Path Synopsis
Package money provides functionality for handling monetary values.
Package money provides functionality for handling monetary values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL