简体   繁体   English

带JavaScript云代码的Stripe Integration iOS eCommerce Parse

[英]Stripe Integration iOS eCommerce Parse with JavaScript Cloud Code

Please please help if you know how to integrate these programs. 如果您知道如何集成这些程序,请提供帮助。 I have spent 3 days trying to get around this problem. 我花了3天的时间来解决这个问题。 strong text 强文本

I am building an eCommerce platform into my app for accepting payment of Credit Cards and Apple Pay. 我正在将我的应用程序构建为一个电子商务平台,以接受信用卡和Apple Pay的付款。 There are two viewControllers included in this process, BagTableViewController and AddCreditCardViewController. 此过程中包含两个viewController,BagTableViewController和AddCreditCardViewController。 There is also javascript for the Parse Cloud Code. 还有用于解析云代码的javascript。 I have included all code. 我已包含所有代码。

My pods are all up-to-date and have reverted the Parse JavaScript SDK to version 1.5.0 because parse has not updated their libraries. 我的Pod都是最新的,并已将Parse JavaScript SDK还原到1.5.0版,因为parse尚未更新其库。

My current issue occurs when I attempt to Authorize a Credit Card in the AddCreditCardViewController. 当我尝试在AddCreditCardViewController中授权信用卡时,会发生我当前的问题。 After entering the test credit card information provided by Stripe, the user then presses the Authorize bar button. 输入Stripe提供的测试信用卡信息后,用户按“授权”栏按钮。

When I press "Authorize", Stripe creates the Tokens and Customers, but it does not charge the customer. 当我按“授权”时,Stripe创建令牌和客户,但不向客户收费。 Instead, I receive this error in Xcode: 相反,我在Xcode中收到此错误:

[Bolts] Warning: BFTask caught an exception in the continuation block. [螺栓]警告: BFTask在继续块中捕获到异常。 This behavior is discouraged and will be removed in a future release. 不鼓励这种行为,并将在以后的版本中将其删除。 Caught Exception: *** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1] 引发异常:***-[__ NSPlaceholderDictionary initWithObjects:forKeys:count:]:尝试从对象中插入零对象[1]

In my attempts to debug this issue, I located this line as the point where a breakpoint initiates instead of the error. 在尝试调试此问题时,我将此行定位为断点启动的位置,而不是错误。

NSDictionary *params = @{@"chargeCustomer":customerId, @"orderId":weakSelf.order.objectId};

Which makes sense because the charges are not being created on Stripe because the error happens on that line, and the very next line is the PFCloud callFuctionInBackround to charge the customer. 这是有道理的,因为未在Stripe上创建收费,因为该行发生错误,并且下一行是PFCloud callFuctionInBackround向客户收费。

I can find very little information regarding this error, but I believe I am passing the wrong information into the NSDictionary for *params. 我几乎找不到有关此错误的信息,但我相信我会将错误的信息传递给* params的NSDictionary。

Can anyone help me out here? 有人可以帮我从这里出去吗? I am totally lost 我完全迷路了

//  BagTableViewController.h
//  Created by Chris Stahl on 6/28/16.
//  Copyright © 2016 Memory Jar. All rights reserved.

#import <UIKit/UIKit.h>
@interface BagTableViewController : UITableViewController
@end   

