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

Fixes coupon resolving when switching subscription plans #489

Merged
merged 1 commit into from
Oct 31, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
Fixes coupon resolving when switching subscription plans
- 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
commit e9597fa940f876b04bea50153ff1e07a83e38886
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
Copy link
Member Author

@chrissrogers chrissrogers Oct 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to pin this at node v10 to alleviate issues in CI -- cause as yet is undetermined. Only PhantomJS runs were affected by the bump to node v11, perhaps due to the wide impact of its upgrade of v8 internals.

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();
});
});
});
});
});