@@ -173,6 +173,38 @@ func (t *Tax) AppliesTo(country, productType string) bool {
173
173
return applies
174
174
}
175
175
176
+ func calculateAmountsForSingleItem (settings * Settings , lineLogger logrus.FieldLogger , jwtClaims map [string ]interface {}, params PriceParameters , item Item , multiplier uint64 ) ItemPrice {
177
+ itemPrice := ItemPrice {Quantity : item .GetQuantity ()}
178
+
179
+ singlePrice := item .PriceInLowestUnit () * multiplier
180
+ _ , itemPrice .Subtotal = calculateTaxes (singlePrice , item , params , settings )
181
+
182
+ // apply discount to original price
183
+ coupon := params .Coupon
184
+ if coupon != nil && coupon .ValidForType (item .ProductType ()) && coupon .ValidForProduct (item .ProductSku ()) {
185
+ itemPrice .Discount = calculateDiscount (singlePrice , coupon .PercentageDiscount (), coupon .FixedDiscount (params .Currency )* multiplier )
186
+ }
187
+ if settings != nil && settings .MemberDiscounts != nil {
188
+ for _ , discount := range settings .MemberDiscounts {
189
+
190
+ if jwtClaims != nil && claims .HasClaims (jwtClaims , discount .Claims ) && discount .ValidForType (item .ProductType ()) && discount .ValidForProduct (item .ProductSku ()) {
191
+ lineLogger = lineLogger .WithField ("discount" , discount .Claims )
192
+ itemPrice .Discount += calculateDiscount (singlePrice , discount .Percentage , discount .FixedDiscount (params .Currency )* multiplier )
193
+ }
194
+ }
195
+ }
196
+
197
+ discountedPrice := uint64 (0 )
198
+ if itemPrice .Discount < singlePrice {
199
+ discountedPrice = singlePrice - itemPrice .Discount
200
+ }
201
+
202
+ itemPrice .Taxes , itemPrice .NetTotal = calculateTaxes (discountedPrice , item , params , settings )
203
+ itemPrice .Total = int64 (itemPrice .NetTotal + itemPrice .Taxes )
204
+
205
+ return itemPrice
206
+ }
207
+
176
208
// CalculatePrice will calculate the final total price. It takes into account
177
209
// currency, country, coupons, and discounts.
178
210
func CalculatePrice (settings * Settings , jwtClaims map [string ]interface {}, params PriceParameters , log logrus.FieldLogger ) Price {
@@ -193,34 +225,7 @@ func CalculatePrice(settings *Settings, jwtClaims map[string]interface{}, params
193
225
"product_sku" : item .ProductSku (),
194
226
})
195
227
196
- itemPrice := ItemPrice {Quantity : item .GetQuantity ()}
197
-
198
- singlePrice := item .PriceInLowestUnit ()
199
- _ , itemPrice .Subtotal = calculateTaxes (singlePrice , item , params , settings )
200
-
201
- // apply discount to original price
202
- coupon := params .Coupon
203
- if coupon != nil && coupon .ValidForType (item .ProductType ()) && coupon .ValidForProduct (item .ProductSku ()) {
204
- itemPrice .Discount = calculateDiscount (singlePrice , coupon .PercentageDiscount (), coupon .FixedDiscount (params .Currency ))
205
- }
206
- if settings != nil && settings .MemberDiscounts != nil {
207
- for _ , discount := range settings .MemberDiscounts {
208
-
209
- if jwtClaims != nil && claims .HasClaims (jwtClaims , discount .Claims ) && discount .ValidForType (item .ProductType ()) && discount .ValidForProduct (item .ProductSku ()) {
210
- lineLogger = lineLogger .WithField ("discount" , discount .Claims )
211
- itemPrice .Discount += calculateDiscount (singlePrice , discount .Percentage , discount .FixedDiscount (params .Currency ))
212
- }
213
- }
214
- }
215
-
216
- discountedPrice := uint64 (0 )
217
- if itemPrice .Discount < singlePrice {
218
- discountedPrice = singlePrice - itemPrice .Discount
219
- }
220
-
221
- itemPrice .Taxes , itemPrice .NetTotal = calculateTaxes (discountedPrice , item , params , settings )
222
-
223
- itemPrice .Total = int64 (itemPrice .NetTotal + itemPrice .Taxes )
228
+ itemPrice := calculateAmountsForSingleItem (settings , lineLogger , jwtClaims , params , item , 1 )
224
229
225
230
lineLogger .WithFields (
226
231
logrus.Fields {
@@ -233,11 +238,13 @@ func CalculatePrice(settings *Settings, jwtClaims map[string]interface{}, params
233
238
234
239
price .Items = append (price .Items , itemPrice )
235
240
236
- price .Subtotal += (itemPrice .Subtotal * itemPrice .Quantity )
237
- price .Discount += (itemPrice .Discount * itemPrice .Quantity )
238
- price .NetTotal += (itemPrice .NetTotal * itemPrice .Quantity )
239
- price .Taxes += (itemPrice .Taxes * itemPrice .Quantity )
240
- price .Total += (itemPrice .Total * int64 (itemPrice .Quantity ))
241
+ // avoid issues with rounding when multiplying by quantity before taxation
242
+ itemPriceMultiple := calculateAmountsForSingleItem (settings , lineLogger , jwtClaims , params , item , item .GetQuantity ())
243
+ price .Subtotal += itemPriceMultiple .Subtotal
244
+ price .Discount += itemPriceMultiple .Discount
245
+ price .NetTotal += itemPriceMultiple .NetTotal
246
+ price .Taxes += itemPriceMultiple .Taxes
247
+ price .Total += itemPriceMultiple .Total
241
248
}
242
249
243
250
price .Total = int64 (price .NetTotal + price .Taxes )
0 commit comments