//  BagTableViewController.m
//  Created by Chris Stahl on 6/28/16.
//  Copyright © 2016 Memory Jar. All rights reserved.

    #import "BagTableViewController.h"
    #import "OrderItemTableViewCell.h"
    #import "Constants.h"
    #import "User.h"
    #import "Order.h"
    #import "OrderItem.h"
    #import "Product.h"
    #import "UserProfileTableViewController.h"
    #import "UserPaymentMethodTableViewController.h"
    #import "PaymentMethod.h"
    #import "AddCreditCardViewController.h"
    #import "SVProgressHUD/SVProgressHUD.h"
    #import "PassKit/PassKit.h"

    @interface BagTableViewController () <PKPaymentAuthorizationViewControllerDelegate>
    @property (nonatomic, weak) IBOutlet UILabel *orderNoLabel;
    @property (nonatomic, weak) IBOutlet UILabel *orderDateLabel;
    @property (nonatomic, weak) IBOutlet UILabel *totalLabel;
    @property (nonatomic, weak) IBOutlet UILabel *totalTextLabel;

    @property (nonatomic, weak) IBOutlet UIButton *payWithCCButton;
    @property (nonatomic, weak) IBOutlet UIButton *payWithApplePayButton;
    @property (nonatomic, strong) Order *order;
    @property (nonatomic, weak) NSArray *creditCards;
    @property (nonatomic) NSDecimalNumber *amount;
    @property (nonatomic, strong) PKPaymentRequest *paymentRequest;
    @end

    @implementation BagTableViewController

    -(void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        if ([User currentUser]) {
            [self queryForUnfinishedOrder];
        }
    }

    - (void)viewDidLoad {
        [self.refreshControl addTarget:self action:@selector(queryForUnfinishedOrder) forControlEvents:UIControlEventValueChanged];
    }

    -(void)viewWillDisappear:(BOOL)animated {
        if (self.order && self.order.isDirty) {
            [self.order saveInBackground];
        }
    }

    -(IBAction)queryForUnfinishedOrder {
        self.order = nil; //to get ride of the cache
        PFQuery *orderQuery = [Order queryForCustomer:[User currentUser] orderStatus:ORDER_NOT_MADE];
        __weak typeof(self) weakSelf = self;
        [orderQuery getFirstObjectInBackgroundWithBlock:^(PFObject *order, NSError *error){
            if ([weakSelf.refreshControl isRefreshing]) {
                [weakSelf.refreshControl endRefreshing];
            }
            if (!error) {
                if (order) {
                    weakSelf.order = (Order *)order;
                    weakSelf.orderNoLabel.text = @"";
                    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
                    [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
                    weakSelf.orderDateLabel.text = [dateFormatter stringFromDate:[NSDate date]];
                    weakSelf.totalLabel.text = [self.order friendlyTotal];
                    [weakSelf updateUI];
                } else {
                    [weakSelf updateUI];
                }

            } else {
                [weakSelf updateUI];
            }
        }];
    }

    -(void)updateUI {
        BOOL shouldClear = self.order == nil;
        if (shouldClear) {
            self.orderNoLabel.text = NSLocalizedString(@"Your bag is empty.", @"");
            self.orderDateLabel.text = @"";
            self.totalLabel.text = @"";
            self.totalTextLabel.text = @"";
            self.payWithApplePayButton.hidden = YES;
            self.payWithCCButton.hidden = YES;
            self.payWithApplePayButton.enabled = NO;
            self.payWithCCButton.enabled = NO;
        } else {
            self.totalTextLabel.text = NSLocalizedString(@"Total: ", @"");
            self.payWithApplePayButton.hidden = NO;
            self.payWithCCButton.hidden = NO;
            self.payWithApplePayButton.enabled = YES;
            self.payWithCCButton.enabled = YES;
        }
        [self.tableView reloadData];
    }

    #pragma Mark --- APPLE PAY PROCESS
    -(IBAction)onApplePay:(id)sender{
        NSString *merchantId = kAppleMerchatID;
        self.paymentRequest = [Stripe paymentRequestWithMerchantIdentifier:merchantId];
        if ([Stripe canSubmitPaymentRequest:self.paymentRequest]) {
            [self.paymentRequest setRequiredShippingAddressFields:PKAddressFieldPostalAddress];
            [self.paymentRequest setRequiredBillingAddressFields:PKAddressFieldPostalAddress];
            self.paymentRequest.paymentSummaryItems = [self summaryItemsForShippingMethod:nil];
            PKPaymentAuthorizationViewController *auth = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:self.paymentRequest];
            auth.delegate = self;
            if (auth) {
                [self presentViewController:auth animated:YES completion:nil];
            } else
                [SVProgressHUD showErrorWithStatus:NSLocalizedString(@"Something Wrong", @"Something Wrong")];
        } else {
            [SVProgressHUD showErrorWithStatus:NSLocalizedString(@"Apple Pay is not enabled. Please enable your Apple Pay or Pay with Credit Card.", @"")];
        }
    }
    -(void)paymentAuthorizationViewController:(nonnull PKPaymentAuthorizationViewController *) controller didAuthorizePayment:(nonnull PKPayment *)payment completion:(nonnull void (^)(PKPaymentAuthorizationStatus))completion{
        [self handlePaymentAuthorizationWithPayment:payment completion:nil];
    }
    -(void)paymentAuthorizationViewControllerDidFinish:(nonnull PKPaymentAuthorizationViewController *)controller {
        [self dismissViewControllerAnimated:YES completion:nil];
        [self queryForUnfinishedOrder];
    }
    - (void)handlePaymentAuthorizationWithPayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {
        [[STPAPIClient sharedClient] createTokenWithPayment:payment
                                                 completion:^(STPToken *token, NSError *error) {
                                                     if (error) {
                                                         completion(PKPaymentAuthorizationStatusFailure);
                                                         return;
                                                     }
                                                     [self createBackendChargeWithToken:token completion:completion];
                                                 }];
    }
    - (void)createBackendChargeWithToken:(STPToken *)token completion:(void (^)(PKPaymentAuthorizationStatus))completion {
        [self chargeWithToken:token.tokenId];
    }
    -(void)chargeWithToken:(NSString *)tokenId {
        [self.order saveInBackgroundWithBlock:^(BOOL success, NSError *error){
            if (!error) {
                __weak typeof(self) weakSelf = self;
                NSDictionary *params = @{@"chargeToken":tokenId, @"orderId":weakSelf.order.objectId};
                [PFCloud callFunctionInBackground:@"chargeToken" withParameters:params block:^(NSString *message, NSError *error){
                    if (!error) {
                        [weakSelf queryForUnfinishedOrder];

                    }
                }];
            }
        }];

    }

    #pragma mark - Credit Card Process
    -(IBAction)onPayWithCreditCard:(id)sender{
        if ([[User currentUser] isShippingAddressCompleted]) {
            [self inputCreditCard];
        } else {
            UserProfileTableViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:@"UserProfileTableViewController"];
            [self.navigationController pushViewController:viewController animated:YES];
        }
    }

    - (void)inputCreditCard {
        AddCreditCardViewController *addCreditCardViewController = (AddCreditCardViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"AddCreditCardViewController"];
            __weak typeof(self) weakSelf = self;
            addCreditCardViewController.finishBlock = ^(NSString *customerId){
                [weakSelf charge:customerId];
            };
        [self.navigationController pushViewController:addCreditCardViewController animated:YES];
        }

    -(void)charge:(NSString *)customerId {
        [self.order saveInBackgroundWithBlock:^(BOOL success, NSError *error){
            if (!error) {
                __weak typeof(self) weakSelf = self;
                NSDictionary *params = @{@"chargeCustomer":customerId, @"orderId":weakSelf.order.objectId};
                [PFCloud callFunctionInBackground:@"chargeCustomer" withParameters:params block:^(NSString *message, NSError *error){
                    if (!error) {
                        [weakSelf queryForUnfinishedOrder];
                    }
                }];
            }
        }];
    }

    - (NSArray *)summaryItemsForShippingMethod:(PKShippingMethod *)shippingMethod {
        NSMutableArray *purchasedItems = [NSMutableArray arrayWithCapacity:[self.order.items count]];
        for (OrderItem *item in self.order.items) {
            double total = item.quantity * item.product.unitPrice;
            NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithMantissa:total exponent:-2 isNegative:NO];
            PKPaymentSummaryItem *purchasedItem = [PKPaymentSummaryItem summaryItemWithLabel:item.product.name amount:price];
            [purchasedItems addObject:purchasedItem];
        }
        return [NSArray arrayWithArray:purchasedItems];
    }


    -(IBAction)onStepper:(id)sender {
        UIStepper *stepper = (UIStepper *)sender;
        NSInteger index = stepper.tag - 100;
        NSMutableArray *orderItems = [NSMutableArray arrayWithArray:self.order.items];
        OrderItem *orderItem = orderItems[index];
        orderItem.quantity = (int)stepper.value;
        if ((int)stepper.value == 0) {
            [orderItems removeObjectAtIndex:index];
        } else {
            [orderItems replaceObjectAtIndex:index withObject:orderItem];
        }
        if ([orderItems count] == 0) {
            [self showDeleteAlert];
        } else {
            self.order.items = [orderItems copy];
            [self.tableView reloadData];
            self.totalLabel.text = [self.order friendlyTotal];
        }
    }

    #pragma mark - Table view data source
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80.0;
    }
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.order.items count];
    }

    - (OrderItemTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        OrderItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BagItemCell" forIndexPath:indexPath];
        if (self.order) [cell configureItem:self.order.items[indexPath.row] tag:indexPath.row];
        else [cell configureItem:nil tag:100+indexPath.row];
        return cell;
    }

    -(void)showDeleteAlert {
        UIAlertController* alert = [UIAlertController alertControllerWithTitle:NSLocalizedString
                                    (@"Empty Bag",@"")
                                                                       message:NSLocalizedString(@"Are you sure you want to empty your bag?",@"")
                                                                preferredStyle:UIAlertControllerStyleAlert];
        __weak typeof(self) weakSelf = self;
        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString
                                        (@"Yes",@"") style:UIAlertActionStyleDefault
                                                              handler:^(UIAlertAction * action) {
                                                                  [weakSelf.order deleteInBackgroundWithBlock:^(BOOL success, NSError *error){
                                                                      if (!error) {
                                                                          [weakSelf queryForUnfinishedOrder];
                                                                      } }];
                                                              }];
        UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString
                                       (@"cancel",@"") style:UIAlertActionStyleCancel
                                                             handler:^(UIAlertAction * action) {}];
        [alert addAction:defaultAction];
        [alert addAction:cancelAction];
        [self presentViewController:alert animated:YES completion:nil];
    }
    @end

