forked from leekchan/accounting
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
319 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
language: go | ||
go: | ||
- tip | ||
before_install: | ||
- go get github.com/axw/gocov/gocov | ||
- go get github.com/mattn/goveralls | ||
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi | ||
script: | ||
- $HOME/gopath/bin/goveralls -service=travis-ci |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 Kyoung-chan Lee | ||
Copyright (c) 2015 Kyoung-chan Lee ([email protected]) | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package accounting | ||
|
||
import ( | ||
"strings" | ||
) | ||
|
||
type Accounting struct { | ||
Symbol string | ||
Precision int | ||
Thousand string | ||
Decimal string | ||
Format string | ||
FormatNegative string | ||
FormatZero string | ||
} | ||
|
||
func (accounting *Accounting) init() { | ||
if accounting.Thousand == "" { | ||
accounting.Thousand = "," | ||
} | ||
|
||
if accounting.Decimal == "" { | ||
accounting.Decimal = "." | ||
} | ||
|
||
if accounting.Format == "" { | ||
accounting.Format = "%s%v" | ||
} | ||
|
||
if accounting.FormatNegative == "" { | ||
accounting.FormatNegative = strings.Replace(strings.Replace(accounting.Format, "-", "", -1), "%v", "-%v", -1) | ||
} | ||
|
||
if accounting.FormatZero == "" { | ||
accounting.FormatZero = "0" | ||
} | ||
} | ||
|
||
func (accounting *Accounting) formatMoneyString(formattedNumber string) string { | ||
var format string | ||
|
||
if formattedNumber[0] == '-' { | ||
format = accounting.FormatNegative | ||
formattedNumber = formattedNumber[1:] | ||
} else if formattedNumber == "0" { | ||
format = accounting.FormatZero | ||
} else { | ||
format = accounting.Format | ||
} | ||
|
||
result := strings.Replace(format, "%s", accounting.Symbol, -1) | ||
result = strings.Replace(result, "%v", formattedNumber, -1) | ||
|
||
return result | ||
} | ||
|
||
func (accounting *Accounting) FormatMoney(value interface{}) string { | ||
accounting.init() | ||
formattedNumber := FormatNumber(value, accounting.Precision, accounting.Thousand, accounting.Decimal) | ||
return accounting.formatMoneyString(formattedNumber) | ||
} | ||
|
||
func (accounting *Accounting) FormatMoneyInt(value int) string { | ||
accounting.init() | ||
formattedNumber := FormatNumberInt(value, accounting.Precision, accounting.Thousand, accounting.Decimal) | ||
return accounting.formatMoneyString(formattedNumber) | ||
} | ||
|
||
func (accounting *Accounting) FormatMoneyFloat64(value float64) string { | ||
accounting.init() | ||
formattedNumber := FormatNumberFloat64(value, accounting.Precision, accounting.Thousand, accounting.Decimal) | ||
return accounting.formatMoneyString(formattedNumber) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package accounting | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func AssertEqual(t *testing.T, x, y string) { | ||
if x != y { | ||
t.Error("Expected ", y, ", got ", x) | ||
} | ||
} | ||
|
||
func TestFormatMoney(t *testing.T) { | ||
accounting := Accounting{Symbol: "$", Precision: 2} | ||
AssertEqual(t, accounting.FormatMoney(123456789.213123), "$123,456,789.21") | ||
AssertEqual(t, accounting.FormatMoney(12345678), "$12,345,678.00") | ||
|
||
accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","} | ||
AssertEqual(t, accounting.FormatMoney(4999.99), "€4.999,99") | ||
AssertEqual(t, accounting.FormatMoney(-4999.99), "€-4.999,99") | ||
|
||
accounting = Accounting{Symbol: "£ ", Precision: 0} | ||
AssertEqual(t, accounting.FormatMoney(-500000), "£ -500,000") | ||
|
||
accounting = Accounting{Symbol: "GBP", Precision: 0, | ||
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"} | ||
AssertEqual(t, accounting.FormatMoney(1000000), "GBP 1,000,000") | ||
AssertEqual(t, accounting.FormatMoney(-5000), "GBP (5,000)") | ||
AssertEqual(t, accounting.FormatMoney(0), "GBP --") | ||
} | ||
|
||
func TestFormatMoneyInt(t *testing.T) { | ||
accounting := Accounting{Symbol: "$", Precision: 2} | ||
AssertEqual(t, accounting.FormatMoneyInt(12345678), "$12,345,678.00") | ||
|
||
accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","} | ||
AssertEqual(t, accounting.FormatMoneyInt(4999), "€4.999,00") | ||
AssertEqual(t, accounting.FormatMoneyInt(-4999), "€-4.999,00") | ||
|
||
accounting = Accounting{Symbol: "£ ", Precision: 0} | ||
AssertEqual(t, accounting.FormatMoneyInt(-500000), "£ -500,000") | ||
|
||
accounting = Accounting{Symbol: "GBP", Precision: 0, | ||
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"} | ||
AssertEqual(t, accounting.FormatMoneyInt(1000000), "GBP 1,000,000") | ||
AssertEqual(t, accounting.FormatMoneyInt(-5000), "GBP (5,000)") | ||
AssertEqual(t, accounting.FormatMoneyInt(0), "GBP --") | ||
} | ||
|
||
func TestFormatMoneyFloat64(t *testing.T) { | ||
accounting := Accounting{Symbol: "$", Precision: 2} | ||
AssertEqual(t, accounting.FormatMoneyFloat64(123456789.213123), "$123,456,789.21") | ||
|
||
accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","} | ||
AssertEqual(t, accounting.FormatMoneyFloat64(4999.99), "€4.999,99") | ||
AssertEqual(t, accounting.FormatMoneyFloat64(-4999.99), "€-4.999,99") | ||
|
||
accounting = Accounting{Symbol: "£ ", Precision: 0} | ||
AssertEqual(t, accounting.FormatMoneyFloat64(-500000.0), "£ -500,000") | ||
|
||
accounting = Accounting{Symbol: "GBP", Precision: 0, | ||
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"} | ||
AssertEqual(t, accounting.FormatMoneyFloat64(1000000.0), "GBP 1,000,000") | ||
AssertEqual(t, accounting.FormatMoneyFloat64(-5000.0), "GBP (5,000)") | ||
AssertEqual(t, accounting.FormatMoneyFloat64(0.0), "GBP --") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package accounting | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"math" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
func formatNumberString(x string, precision int, thousand string, decimal string) string { | ||
lastIndex := strings.Index(x, ".") - 1 | ||
|
||
if lastIndex < 0 { | ||
lastIndex = len(x) - 1 | ||
} | ||
|
||
var buffer []byte | ||
var strBuffer bytes.Buffer | ||
|
||
j := 0 | ||
for i := lastIndex; i >= 0; i-- { | ||
j++ | ||
buffer = append(buffer, x[i]) | ||
|
||
if j == 3 && i > 0 && !(i == 1 && x[0] == '-') { | ||
buffer = append(buffer, ',') | ||
j = 0 | ||
} | ||
} | ||
|
||
for i := len(buffer) - 1; i >= 0; i-- { | ||
strBuffer.WriteByte(buffer[i]) | ||
} | ||
result := strBuffer.String() | ||
|
||
if thousand != "," { | ||
result = strings.Replace(result, ",", thousand, -1) | ||
} | ||
|
||
extra := x[lastIndex+1:] | ||
if decimal != "." { | ||
extra = strings.Replace(extra, ".", decimal, 1) | ||
} | ||
|
||
return result + extra | ||
} | ||
|
||
func FormatNumber(value interface{}, precision int, thousand string, decimal string) string { | ||
v := reflect.ValueOf(value) | ||
|
||
var x string | ||
switch v.Kind() { | ||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
x = fmt.Sprintf("%d", v.Int()) | ||
if precision > 0 { | ||
x += "." + strings.Repeat("0", precision) | ||
} | ||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
x = fmt.Sprintf("%d", v.Uint()) | ||
if precision > 0 { | ||
x += "." + strings.Repeat("0", precision) | ||
} | ||
case reflect.Float32, reflect.Float64: | ||
x = fmt.Sprintf(fmt.Sprintf("%%.%df", precision), v.Float()) | ||
default: | ||
return "" | ||
} | ||
|
||
return formatNumberString(x, precision, thousand, decimal) | ||
} | ||
|
||
func FormatNumberInt(x int, precision int, thousand string, decimal string) string { | ||
var result string | ||
var minus bool | ||
|
||
if x == math.MinInt64 { | ||
return FormatNumber(x, precision, thousand, decimal) | ||
} | ||
|
||
if x < 0 { | ||
minus = true | ||
x *= -1 | ||
} | ||
|
||
for x >= 1000 { | ||
result = fmt.Sprintf("%s%03d%s", thousand, x%1000, result) | ||
x /= 1000 | ||
} | ||
result = fmt.Sprintf("%d%s", x, result) | ||
|
||
if minus { | ||
result = "-" + result | ||
} | ||
|
||
if precision > 0 { | ||
result += decimal + strings.Repeat("0", precision) | ||
} | ||
|
||
return result | ||
} | ||
|
||
func FormatNumberFloat64(x float64, precision int, thousand string, decimal string) string { | ||
return formatNumberString(fmt.Sprintf(fmt.Sprintf("%%.%df", precision), x), precision, thousand, decimal) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package accounting | ||
|
||
import ( | ||
"math" | ||
"testing" | ||
) | ||
|
||
func TestFormatNumber(t *testing.T) { | ||
AssertEqual(t, FormatNumber(123456789.213123, 3, ",", "."), "123,456,789.213") | ||
AssertEqual(t, FormatNumber(123456789.213123, 3, ".", ","), "123.456.789,213") | ||
AssertEqual(t, FormatNumber(-12345.123123, 5, ",", "."), "-12,345.12312") | ||
AssertEqual(t, FormatNumber(-1234.123123, 5, ",", "."), "-1,234.12312") | ||
AssertEqual(t, FormatNumber(-123.123123, 5, ",", "."), "-123.12312") | ||
AssertEqual(t, FormatNumber(-12.123123, 5, ",", "."), "-12.12312") | ||
AssertEqual(t, FormatNumber(-1.123123, 5, ",", "."), "-1.12312") | ||
AssertEqual(t, FormatNumber(math.MaxInt64, 10, ",", "."), "9,223,372,036,854,775,807.0000000000") | ||
AssertEqual(t, FormatNumber(math.MinInt64, 10, ",", "."), "-9,223,372,036,854,775,808.0000000000") | ||
AssertEqual(t, FormatNumber(-1, 3, ",", "."), "-1.000") | ||
AssertEqual(t, FormatNumber(-10, 3, ",", "."), "-10.000") | ||
AssertEqual(t, FormatNumber(-100, 3, ",", "."), "-100.000") | ||
AssertEqual(t, FormatNumber(-1000, 3, ",", "."), "-1,000.000") | ||
AssertEqual(t, FormatNumber(-10000, 3, ",", "."), "-10,000.000") | ||
AssertEqual(t, FormatNumber(-100000, 3, ",", "."), "-100,000.000") | ||
AssertEqual(t, FormatNumber(-1000000, 3, ",", "."), "-1,000,000.000") | ||
AssertEqual(t, FormatNumber(1, 3, ",", "."), "1.000") | ||
AssertEqual(t, FormatNumber(10, 3, ",", "."), "10.000") | ||
AssertEqual(t, FormatNumber(100, 3, ",", "."), "100.000") | ||
AssertEqual(t, FormatNumber(1000, 3, ",", "."), "1,000.000") | ||
AssertEqual(t, FormatNumber(10000, 3, ",", "."), "10,000.000") | ||
AssertEqual(t, FormatNumber(100000, 3, ",", "."), "100,000.000") | ||
AssertEqual(t, FormatNumber(1000000, 3, ",", "."), "1,000,000.000") | ||
AssertEqual(t, FormatNumber(1000000, 10, " ", "."), "1 000 000.0000000000") | ||
AssertEqual(t, FormatNumber(1000000, 10, " ", "."), "1 000 000.0000000000") | ||
} | ||
|
||
func TestFormatNumberInt(t *testing.T) { | ||
AssertEqual(t, FormatNumberInt(math.MaxInt64, 10, ",", "."), "9,223,372,036,854,775,807.0000000000") | ||
AssertEqual(t, FormatNumberInt(math.MinInt64+1, 10, ",", "."), "-9,223,372,036,854,775,807.0000000000") | ||
AssertEqual(t, FormatNumberInt(math.MinInt64, 10, ",", "."), "-9,223,372,036,854,775,808.0000000000") | ||
AssertEqual(t, FormatNumberInt(-1, 3, ",", "."), "-1.000") | ||
AssertEqual(t, FormatNumberInt(-10, 3, ",", "."), "-10.000") | ||
AssertEqual(t, FormatNumberInt(-100, 3, ",", "."), "-100.000") | ||
AssertEqual(t, FormatNumberInt(-1000, 3, ",", "."), "-1,000.000") | ||
AssertEqual(t, FormatNumberInt(-10000, 3, ",", "."), "-10,000.000") | ||
AssertEqual(t, FormatNumberInt(-100000, 3, ",", "."), "-100,000.000") | ||
AssertEqual(t, FormatNumberInt(-1000000, 3, ",", "."), "-1,000,000.000") | ||
AssertEqual(t, FormatNumberInt(1, 3, ",", "."), "1.000") | ||
AssertEqual(t, FormatNumberInt(10, 3, ",", "."), "10.000") | ||
AssertEqual(t, FormatNumberInt(100, 3, ",", "."), "100.000") | ||
AssertEqual(t, FormatNumberInt(1000, 3, ",", "."), "1,000.000") | ||
AssertEqual(t, FormatNumberInt(10000, 3, ",", "."), "10,000.000") | ||
AssertEqual(t, FormatNumberInt(100000, 3, ",", "."), "100,000.000") | ||
AssertEqual(t, FormatNumberInt(1000000, 3, ",", "."), "1,000,000.000") | ||
AssertEqual(t, FormatNumberInt(1000000, 10, " ", "."), "1 000 000.0000000000") | ||
AssertEqual(t, FormatNumberInt(1000000, 10, " ", "."), "1 000 000.0000000000") | ||
} | ||
|
||
func TestFormatNumberFloat64(t *testing.T) { | ||
AssertEqual(t, FormatNumber(123456789.213123, 3, ",", "."), "123,456,789.213") | ||
AssertEqual(t, FormatNumber(-12345.123123, 5, ",", "."), "-12,345.12312") | ||
AssertEqual(t, FormatNumber(-1234.123123, 5, ",", "."), "-1,234.12312") | ||
AssertEqual(t, FormatNumber(-123.123123, 5, ",", "."), "-123.12312") | ||
AssertEqual(t, FormatNumber(-12.123123, 5, ",", "."), "-12.12312") | ||
AssertEqual(t, FormatNumber(-1.123123, 5, ",", "."), "-1.12312") | ||
} |