Wrapping Stripe在Meteor中的Fibers中创建客户回调

时间:2015-06-24 19:20:28

标签: meteor stripe-payments

我在创建新客户时无法让Stripe.js工作。这是他们的教程中的Node.js代码:

// Set your secret key: remember to change this to your live secret key in production
// See your keys here https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_9999999999999999999999");

// (Assuming you're using express - expressjs.com)
// Get the credit card details submitted by the form
var stripeToken = request.body.stripeToken;

stripe.customers.create({
  source: stripeToken,
  description: 'payinguser@example.com'
}).then(function(customer) {
  return stripe.charges.create({
    amount: 1000, // amount in cents, again
    currency: "usd",
    customer: customer.id
  });
}).then(function(charge) {
  saveStripeCustomerId(user, charge.customer);
});

这是我的尝试。我将所有回调包装在Meteor.bindEnvironment中,因为异步回调需要在光纤中运行。我在服务器控制台中收到错误:

Exception while invoking method 'submitOrder' Error: Stripe: Unknown arguments (function (/* arguments */) {  

有人能指出我正确的方向将其包裹在纤维中吗?或者使用Meteor.wrapAsync?

var createStripeCustomer = function(ShoppingCartObject){
    check(ShoppingCartObject, Object);
    var stripe = Stripe("sk_test_9999999999999999");
    // (Assuming you're using express - expressjs.com)
    // Get the credit card details submitted by the form
    var stripeToken = ShoppingCartObject.charge.token;

    stripe.customers.create(
        {
          source: stripeToken,
          description: ShoppingCartObject._id,
          email: ShoppingCartObject.customerInfo.agentEmail,
        }, 
        Meteor.bindEnvironment(function(customer){
            return stripe.charges.create({
            amount: ShoppingCartObject.totalPrice, // amount in cents, again
            currency: "usd",
            customer: customer.id
            });
        }), 
        Meteor.bindEnvironment(function(charge){
            ShoppingCartObject.charge.customer = charge.customer;
            submitOrder(ShoppingCartObject);
        })
    );
};

var submitOrder = function(ShoppingCartObject){
  check(ShoppingCartObject, Object);
  var data = _.omit(ShoppingCartObject, '_id');
  var setHash = { $set: data };
  ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
};

2 个答案:

答案 0 :(得分:2)

以下是一种适用于我的方法的简化版本。我基本上为每个返回Future的Stripe调用创建一个函数。

// Server

var Future = Npm.require('fibers/future');

function createCustomer(token){
    var future = new Future;
    Stripe.customers.create({
      card: token.id,
      email: token.email
    }, function(error, result){
      if (error){
        future.return(error);
      } else {
        future.return(result);
      }
    });
    return future.wait();
  }

Meteor.methods({
  purchase: function(token){
    check(token: Object);
    try {
      var customer = createCustomer(token);
    } catch(error) {
      // error handle
    }
    // create charge, etc. repeating same pattern
  }
});

答案 1 :(得分:0)

我决定使用Meteor.wrapAsync()解决所有问题。以下代码:

编辑

考虑到这一点后,wrapAsync()似乎有一些严重的错误处理限制,特别是对于Stripe,错误很常见,我的实现可能不太合适。

此处的相关讨论:https://github.com/meteor/meteor/issues/2774

用户faceyspacey使用此代码创建“更好”wrapAsync,更直观地处理错误,但我还没有尝试过。

Meteor.makeAsync = function(fn, context) {
  return function (/* arguments */) {
    var self = context || this;
    var newArgs = _.toArray(arguments);
    var callback;

    for (var i = newArgs.length - 1; i >= 0; --i) {
      var arg = newArgs[i];
      var type = typeof arg;
      if (type !== "undefined") {
        if (type === "function") {
          callback = arg;
        }
        break;
      }
    }

    if(!callback) {
      var fut = new Future();
            callback = function(error, data) {
               fut.return({error:  error, data: data});
            };

      ++i; 
    }

    newArgs[i] = Meteor.bindEnvironment(callback);
    var result = fn.apply(self, newArgs);
    return fut ? fut.wait() : result;
  };
};

原始代码

  1. ShoppingCartObject包含订单的详细信息以及cardToken在您将其提供给客户的信用卡详细信息时生成的Stripe.js

    < / LI>
  2. 在保存cardToken的情况下创建了一个新客户,基本上保存了他们的CC信息供以后使用。

  3. 最后,使用他们的CC为客户创建费用。

  4. 以下代码

    var createStripeCustomerAsync = function(ShoppingCartObject, callback){
    
        var stripe = Stripe("sk_test_999999999999999999");
    
        stripe.customers.create({
            // this is the token generated on the client side from the CC info
          source: ShoppingCartObject.charge.cardToken,
          email: ShoppingCartObject.customer.email
        }, function(err, customer) {
          callback(err, customer);
        });
    
    };
    
    var createStripeCustomerSync = Meteor.wrapAsync(createStripeCustomerAsync);
    
    var createStripeChargeAsync = function(customer, ShoppingCartObject, callback){
    
      var stripe = Stripe("sk_test_999999999999999999");
    
        stripe.charges.create({
          amount: ShoppingCartObject.totalPrice, // amount in cents, again
          currency: "usd",
          customer: customer.id
        }, function(error, charge){
            callback(error, charge);
        });
    
    };
    
    var createStripeChargeSync = Meteor.wrapAsync(createStripeChargeAsync);
    
    var submitOrder = function(ShoppingCartObject){
        check(ShoppingCartObject, Object);
    
        var customer = createStripeCustomerSync(ShoppingCartObject);
        console.log("customer: ", customer);
    
        var charge = createStripeChargeSync(customer, ShoppingCartObject);
        console.log("charge: ", charge);
    
      var data = _.omit(ShoppingCartObject, '_id');
      var setHash = { $set: data };
    
      ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
    };