//  AddCreditCardViewController.h
//  Created by Chris Stahl on 6/28/16.
//  Copyright © 2016 Memory Jar. All rights reserved.

#import <UIKit/UIKit.h>
@class AddCreditCardViewController;
typedef void (^AddCreditCardViewControllerDidFinish)(NSString *customerId);
@interface AddCreditCardViewController : UIViewController
@property (nonatomic, copy) AddCreditCardViewControllerDidFinish finishBlock;
@end

//  AddCreditCardViewController.m
//  Created by Chris Stahl on 6/28/16.
//  Copyright © 2016 Memory Jar. All rights reserved.

#import "AddCreditCardViewController.h"
#import "Stripe/Stripe.h"
#import "User.h"
#import "PaymentMethod.h"

@interface AddCreditCardViewController ()<STPPaymentCardTextFieldDelegate>
@property (nonatomic, weak) IBOutlet STPPaymentCardTextField *paymentView;
@property (weak, nonatomic) UIActivityIndicatorView *activityIndicator;
@end

@implementation AddCreditCardViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Authorize", @"") style:UIBarButtonItemStylePlain target:self action:@selector(onAuthorize:)];

    UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    activityIndicator.hidesWhenStopped = YES;
    self.activityIndicator = activityIndicator;
    [self.view addSubview:activityIndicator];
}
- (void)paymentView:(STPPaymentCardTextField *)paymentView withCard:(STPPaymentCardTextField *)card isValid:(BOOL)valid {
    self.navigationItem.rightBarButtonItem.enabled = valid;
}
- (void)paymentCardTextFieldDidChange:(STPPaymentCardTextField *)textField {
    self.navigationItem.rightBarButtonItem.enabled = textField.isValid;
}
- (void)onCancel:(id)sender {
    [self.navigationController popViewControllerAnimated:YES];
}


