# Money

GoMoney provides ability to work with monetary value using a currency's smallest unit. This package provides basic and precise Money operations such as rounding, splitting and allocating. Monetary values should not be stored as floats due to small rounding differences.

```package main

import "github.com/Rhymond/go-money"

func main() {
pound := money.New(100, money.GBP)

if err != nil {
log.Fatal(err)
}

parties, err := twoPounds.Split(3)

if err != nil {
log.Fatal(err)
}

parties[0].Display() // £0.67
parties[1].Display() // £0.67
parties[2].Display() // £0.66
}```

## Quick start

Get the package:

`\$ go get github.com/Rhymond/go-money`

## Features

• Provides a Money struct which stores information about an Money amount value and its currency.
• Provides a `Money.Amount` struct which encapsulates all information about a monetary unit.
• Represents monetary values as integers, in cents. This avoids floating point rounding errors.
• Represents currency as `Money.Currency` instances providing a high level of flexibility.

## Usage

### Initialization

Initialize Money by using smallest unit value (e.g 100 represents 1 pound). Use ISO 4217 Currency Code to set money Currency. Note that constants are also provided for all ISO 4217 currency codes.

`pound := money.New(100, money.GBP)`

## Comparison

Go-money provides base compare operations like:

• Equals
• GreaterThan
• GreaterThanOrEqual
• LessThan
• LessThanOrEqual

Comparisons must be made between the same currency units.

```pound := money.New(100, money.GBP)
twoPounds := money.New(200, money.GBP)
twoEuros := money.New(200, money.EUR)

pound.GreaterThan(twoPounds) // false, nil
pound.LessThan(twoPounds) // true, nil
twoPounds.Equals(twoEuros) // false, error: Currencies don't match```

## Asserts

• IsZero
• IsNegative
• IsPositive

#### Zero value

To assert if Money value is equal to zero use `IsZero()`

```pound := money.New(100, money.GBP)
result := pound.IsZero(pound) // false```

#### Positive value

To assert if Money value is more than zero use `IsPositive()`

```pound := money.New(100, money.GBP)
pound.IsPositive(pound) // true```

#### Negative value

To assert if Money value is less than zero use `IsNegative()`

```pound := money.New(100, money.GBP)
pound.IsNegative(pound) // false```

## Operations

• Subtract
• Multiply
• Absolute
• Negative

Comparisons must be made between the same currency units.

Additions can be performed using `Add()`.

```pound := money.New(100, money.GBP)
twoPounds := money.New(200, money.GBP)

result, err := pound.Add(twoPounds) // £3.00, nil```

#### Subtraction

Subtraction can be performed using `Subtract()`.

```pound := money.New(100, money.GBP)
twoPounds := money.New(200, money.GBP)

result, err := pound.Subtract(twoPounds) // -£1.00, nil```

#### Multiplication

Multiplication can be performed using `Multiply()`.

```pound := money.New(100, money.GBP)

result := pound.Multiply(2) // £2.00```

#### Absolute

Return `absolute` value of Money structure

```pound := money.New(-100, money.GBP)

result := pound.Absolute() // £1.00```

#### Negative

Return `negative` value of Money structure

```pound := money.New(100, money.GBP)

result := pound.Negative() // -£1.00```

## Allocation

• Split
• Allocate

#### Splitting

In order to split Money for parties without losing any pennies due to rounding differences, use `Split()`.

After division leftover pennies will be distributed round-robin amongst the parties. This means that parties listed first will likely receive more pennies than ones that are listed later.

```pound := money.New(100, money.GBP)
parties, err := pound.Split(3)

if err != nil {
log.Fatal(err)
}

parties[0].Display() // £0.34
parties[1].Display() // £0.33
parties[2].Display() // £0.33```

#### Allocation

To perform allocation operation use `Allocate()`.

It splits money using the given ratios without losing pennies and as Split operations distributes leftover pennies amongst the parties with round-robin principle.

```pound := money.New(100, money.GBP)
// slice (int[]{33, 33, 33}...) or separated by a comma integers
parties, err := pound.Allocate(33, 33, 33)

if err != nil {
log.Fatal(err)
}

parties[0].Display() // £0.34
parties[1].Display() // £0.33
parties[2].Display() // £0.33```

## Format

To format and return Money as a string use `Display()`.

