mirror of
https://github.com/hanzoai/commerce.git
synced 2026-10-30 15:08:42 +00:00
Multi-tenant commerce and billing: orders, subscriptions, invoices, plans, usage metering and a credit ledger. One Go binary. MIT OR Apache-2.0. Claude-Session: https://claude.ai/code/session_01SAtaDFm8VDiWrhYHNNtxMw
299 lines
10 KiB
Go
299 lines
10 KiB
Go
package test
|
|
|
|
import (
|
|
"github.com/hanzoai/commerce/models/lineitem"
|
|
"github.com/hanzoai/commerce/models/order"
|
|
"github.com/hanzoai/commerce/models/types/currency"
|
|
"github.com/hanzoai/commerce/util/rand"
|
|
|
|
. "github.com/hanzoai/commerce/util/test/ginkgo"
|
|
)
|
|
|
|
var _ = Describe("Order.UpdateAndTally", func() {
|
|
Context("Storeless (Deprecated)", func() {
|
|
// Make sure out of order execution works because tax is left alone in
|
|
// deprecated flow
|
|
BeforeEach(func() {
|
|
// Scramble currency values so we know they are being replaced
|
|
for i := range ord.Coupons {
|
|
ord.Coupons[i].Amount = rand.Int()
|
|
}
|
|
|
|
for i := range ord.Items {
|
|
ord.Items[i].Price = currency.Cents(rand.Int64())
|
|
}
|
|
|
|
ord.LineTotal = currency.Cents(rand.Int64())
|
|
ord.Discount = currency.Cents(rand.Int64())
|
|
ord.Subtotal = currency.Cents(rand.Int64())
|
|
ord.Tax = 0 //currency.Cents(rand.Int64())
|
|
ord.Shipping = 0 //currency.Cents(rand.Int64())
|
|
ord.Total = currency.Cents(rand.Int64())
|
|
ord.TokenSaleId = ""
|
|
ord.WalletId = ""
|
|
ord.WalletPassphrase = ""
|
|
ord.Mode = order.DefaultMode
|
|
})
|
|
|
|
It("Should UpdateAndTally", func() {
|
|
ord.CouponCodes = []string{}
|
|
err := ord.UpdateAndTally(nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(50000)))
|
|
Expect(ord.Total).To(Equal(currency.Cents(50000)))
|
|
})
|
|
|
|
It("Should UpdateAndTally With No Tax or ShippingRates without crashing", func() {
|
|
sr, _ := stor2.GetShippingRates()
|
|
Expect(sr).To(BeNil())
|
|
|
|
tr, _ := stor2.GetTaxRates()
|
|
Expect(tr).To(BeNil())
|
|
|
|
ord.CouponCodes = []string{}
|
|
err := ord.UpdateAndTally(stor2)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(50000)))
|
|
|
|
tax := currency.Cents(0)
|
|
shipping := currency.Cents(0)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally With Coupon", func() {
|
|
ord.CouponCodes = []string{"such-coupon"}
|
|
err := ord.UpdateAndTally(nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(49500)))
|
|
Expect(ord.Total).To(Equal(currency.Cents(49500)))
|
|
})
|
|
|
|
It("Should UpdateAndTally And Dedupe Coupons", func() {
|
|
ord.CouponCodes = []string{"such-coupon", "such-coupon"}
|
|
err := ord.UpdateAndTally(nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(len(ord.CouponCodes)).To(Equal(1))
|
|
Expect(ord.CouponCodes[0]).To(Equal("such-coupon"))
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(49500)))
|
|
Expect(ord.Total).To(Equal(currency.Cents(49500)))
|
|
})
|
|
|
|
It("Should UpdateAndTally Only Applicable Coupons", func() {
|
|
ord2 := order.New(ord.Datastore())
|
|
ord2.CouponCodes = []string{"sad-coupon"}
|
|
ord2.Items = []lineitem.LineItem{{ProductSlug: "doge-shirt", Quantity: 1}}
|
|
err := ord2.UpdateAndTally(nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord2.Subtotal).To(Equal(currency.Cents(2000)))
|
|
Expect(ord2.Total).To(Equal(currency.Cents(2000)))
|
|
|
|
ord2 = order.New(ord.Datastore())
|
|
ord2.CouponCodes = []string{"sad-coupon"}
|
|
ord2.Items = []lineitem.LineItem{{ProductSlug: "sad-keanu-shirt", Quantity: 1}}
|
|
err = ord2.UpdateAndTally(nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord2.Subtotal).To(Equal(currency.Cents(2000)))
|
|
Expect(ord2.Total).To(Equal(currency.Cents(2000)))
|
|
})
|
|
|
|
It("Should Serialize Line Items", func() {
|
|
ord2 := order.New(ord.Datastore())
|
|
ord2.CouponCodes = []string{"sad-coupon"}
|
|
ord2.Items = []lineitem.LineItem{{ProductSlug: "doge-shirt", ProductName: "Doge Shirt", Quantity: 1}}
|
|
|
|
memo := ord2.DescriptionLong()
|
|
Expect(memo).To(Equal("Doge Shirt (doge-shirt) x 1\n"))
|
|
})
|
|
})
|
|
|
|
Context("Store", func() {
|
|
BeforeEach(func() {
|
|
// Scramble currency values so we know they are being replaced
|
|
for i := range ord.Coupons {
|
|
ord.Coupons[i].Amount = rand.Int()
|
|
}
|
|
|
|
for i := range ord.Items {
|
|
ord.Items[i].Price = currency.Cents(rand.Int64())
|
|
}
|
|
|
|
ord.LineTotal = currency.Cents(rand.Int64())
|
|
ord.Discount = currency.Cents(rand.Int64())
|
|
ord.Subtotal = currency.Cents(rand.Int64())
|
|
ord.Tax = currency.Cents(rand.Int64())
|
|
ord.Shipping = currency.Cents(rand.Int64())
|
|
ord.Total = currency.Cents(rand.Int64())
|
|
ord.TokenSaleId = ""
|
|
ord.WalletId = ""
|
|
ord.WalletPassphrase = ""
|
|
ord.Mode = order.DefaultMode
|
|
})
|
|
|
|
It("Should UpdateAndTally", func() {
|
|
ord.CouponCodes = []string{}
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(50000)))
|
|
|
|
tax := 1 + (ord.Subtotal).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally Price Overrides", func() {
|
|
ord.CouponCodes = []string{}
|
|
err := ord.UpdateAndTally(stor3)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(24680)))
|
|
Expect(ord.Currency).To(Equal(currency.ETH))
|
|
|
|
Expect(ord.Total).To(Equal(ord.Subtotal))
|
|
|
|
})
|
|
|
|
It("Should UpdateAndTally with Provided Subtotal for Contributions", func() {
|
|
ord.CouponCodes = []string{}
|
|
ord.Mode = order.ContributionMode
|
|
subTotal := ord.Subtotal
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(subTotal))
|
|
|
|
tax := 1 + (ord.Subtotal).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally with Provided Subtotal for Deposit", func() {
|
|
ord.CouponCodes = []string{}
|
|
ord.Mode = order.ContributionMode
|
|
subTotal := ord.Subtotal
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(subTotal))
|
|
|
|
tax := 1 + (ord.Subtotal).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
// The tests above apply the rate to whatever subtotal the fixture produced, which
|
|
// happens to divide evenly, so none of them can tell a rounded tax from a
|
|
// truncated one. This one picks a subtotal that cannot: $19.99 at the store's
|
|
// 8.85% is 176.9115 cents of tax, and at 10% is 199.9 of shipping. Truncating
|
|
// billed 176 and 199; both fractions are over half and both belong to the
|
|
// jurisdiction and the carrier, not to whichever way int64() happens to fall.
|
|
It("Should round tax and shipping rather than truncate them", func() {
|
|
ord.CouponCodes = []string{}
|
|
ord.Mode = order.ContributionMode
|
|
ord.Subtotal = 1999
|
|
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(1999)))
|
|
|
|
Expect(ord.Tax).To(Equal(currency.Cents(1 + 177))) // truncating gave 1 + 176
|
|
Expect(ord.Shipping).To(Equal(currency.Cents(499 + 200))) // truncating gave 499 + 199
|
|
Expect(ord.Total).To(Equal(currency.Cents(1999 + 178 + 699)))
|
|
})
|
|
|
|
It("Should UpdateAndTally with Provided Subtotal for TokenSales", func() {
|
|
ord.CouponCodes = []string{}
|
|
ord.TokenSaleId = "1234"
|
|
subTotal := ord.Subtotal
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord.Subtotal).To(Equal(subTotal))
|
|
|
|
tax := 1 + (ord.Subtotal).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally With Coupon", func() {
|
|
ord.CouponCodes = []string{"such-coupon"}
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(49500)))
|
|
|
|
tax := 1 + (ord.Subtotal + ord.Discount).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally And Dedupe Coupons", func() {
|
|
ord.CouponCodes = []string{"such-coupon", "such-coupon"}
|
|
err := ord.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(len(ord.CouponCodes)).To(Equal(1))
|
|
Expect(ord.CouponCodes[0]).To(Equal("such-coupon"))
|
|
|
|
Expect(ord.Subtotal).To(Equal(currency.Cents(49500)))
|
|
|
|
tax := 1 + (ord.Subtotal + ord.Discount).Scale(taxRate)
|
|
shipping := 499 + (ord.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord.Tax).To(Equal(tax))
|
|
Expect(ord.Shipping).To(Equal(shipping))
|
|
Expect(ord.Total).To(Equal(ord.Subtotal + tax + shipping))
|
|
})
|
|
|
|
It("Should UpdateAndTally Only Applicable Coupons", func() {
|
|
ord2 := order.New(ord.Datastore())
|
|
ord2.CouponCodes = []string{"sad-coupon"}
|
|
ord2.Items = []lineitem.LineItem{{ProductSlug: "doge-shirt", Quantity: 1}}
|
|
ord2.ShippingAddress.Country = "us"
|
|
ord2.ShippingAddress.State = "ks"
|
|
ord2.ShippingAddress.PostalCode = "66212"
|
|
|
|
err := ord2.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord2.Subtotal).To(Equal(currency.Cents(2000)))
|
|
|
|
tax := 1 + (ord2.Subtotal).Scale(taxRate)
|
|
shipping := 499 + (ord2.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord2.Tax).To(Equal(tax))
|
|
Expect(ord2.Shipping).To(Equal(shipping))
|
|
Expect(ord2.Total).To(Equal(ord2.Subtotal + tax + shipping))
|
|
|
|
ord2 = order.New(ord.Datastore())
|
|
ord2.CouponCodes = []string{"sad-coupon"}
|
|
ord2.Items = []lineitem.LineItem{{ProductSlug: "sad-keanu-shirt", Quantity: 1}}
|
|
ord2.ShippingAddress.Country = "us"
|
|
ord2.ShippingAddress.State = "ks"
|
|
ord2.ShippingAddress.PostalCode = "66212"
|
|
|
|
err = ord2.UpdateAndTally(stor)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(ord2.Subtotal).To(Equal(currency.Cents(2000)))
|
|
|
|
tax = 1 + (ord2.Subtotal).Scale(taxRate)
|
|
shipping = 499 + (ord2.Subtotal).Scale(shipRate)
|
|
|
|
Expect(ord2.Tax).To(Equal(tax))
|
|
Expect(ord2.Shipping).To(Equal(shipping))
|
|
Expect(ord2.Total).To(Equal(ord2.Subtotal + tax + shipping))
|
|
})
|
|
})
|
|
})
|