#pragma mark - Authorize the payment (get paid)

- (void)onAuthorize:(id)sender {
    if (![self.paymentView isValid]) {
        return;
    }

    STPCardParams *card = [[STPCardParams alloc] init];
        card.number = self.paymentView.cardParams.number;
        card.expMonth = self.paymentView.cardParams.expMonth;
        card.expYear = self.paymentView.cardParams.expYear;
        card.cvc = self.paymentView.cardParams.cvc;

    __weak typeof(self) weakSelf = self;

    [[STPAPIClient sharedClient] createTokenWithCard:card
                                          completion:^(STPToken *token, NSError *error) {
                                              if (error) {
                                              } else {
                                                  User *user = [User currentUser];
                                                  NSDictionary *stripeCustomerDictionary = @{@"tokenId":token.tokenId, @"customerEmail":user.email};


      [PFCloud callFunctionInBackground:@"createStripeCustomer" withParameters:stripeCustomerDictionary block:^(NSString *customerId, NSError *error) {

          if (!error) {
            PaymentMethod *creditCard = [PaymentMethod object];
              creditCard.owner  = user;
              creditCard.stripeCustomerId = customerId;
              creditCard.expirationMonth = card.expMonth;
              creditCard.expirationYear = card.expYear;
              creditCard.type = [creditCard friendlyType:(STPCardBrand)creditCard];
              creditCard.lastFourDigit = card.last4;
              creditCard.stripeCustomerId = customerId;

              [creditCard saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                  if (!error) {
                    [weakSelf readyToCharge:customerId];
                }
            }];

          } else {

          }
      }];
            }
    }];
}