`money.New(123456789, money.EUR).Display() // €1,234,567.89`

To format and return Money as a float64 representing the amount value in the currency's subunit use `AsMajorUnits()`.

`money.New(123456789, money.EUR).AsMajorUnits() // 1234567.89`

## Contributing

Thank you for considering contributing! Please use GitHub issues and Pull Requests for contributing.

##### Issues

@Rhymond I've waited to be merged #38, but it looks have not updated long time. I need JSON marshaling/unmarshaling feature for go-money. I've tried to update and fix it. Could you check this PR?

opened by k315k1010 11
• #### Refactor for abstraction

• Amount struct with conversion methods and hidden internals
• Remove all pointers and dereferences. Unneeded. This should be faster (stay on stack)
• Remove calculator file and move all calculations to new Amount object

Due to the Amount struct hiding the internals, we can change the implementation to a `Big` implementation in the future, if necessary, without impacting existing code. We would simply add a `Big()` method to return the internal as a `Big`, as well as alter how the `toAmount` function parses the incoming values.

opened by tylerstillwater 11
• #### Proposal: Add function NewFromFloat

It would be really useful to be able to create a new Money struct from a float or maybe a decimal string ('1.243'). Formatting the decimal amount from a source (API response, file, ...) to a Money struct can get really tedious, that's why I propose a util function inside the money package for dealing with this cases.

This is my current implementation:

``````func NewFromFloat(amount float64, currency string) *money.Money {
currencyDecimals := math.Pow(10, float64(money.GetCurrency(currency).Fraction))
amountCents := int64(amount * currencyDecimals)
return money.New(amountCents, currency)
}
``````

To not lose precision dealing with floats there can also be a NewFromString, but I haven gotten around to implementing it.

What do you guys think?

opened by npinochet 6
• #### Find Currency by numeric code

Hello, I'm adding the option to search Currencies by its numeric code ISO number. This helps because many implementations works around the iso numerical code numbers (like Visa and Mastercard for instance).

• This code will load a second map of currencies but now this map uses the numerical ISO code as key of the map.
• The reason to have another map is to avoid having a loop each time we need to access a currency its iso numerical code
• Added idea and ds_store files to git ignore
opened by Stocco 5
• #### Addition of currency code constants

See #72 for the original proposal.

This pull request includes the addition of constants for the 168 ISO 4217 currency codes that are currently present in this package.

In addition to adding these, I have updated the map of currencies in `currency.go` for both the key in the map and the currency code in the struct to be returned. Similarly, I have updated the tests to include their usage and updated the examples in the README to include their usage.

Definitely willing to have a discussion about how we include their usage in the README. This is certainly the part of this pull request that I have the most questions about so far. In particular, I worry about causing confusion with the usage of the constants with regards to a consumer of the package adding their own currencies.

opened by jamesallured 5
• #### Use of int causes overflows and arch-specific variability

Using the architecture-independent `int` type will cause 32-bit binaries to overflow if more than `21,474,836.47` is used in a base-100 currency, introducing architecture-dependent behaviour differences which may not be caught.

This can be resolved by switching amounts to use the `int64` data type. This will still work on 32-bit architectures, at the slight expense of performance, and allow base-100 currency values up to an amount of `92,233,720,368,547,758.07` ... More than likely enough for most consumers of this package :)

opened by bbrks 5
• #### Get Currency by Numeric Code

Code changes allow to get the currency by numeric code or a code used to index currencies map. The PR fixes issues with the PR https://github.com/Rhymond/go-money/pull/96

opened by Rhymond 4
• #### go get fails

Running `go get github.com/rhymond/go-money` fails and spits out the message:

``````go: github.com/rhymond/[email protected]: parsing go.mod: unexpected module path "github.com/Rhymond/go-money"
``````

seems to be related to https://github.com/golang/go/issues/27154

opened by logitick 4
• #### Does not have i18n for formatting ?

Am building a templating system and need to handle currency properly. Does this library have functionality for this ? E.g in Sweden and Germany money is displayed differently

If you know of I lib I can combine and PR if you want too

opened by ghost 4
• #### Why does money.New() take an int64

By making `money.New()` accept an `int64` rather than a float or more inline with other libraries do (possibly more idiomatic?) a `*big.Float` it cuts off the ability to use a value with a decimal amount during allocation.

