Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cart: Reverse the order of split items discount #320

Merged
merged 3 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions cart/domain/cart/delivery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ func TestDeliveryInfo_TotalCalculations(t *testing.T) {
df := DeliveryBuilder{}
df.SetDeliveryCode("test")

//Add item with 4,1 $ - 10 Qty and Tax of 7
// Add item with 4,1 $ - 10 Qty and Tax of 7
itemf := ItemBuilder{}
//Set net price 410
// Set net price 410
itemf.SetSinglePriceNet(
priceDomain.NewFromInt(410, 100, "$"),
).SetQty(10).AddTaxInfo(
Expand All @@ -34,8 +34,8 @@ func TestDeliveryInfo_TotalCalculations(t *testing.T) {
assert.Equal(t, priceDomain.NewFromInt(4387, 100, "$"), item.RowPriceGross, "item1 gross price wrong")
df.AddItem(*item)

//Add item with 10 $ - 5 Qty / Discount of 25 (505) and Tax of 7
//Set net price 410
// Add item with 10 $ - 5 Qty / Discount of 25 (505) and Tax of 7
// Set net price 410
itemf.SetSinglePriceNet(
priceDomain.NewFromInt(1000, 100, "$"),
).SetQty(5).AddTaxInfo(
Expand All @@ -53,42 +53,47 @@ func TestDeliveryInfo_TotalCalculations(t *testing.T) {
if item2 == nil {
t.Fatal("item2 is nil but no error?")
}
//item2 gros should be tax = (5 * 10) - discount (25) * 0.07 = 1,75
assert.Equal(t, priceDomain.NewFromInt(5175, 100, "$"), item2.RowPriceGross, "item2 gross price wrong")
// item2 gros should be tax = (5 * 10) - discount (25) * 0.07 = 1,75
assert.Equal(
t,
priceDomain.NewFromInt(5175, 100, "$").FloatAmount(),
item2.RowPriceGross.FloatAmount(),
"item2 gross price wrong",
)
df.AddItem(*item2)

//Check totals
// Check totals
d, err := df.Build()
assert.NoError(t, err)

//SubTotalGross - need to be 5175 + 4387
// SubTotalGross - need to be 5175 + 4387
assertPricesWithLikelyEqual(t, priceDomain.NewFromInt(9562, 100, "$"), d.SubTotalGross(), "SubTotalGross result should match 95,62")

//assert.Equal(t, priceDomain.NewFromInt(9562, 100, "$"), d.SubTotalGross(), fmt.Sprintf("SubTotalGross result should match 95,62 but is %f", d.SubTotalGross().FloatAmount()))
// assert.Equal(t, priceDomain.NewFromInt(9562, 100, "$"), d.SubTotalGross(), fmt.Sprintf("SubTotalGross result should match 95,62 but is %f", d.SubTotalGross().FloatAmount()))

//SubTotalGross - need to be 4100 + 5000
// SubTotalGross - need to be 4100 + 5000
assert.True(t, priceDomain.NewFromInt(9100, 100, "$").Equal(d.SubTotalNet()), "SubTotalNet wrong")

//SumTotalTaxAmount is the difference
// SumTotalTaxAmount is the difference
assert.True(t, priceDomain.NewFromInt(462, 100, "$").Equal(d.SumTotalTaxAmount()), fmt.Sprintf("result wrong %f", d.SumTotalTaxAmount().FloatAmount()))

//SumTotalDiscountAmount
// SumTotalDiscountAmount
assert.True(t, priceDomain.NewFromInt(-2500, 100, "$").Equal(d.SumTotalDiscountAmount()), "SumTotalDiscountAmount")

//SubTotalNetWithDiscounts
// SubTotalNetWithDiscounts
assert.True(t, priceDomain.NewFromInt(9100-2500, 100, "$").Equal(d.SubTotalNetWithDiscounts()), fmt.Sprintf("SubTotalNetWithDiscounts result wrong %f", d.SubTotalNetWithDiscounts().FloatAmount()))

//SubTotalGrossWithDiscounts
// SubTotalGrossWithDiscounts
assertPricesWithLikelyEqual(t, priceDomain.NewFromInt(9562-2500, 100, "$"), d.SubTotalGrossWithDiscounts(), "SubTotalGrossWithDiscount")

//Taxes check
// Taxes check
taxes := d.SumRowTaxes()
assert.Equal(t, 1, len(taxes), "expected one merged tax")
assertPricesWithLikelyEqual(t, priceDomain.NewFromInt(462, 100, "$"), taxes.TotalAmount(), "taxes check wrong")

}

//assertPricesWithLikelyEqual - helper
// assertPricesWithLikelyEqual - helper
func assertPricesWithLikelyEqual(t *testing.T, p1 priceDomain.Price, p2 priceDomain.Price, msg string) {
t.Helper()
assert.True(t, p1.LikelyEqual(p2), fmt.Sprintf("%v (%f != %f)", msg, p1.FloatAmount(), p2.FloatAmount()))
Expand Down
12 changes: 12 additions & 0 deletions cart/domain/cart/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math/big"
"sort"

priceDomain "flamingo.me/flamingo-commerce/v3/price/domain"
"flamingo.me/flamingo-commerce/v3/product/domain"
Expand Down Expand Up @@ -468,6 +469,17 @@ func (s *ItemSplitter) SplitInSingleQtyItems(givenItem Item) ([]Item, error) {
itemBuilder.SetQty(1)
for _, ap := range givenItem.AppliedDiscounts {
apSplitted, err := ap.Applied.SplitInPayables(givenItem.Qty)
// The split adds the moving cents to the first ones, resulting in
// having the smallest prices at the end but since discounts are
// negative, we need to reverse it to ensure that a split of the row
// totals has the rounding cents at the same positions
sort.Slice(apSplitted, func(i, j int) bool {
return apSplitted[i].FloatAmount() > apSplitted[j].FloatAmount()
})
p := make([]float64, 0)
for _, i := range apSplitted {
p = append(p, i.FloatAmount())
}
if err != nil {
return nil, err
}
Expand Down
17 changes: 10 additions & 7 deletions cart/domain/cart/item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,30 +98,30 @@ func TestItemSplitter_SplitGrossBased(t *testing.T) {
builder.SetSinglePriceGross(priceDomain.NewFromInt(2065, 100, "€")).
SetQty(5).AddTaxInfo("tax", big.NewFloat(7), nil).
SetID("2").
AddDiscount(cartDomain.AppliedDiscount{Applied: priceDomain.NewFromInt(-3170, 100, "€")}).
AddDiscount(cartDomain.AppliedDiscount{Applied: priceDomain.NewFromInt(-3172, 100, "€")}).
CalculatePricesAndTaxAmountsFromSinglePriceGross()
item, err := builder.Build()
require.NoError(t, err)

splittedItems, err := splitter.SplitInSingleQtyItems(*item)
require.NoError(t, err)

//20.65 * 5 = 103.25
// 20.65 * 5 = 103.25
assert.Equal(t, 103.25, item.RowPriceGross.FloatAmount())
assert.Equal(t, -31.70, item.TotalDiscountAmount().FloatAmount())
assert.Equal(t, -31.72, item.TotalDiscountAmount().FloatAmount())
// (98.57 - 31.70) * 0.07
assert.Equal(t, 4.68, item.TotalTaxAmount().FloatAmount())
// TotalTaxAmount + 98.57 = 103.25
assert.Equal(t, 98.57, item.RowPriceNet.FloatAmount())
assert.Equal(t, 66.87, item.RowPriceNetWithDiscount().FloatAmount())
assert.Equal(t, 66.85, item.RowPriceNetWithDiscount().FloatAmount())

var rowGrossTotal, rowNetTotal, totalTaxAmount, totalDiscountAmount float64
var discount, rowGrossTotal, rowNetTotal, totalTaxAmount, totalDiscountAmount float64
for _, splitItem := range splittedItems {
assert.Equal(t, 1, splitItem.Qty)
//make sure single and row price are equal:
// make sure single and row price are equal:
assert.Equal(t, splitItem.SinglePriceNet.FloatAmount(), splitItem.RowPriceNet.FloatAmount())
assert.Equal(t, splitItem.SinglePriceGross.FloatAmount(), splitItem.RowPriceGross.FloatAmount())
//make sure its constitent (net+tax=gross):
// make sure it's consistent (net+tax=gross):
assert.Equal(t, splitItem.RowPriceGross.FloatAmount(), splitItem.RowPriceNet.ForceAdd(splitItem.TotalTaxAmount()).FloatAmount())
rowGrossTotal = rowGrossTotal + splitItem.RowPriceGross.FloatAmount()
rowNetTotal = rowNetTotal + splitItem.RowPriceNet.FloatAmount()
Expand All @@ -130,6 +130,9 @@ func TestItemSplitter_SplitGrossBased(t *testing.T) {
assert.Equal(t, 7.0, rate)
totalDiscountAmount = totalDiscountAmount + splitItem.TotalDiscountAmount().FloatAmount()

// discount split cents should be at the end, so the next discount must be the same or smaller
assert.GreaterOrEqual(t, discount, splitItem.TotalDiscountAmount().FloatAmount())
discount = splitItem.TotalDiscountAmount().FloatAmount()
}
assert.Equal(t, item.RowPriceGross.FloatAmount(), rowGrossTotal)
assert.Equal(t, item.RowPriceNet.FloatAmount(), rowNetTotal)
Expand Down