-(void)readyToCharge:(NSString *)customerId {
    self.finishBlock(customerId);
    [self.navigationController popViewControllerAnimated:YES];
}
@end

 Parse.Cloud.define("sendNotification", function(request, response) { var query = new Parse.Query(Parse.Installation); var userObj = new Parse.User({ id: request.params.userId }); query.equalTo("user", userObj); Parse.Push.send({ where: query, data: { alert: request.params.message } }, { success: function() { response.success(0); }, error: function(error) { response.error('push notification error'); } }); }); var Stripe = require('stripe'); Stripe.initialize('sk_test_xxx'); var STRIPE_API_BASE_URL = 'api.stripe.com/v1'; Stripe.initialize('sk_test_xxx'); var Mailgun = require('mailgun'); Mailgun.initialize("Memory_Jar", "pubkey-xxx"); //Create a stripe customer Parse.Cloud.define("createStripeCustomer", function(request, response) { Parse.Cloud.useMasterKey(); Parse.Promise.as().then(function() { return Stripe.Customers.create({ description: 'customer for Memory Jar', card: request.params.tokenId, email: request.params.customerEmail, }).then(null, function(error) { console.log('Creating customer with stripe failed. Error: ' + error); return Parse.Promise.error('An error has occurred.'); }); }).then(function(customer) { response.success(customer.id); }, function(error) { response.error('error with customer creation'); }); }); //Charge the customer Parse.Cloud.define("chargeCustomer", function(request, response) { Parse.Cloud.useMasterKey(); var order; var orderNo; var total; Parse.Promise.as().then(function() { var orderQuery = new Parse.Query('Order'); orderQuery.equalTo('objectId', request.params.orderId); orderQuery.include("customer"); orderQuery.include(["items.product"]); orderQuery.descending("createdAt"); return orderQuery.first().then(null, function(error) { return Parse.Promise.error('Sorry, this order doesn\\'t exist.'); }); }).then(function(result) { order = result; var items = order.get("items"); for (var i = 0; i < items.length; i++) { var item = items[i]; var unitPrice = item.get("product").get("unitPrice"); var quantity = item.get("quantity"); total += unitPrice * quantity; } }).then(function(result) { var countQuery = new Parse.Query("Order"); return countQuery.count().then(null, function(error) { return Parse.Promise.error('Something wrong.'); }); }).then(function(result) { orderNo = result; }).then(function(order) { return Stripe.Charges.create({ amount: 10000, //total.toFixed(2)*100, // express dollars in cents currency: 'usd', customer: request.params.customerId }).then(null, function(error) { console.log('Charging with stripe failed. Error: ' + error); return Parse.Promise.error('An error has occurred. Your credit card was not charged.'); }); }).then(function(purchase) { orderNo = 1000000 + orderNo + 1; order.set('stripePaymentId', purchase.id); order.set('orderStatus', 1); order.set('orderNo', orderNo); return order.save().then(null, function(error) { return Parse.Promise.error('A critical error has occurred with your order. Please ' + 'contact us at your earliest convinience. '); }); }).then(function(order) { var greeting = "Dear "; // if (request.params.firstName !== "N/A") greeting += request.params.firstName + ",\\n\\n"; // var orderId = "Order No. " + orderNo + "\\n"; var body = greeting + orderId + "We have received your order for the following item(s): \\n\\n" + request.params.itemDesc + "\\n"; var note = "Note: " + request.params.note + "\\n\\n"; body += "\\Total: $" + 1000 + "\\n\\n"; //total.toFixed(2) var thankyou = "Contact us if you have any question!\\n\\n" + "\\n Thank you,\\n"; body += thankyou; return Mailgun.sendEmail({ to: request.params.email, bcc: 'CUSTOMER-EMAIL', from: 'YOUR-EMAIL', subject: '', text: body }).then(null, function(error) { return Parse.Promise.error('Your purchase was successful, but we were not able to ' + 'send you an email. Contact us at customer.service@memoryjar.com ' + 'you have any questions.'); }); }).then(function(charge) { response.success(charge.id); }, function(error) { response.error(error); }); }); //Create Stripe token for charged customer Parse.Cloud.define("chargeToken", function(request, response) { Parse.Cloud.useMasterKey(); var order; var orderNo; var total; Parse.Promise.as().then(function() { var orderQuery = new Parse.Query('Order'); orderQuery.equalTo('objectId', request.params.orderId); orderQuery.include("customer"); orderQuery.include(["items.product"]); orderQuery.descending("createdAt"); return orderQuery.first().then(null, function(error) { return Parse.Promise.error('Sorry, this order doesn\\'t exist.'); }); }).then(function(result) { order = result; var items = order.get("items"); for (var i = 0; i < items.length; i++) { var item = items[i]; var unitPrice = item.get("product").get("unitPrice"); var quantity = item.get("quantity"); total += unitPrice * quantity; } }).then(function(result) { var countQuery = new Parse.Query("Order"); return countQuery.count().then(null, function(error) { return Parse.Promise.error('Something wrong.'); }); }).then(function(result) { orderNo = result; }).then(function(order) { return Stripe.Charges.create({ amount: 10000, //amount: total.toFixed(2)*100, // express dollars in cents currency: 'usd', card: request.params.chargeToken, }).then(null, function(error) { console.log('Charging with stripe failed. Error: ' + error); return Parse.Promise.error('An error has occurred. Your credit card was not charged.'); }); }).then(function(purchase) { orderNo = 1000000 + orderNo + 1; order.set('orderStatus', 1); // order made order.set('orderNo', orderNo); order.set('stripePaymentId', purchase.id); return order.save().then(null, function(error) { return Parse.Promise.error('A critical error has occurred with your order. Please ' + 'contact us at your earliest convinience. '); }); }).then(function(result) { var greeting = "Dear "; // if (order.customer.firstName !== "N/A") greeting += // order.customer.firstName + ",\\n\\n"; var orderId = "Order No. " + orderNo + "\\n"; var body = greeting + orderId + " We have received your order for the following item(s): \\n\\n" + request.params.itemDesc + "\\n"; body += "\\Total: $" + 1000 + "\\n\\n"; var thankyou = "Contact us if you have any question!\\n\\n" + "\\n Thank you,\\n"; body += thankyou; return Mailgun.sendEmail({ to: 'chris.stahl12@gmail.com', //order.customer.email, from: 'YOUR-CONTACT-EMAIL', subject: 'Your order was successful!', text: body }).then(null, function(error) { return Parse.Promise.error('Your purchase was successful, but we were not able to ' + 'send you an email. Contact us if you have any questions.'); }); }).then(function() { response.success('Success'); }, function(error) { response.error(error); }); }); Parse.Cloud.define("StripeUserCards", function(request, response) { Parse.Cloud.httpRequest({ method: "GET", url: "https://" + 'sk_test_bSJVNSp6BUre8e6wOzxhHYgQ' + ':@' + STRIPE_API_BASE_URL + "/customers/" + request.params.customer_id + "/cards", success: function(cards) { response.success(cards["data"]); }, error: function(httpResponse) { response.error('Request failed with response code ' + httpResponse.status); } }); }); 

