mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
199 lines
5.5 KiB
JavaScript
199 lines
5.5 KiB
JavaScript
import nconf from 'nconf';
|
|
|
|
import { getStripeApi } from './api';
|
|
import {
|
|
NotAuthorized,
|
|
NotFound,
|
|
} from '../../errors';
|
|
import { // eslint-disable-line import/no-cycle
|
|
model as Group,
|
|
basicFields as basicGroupFields,
|
|
} from '../../../models/group';
|
|
import shared from '../../../../common';
|
|
import { getOneTimePaymentInfo } from './oneTimePayments'; // eslint-disable-line import/no-cycle
|
|
import { checkSubData } from './subscriptions'; // eslint-disable-line import/no-cycle
|
|
import { validateGiftMessage } from '../gems'; // eslint-disable-line import/no-cycle
|
|
|
|
const BASE_URL = nconf.get('BASE_URL');
|
|
|
|
export async function createCheckoutSession (options, stripeInc) {
|
|
const {
|
|
user,
|
|
gift,
|
|
gemsBlock: gemsBlockKey,
|
|
sub,
|
|
groupId,
|
|
coupon,
|
|
sku,
|
|
} = options;
|
|
|
|
// @TODO: We need to mock this, but curently we don't have correct
|
|
// Dependency Injection. And the Stripe Api doesn't seem to be a singleton?
|
|
let stripeApi = getStripeApi();
|
|
if (stripeInc) stripeApi = stripeInc;
|
|
|
|
let type = 'gems';
|
|
if (gift) {
|
|
type = gift.type === 'gems' ? 'gift-gems' : 'gift-sub';
|
|
validateGiftMessage(gift, user);
|
|
} else if (sub) {
|
|
type = 'subscription';
|
|
} else if (sku) {
|
|
type = 'sku';
|
|
}
|
|
|
|
const metadata = {
|
|
type,
|
|
userId: user._id,
|
|
gift: gift ? JSON.stringify(gift) : undefined,
|
|
sub: sub ? JSON.stringify(sub) : undefined,
|
|
server_url: BASE_URL,
|
|
};
|
|
|
|
let lineItems;
|
|
|
|
if (type === 'subscription') {
|
|
let quantity = 1;
|
|
|
|
if (groupId) {
|
|
quantity = sub.quantity;
|
|
const groupFields = basicGroupFields.concat(' purchased');
|
|
const group = await Group.getGroup({
|
|
user, groupId, populateLeader: false, groupFields,
|
|
});
|
|
if (!group) {
|
|
throw new NotFound(shared.i18n.t('groupNotFound', user.preferences.language));
|
|
}
|
|
const membersCount = await group.getMemberCount();
|
|
quantity = membersCount + sub.quantity - 1;
|
|
metadata.groupId = groupId;
|
|
}
|
|
|
|
await checkSubData(sub, Boolean(groupId), coupon);
|
|
|
|
lineItems = [{
|
|
price: sub.key,
|
|
quantity,
|
|
}];
|
|
} else if (type === 'sku') {
|
|
metadata.sku = sku;
|
|
lineItems = [{
|
|
price: sku,
|
|
quantity: 1,
|
|
}];
|
|
} else {
|
|
const {
|
|
amount,
|
|
gemsBlock,
|
|
subscription,
|
|
} = await getOneTimePaymentInfo(gemsBlockKey, gift, user);
|
|
|
|
metadata.gemsBlock = gemsBlock ? gemsBlock.key : undefined;
|
|
|
|
let productName;
|
|
|
|
if (gift) {
|
|
if (gift.type === 'subscription') {
|
|
productName = shared.i18n.t('nMonthsSubscriptionGift', { nMonths: subscription.months }, user.preferences.language);
|
|
} else {
|
|
productName = shared.i18n.t('nGemsGift', { nGems: gift.gems.amount }, user.preferences.language);
|
|
}
|
|
} else {
|
|
productName = shared.i18n.t('nGems', { nGems: gemsBlock.gems }, user.preferences.language);
|
|
}
|
|
|
|
lineItems = [{
|
|
price_data: {
|
|
product_data: {
|
|
name: productName,
|
|
},
|
|
unit_amount: amount,
|
|
currency: 'usd',
|
|
},
|
|
quantity: 1,
|
|
}];
|
|
}
|
|
|
|
const session = await stripeApi.checkout.sessions.create({
|
|
payment_method_types: ['card'],
|
|
metadata,
|
|
line_items: lineItems,
|
|
mode: type === 'subscription' ? 'subscription' : 'payment',
|
|
success_url: `${BASE_URL}/redirect/stripe-success-checkout`,
|
|
cancel_url: `${BASE_URL}/redirect/stripe-error-checkout`,
|
|
});
|
|
|
|
return session;
|
|
}
|
|
|
|
export async function createEditCardCheckoutSession (options, stripeInc) {
|
|
const {
|
|
user,
|
|
groupId,
|
|
} = options;
|
|
|
|
// @TODO: We need to mock this, but curently we don't have correct
|
|
// Dependency Injection. And the Stripe Api doesn't seem to be a singleton?
|
|
let stripeApi = getStripeApi();
|
|
if (stripeInc) stripeApi = stripeInc;
|
|
|
|
const type = groupId ? 'edit-card-group' : 'edit-card-user';
|
|
|
|
const metadata = {
|
|
type,
|
|
userId: user._id,
|
|
server_url: BASE_URL,
|
|
};
|
|
|
|
let customerId;
|
|
let subscriptionId;
|
|
|
|
if (type === 'edit-card-group') {
|
|
const groupFields = basicGroupFields.concat(' purchased');
|
|
const group = await Group.getGroup({
|
|
user, groupId, populateLeader: false, groupFields,
|
|
});
|
|
if (!group) {
|
|
throw new NotFound(shared.i18n.t('groupNotFound', user.preferences.language));
|
|
}
|
|
|
|
const allowedManagers = [group.leader, group.purchased.plan.owner];
|
|
|
|
if (allowedManagers.indexOf(user._id) === -1) {
|
|
throw new NotAuthorized(shared.i18n.t('onlyGroupLeaderCanManageSubscription', user.preferences.language));
|
|
}
|
|
metadata.groupId = groupId;
|
|
customerId = group.purchased.plan.customerId;
|
|
subscriptionId = group.purchased.plan.subscriptionId;
|
|
} else {
|
|
customerId = user.purchased.plan.customerId;
|
|
subscriptionId = user.purchased.plan.subscriptionId;
|
|
}
|
|
|
|
if (!customerId) throw new NotAuthorized(shared.i18n.t('missingSubscription', user.preferences.language));
|
|
|
|
if (!subscriptionId) {
|
|
const subscriptions = await stripeApi.subscriptions.list({ customer: customerId });
|
|
subscriptionId = subscriptions.data[0] && subscriptions.data[0].id;
|
|
}
|
|
|
|
if (!subscriptionId) throw new NotAuthorized(shared.i18n.t('missingSubscription', user.preferences.language));
|
|
|
|
const session = await stripeApi.checkout.sessions.create({
|
|
mode: 'setup',
|
|
payment_method_types: ['card'],
|
|
metadata,
|
|
customer: customerId,
|
|
setup_intent_data: {
|
|
metadata: {
|
|
customer_id: customerId,
|
|
subscription_id: subscriptionId,
|
|
},
|
|
},
|
|
success_url: `${BASE_URL}/redirect/stripe-success-checkout`,
|
|
cancel_url: `${BASE_URL}/redirect/stripe-error-checkout`,
|
|
});
|
|
|
|
return session;
|
|
}
|