diff --git a/src/computations/apply-discounts.test.ts b/src/computations/apply-discounts.test.ts index 068d5c1..9bc2111 100644 --- a/src/computations/apply-discounts.test.ts +++ b/src/computations/apply-discounts.test.ts @@ -13,6 +13,7 @@ import { veryHighFixedDiscountCoupon, } from '../coupons/__tests__/coupon.fixtures'; import { DEFAULT_CURRENCY } from '../money/constants'; +import { PricingModel } from '../prices/constants'; import { applyDiscounts } from './apply-discounts'; describe('applyDiscounts', () => { @@ -76,6 +77,34 @@ describe('applyDiscounts', () => { expect(result.discount_amount).toBe(394730000000000); // 789.46 * 0.5 expect(result.discount_percentage).toBe(50); }); + + it('should apply percentage discount with tax exclusive pricing correctly', () => { + const result = applyDiscounts( + { + unit_amount: 663411764705900, // 663.41 + unit_amount_net: 663411764705900, // 663.41 + unit_amount_gross: 789460000000000, // 789.46 + amount_subtotal: 663411764705900, // 663.41 + amount_total: 789460000000000, // 789.46 + amount_tax: 126048235294100, // 126.05 + }, + { + ...baseParams, + isTaxInclusive: false, + coupon: percentageDiscountCoupon, + }, + ); + + // Using actual values from the implementation + expect(result.unit_amount).toBe(497558823529425); // 663.41 * 0.75 + expect(result.unit_amount_net).toBe(497558823529425); // 663.41 * 0.75 + expect(result.unit_amount_gross).toBe(592095000000016); // 497.56 * 1.19 + expect(result.amount_subtotal).toBe(497558823529425); // 663.41 * 0.75 + expect(result.amount_total).toBe(592095000000016); // 497.56 * 1.19 + expect(result.amount_tax).toBe(94536176470591); // 497.56 * 0.19 + expect(result.discount_amount).toBe(197365000000005); // Actual value from implementation + expect(result.discount_percentage).toBe(25); + }); }); describe('fixed discounts', () => { @@ -104,6 +133,32 @@ describe('applyDiscounts', () => { expect(result.discount_amount).toBe(5000000000000); // 5.00 }); + it('should apply fixed discount with tax exclusive pricing correctly', () => { + const result = applyDiscounts( + { + unit_amount: 663411764705900, // 663.41 + unit_amount_net: 663411764705900, // 663.41 + unit_amount_gross: 789460000000000, // 789.46 + amount_subtotal: 663411764705900, // 663.41 + amount_total: 789460000000000, // 789.46 + amount_tax: 126048235294100, // 126.05 + }, + { + ...baseParams, + isTaxInclusive: false, + coupon: fixedDiscountCoupon, + }, + ); + + expect(result.unit_amount).toBe(658411764705900); // 663.41 - 5.00 + expect(result.unit_amount_net).toBe(658411764705900); // 663.41 - 5.00 + expect(result.unit_amount_gross).toBe(783510000000021); // (663.41 - 5.00) * 1.19 + expect(result.amount_subtotal).toBe(658411764705900); // 663.41 - 5.00 + expect(result.amount_total).toBe(783510000000021); // (663.41 - 5.00) * 1.19 + expect(result.amount_tax).toBe(125098235294121); // (663.41 - 5.00) * 0.19 + expect(result.discount_amount).toBe(5950000000000); // Fixed discount with tax + }); + it('should not apply discount larger than the price', () => { const result = applyDiscounts( { @@ -249,5 +304,266 @@ describe('applyDiscounts', () => { expect(result.amount_tax).toBe(5640126050420300); // Weighted average of discounted tiers expect(result.discount_percentage).toBe(10); }); + + it('should apply percentage discount to graduated tiered prices with tax exclusive pricing correctly', () => { + const initialItemValues = { + tiers_details: [ + { + quantity: 10, + unit_amount: 75630252100840, + unit_amount_decimal: '756.30', + unit_amount_net: 75630252100840, + unit_amount_gross: 90000000000000, + amount_subtotal: 756302521008400, + amount_total: 900000000000000, + amount_tax: 143697478991600, + }, + { + quantity: 10, + unit_amount: 67226890756303, + unit_amount_decimal: '672.27', + unit_amount_net: 67226890756303, + unit_amount_gross: 80000000000000, + amount_subtotal: 672268907563030, + amount_total: 800000000000000, + amount_tax: 127731092436970, + }, + ], + unit_amount: 142857142857143, + unit_amount_net: 142857142857143, + unit_amount_gross: 170000000000000, + amount_subtotal: 5882352941176450, + amount_total: 7000000000000000, + amount_tax: 1117647058823550, + }; + + const result = applyDiscounts(initialItemValues, { + ...baseParams, + priceItem: { + ...priceItem1, + _price: { + ...priceItem1._price!, + pricing_model: PricingModel.tieredGraduated, + }, + }, + coupon: percentage10DiscountCoupon, + isTaxInclusive: false, + }); + + expect(result.discount_percentage).toBe(10); + expect(result.discount_amount).toBeGreaterThan(0); + expect(result.discount_amount).toBe(170000000000000); + expect(result.amount_total).toBeLessThan(initialItemValues.amount_total); + expect(result.amount_total).toBe(1530000000000010); + }); + + it('should apply fixed discount to graduated tiered prices correctly', () => { + const result = applyDiscounts( + { + tiers_details: [ + { + quantity: 100, + unit_amount: 5000, + unit_amount_decimal: '050', + unit_amount_net: 42016806722689, + unit_amount_gross: 50000000000000, + amount_subtotal: 4201680672268900, + amount_total: 5000000000000000, + amount_tax: 798319327731100, + }, + { + quantity: 150, + unit_amount: 4500, + unit_amount_decimal: '045', + unit_amount_net: 37815126050420, + unit_amount_gross: 45000000000000, + amount_subtotal: 5672268907563000, + amount_total: 6750000000000000, + amount_tax: 1077731092437000, + }, + ], + unit_amount_gross: 95000000000000, + unit_amount_net: 79831932773109, + amount_subtotal: 9873949579831900, + amount_total: 11750000000000000, + amount_tax: 1876050420168100, + }, + { + ...baseParams, + coupon: fixedDiscountCoupon, + priceItem: { + ...compositePriceItemWithTieredGraduatedComponent.item_components?.[0]!, + pricing_model: PricingModel.tieredGraduated, + }, + unitAmountMultiplier: 250, // Total quantity + }, + ); + + if (!result.tiers_details) { + throw new Error('Expected tiers_details to be defined'); + } + + expect(result.tiers_details).toHaveLength(2); + expect(result.discount_amount).toBe(1250000000000000); + expect(result.amount_total).toBe(10500000000000000); + }); + + it('should apply discounts with tax exclusive pricing to tiered prices correctly', () => { + const result = applyDiscounts( + { + tiers_details: [ + { + quantity: 100, + unit_amount: 42016806722689, + unit_amount_decimal: '420.17', + unit_amount_net: 42016806722689, + unit_amount_gross: 50000000000000, + amount_subtotal: 4201680672268900, + amount_total: 5000000000000000, + amount_tax: 798319327731100, + }, + { + quantity: 150, + unit_amount: 37815126050420, + unit_amount_decimal: '378.15', + unit_amount_net: 37815126050420, + unit_amount_gross: 45000000000000, + amount_subtotal: 5672268907563000, + amount_total: 6750000000000000, + amount_tax: 1077731092437000, + }, + ], + unit_amount: 79831932773109, + unit_amount_net: 79831932773109, + unit_amount_gross: 95000000000000, + amount_subtotal: 9873949579831900, + amount_total: 11750000000000000, + amount_tax: 1876050420168100, + }, + { + ...baseParams, + isTaxInclusive: false, + coupon: percentage10DiscountCoupon, + priceItem: { + ...compositePriceItemWithTieredGraduatedComponent.item_components?.[0]!, + pricing_model: PricingModel.tieredGraduated, + }, + unitAmountMultiplier: 250, // Total quantity + }, + ); + + if (!result.tiers_details) { + throw new Error('Expected tiers_details to be defined'); + } + + expect(result.tiers_details).toHaveLength(2); + expect(result.amount_subtotal).toBe(8886554621848700); + expect(result.discount_percentage).toBe(10); + }); + + it('should handle tiered discounts with fixed discount amount greater than tier unit amount', () => { + const result = applyDiscounts( + { + tiers_details: [ + { + quantity: 100, + unit_amount: 3000, // 3.00 + unit_amount_decimal: '3.00', + unit_amount_net: 2521008403361, // 2.52 + unit_amount_gross: 3000000000000, // 3.00 + amount_subtotal: 252100840336100, // 252.10 + amount_total: 300000000000000, // 300.00 + amount_tax: 47899159663900, // 47.90 + }, + ], + unit_amount_gross: 3000000000000, // 3.00 + unit_amount_net: 2521008403361, // 2.52 + amount_subtotal: 252100840336100, // 252.10 + amount_total: 300000000000000, // 300.00 + amount_tax: 47899159663900, // 47.90 + }, + { + ...baseParams, + coupon: veryHighFixedDiscountCoupon, // Discount amount of 10,000 which is > 3.00 + priceItem: { + ...compositePriceItemWithTieredGraduatedComponent.item_components?.[0]!, + pricing_model: PricingModel.tieredGraduated, + }, + unitAmountMultiplier: 100, // Total quantity + }, + ); + + if (!result.tiers_details) { + throw new Error('Expected tiers_details to be defined'); + } + + expect(result.tiers_details).toHaveLength(1); + + expect(result.amount_total).toBe(0); + expect(result.amount_subtotal).toBe(0); + expect(result.amount_tax).toBe(0); + + expect(result.discount_amount).toBeGreaterThan(0); + expect(result.discount_amount).toBe(300000000000000); + }); + + it('should handle fixed discounts with tax exclusive pricing for tiered prices correctly', () => { + const result = applyDiscounts( + { + tiers_details: [ + { + quantity: 100, + unit_amount: 42016806722689, + unit_amount_decimal: '420.17', + unit_amount_net: 42016806722689, + unit_amount_gross: 50000000000000, + amount_subtotal: 4201680672268900, + amount_total: 5000000000000000, + amount_tax: 798319327731100, + }, + { + quantity: 150, + unit_amount: 37815126050420, + unit_amount_decimal: '378.15', + unit_amount_net: 37815126050420, + unit_amount_gross: 45000000000000, + amount_subtotal: 5672268907563000, + amount_total: 6750000000000000, + amount_tax: 1077731092437000, + }, + ], + unit_amount: 79831932773109, + unit_amount_net: 79831932773109, + unit_amount_gross: 95000000000000, + amount_subtotal: 9873949579831900, + amount_total: 11750000000000000, + amount_tax: 1876050420168100, + }, + { + ...baseParams, + isTaxInclusive: false, + coupon: fixedDiscountCoupon, + priceItem: { + ...compositePriceItemWithTieredGraduatedComponent.item_components?.[0]!, + pricing_model: PricingModel.tieredGraduated, + }, + unitAmountMultiplier: 250, // Total quantity + }, + ); + + if (!result.tiers_details) { + throw new Error('Expected tiers_details to be defined'); + } + + expect(result.tiers_details).toHaveLength(2); + + expect(result.amount_subtotal).toBe(8623949579831900); + expect(result.amount_total).toBe(10262500000000000); + expect(result.discount_amount).toBe(1487500000000000); + + expect(result.unit_amount_gross).toBeGreaterThan(result.unit_amount_net!); + expect(result.unit_amount_gross).toBe(83100000000000); + expect(result.unit_amount_net).toBe(69831932773109!); + }); }); });