So, I finally figured this out. 所以,我终于想通了。 It was confusing but I was sending the wrong variables to the javascript from the AddCreditCard and Bag table view controllers. 这令人困惑,但是我从AddCreditCard和Bag表视图控制器向JavaScript发送了错误的变量。

Inside the AddCreditCardViewController, we create the stripe customer for either an Apple Pay or Credit Card Transation. 在AddCreditCardViewController内,我们为Apple Pay或信用卡交易创建条带客户。 The dictionary is: 字典是:

NSDictionary *stripeCustomerDictionary = @{@"token":token.tokenId,
                                           @"email":user.email 
};

and the corresponding javascript Parse Cloud Code is: 并且相应的javascript解析云代码为:

return Stripe.Customers.create({

                            description: 'customer for Memory Jar',
                            card: request.params.token,
                            email: request.params.email,

Then in BagTableViewController the dictionary for ChargeToken (Apple Pay) is: 然后在BagTableViewController中,ChargeToken(Apple Pay)的字典是:

NSDictionary *params = @{@"chargeToken":tokenId,
                       @"amount":[NSNumber numberWithDouble:(weakSelf.order.total*100)],
                           @"orderId":weakSelf.order.objectId 
};

and the corresponding call for ChargeToken in the javascript Parse Cloud Code is: 并且JavaScript解析云代码中对ChargeToken的相应调用是:

return Stripe.Charges.create({
                             amount: request.params.amount,  // express dollars in cents
                             currency: 'usd',
                             card: request.params.chargeToken

for ChargeCustomer (Credit Card) it is: 对于ChargeCustomer(信用卡),它是:

NSDictionary *params = @{
                       @"customerId":customerId,
                       @"amount":[NSNumber numberWithDouble:(weakSelf.order.total*100)],
                       @"orderId":weakSelf.order.objectId
};

and the corresponding call in the javascript Parse Cloud Code is: 并且javascript解析云代码中的相应调用是:

return Stripe.Charges.create({

                        customer: request.params.customerId,
                        currency: 'usd',
                        amount: request.params.amount  // express dollars in cents

The error was being produced because I did not have the dictionary's aligned. 因为我没有对齐字典,所以产生了错误。 I thought the first word in the javascript was the corresponding word in the Objective C code, but I was wrong. 我认为javascript中的第一个单词是目标C代码中的相应单词,但我错了。

The last word is what javascript looks for in the ObjC code. 最后一个词是javascript在ObjC代码中查找的内容。

Ex: card: request.params.chargeToken (called in ChargeToken) 例如: card: request.params.chargeToken (在ChargeToken中调用)

lines up with @"chargeToken":tokenId in the NSDictionary. 在NSDictionary中与@"chargeToken":tokenId Javascript is asking you to provide the dictionary definition for the chargeToken which is then passed back as the tokenId. Javascript要求您提供chargeToken的字典定义,然后将其作为tokenId传递回去。

I hope this helps someone along the way. 我希望这可以对整个过程有所帮助。 I lost about 8 days to this problem. 我为此问题损失了大约8天的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM