Skip to content

Commit

Permalink
Fixes coupon resolving when switching subscription plans
Browse files Browse the repository at this point in the history
- When switching plans on a SubscriptionCheckout instance,
  the constituent discounts must be checked for compatibility and
  removed accordingly
- Fixes #488
  • Loading branch information
chrissrogers committed Oct 31, 2018
1 parent 3d45b06 commit e9597fa
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: node_js
sudo: false
node_js:
- 'node'
- 10
before_install:
- bash .travis-install-phantom.sh
cache:
Expand Down
2 changes: 1 addition & 1 deletion lib/recurly/pricing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class Pricing extends Emitter {
*/
remove (opts, done) {
let item;
this.debug('remove');
this.debug('remove', opts);

return new PricingPromise((resolve, reject) => {
let prop = Object.keys(opts)[0];
Expand Down
31 changes: 24 additions & 7 deletions lib/recurly/pricing/subscription/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,22 @@ export default class SubscriptionPricing extends Pricing {
* @public
*/
coupon (newCoupon, done) {
// If the new coupon matches the current one, we just need to ensure it
// still applies to the current plan
if (~this.couponCodes.indexOf(newCoupon)) {
return new PricingPromise(resolve => resolve(clone(this.items.coupon)), this);
return new PricingPromise((resolve, reject) => {
if (!this.couponIsValidForSubscription(this.items.coupon)) {
this.removeCurrentCoupon();
return this.error('invalid-coupon-for-subscription', reject, 'coupon');
}
resolve(clone(this.items.coupon));
}, this);
}

return new PricingPromise((resolve, reject) => {
if (!this.items.plan) return this.error(errors('missing-plan'), reject, 'coupon');

if (this.items.coupon) {
const priorCoupon = clone(this.items.coupon);
debug('unset.coupon');
this.remove({ coupon: priorCoupon.code })
.then(() => this.emit('unset.coupon', priorCoupon));
}
if (this.items.coupon) this.removeCurrentCoupon();

// A blank coupon is handled as ok
if (!newCoupon) return resolve();
Expand Down Expand Up @@ -328,6 +331,20 @@ export default class SubscriptionPricing extends Pricing {
return false;
}

/**
* Removes the current coupon
*
* emits `unset.coupon`
*
* @private
*/
removeCurrentCoupon () {
if (!this.items.coupon) return;
const currentCoupon = clone(this.items.coupon);
debug('unset.coupon');
this.remove({ coupon: currentCoupon.code }).then(() => this.emit('unset.coupon', currentCoupon));
}

/**
* Parses plan method options
*
Expand Down
28 changes: 28 additions & 0 deletions test/pricing/subscription/subscription.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,5 +518,33 @@ describe('Recurly.Pricing.Subscription', function () {
})
.done();
});

describe('when the plan is changed', () => {
it('removes coupons which are incompatible with the new plan', function (done) {
this.pricing
.plan('basic', { quantity: 1 })
.coupon('coop-pct-plan-basic')
.then(coupon => {
assert.equal(coupon.code, 'coop-pct-plan-basic');
assert.equal(this.pricing.items.coupon.code, 'coop-pct-plan-basic');
})
.reprice()
.then(price => {
assert.equal(price.now.discount, '3.00');
assert.equal(price.next.discount, '3.00');
assert.equal(price.now.total, '18.99');
assert.equal(price.next.total, '16.99');
})
.plan('basic-2', { quantity: 1 })
.done(price => {
assert.equal(this.pricing.items.coupon, undefined);
assert.equal(price.now.discount, '0.00');
assert.equal(price.next.discount, '0.00');
assert.equal(price.now.total, '95.09');
assert.equal(price.next.total, '90.09');
done();
});
});
});
});
});

0 comments on commit e9597fa

Please sign in to comment.