``````dollar := money.New(3.50, "USD") // type error
dollar := money.New(big.NewFloat(3.50), "USD") // would work
``````
opened by vendion 4
• #### Future development of go-money

Hi @Rhymond,

I was wondering how do you envision the future of go-money in terms of:

• Integration with existing `golang.org/x/text/currency`
• Complete currency list support (fiat, crypto, commodities).
• Supporting exchange rates from an external service

Thanks!

opened by llonchj 4
• #### Question about the rounding for NewFromFloat

Love the new addition of `NewFromFloat`. Just wanted to get a clearer understanding of always rounding trailing decimals down when given.

`````` cents := money.NewFromFloat(99.999999, money.USD)
//->  cents: 9999
``````

Just want to know the why between getting 9999 vs 10000?

Thanks!

opened by TimothyIp 4
• #### Add, Subtract, Multiply Many

• Please check if the PR fulfills these requirements
• [X] Tests for the changes have been added (for bug fixes / features)
• [X] Docs have been added / updated (for bug fixes / features)
• What kind of change does this PR introduce? (Bug fix, feature, docs update, ...) Feature

• What is the current behavior? (You can also link to an open issue here) Addition, subtraction, and multiplication can only be done with single values.

• What is the new behavior (if this is a feature change)? Addition, subtraction, and multiplication using many values.

• Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?) NO

• Other information:

• Fixes #74

• Credit to @SepehrAsh for opening #78 ,but it got closed.

opened by AyoobMH 4

There are several methods to compare two Money object but there is no `Money.Compare(Money)` function.

The proposal is to add a Compare function for Money.

``````// Compare returns an integer comparing two Money objects
// If Money objects are of different currency, an ErrCurrencyMismatch is returned.
// If both objects are for same currency, their amounts are compared.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
func (m *Money) Compare(om *Money) int {
if err := m.assertSameCurrency(om); err != nil {
return false, err
}

return m.compare(om), nil
}

``````

I'll provide a PR.

opened by totemcaf 1
• #### 1.18 Generics

Add 1.18 generics to go-money to allow working with different numeric types of Money (e.g. int, int64)

• JSON marshal/unmarshal not yet working properly
• Write tests to make sure all numeric types defined in Numeric interface are tested
opened by Rhymond 4
• #### GH-44 implement driver.Valuer and sql.Scanner for Amount and Currency

Implements the `driver.Valuer` and `sql.Scanner` interfaces for `money.Currency`.

Implements the `sql.Scanner` interface for `money.Money` such that it expects to read a single string value of the format "amount|currency_code"

``````type MyCustomThing struct {
Amount  *money.Money `json:"amount" db:"amount"`
}
``````

This allows the client to save a `money.Money` object in a single string field like this "amount|currency_code" or in two discrete where "amount" and "currency" are stored separately and recomposed for scanning like this:

``````    SELECT
amount || "|" || currency as amount
``````

If the pipe (`|`) delimeter causes problems for your use case you can customize it by setting `money.DBMoneyValueSeparator` to a different value; this package-level `var` is used when converting a `money.Money` object to a string Value and also when scanning a string Value back into a `money.Money` instance.

``````    money.DBMoneyValueSeparator = "@"
``````

I have tested this in my own project where the amount is stored as an integer field and the currency code is stored as a text field and they two are joined together in a hand-written SELECT query before passing it to `money.Scan()`

``````CREATE TABLE MyCustomThings
(
id          INTEGER NOT NULL PRIMARY KEY autoincrement,
amount      INTEGER NOT NULL,
currency    TEXT  NOT NULL,
);
``````

In my project I am using `sqlx` so I am fairly certain that this implementation will support any ORM or db wrapper which makes use of the `sql.Scanner` interface.

opened by davidalpert 3

## What's Changed

