From 7510b22235d0fa3376a6d95e1884ae09c1df0889 Mon Sep 17 00:00:00 2001 From: Seth Brown Date: Thu, 2 Nov 2023 16:59:18 -0400 Subject: [PATCH 1/4] fix tax calculations on next object with single-use coupons --- lib/recurly/pricing/checkout/calculations.js | 38 ++++++++++++++++--- test/unit/pricing/checkout/checkout.test.js | 40 ++++++++++++++------ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/recurly/pricing/checkout/calculations.js b/lib/recurly/pricing/checkout/calculations.js index 3a3494809..9aa7401af 100644 --- a/lib/recurly/pricing/checkout/calculations.js +++ b/lib/recurly/pricing/checkout/calculations.js @@ -149,9 +149,11 @@ export default class Calculations { this.price.next.discount = discountNext; } - return promise.then(() => { - if (coupon.single_use) this.price.next.discount = 0; - }); + // return promise.then(() => { + // if (coupon.single_use) this.price.next.discount = 0; + // }); + + return promise; } /** @@ -339,18 +341,44 @@ export default class Calculations { } else if (coupon.discount.rate) { const { discountableNow, discountableNext } = this.discountableSubtotals(coupon, { setupFees: false }); discountNow = roundForDiscount(discountableNow * coupon.discount.rate); - discountNext = roundForDiscount(discountableNext * coupon.discount.rate); + // If coupon is single use, we want discountNext to be zero + if (!coupon.single_use) { + discountNext = roundForDiscount(discountableNext * coupon.discount.rate); + } } else if (coupon.discount.amount) { const { discountableNow, discountableNext } = this.discountableSubtotals(coupon); // Falls back to zero if the coupon does not support the checkout currency const discountAmount = coupon.discount.amount[this.items.currency] || 0; discountNow = Math.min(discountableNow, discountAmount); - discountNext = Math.min(discountableNext, discountAmount); + if (!coupon.single_use) { + discountNext = Math.min(discountableNext, discountAmount); + } } } return { discountNow, discountNext }; } + // discountAmounts () { + // const coupon = this.items.coupon; + // let discountNow = 0; + // let discountNext = 0; + // if (coupon) { + // if (coupon.discount.type === 'free_trial') { + // // Amounts are left zero + // } else if (coupon.discount.rate) { + // const { discountableNow, discountableNext } = this.discountableSubtotals(coupon, { setupFees: false }); + // discountNow = roundForDiscount(discountableNow * coupon.discount.rate); + // discountNext = roundForDiscount(discountableNext * coupon.discount.rate); + // } else if (coupon.discount.amount) { + // const { discountableNow, discountableNext } = this.discountableSubtotals(coupon); + // // Falls back to zero if the coupon does not support the checkout currency + // const discountAmount = coupon.discount.amount[this.items.currency] || 0; + // discountNow = Math.min(discountableNow, discountAmount); + // discountNext = Math.min(discountableNext, discountAmount); + // } + // } + // return { discountNow, discountNext }; + // } /** * Computes the discountable subtotals for a given coupon * diff --git a/test/unit/pricing/checkout/checkout.test.js b/test/unit/pricing/checkout/checkout.test.js index ed3f7cf17..25a638608 100644 --- a/test/unit/pricing/checkout/checkout.test.js +++ b/test/unit/pricing/checkout/checkout.test.js @@ -1750,20 +1750,36 @@ describe('CheckoutPricing', function () { }); describe('when a coupon is applied', () => { - beforeEach(function () { - return this.pricing.coupon('coop-pct-all'); + describe('..', () => { + + beforeEach(function () { + return this.pricing.coupon('coop-pct-all'); + }); + + it('taxes the discounted subtotal', function (done) { + this.pricing + .reprice() + .done(price => { + // 8.75% of taxable amount: 21.99 (sub) + 40 (adj) - 9 (discount) = 52.99 + assert.equal(price.now.taxes, '4.64'); + // 8.75% of taxable amount: 19.99 (sub) - 3 (discount) = 16.99 + assert.equal(price.next.taxes, '1.49'); + done(); + }); + }); }); - it('taxes the discounted subtotal', function (done) { - this.pricing - .reprice() - .done(price => { - // 8.75% of taxable amount: 21.99 (sub) + 40 (adj) - 9 (discount) = 52.99 - assert.equal(price.now.taxes, '4.64'); - // 8.75% of taxable amount: 19.99 (sub) - 3 (discount) = 16.99 - assert.equal(price.next.taxes, '1.49'); - done(); - }); + describe.only('is single-use and applies to subscriptions and adjustments with taxes', () => { + beforeEach(applyCoupon('coop-single-use')); + + it('discounts only the subscriptions now, and applies no discounts next cycle', function () { + assert.equal(this.price.now.subtotal, 41.99); // 19.99 + 2 (setup fee) + 20 (adj) + 20 (adj) - $20 discount + assert.equal(this.price.now.discount, 20); + assert.equal(this.price.next.subscriptions, 19.99); + assert.equal(this.price.next.discount, 0); + assert.equal(this.price.now.taxes, 3.67); + assert.equal(this.price.next.taxes, 1.75); + }); }); }); }); From cd5087296d0bb15ba2b84c51676f28fe7980c8f2 Mon Sep 17 00:00:00 2001 From: Seth Brown Date: Thu, 2 Nov 2023 17:05:39 -0400 Subject: [PATCH 2/4] remove old comments --- lib/recurly/pricing/checkout/calculations.js | 26 +------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/lib/recurly/pricing/checkout/calculations.js b/lib/recurly/pricing/checkout/calculations.js index 9aa7401af..61725a955 100644 --- a/lib/recurly/pricing/checkout/calculations.js +++ b/lib/recurly/pricing/checkout/calculations.js @@ -149,10 +149,6 @@ export default class Calculations { this.price.next.discount = discountNext; } - // return promise.then(() => { - // if (coupon.single_use) this.price.next.discount = 0; - // }); - return promise; } @@ -331,6 +327,7 @@ export default class Calculations { * * @return {Object} { discountNow, discountNext } */ + discountAmounts () { const coupon = this.items.coupon; let discountNow = 0; @@ -358,27 +355,6 @@ export default class Calculations { return { discountNow, discountNext }; } - // discountAmounts () { - // const coupon = this.items.coupon; - // let discountNow = 0; - // let discountNext = 0; - // if (coupon) { - // if (coupon.discount.type === 'free_trial') { - // // Amounts are left zero - // } else if (coupon.discount.rate) { - // const { discountableNow, discountableNext } = this.discountableSubtotals(coupon, { setupFees: false }); - // discountNow = roundForDiscount(discountableNow * coupon.discount.rate); - // discountNext = roundForDiscount(discountableNext * coupon.discount.rate); - // } else if (coupon.discount.amount) { - // const { discountableNow, discountableNext } = this.discountableSubtotals(coupon); - // // Falls back to zero if the coupon does not support the checkout currency - // const discountAmount = coupon.discount.amount[this.items.currency] || 0; - // discountNow = Math.min(discountableNow, discountAmount); - // discountNext = Math.min(discountableNext, discountAmount); - // } - // } - // return { discountNow, discountNext }; - // } /** * Computes the discountable subtotals for a given coupon * From d2d238e0c3b4b5b29f3a3e735b15f0358491b7de Mon Sep 17 00:00:00 2001 From: Seth Brown Date: Fri, 3 Nov 2023 09:42:47 -0400 Subject: [PATCH 3/4] remove extraneous describe block --- test/unit/pricing/checkout/checkout.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/unit/pricing/checkout/checkout.test.js b/test/unit/pricing/checkout/checkout.test.js index 25a638608..d196f53b4 100644 --- a/test/unit/pricing/checkout/checkout.test.js +++ b/test/unit/pricing/checkout/checkout.test.js @@ -1750,8 +1750,6 @@ describe('CheckoutPricing', function () { }); describe('when a coupon is applied', () => { - describe('..', () => { - beforeEach(function () { return this.pricing.coupon('coop-pct-all'); }); @@ -1766,7 +1764,6 @@ describe('CheckoutPricing', function () { assert.equal(price.next.taxes, '1.49'); done(); }); - }); }); describe.only('is single-use and applies to subscriptions and adjustments with taxes', () => { From 0669732ed74916efefd1585ccc078a15a0069330 Mon Sep 17 00:00:00 2001 From: Seth Brown Date: Fri, 3 Nov 2023 09:56:00 -0400 Subject: [PATCH 4/4] remove .only and fix indent --- test/unit/pricing/checkout/checkout.test.js | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/unit/pricing/checkout/checkout.test.js b/test/unit/pricing/checkout/checkout.test.js index d196f53b4..e975eac1d 100644 --- a/test/unit/pricing/checkout/checkout.test.js +++ b/test/unit/pricing/checkout/checkout.test.js @@ -1750,23 +1750,23 @@ describe('CheckoutPricing', function () { }); describe('when a coupon is applied', () => { - beforeEach(function () { - return this.pricing.coupon('coop-pct-all'); - }); + beforeEach(function () { + return this.pricing.coupon('coop-pct-all'); + }); - it('taxes the discounted subtotal', function (done) { - this.pricing - .reprice() - .done(price => { - // 8.75% of taxable amount: 21.99 (sub) + 40 (adj) - 9 (discount) = 52.99 - assert.equal(price.now.taxes, '4.64'); - // 8.75% of taxable amount: 19.99 (sub) - 3 (discount) = 16.99 - assert.equal(price.next.taxes, '1.49'); - done(); - }); + it('taxes the discounted subtotal', function (done) { + this.pricing + .reprice() + .done(price => { + // 8.75% of taxable amount: 21.99 (sub) + 40 (adj) - 9 (discount) = 52.99 + assert.equal(price.now.taxes, '4.64'); + // 8.75% of taxable amount: 19.99 (sub) - 3 (discount) = 16.99 + assert.equal(price.next.taxes, '1.49'); + done(); + }); }); - describe.only('is single-use and applies to subscriptions and adjustments with taxes', () => { + describe('is single-use and applies to subscriptions and adjustments with taxes', () => { beforeEach(applyCoupon('coop-single-use')); it('discounts only the subscriptions now, and applies no discounts next cycle', function () {