Skip to content

Commit

Permalink
feat(stripe): ivoice sync quantity
Browse files Browse the repository at this point in the history
  • Loading branch information
hekike committed Jan 1, 2025
1 parent 43d4208 commit df815c2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 3 deletions.
31 changes: 31 additions & 0 deletions openmeter/app/stripe/entity/app/calculator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"

"github.com/alpacahq/alpacadecimal"
"github.com/invopop/gobl/num"
"golang.org/x/text/language"
"golang.org/x/text/message"

"github.com/openmeterio/openmeter/pkg/currencyx"
)
Expand All @@ -17,17 +20,45 @@ func NewStripeCalculator(currency currencyx.Code) (StripeCalculator, error) {

return StripeCalculator{
calculator: calculator,
printer: message.NewPrinter(language.English),
multiplier: alpacadecimal.NewFromInt(10).Pow(alpacadecimal.NewFromInt(int64(calculator.Def.Subunits))),
}, nil
}

// StripeCalculator provides a currency calculator object.
type StripeCalculator struct {
calculator currencyx.Calculator
printer *message.Printer
multiplier alpacadecimal.Decimal
}

// RoundToAmount rounds the amount to the precision of the Stripe currency in Stripe amount.
func (c StripeCalculator) RoundToAmount(amount alpacadecimal.Decimal) int64 {
return amount.Mul(c.multiplier).Round(0).IntPart()
}

// FormatAmount formats the amount
func (c StripeCalculator) FormatAmount(amount alpacadecimal.Decimal) string {
if amount.IsInteger() {
return c.calculator.Def.FormatAmount(num.MakeAmount(amount.IntPart(), 0))
}

am, _ := amount.Float64()
return c.calculator.Def.FormatAmount(num.AmountFromFloat64(am, uint32(amount.NumDigits())))
}

// FormatQuantity formats the quantity to two decimal places.
// This should be only used to display the quantity not for calculations.
func (c StripeCalculator) FormatQuantity(quantity alpacadecimal.Decimal) string {
if quantity.IsInteger() {
return c.printer.Sprintf("%d", quantity.IntPart())
} else {
f, _ := quantity.Float64()
return c.printer.Sprintf("%.2f", f)
}
}

// IsInteger checks if the amount is an integer in the Stripe currency.
func (c StripeCalculator) IsInteger(amount alpacadecimal.Decimal) bool {
return amount.Mul(c.multiplier).IsInteger()
}
16 changes: 13 additions & 3 deletions openmeter/app/stripe/entity/app/invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"sort"

"github.com/alpacahq/alpacadecimal"
"github.com/samber/lo"
"github.com/stripe/stripe-go/v80"

Expand Down Expand Up @@ -457,9 +458,8 @@ func getStripeUpdateLinesLineParams(

// getStripeAddLinesLineParams returns the Stripe line item
func getStripeAddLinesLineParams(line *billing.Line, calculator StripeCalculator) *stripe.InvoiceAddLinesLineParams {
name := getLineName(line)
description := getLineName(line)
period := getPeriod(line)

amount := line.Totals.Amount

// Handle usage based commitments like minimum spend
Expand All @@ -469,9 +469,19 @@ func getStripeAddLinesLineParams(line *billing.Line, calculator StripeCalculator
amount = line.Totals.ChargesTotal
}

// If the line has a quantity we add the quantity and per unit amount to the description
if line.FlatFee.Quantity.GreaterThan(alpacadecimal.NewFromInt(1)) {
description = fmt.Sprintf(
"%s (%s x %s)",
description,
calculator.FormatQuantity(line.FlatFee.Quantity),
calculator.FormatAmount(line.FlatFee.PerUnitAmount),
)
}

// Otherwise we add the calculated total with with quantity one
return &stripe.InvoiceAddLinesLineParams{
Description: lo.ToPtr(name),
Description: lo.ToPtr(description),
Amount: lo.ToPtr(calculator.RoundToAmount(amount)),
Period: period,
Metadata: map[string]string{
Expand Down

0 comments on commit df815c2

Please sign in to comment.