• Fix Any reason for Amount being a data-structure? #73 by @totemcaf in https://github.com/Rhymond/go-money/pull/113
• Add NewFromFloat (#108) by @npinochet in https://github.com/Rhymond/go-money/pull/116

## New Contributors

• @totemcaf made their first contribution in https://github.com/Rhymond/go-money/pull/113
• @npinochet made their first contribution in https://github.com/Rhymond/go-money/pull/116

Full Changelog: https://github.com/Rhymond/go-money/compare/v1.0.8...v1.0.9

Source code(tar.gz)
Source code(zip)

## What's Changed

• Fix ARS decimal and thousand separators and add testable examples by @unkiwii in https://github.com/Rhymond/go-money/pull/81

## New Contributors

• @unkiwii made their first contribution in https://github.com/Rhymond/go-money/pull/81

Full Changelog: https://github.com/Rhymond/go-money/compare/v1.0.7...v1.0.8

Source code(tar.gz)
Source code(zip)

## What's Changed

• Add XOF and MGA currencies by @r1cm3d in https://github.com/Rhymond/go-money/pull/110

## New Contributors

• @r1cm3d made their first contribution in https://github.com/Rhymond/go-money/pull/110

Full Changelog: https://github.com/Rhymond/go-money/compare/v1.0.6...v1.0.7

Source code(tar.gz)
Source code(zip)

## What's Changed

• Split small negative values fix @arzonus in https://github.com/Rhymond/go-money/pull/107

Full Changelog: https://github.com/Rhymond/go-money/compare/v1.0.5...v1.0.6

Source code(tar.gz)
Source code(zip)

## What's Changed

• Get Currency by Numeric Code by @Stocco in https://github.com/Rhymond/go-money/pull/104

Full Changelog: https://github.com/Rhymond/go-money/compare/v1.0.4...v1.0.5

Source code(tar.gz)
Source code(zip)
• #### v1.0.4(Mar 31, 2022)

• Ubuntu version changed from `ubuntu-16.04` to `latest` in github workflow
• Merged #101 Fix marshalling the zero value of Money to JSON. Thanks @bencrouse
• Merged #94 Fix negative split remainder. Thanks @ConradKurth
Source code(tar.gz)
Source code(zip)

• #### v0.4.0(Jul 26, 2019)

• Updated list of currencies.
• Added AsMajorUnits function to return Money as a float64 representing the amount value in the currency's subunit.
Source code(tar.gz)
Source code(zip)

• #### v0.0.1(Apr 3, 2017)

###### Raymond
In order to understand recursion, you must first understand recursion
476 Aug 5, 2022
###### Utility package that provides the ability to more conveniently work with URL parameters.

Utility package that provides the ability to more conveniently work with URL parameters.

1 Feb 8, 2022
###### Go compiler made from scratch, which can compile itself. It's going to be the smallest and simplest go compiler in the world.

Babygo, a go compiler made from scratch Babygo is a small and simple go compiler. (Smallest and simplest in the world, I believe.) It is made from scr

216 Jul 31, 2022
###### Nipo is a powerful, fast, multi-thread, clustered and in-memory key-value database, with ability to configure token and acl on commands and key-regexes written by GO

Welcome to NIPO Nipo is a powerful, fast, multi-thread, clustered and in-memory key-value database, with ability to configure token and acl on command

16 Jun 13, 2022
###### PingMe is a CLI tool which provides the ability to send messages or alerts to multiple messaging platforms & email.

PingMe is a personal project to satisfy my needs of having alerts, most major platforms have integration to send alerts but its not always useful, either you are stuck with one particular platform, or you have to do alot of integrations. I needed a small app which i can just call from my backup scripts, cron jobs, CI/CD pipelines or from anywhere to send a message with particular information. And i can ship it everywhere with ease. Hence, the birth of PingMe.

541 Aug 6, 2022
###### Minutes is a CLI tool for synchronizing work logs between multiple time trackers, invoicing, and bookkeeping software to make entrepreneurs' daily work easier.

Minutes is a CLI tool for synchronizing work logs between multiple time trackers, invoicing, and bookkeeping software to make entrepreneurs' daily work easier.

21 Aug 8, 2022
###### onnx-go gives the ability to import a pre-trained neural network within Go without being linked to a framework or library.

This is a Go Interface to Open Neural Network Exchange (ONNX). Overview onnx-go contains primitives to decode a onnx binary model into a computation b

407 Aug 13, 2022
###### Gowl is a process management and process monitoring tool at once. An infinite worker pool gives you the ability to control the pool and processes and monitor their status.

Gowl is a process management and process monitoring tool at once. An infinite worker pool gives you the ability to control the pool and processes and monitor their status.

33 Aug 11, 2022
###### `ctxio` gives `io.copy` operations the ability to cancel with context and retrieve progress data.

ctxio The ctxio package gives golang io.copy operations the ability to terminate with context and retrieve progress data. Install go get github.com/

11 Apr 17, 2022
###### GitHub CLI extension to clone (or update) all repositories in an Organization, with the ability to filter via search queries.

gh-org-repo-sync GitHub CLI extension to clone all repositories in an Organization, with the ability to filter via search queries. If a local clone al

8 Jul 29, 2022
###### Impress your friends with your ability to maybe solve the Wordle most of the time (probably)

wordle-assistant Impress your friends with your ability to maybe solve the Wordle most of the time (probably). This was coded as quickly and dirtily a

0 Feb 10, 2022
###### go-jsonc provides a way to work with commented json by converting it to plain json.

JSON with comments for GO Decodes a "commented json" to "json". Provided, the input must be a valid jsonc document. Supports io.Reader With this, we c

9 Apr 6, 2022
###### Package GoEagi provides some fundamental functionalities that work with Asterisk's EAGI

GoEagi Package GoEagi provides some fundamental functionalities that work with Asterisk's EAGI. It has the following features: Audio Streaming Google'

5 Jul 1, 2022
###### :steam_locomotive: Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

Package form Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. It has the following features: Supports map of

544 Aug 5, 2022
###### Traefik proxy plugin to extract HTTP header value and create a new header with extracted value

Copy header value Traefik plugin Traefik plugin that copies HTTP header value with format key1=value1; key2=value2 into a new header. Motivation for t

3 May 26, 2022
###### Golang-key-value-store - Key Value Store API Service with Go DDD Architecture

This document specifies the tools used in the Key-Value store and reorganizes how to use them. In this created service, In-Memory Key-Value Service was created and how to use the API is specified in the HTML file in the folder named "doc"

2 Jul 31, 2022
###### go websocket client for unit testing of a websocket handler

wstest A websocket client for unit-testing a websocket server The gorilla organization provides full featured websocket implementation that the standa

92 Aug 2, 2022
###### Unit tests generator for Go programming language

GoUnit GoUnit is a commandline tool that generates tests stubs based on source function or method signature. There are plugins for Vim Emacs Atom Subl

62 Jul 8, 2022
###### Easier way to unit test terraform

Unit testing terraform (WIP) Disclaimer Currently, the only way to compare values is using JSON query path and all types are strings. want := terraf

50 Jun 27, 2022
###### A Golang tool that does static analysis, unit testing, code review and generate code quality report.

goreporter A Golang tool that does static analysis, unit testing, code review and generate code quality report. This is a tool that concurrently runs

3k Aug 5, 2022
###### gostub is a library to make stubbing in unit tests easy

gostub gostub is a library to make stubbing in unit tests easy. Getting started Import the following package: github.com/prashantv/gostub Click here t

243 Jul 29, 2022
###### Demo project for unit testing presentation @ GoJKT meetup

go-demo-service Demo project for unit testing presentation @ GoJKT meetup This is a demo project to show examples of unit testing for GoJKT meetup Use

3 Jul 10, 2021
###### gomonkey is a library to make monkey patching in unit tests easy

gomonkey is a library to make monkey patching in unit tests easy, and the core idea of monkey patching comes from Bouke, you can read this blogpost for an explanation on how it works.

1.2k Aug 12, 2022
###### A mock of Go's net package for unit/integration testing

netmock: Simulate Go network connections netmock is a Go package for simulating net connections, including delays and disconnects. This is work in pro

1 Oct 27, 2021
###### How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race. The basic

1 Oct 31, 2021
###### An example repo for RESTful API with swagger docs & unit testing

go REST API An example repo for RESTful API with swagger docs & unit testing Starting development server Copy .env.example to .env in the same directo

0 Nov 5, 2021
###### Go Unit Testing Clean Arch

Golang Unit Testing Tutorial melakukan unit testing di Golang yang sudah menerapkan clean architecture Menjalankan Service PSQL_HOST=<IP Database Serv

2 Feb 12, 2022
###### A best practices Go source project with unit-test and integration test, also use skaffold & helm to automate CI & CD at local to optimize development cycle

Dependencies Docker Go 1.17 MySQL 8.0.25 Bootstrap Run chmod +x start.sh if start.sh script does not have privileged to run Run ./start.sh --bootstrap

4 Apr 4, 2022