service backend
This commit is contained in:
129
api/pkg/decimal/money.go
Normal file
129
api/pkg/decimal/money.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package decimal
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
)
|
||||
|
||||
// Money represents a monetary amount with currency and precision handling
|
||||
type Money struct {
|
||||
Amount *big.Rat
|
||||
Currency string
|
||||
Scale uint32 // decimal places for this currency
|
||||
}
|
||||
|
||||
// NewMoney creates a new Money value from a decimal string
|
||||
func NewMoney(amount, currency string, scale uint32) (*Money, error) {
|
||||
rat, err := RatFromString(amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Money{
|
||||
Amount: rat,
|
||||
Currency: currency,
|
||||
Scale: scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Add adds two money values (must have same currency)
|
||||
func (m *Money) Add(other *Money) (*Money, error) {
|
||||
if m.Currency != other.Currency {
|
||||
return nil, merrors.InvalidArgument("decimal: currency mismatch: " + m.Currency + " != " + other.Currency)
|
||||
}
|
||||
return &Money{
|
||||
Amount: AddRat(m.Amount, other.Amount),
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sub subtracts two money values (must have same currency)
|
||||
func (m *Money) Sub(other *Money) (*Money, error) {
|
||||
if m.Currency != other.Currency {
|
||||
return nil, merrors.InvalidArgument("decimal: currency mismatch: " + m.Currency + " != " + other.Currency)
|
||||
}
|
||||
return &Money{
|
||||
Amount: SubRat(m.Amount, other.Amount),
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Mul multiplies money by a rational number (for fees, percentages, etc.)
|
||||
func (m *Money) Mul(factor *big.Rat) *Money {
|
||||
return &Money{
|
||||
Amount: MulRat(m.Amount, factor),
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}
|
||||
}
|
||||
|
||||
// Div divides money by a rational number
|
||||
func (m *Money) Div(divisor *big.Rat) (*Money, error) {
|
||||
result, err := DivRat(m.Amount, divisor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Money{
|
||||
Amount: result,
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Negate returns the negative of this money value
|
||||
func (m *Money) Negate() *Money {
|
||||
return &Money{
|
||||
Amount: NegRat(m.Amount),
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}
|
||||
}
|
||||
|
||||
// Round rounds the money to its scale using the specified rounding mode
|
||||
func (m *Money) Round(mode RoundingMode) (*Money, error) {
|
||||
rounded, err := RoundRatToScale(m.Amount, m.Scale, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Money{
|
||||
Amount: rounded,
|
||||
Currency: m.Currency,
|
||||
Scale: m.Scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the formatted money value
|
||||
func (m *Money) String() string {
|
||||
return FormatRat(m.Amount, m.Scale) + " " + m.Currency
|
||||
}
|
||||
|
||||
// StringAmount returns just the formatted amount
|
||||
func (m *Money) StringAmount() string {
|
||||
return FormatRat(m.Amount, m.Scale)
|
||||
}
|
||||
|
||||
// IsZero checks if the money amount is zero
|
||||
func (m *Money) IsZero() bool {
|
||||
return IsZero(m.Amount)
|
||||
}
|
||||
|
||||
// IsPositive checks if the money amount is positive
|
||||
func (m *Money) IsPositive() bool {
|
||||
return IsPositive(m.Amount)
|
||||
}
|
||||
|
||||
// IsNegative checks if the money amount is negative
|
||||
func (m *Money) IsNegative() bool {
|
||||
return IsNegative(m.Amount)
|
||||
}
|
||||
|
||||
// Cmp compares two money values (must have same currency)
|
||||
// Returns -1 if m < other, 0 if m == other, 1 if m > other
|
||||
func (m *Money) Cmp(other *Money) (int, error) {
|
||||
if m.Currency != other.Currency {
|
||||
return 0, merrors.InvalidArgument("decimal: currency mismatch: " + m.Currency + " != " + other.Currency)
|
||||
}
|
||||
return CmpRat(m.Amount, other.Amount), nil
|
||||
}
|
||||
Reference in New Issue
Block a user