-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathplans-stripe-server.js
198 lines (173 loc) · 6.89 KB
/
plans-stripe-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
var stripeAPI = Npm.require('stripe');
var Stripe;
AppPlans.registerService('stripe', {
/**
* {String} options.customerId: Provided if the user already has customer record in Stripe
* {String} options.plan: Plan name
* {String} options.token: Payment token from the client. Needed if there is no customerId
* {String} options.email: Email address. Needed if no customerId
* {String} options.userId: User ID. Needed if no customerId
*/
subscribe: function (options) {
var customer, subscription, subscriptionId, customerId;
if (options.customerId) {
// If Stripe already has an active subscription for this customer+plan,
// use that. We can update it with same plan name and quantity 1, and that
// will turn off any "end of cycle" cancellation that might have been
// scheduled by calling "unsubscribe".
var subscriptionList;
try {
subscriptionList = Stripe.subscriptions.listSync({
customer: options.customerId,
plan: options.plan,
});
} catch (error) {
throw new Error('AppPlans: There was a problem listing subscriptions for Stripe customer: ' + error.message);
}
subscription = subscriptionList.data && subscriptionList.data[0];
if (subscription) {
try {
Stripe.subscriptions.updateSync(subscription.id, {
plan: options.plan,
quantity: 1,
});
} catch (error) {
throw new Error('AppPlans: There was a problem updating a subscription for Stripe customer: ' + error.message);
}
} else {
// Call the Stripe API to assign this customer
// to an additional plan.
try {
subscription = Stripe.subscriptions.createSync({
customer: options.customerId,
plan: options.plan,
});
} catch (error) {
throw new Error('AppPlans: There was a problem adding a subscription for Stripe customer: ' + error.message);
}
}
if (!subscription) {
throw new Error('AppPlans: There was an unknown problem adding a subscription for Stripe customer');
}
subscriptionId = subscription.id;
customerId = options.customerId;
} else {
if (!options.token) {
throw new Error('AppPlans: A token is required when adding a subscription and an external customer has not yet been created.');
}
// Call the Stripe API to create a new customer
// in their system and assign them to the plan.
try {
customer = Stripe.customers.createSync({
email: options.email,
plan: options.plan,
source: options.token,
metadata: {
userId: options.userId
}
});
} catch (error) {
console.log(error.stack);
throw new Error('AppPlans: There was a problem creating Stripe customer: ' + error.message);
}
if (!customer) {
throw new Error('AppPlans: There was an unknown problem creating Stripe customer');
}
subscriptionId = customer.subscriptions.data[0].id;
customerId = customer.id;
}
return {
subscriptionId: subscriptionId,
customerId: customerId
};
},
unsubscribe: function (options) {
// Call the Stripe API to cancel the plan for the user
// XXX To cancel immediately and refund, could change quantity to 0
var date;
try {
var result = Stripe.subscriptions.delSync(options.subscriptionId, { at_period_end: true });
if (result.cancel_at_period_end && result.current_period_end) {
date = new Date(result.current_period_end * 1000);
}
} catch (error) {
if (
error.message.indexOf('does not have a subscription with ID') === -1 &&
error.message.indexOf('No such subscription') === -1
) {
throw new Meteor.Error('AppPlans: There was a problem canceling stripe subscription:', error.message);
}
}
// We return the date at which the cancelation will happen
return date;
},
isSubscribed: function (options) {
var result;
if (!options.subscriptionId) return false;
// Call the Stripe API to check a plan for the user
try {
result = Stripe.subscriptions.retrieveSync(options.subscriptionId);
} catch (error) {
if (
error.message.indexOf('does not have a subscription with ID') === -1 &&
error.message.indexOf('No such subscription') === -1
) {
throw new Meteor.Error('AppPlans: There was a problem retrieving stripe subscription:', error.message);
}
return false;
}
return result && _.contains(['active', 'trialing'], result.status);
},
// NOTE THIS ONE IS NOT YET USED
getExternalPlansStatus: function (options) {
var result;
// Call the Stripe API to get all plans for the user
try {
result = Stripe.customers.listSubscriptionsSync(options.customerId);
} catch (error) {
throw new Meteor.Error('AppPlans: There was a problem listing stripe subscriptions:', error.message);
}
var list = result && result.data || [];
var planHash = {};
_.each(list, function (sub) {
var planId = sub.plan.id;
// If a plan is listed multiple times, we want to record `true`
// if any of them have "active" status.
if (!_.has(planHash, planId) || planHash[planId] === false) {
planHash[planId] = (sub.status === 'active');
}
});
return planHash;
}
});
/*
* Here we will create and configure the `Stripe` object
* immediately after the Meteor server starts up
*/
// After the Meteor server starts up
Meteor.startup(function () {
// If Stripe secret key is configured in the Meteor settings JSON file
if (Meteor.settings.Stripe && Meteor.settings.Stripe.secretKey) {
// Configure the Stripe server API
// StripeAPI is an object that is defined in the mrgalaxy:stripe package.
// It simply exposes Stripe's API documented here:
// https://stripe.com/docs/checkout
// It does this by wrapping a Node.js package
Stripe = stripeAPI(Meteor.settings.Stripe.secretKey);
// Make synchronous versions of the functions we need
Stripe.customers.createSync =
Meteor.wrapAsync(Stripe.customers.create, Stripe.customers);
Stripe.subscriptions.createSync =
Meteor.wrapAsync(Stripe.subscriptions.create, Stripe.subscriptions);
Stripe.subscriptions.delSync =
Meteor.wrapAsync(Stripe.subscriptions.del, Stripe.subscriptions);
Stripe.customers.listSubscriptionsSync =
Meteor.wrapAsync(Stripe.customers.listSubscriptions, Stripe.customers);
Stripe.subscriptions.retrieveSync =
Meteor.wrapAsync(Stripe.subscriptions.retrieve, Stripe.subscriptions);
Stripe.subscriptions.listSync =
Meteor.wrapAsync(Stripe.subscriptions.list, Stripe.subscriptions);
Stripe.subscriptions.updateSync =
Meteor.wrapAsync(Stripe.subscriptions.update, Stripe.subscriptions);
} // END if
}); // END Meteor.startup