all the refactor
This commit is contained in:
+18
-151
@@ -1,159 +1,26 @@
|
||||
package cart
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"git.k6n.net/mats/platform/money"
|
||||
"git.k6n.net/mats/platform/tax"
|
||||
)
|
||||
|
||||
func GetTaxAmount(total int64, tax int) int64 {
|
||||
taxD := 10000 / float64(tax)
|
||||
return int64(float64(total) / float64((1 + taxD)))
|
||||
// Price represents a monetary amount with optional VAT breakdown by rate.
|
||||
// The canonical definition is now in platform/tax; this is a type alias
|
||||
// for backward compatibility.
|
||||
type Price = tax.Price
|
||||
|
||||
// NewPrice returns a new zero Price.
|
||||
func NewPrice() *Price { return tax.NewPrice() }
|
||||
|
||||
// NewPriceFromIncVat creates a Price from an inc-VAT total and a tax rate in
|
||||
// basis points (2500 = 25%, 1250 = 12.5%). Re-exported from platform/tax.
|
||||
func NewPriceFromIncVat(incVat int64, rateBp int) *Price {
|
||||
return tax.NewPriceFromIncVat(money.Cents(incVat), rateBp)
|
||||
}
|
||||
|
||||
type Price struct {
|
||||
IncVat int64 `json:"incVat"`
|
||||
VatRates map[float32]int64 `json:"vat,omitempty"`
|
||||
}
|
||||
// MultiplyPrice multiplies a Price by quantity and returns a new Price.
|
||||
func MultiplyPrice(p Price, qty int64) *Price { return tax.MultiplyPrice(p, qty) }
|
||||
|
||||
func NewPrice() *Price {
|
||||
return &Price{
|
||||
IncVat: 0,
|
||||
VatRates: make(map[float32]int64),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPriceFromIncVat(incVat int64, taxRate float32) *Price {
|
||||
tax := GetTaxAmount(incVat, int(taxRate*100))
|
||||
return &Price{
|
||||
IncVat: incVat,
|
||||
VatRates: map[float32]int64{
|
||||
taxRate: tax,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Price) ValueExVat() int64 {
|
||||
exVat := p.IncVat
|
||||
for _, amount := range p.VatRates {
|
||||
exVat -= amount
|
||||
}
|
||||
return exVat
|
||||
}
|
||||
|
||||
func (p *Price) TotalVat() int64 {
|
||||
total := int64(0)
|
||||
for _, amount := range p.VatRates {
|
||||
total += amount
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func MultiplyPrice(p Price, qty int64) *Price {
|
||||
ret := &Price{
|
||||
IncVat: p.IncVat * qty,
|
||||
VatRates: make(map[float32]int64),
|
||||
}
|
||||
for rate, amount := range p.VatRates {
|
||||
ret.VatRates[rate] = amount * qty
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *Price) Multiply(qty int64) {
|
||||
p.IncVat *= qty
|
||||
for rate, amount := range p.VatRates {
|
||||
p.VatRates[rate] = amount * qty
|
||||
}
|
||||
}
|
||||
|
||||
func (p Price) MarshalJSON() ([]byte, error) {
|
||||
// Build a stable wire format without calling Price.MarshalJSON recursively
|
||||
exVat := p.ValueExVat()
|
||||
var vat map[string]int64
|
||||
if len(p.VatRates) > 0 {
|
||||
vat = make(map[string]int64, len(p.VatRates))
|
||||
for rate, amount := range p.VatRates {
|
||||
// Rely on default formatting that trims trailing zeros for whole numbers
|
||||
// Using %g could output scientific notation for large numbers; float32 rates here are small.
|
||||
key := trimFloat(rate)
|
||||
vat[key] = amount
|
||||
}
|
||||
}
|
||||
type wire struct {
|
||||
ExVat int64 `json:"exVat"`
|
||||
IncVat int64 `json:"incVat"`
|
||||
Vat map[string]int64 `json:"vat,omitempty"`
|
||||
}
|
||||
return json.Marshal(wire{ExVat: exVat, IncVat: p.IncVat, Vat: vat})
|
||||
}
|
||||
|
||||
func (p *Price) UnmarshalJSON(data []byte) error {
|
||||
type wire struct {
|
||||
ExVat int64 `json:"exVat"`
|
||||
IncVat int64 `json:"incVat"`
|
||||
Vat map[string]int64 `json:"vat,omitempty"`
|
||||
}
|
||||
var w wire
|
||||
if err := json.Unmarshal(data, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.IncVat = w.IncVat
|
||||
if len(w.Vat) > 0 {
|
||||
p.VatRates = make(map[float32]int64, len(w.Vat))
|
||||
for rateStr, amount := range w.Vat {
|
||||
rate, err := strconv.ParseFloat(rateStr, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.VatRates[float32(rate)] = amount
|
||||
}
|
||||
} else {
|
||||
p.VatRates = make(map[float32]int64)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// trimFloat converts a float32 tax rate like 25 or 12.5 into a compact string without
|
||||
// unnecessary decimals ("25", "12.5").
|
||||
func trimFloat(f float32) string {
|
||||
// Convert via FormatFloat then trim trailing zeros and dot.
|
||||
s := strconv.FormatFloat(float64(f), 'f', -1, 32)
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *Price) Add(price Price) {
|
||||
p.IncVat += price.IncVat
|
||||
for rate, amount := range price.VatRates {
|
||||
p.VatRates[rate] += amount
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Price) Subtract(price Price) {
|
||||
p.IncVat -= price.IncVat
|
||||
for rate, amount := range price.VatRates {
|
||||
p.VatRates[rate] -= amount
|
||||
}
|
||||
}
|
||||
|
||||
func SumPrices(prices ...Price) *Price {
|
||||
if len(prices) == 0 {
|
||||
return NewPrice()
|
||||
}
|
||||
|
||||
aggregated := NewPrice()
|
||||
|
||||
for _, price := range prices {
|
||||
aggregated.IncVat += price.IncVat
|
||||
for rate, amount := range price.VatRates {
|
||||
aggregated.VatRates[rate] += amount
|
||||
}
|
||||
}
|
||||
|
||||
if len(aggregated.VatRates) == 0 {
|
||||
aggregated.VatRates = nil
|
||||
}
|
||||
|
||||
return aggregated
|
||||
}
|
||||
// SumPrices aggregates multiple Prices into one.
|
||||
func SumPrices(prices ...Price) *Price { return tax.SumPrices(prices...) }
|
||||
|
||||
Reference in New Issue
Block a user