mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
v3 payments: port amazon payments
This commit is contained in:
@@ -127,12 +127,12 @@ function($rootScope, User, $http, Content) {
|
||||
var url = '/amazon/createOrderReferenceId'
|
||||
$http.post(url, {
|
||||
billingAgreementId: Payments.amazonPayments.billingAgreementId
|
||||
}).success(function(data){
|
||||
}).success(function(res){
|
||||
Payments.amazonPayments.loggedIn = true;
|
||||
Payments.amazonPayments.orderReferenceId = data.orderReferenceId;
|
||||
Payments.amazonPayments.orderReferenceId = res.data.orderReferenceId;
|
||||
Payments.amazonPayments.initWidgets();
|
||||
}).error(function(res){
|
||||
alert(res.err);
|
||||
alert(res.message);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -146,7 +146,7 @@ function($rootScope, User, $http, Content) {
|
||||
|
||||
var url = '/amazon/verifyAccessToken'
|
||||
$http.post(url, response).error(function(res){
|
||||
alert(res.err);
|
||||
alert(res.message);
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -232,7 +232,7 @@ function($rootScope, User, $http, Content) {
|
||||
Payments.amazonPayments.reset();
|
||||
window.location.reload(true);
|
||||
}).error(function(res){
|
||||
alert(res.err);
|
||||
alert(res.message);
|
||||
Payments.amazonPayments.reset();
|
||||
});
|
||||
}else if(Payments.amazonPayments.type === 'subscription'){
|
||||
@@ -246,7 +246,7 @@ function($rootScope, User, $http, Content) {
|
||||
Payments.amazonPayments.reset();
|
||||
window.location.reload(true);
|
||||
}).error(function(res){
|
||||
alert(res.err);
|
||||
alert(res.message);
|
||||
Payments.amazonPayments.reset();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@ let api = {};
|
||||
|
||||
/**
|
||||
* @apiIgnore Payments are considered part of the private API
|
||||
* @api {post} /amazon/verifyAccessToken verify access token
|
||||
* @api {post} /amazon/verifyAccessToken Amazon Payments: verify access token
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName AmazonVerifyAccessToken
|
||||
* @apiGroup Payments
|
||||
*
|
||||
* @apiParam {string} access_token the access token
|
||||
*
|
||||
* @apiSuccess {Object} data Empty object
|
||||
**/
|
||||
api.verifyAccessToken = {
|
||||
@@ -32,56 +30,53 @@ api.verifyAccessToken = {
|
||||
url: '/amazon/verifyAccessToken',
|
||||
middlewares: [authWithHeaders()],
|
||||
async handler (req, res) {
|
||||
try {
|
||||
await amzLib.getTokenInfo(req.body.access_token);
|
||||
res.respond(200, {});
|
||||
} catch (error) {
|
||||
throw new BadRequest(error.body.error_description);
|
||||
}
|
||||
let accessToken = req.body.access_token;
|
||||
|
||||
if (!accessToken) throw new BadRequest('Missing req.body.access_token');
|
||||
|
||||
await amzLib.getTokenInfo(accessToken);
|
||||
res.respond(200, {});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @apiIgnore Payments are considered part of the private API
|
||||
* @api {post} /amazon/createOrderReferenceId create order reference id
|
||||
* @api {post} /amazon/createOrderReferenceId Amazon Payments: create order reference id
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName AmazonCreateOrderReferenceId
|
||||
* @apiGroup Payments
|
||||
*
|
||||
* @apiParam {string} billingAgreementId billing agreement id
|
||||
*
|
||||
* @apiSuccess {object} data.orderReferenceId The order reference id.
|
||||
* @apiSuccess {string} data.orderReferenceId The order reference id.
|
||||
**/
|
||||
api.createOrderReferenceId = {
|
||||
method: 'POST',
|
||||
url: '/amazon/createOrderReferenceId',
|
||||
middlewares: [authWithHeaders()],
|
||||
async handler (req, res) {
|
||||
try {
|
||||
let response = await amzLib.createOrderReferenceId({
|
||||
Id: req.body.billingAgreementId,
|
||||
IdType: 'BillingAgreement',
|
||||
ConfirmNow: false,
|
||||
});
|
||||
res.respond(200, {
|
||||
orderReferenceId: response.OrderReferenceDetails.AmazonOrderReferenceId,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new BadRequest(error);
|
||||
}
|
||||
let billingAgreementId = req.body.billingAgreementId;
|
||||
|
||||
if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId');
|
||||
|
||||
let response = await amzLib.createOrderReferenceId({
|
||||
Id: billingAgreementId,
|
||||
IdType: 'BillingAgreement',
|
||||
ConfirmNow: false,
|
||||
});
|
||||
|
||||
res.respond(200, {
|
||||
orderReferenceId: response.OrderReferenceDetails.AmazonOrderReferenceId,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @apiIgnore Payments are considered part of the private API
|
||||
* @api {post} /amazon/checkout do checkout
|
||||
* @api {post} /amazon/checkout Amazon Payments: checkout
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName AmazonCheckout
|
||||
* @apiGroup Payments
|
||||
*
|
||||
* @apiParam {string} billingAgreementId billing agreement id
|
||||
*
|
||||
* @apiSuccess {object} object containing { orderReferenceId }
|
||||
* @apiSuccess {object} data Empty object
|
||||
**/
|
||||
api.checkout = {
|
||||
method: 'POST',
|
||||
@@ -93,6 +88,8 @@ api.checkout = {
|
||||
let orderReferenceId = req.body.orderReferenceId;
|
||||
let amount = 5;
|
||||
|
||||
if (!orderReferenceId) throw new BadRequest('Missing req.body.orderReferenceId');
|
||||
|
||||
if (gift) {
|
||||
if (gift.type === 'gems') {
|
||||
amount = gift.gems.amount / 4;
|
||||
@@ -101,68 +98,62 @@ api.checkout = {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await amzLib.setOrderReferenceDetails({
|
||||
AmazonOrderReferenceId: orderReferenceId,
|
||||
OrderReferenceAttributes: {
|
||||
OrderTotal: {
|
||||
CurrencyCode: 'USD',
|
||||
Amount: amount,
|
||||
},
|
||||
SellerNote: 'HabitRPG Payment',
|
||||
SellerOrderAttributes: {
|
||||
SellerOrderId: shared.uuid(),
|
||||
StoreName: 'HabitRPG',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await amzLib.confirmOrderReference({ AmazonOrderReferenceId: orderReferenceId });
|
||||
|
||||
await amzLib.authorize({
|
||||
AmazonOrderReferenceId: orderReferenceId,
|
||||
AuthorizationReferenceId: shared.uuid().substring(0, 32),
|
||||
AuthorizationAmount: {
|
||||
await amzLib.setOrderReferenceDetails({
|
||||
AmazonOrderReferenceId: orderReferenceId,
|
||||
OrderReferenceAttributes: {
|
||||
OrderTotal: {
|
||||
CurrencyCode: 'USD',
|
||||
Amount: amount,
|
||||
},
|
||||
SellerAuthorizationNote: 'HabitRPG Payment',
|
||||
TransactionTimeout: 0,
|
||||
CaptureNow: true,
|
||||
});
|
||||
SellerNote: 'HabitRPG Payment',
|
||||
SellerOrderAttributes: {
|
||||
SellerOrderId: shared.uuid(),
|
||||
StoreName: 'HabitRPG',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await amzLib.closeOrderReference({ AmazonOrderReferenceId: orderReferenceId });
|
||||
await amzLib.confirmOrderReference({ AmazonOrderReferenceId: orderReferenceId });
|
||||
|
||||
// execute payment
|
||||
let method = 'buyGems';
|
||||
let data = { user, paymentMethod: 'Amazon Payments' };
|
||||
if (gift) {
|
||||
if (gift.type === 'subscription') method = 'createSubscription';
|
||||
gift.member = await User.findById(gift ? gift.uuid : undefined);
|
||||
data.gift = gift;
|
||||
data.paymentMethod = 'Gift';
|
||||
}
|
||||
await payments[method](data);
|
||||
await amzLib.authorize({
|
||||
AmazonOrderReferenceId: orderReferenceId,
|
||||
AuthorizationReferenceId: shared.uuid().substring(0, 32),
|
||||
AuthorizationAmount: {
|
||||
CurrencyCode: 'USD',
|
||||
Amount: amount,
|
||||
},
|
||||
SellerAuthorizationNote: 'HabitRPG Payment',
|
||||
TransactionTimeout: 0,
|
||||
CaptureNow: true,
|
||||
});
|
||||
|
||||
res.respond(200);
|
||||
} catch (error) {
|
||||
throw new BadRequest(error);
|
||||
await amzLib.closeOrderReference({ AmazonOrderReferenceId: orderReferenceId });
|
||||
|
||||
// execute payment
|
||||
let method = 'buyGems';
|
||||
let data = { user, paymentMethod: 'Amazon Payments' };
|
||||
|
||||
if (gift) {
|
||||
if (gift.type === 'subscription') method = 'createSubscription';
|
||||
gift.member = await User.findById(gift ? gift.uuid : undefined);
|
||||
data.gift = gift;
|
||||
data.paymentMethod = 'Gift';
|
||||
}
|
||||
|
||||
await payments[method](data);
|
||||
|
||||
res.respond(200);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @apiIgnore Payments are considered part of the private API
|
||||
* @api {post} /amazon/subscribe Subscribe
|
||||
* @api {post} /amazon/subscribe Amazon Payments: subscribe
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName AmazonSubscribe
|
||||
* @apiGroup Payments
|
||||
*
|
||||
* @apiParam {string} billingAgreementId billing agreement id
|
||||
* @apiParam {string} subscription Subscription plan
|
||||
* @apiParam {string} coupon Coupon
|
||||
*
|
||||
* @apiSuccess {object} data.orderReferenceId The order reference id.
|
||||
* @apiSuccess {object} data Empty object
|
||||
**/
|
||||
api.subscribe = {
|
||||
method: 'POST',
|
||||
@@ -174,67 +165,62 @@ api.subscribe = {
|
||||
let coupon = req.body.coupon;
|
||||
let user = res.locals.user;
|
||||
|
||||
if (!sub) {
|
||||
throw new BadRequest(res.t('missingSubscriptionCode'));
|
||||
if (!sub) throw new BadRequest(res.t('missingSubscriptionCode'));
|
||||
if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId');
|
||||
|
||||
if (sub.discount) { // apply discount
|
||||
if (!coupon) throw new BadRequest(res.t('couponCodeRequired'));
|
||||
let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key});
|
||||
if (!result) throw new NotAuthorized(res.t('invalidCoupon'));
|
||||
}
|
||||
|
||||
try {
|
||||
if (sub.discount) { // apply discount
|
||||
if (!coupon) throw new BadRequest(res.t('couponCodeRequired'));
|
||||
let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key});
|
||||
if (!result) throw new BadRequest(res.t('invalidCoupon'));
|
||||
}
|
||||
|
||||
await amzLib.setBillingAgreementDetails({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
BillingAgreementAttributes: {
|
||||
SellerNote: 'HabitRPG Subscription',
|
||||
SellerBillingAgreementAttributes: {
|
||||
SellerBillingAgreementId: shared.uuid(),
|
||||
StoreName: 'HabitRPG',
|
||||
CustomInformation: 'HabitRPG Subscription',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await amzLib.confirmBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
});
|
||||
|
||||
await amzLib.authorizeOnBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
AuthorizationReferenceId: shared.uuid().substring(0, 32),
|
||||
AuthorizationAmount: {
|
||||
CurrencyCode: 'USD',
|
||||
Amount: sub.price,
|
||||
},
|
||||
SellerAuthorizationNote: 'HabitRPG Subscription Payment',
|
||||
TransactionTimeout: 0,
|
||||
CaptureNow: true,
|
||||
SellerNote: 'HabitRPG Subscription Payment',
|
||||
SellerOrderAttributes: {
|
||||
SellerOrderId: shared.uuid(),
|
||||
await amzLib.setBillingAgreementDetails({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
BillingAgreementAttributes: {
|
||||
SellerNote: 'HabitRPG Subscription',
|
||||
SellerBillingAgreementAttributes: {
|
||||
SellerBillingAgreementId: shared.uuid(),
|
||||
StoreName: 'HabitRPG',
|
||||
CustomInformation: 'HabitRPG Subscription',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await payments.createSubscription({
|
||||
user,
|
||||
customerId: billingAgreementId,
|
||||
paymentMethod: 'Amazon Payments',
|
||||
sub,
|
||||
});
|
||||
await amzLib.confirmBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
});
|
||||
|
||||
res.respond(200);
|
||||
} catch (error) {
|
||||
throw new BadRequest(error);
|
||||
}
|
||||
await amzLib.authorizeOnBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
AuthorizationReferenceId: shared.uuid().substring(0, 32),
|
||||
AuthorizationAmount: {
|
||||
CurrencyCode: 'USD',
|
||||
Amount: sub.price,
|
||||
},
|
||||
SellerAuthorizationNote: 'HabitRPG Subscription Payment',
|
||||
TransactionTimeout: 0,
|
||||
CaptureNow: true,
|
||||
SellerNote: 'HabitRPG Subscription Payment',
|
||||
SellerOrderAttributes: {
|
||||
SellerOrderId: shared.uuid(),
|
||||
StoreName: 'HabitRPG',
|
||||
},
|
||||
});
|
||||
|
||||
await payments.createSubscription({
|
||||
user,
|
||||
customerId: billingAgreementId,
|
||||
paymentMethod: 'Amazon Payments',
|
||||
sub,
|
||||
});
|
||||
|
||||
res.respond(200);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @apiIgnore Payments are considered part of the private API
|
||||
* @api {get} /amazon/subscribe/cancel SubscribeCancel
|
||||
* @api {get} /amazon/subscribe/cancel Amazon Payments: subscribe cancel
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName AmazonSubscribe
|
||||
* @apiGroup Payments
|
||||
@@ -249,21 +235,20 @@ api.subscribeCancel = {
|
||||
|
||||
if (!billingAgreementId) throw new NotAuthorized(res.t('missingSubscription'));
|
||||
|
||||
try {
|
||||
await amzLib.closeBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
});
|
||||
await amzLib.closeBillingAgreement({
|
||||
AmazonBillingAgreementId: billingAgreementId,
|
||||
});
|
||||
|
||||
let data = {
|
||||
user,
|
||||
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: 30 }),
|
||||
paymentMethod: 'Amazon Payments',
|
||||
};
|
||||
await payments.cancelSubscription(data);
|
||||
await payments.cancelSubscription({
|
||||
user,
|
||||
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: 30 }),
|
||||
paymentMethod: 'Amazon Payments',
|
||||
});
|
||||
|
||||
if (req.query.noRedirect) {
|
||||
res.respond(200);
|
||||
} else {
|
||||
res.redirect('/');
|
||||
} catch (error) {
|
||||
throw new BadRequest(error.message);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -45,6 +45,8 @@ api.checkout = {
|
||||
let coupon;
|
||||
let response;
|
||||
|
||||
if (!token) throw new BadRequest('Missing req.body.id');
|
||||
|
||||
if (sub) {
|
||||
if (sub.discount) {
|
||||
if (!req.query.coupon) throw new BadRequest(res.t('couponCodeRequired'));
|
||||
@@ -127,10 +129,12 @@ api.subscribeEdit = {
|
||||
let customerId = user.purchased.plan.customerId;
|
||||
|
||||
if (!customerId) throw new NotAuthorized(res.t('missingSubscription'));
|
||||
if (!token) throw new BadRequest('Missing req.body.id');
|
||||
|
||||
let subscriptions = await stripe.customers.listSubscriptions(customerId);
|
||||
let subscriptionId = subscriptions.data[0].id;
|
||||
await stripe.customers.updateSubscription(customerId, subscriptionId, { card: token });
|
||||
|
||||
res.respond(200, {});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
BadRequest,
|
||||
} from './errors';
|
||||
|
||||
const t = common.i18n.t;
|
||||
// TODO better handling of errors
|
||||
|
||||
const i18n = common.i18n;
|
||||
const IS_PROD = nconf.get('NODE_ENV') === 'production';
|
||||
|
||||
let amzPayment = amazonPayments.connect({
|
||||
@@ -30,7 +32,7 @@ let authorizeOnBillingAgreement = (inputSet) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
amzPayment.offAmazonPayments.authorizeOnBillingAgreement(inputSet, (err, response) => {
|
||||
if (err) return reject(err);
|
||||
if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(t('paymentNotSuccessful')));
|
||||
if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(i18n.t('paymentNotSuccessful')));
|
||||
return resolve(response);
|
||||
});
|
||||
});
|
||||
@@ -40,7 +42,7 @@ let authorize = (inputSet) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
amzPayment.offAmazonPayments.authorize(inputSet, (err, response) => {
|
||||
if (err) return reject(err);
|
||||
if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(t('paymentNotSuccessful')));
|
||||
if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(i18n.t('paymentNotSuccessful')));
|
||||
return resolve(response);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user