feat(gifts): allow gifting gems from paypal/stripe
This commit is contained in:
@@ -29,15 +29,16 @@ api.getMember = function(req, res, next) {
|
||||
})
|
||||
}
|
||||
|
||||
var sendMessage = function(user, member, msg){
|
||||
var message = groups.chatDefaults(msg, user);
|
||||
shared.refPush(member.inbox.messages, message);
|
||||
api.sendMessage = function(user, member, data){
|
||||
var msg = data.amount
|
||||
? "`Hello " + member.profile.name + ", " + user.profile.name + " has sent you " + data.amount + " gems!` " + data.message
|
||||
: data.message;
|
||||
shared.refPush(member.inbox.messages, groups.chatDefaults(msg, user));
|
||||
member.inbox.newMessages++;
|
||||
member._v++;
|
||||
member.markModified('inbox.messages');
|
||||
|
||||
var message = groups.chatDefaults(msg, member);
|
||||
shared.refPush(user.inbox.messages, _.defaults({sent:true},message));
|
||||
shared.refPush(user.inbox.messages, _.defaults({sent:true}, groups.chatDefaults(msg, member)));
|
||||
user.markModified('inbox.messages');
|
||||
}
|
||||
|
||||
@@ -50,7 +51,7 @@ api.sendPrivateMessage = function(req, res, next){
|
||||
|| member.inbox.optOut) { // or if they've opted out of messaging
|
||||
return cb({code: 401, err: "Can't send message to this user."});
|
||||
}
|
||||
sendMessage(res.locals.user, member, req.body.message);
|
||||
api.sendMessage(res.locals.user, member, {message:req.body.message});
|
||||
async.parallel([
|
||||
function (cb2) { member.save(cb2) },
|
||||
function (cb2) { res.locals.user.save(cb2) }
|
||||
@@ -75,12 +76,10 @@ api.sendGift = function(req, res, next){
|
||||
return cb({code: 401, err: "Amount must be within 0 and your current number of gems."});
|
||||
member.balance += amt;
|
||||
user.balance -= amt;
|
||||
var msg = "`Hello "+member.profile.name+", "+user.profile.name+" has sent you "+amt+" gems!` ";
|
||||
if (req.body.message) msg += req.body.message;
|
||||
sendMessage(user, member, msg);
|
||||
api.sendMessage(user, member, {amount:req.body.gems.amount, message:req.body.message});
|
||||
return async.parallel([
|
||||
function (cb2) { member.save(cb2) },
|
||||
function (cb2) { res.locals.user.save(cb2) }
|
||||
function (cb2) { user.save(cb2) }
|
||||
], cb);
|
||||
case "subscription":
|
||||
return cb();
|
||||
|
||||
@@ -7,6 +7,9 @@ var moment = require('moment');
|
||||
var isProduction = nconf.get("NODE_ENV") === "production";
|
||||
var stripe = require('./stripe');
|
||||
var paypal = require('./paypal');
|
||||
var User = require('mongoose').model('User');
|
||||
var members = require('../members')
|
||||
var async = require('async');
|
||||
|
||||
function revealMysteryItems(user) {
|
||||
_.each(shared.content.gear.flat, function(item) {
|
||||
@@ -61,12 +64,21 @@ exports.cancelSubscription = function(user, data) {
|
||||
utils.ga.event('unsubscribe', 'Stripe').send();
|
||||
}
|
||||
|
||||
exports.buyGems = function(user, data) {
|
||||
user.balance += 5;
|
||||
user.purchased.txnCount++;
|
||||
if(isProduction) utils.txnEmail(user, 'donation');
|
||||
utils.ga.event('checkout', data.paymentMethod).send();
|
||||
utils.ga.transaction(data.customerId, 5).item(5, 1, data.paymentMethod.toLowerCase() + "-checkout", "Gems > " + data.paymentMethod).send();
|
||||
exports.buyGems = function(data, cb) {
|
||||
var amt = data.gift ? data.gift.amount/4 : 5;
|
||||
(data.gift ? data.gift.member : data.user).balance += amt;
|
||||
data.user.purchased.txnCount++;
|
||||
if(isProduction) {
|
||||
utils.txnEmail(data.user, 'donation');
|
||||
utils.ga.event('checkout', data.paymentMethod).send();
|
||||
//TODO ga.transaction to reflect whether this is gift or self-purchase
|
||||
utils.ga.transaction(data.customerId, amt).item(amt, 1, data.paymentMethod.toLowerCase() + "-checkout", "Gems > " + data.paymentMethod).send();
|
||||
}
|
||||
if (data.gift) members.sendMessage(data.user, data.gift.member, data.gift);
|
||||
async.parallel([
|
||||
function(cb2){data.user.save(cb2)},
|
||||
function(cb2){data.gift ? data.gift.member.save(cb2) : cb2(null);}
|
||||
], cb);
|
||||
}
|
||||
|
||||
exports.stripeCheckout = stripe.checkout;
|
||||
|
||||
@@ -3,7 +3,7 @@ var moment = require('moment');
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
var url = require('url');
|
||||
var mongoose = require('mongoose');
|
||||
var User = require('mongoose').model('User');
|
||||
var payments = require('./index');
|
||||
var logger = require('../../logging');
|
||||
var ipn = require('paypal-ipn');
|
||||
@@ -51,7 +51,7 @@ exports.executeBillingAgreement = function(req,res,next){
|
||||
paypal.billingAgreement.execute(req.query.token, {}, cb);
|
||||
},
|
||||
function(billingAgreement, cb){
|
||||
mongoose.model('User').findById(req.session.userId, function(err, user){
|
||||
User.findById(req.session.userId, function(err, user){
|
||||
if (err) return cb(err);
|
||||
cb(null, {billingAgreement:billingAgreement, user:user});
|
||||
});
|
||||
@@ -67,6 +67,9 @@ exports.executeBillingAgreement = function(req,res,next){
|
||||
}
|
||||
|
||||
exports.createPayment = function(req, res, next) {
|
||||
// if we're gifting to a user, put it in session for the `execute()`
|
||||
req.session.gift = req.query.gift ? JSON.parse(req.query.gift) : undefined;
|
||||
var price = req.session.gift ? Number(req.session.gift.amount/4).toFixed(2) : 5.00;
|
||||
var create_payment = {
|
||||
"intent": "sale",
|
||||
"payer": {
|
||||
@@ -81,14 +84,14 @@ exports.createPayment = function(req, res, next) {
|
||||
"items": [{
|
||||
"name": "HabitRPG Gems",
|
||||
//"sku": "1",
|
||||
"price": "5.00",
|
||||
"price": price,
|
||||
"currency": "USD",
|
||||
"quantity": 1
|
||||
}]
|
||||
},
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"total": "5.00"
|
||||
"total": price
|
||||
},
|
||||
"description": "HabitRPG Gems"
|
||||
}]
|
||||
@@ -102,20 +105,25 @@ exports.createPayment = function(req, res, next) {
|
||||
|
||||
exports.executePayment = function(req, res, next) {
|
||||
var paymentId = req.query.paymentId,
|
||||
PayerID = req.query.PayerID;
|
||||
PayerID = req.query.PayerID,
|
||||
gift = req.session.gift;
|
||||
async.waterfall([
|
||||
function(cb){
|
||||
paypal.payment.execute(paymentId, {payer_id: PayerID}, cb);
|
||||
},
|
||||
function(payment, cb){
|
||||
mongoose.model('User').findById(req.session.userId, cb);
|
||||
async.parallel([
|
||||
function(cb2){ User.findById(req.session.userId, cb2); },
|
||||
function(cb2){ User.findById(gift ? gift.uuid : undefined, cb2); }
|
||||
], cb);
|
||||
},
|
||||
function(user, cb){
|
||||
if (_.isEmpty(user)) return cb("user not found when completing paypal transaction");
|
||||
payments.buyGems(user, {customerId:PayerID, paymentMethod:'Paypal'});
|
||||
user.save(cb);
|
||||
function(results, cb){
|
||||
if (_.isEmpty(results[0]))
|
||||
return cb("user not found when completing paypal transaction");
|
||||
if (gift) gift.member = results[1];
|
||||
payments.buyGems({user:results[0], customerId:PayerID, paymentMethod:'Paypal', gift:gift}, cb);
|
||||
}
|
||||
],function(err, saved){
|
||||
],function(err, results){
|
||||
if (err) return next(parseErr(err));
|
||||
res.redirect('/');
|
||||
})
|
||||
@@ -153,7 +161,7 @@ exports.ipn = function(req, res, next) {
|
||||
// TODO what's the diff b/w the two data.txn_types below? The docs recommend subscr_cancel, but I'm getting the other one instead...
|
||||
case 'recurring_payment_profile_cancel':
|
||||
case 'subscr_cancel':
|
||||
mongoose.model('User').findOne({'purchased.plan.customerId':req.body.recurring_payment_id},function(err, user){
|
||||
User.findOne({'purchased.plan.customerId':req.body.recurring_payment_id},function(err, user){
|
||||
if (err) return logger.error(err);
|
||||
if (_.isEmpty(user)) return; // looks like the cancellation was already handled properly above (see api.paypalSubscribeCancel)
|
||||
payments.cancelSubscription(user);
|
||||
|
||||
@@ -2,6 +2,7 @@ var nconf = require('nconf');
|
||||
var stripe = require("stripe")(nconf.get('STRIPE_API_KEY'));
|
||||
var async = require('async');
|
||||
var payments = require('./index');
|
||||
var User = require('mongoose').model('User');
|
||||
|
||||
/*
|
||||
Setup Stripe response when posting payment
|
||||
@@ -9,19 +10,20 @@ var payments = require('./index');
|
||||
exports.checkout = function(req, res, next) {
|
||||
var token = req.body.id;
|
||||
var user = res.locals.user;
|
||||
var gift = req.query.gift ? JSON.parse(req.query.gift) : undefined;
|
||||
|
||||
async.waterfall([
|
||||
function(cb){
|
||||
if (req.query.plan) {
|
||||
stripe.customers.create({
|
||||
email: req.body.email,
|
||||
metadata: {uuid: res.locals.user._id},
|
||||
metadata: {uuid: user._id},
|
||||
card: token,
|
||||
plan: req.query.plan
|
||||
}, cb);
|
||||
} else {
|
||||
stripe.charges.create({
|
||||
amount: "500", // $5
|
||||
amount: gift ? ""+gift.amount/4*100 : "500", //"500" = $5
|
||||
currency: "usd",
|
||||
card: token
|
||||
}, cb);
|
||||
@@ -30,10 +32,16 @@ exports.checkout = function(req, res, next) {
|
||||
function(response, cb) {
|
||||
if (req.query.plan) {
|
||||
payments.createSubscription(user, {customerId: response.id, paymentMethod: 'Stripe'});
|
||||
user.save(cb);
|
||||
} else {
|
||||
payments.buyGems(user, {customerId: response.id, paymentMethod: 'Stripe'});
|
||||
async.waterfall([
|
||||
function(cb2){ User.findById(gift ? gift.uuid : undefined, cb2) },
|
||||
function(member, cb2){
|
||||
if (gift) gift.member = member;
|
||||
payments.buyGems({user:user, customerId:response.id, paymentMethod:'Stripe', gift:gift},cb2);
|
||||
}
|
||||
], cb);
|
||||
}
|
||||
user.save(cb);
|
||||
}
|
||||
], function(err, saved){
|
||||
if (err) return res.send(500, err.toString()); // don't json this, let toString() handle errors
|
||||
|
||||
Reference in New Issue
Block a user