diff --git a/include/config/config.xml b/include/config/config.xml
index e193e6f6d..c06053dd2 100755
--- a/include/config/config.xml
+++ b/include/config/config.xml
@@ -138,12 +138,12 @@
- ***REMOVED***
- ***REMOVED***
+ _KEY_
+ _KEY_
- ***REMOVED***
- ***REMOVED***
+ _KEY_
+ _KEY_
diff --git a/include/crunchbutton.php b/include/crunchbutton.php
index eb16fe455..e21389316 100755
--- a/include/crunchbutton.php
+++ b/include/crunchbutton.php
@@ -100,6 +100,7 @@ spl_autoload_register(function ($className) {
\Buzz\Bootstrap::init();
\Github\Bootstrap::init();
\Mailgun\Bootstrap::init();
+\Stripe\Bootstrap::init();
$configFile = $GLOBALS['config']['dirs']['config'].'config.demo.xml';
if (file_exists($GLOBALS['config']['dirs']['config'].'config.xml')) {
diff --git a/include/library/Cana/Stripe.php b/include/library/Cana/_Stripe.php
similarity index 100%
rename from include/library/Cana/Stripe.php
rename to include/library/Cana/_Stripe.php
diff --git a/include/library/Cana/Stripe/Account.php b/include/library/Cana/_Stripe/Account.php
similarity index 100%
rename from include/library/Cana/Stripe/Account.php
rename to include/library/Cana/_Stripe/Account.php
diff --git a/include/library/Cana/Stripe/ApiConnectionError.php b/include/library/Cana/_Stripe/ApiConnectionError.php
similarity index 100%
rename from include/library/Cana/Stripe/ApiConnectionError.php
rename to include/library/Cana/_Stripe/ApiConnectionError.php
diff --git a/include/library/Cana/Stripe/ApiError.php b/include/library/Cana/_Stripe/ApiError.php
similarity index 100%
rename from include/library/Cana/Stripe/ApiError.php
rename to include/library/Cana/_Stripe/ApiError.php
diff --git a/include/library/Cana/Stripe/ApiRequestor.php b/include/library/Cana/_Stripe/ApiRequestor.php
similarity index 100%
rename from include/library/Cana/Stripe/ApiRequestor.php
rename to include/library/Cana/_Stripe/ApiRequestor.php
diff --git a/include/library/Cana/Stripe/ApiResource.php b/include/library/Cana/_Stripe/ApiResource.php
similarity index 100%
rename from include/library/Cana/Stripe/ApiResource.php
rename to include/library/Cana/_Stripe/ApiResource.php
diff --git a/include/library/Cana/Stripe/ApplicationFee.php b/include/library/Cana/_Stripe/ApplicationFee.php
similarity index 100%
rename from include/library/Cana/Stripe/ApplicationFee.php
rename to include/library/Cana/_Stripe/ApplicationFee.php
diff --git a/include/library/Cana/Stripe/AttachedObject.php b/include/library/Cana/_Stripe/AttachedObject.php
similarity index 100%
rename from include/library/Cana/Stripe/AttachedObject.php
rename to include/library/Cana/_Stripe/AttachedObject.php
diff --git a/include/library/Cana/Stripe/AuthenticationError.php b/include/library/Cana/_Stripe/AuthenticationError.php
similarity index 100%
rename from include/library/Cana/Stripe/AuthenticationError.php
rename to include/library/Cana/_Stripe/AuthenticationError.php
diff --git a/include/library/Cana/Stripe/Balance.php b/include/library/Cana/_Stripe/Balance.php
similarity index 100%
rename from include/library/Cana/Stripe/Balance.php
rename to include/library/Cana/_Stripe/Balance.php
diff --git a/include/library/Cana/Stripe/BalanceTransaction.php b/include/library/Cana/_Stripe/BalanceTransaction.php
similarity index 100%
rename from include/library/Cana/Stripe/BalanceTransaction.php
rename to include/library/Cana/_Stripe/BalanceTransaction.php
diff --git a/include/library/Cana/Stripe/Card.php b/include/library/Cana/_Stripe/Card.php
similarity index 100%
rename from include/library/Cana/Stripe/Card.php
rename to include/library/Cana/_Stripe/Card.php
diff --git a/include/library/Cana/Stripe/CardError.php b/include/library/Cana/_Stripe/CardError.php
similarity index 100%
rename from include/library/Cana/Stripe/CardError.php
rename to include/library/Cana/_Stripe/CardError.php
diff --git a/include/library/Cana/Stripe/Charge.php b/include/library/Cana/_Stripe/Charge.php
similarity index 100%
rename from include/library/Cana/Stripe/Charge.php
rename to include/library/Cana/_Stripe/Charge.php
diff --git a/include/library/Cana/Stripe/Coupon.php b/include/library/Cana/_Stripe/Coupon.php
similarity index 100%
rename from include/library/Cana/Stripe/Coupon.php
rename to include/library/Cana/_Stripe/Coupon.php
diff --git a/include/library/Cana/Stripe/Customer.php b/include/library/Cana/_Stripe/Customer.php
similarity index 100%
rename from include/library/Cana/Stripe/Customer.php
rename to include/library/Cana/_Stripe/Customer.php
diff --git a/include/library/Cana/Stripe/Error.php b/include/library/Cana/_Stripe/Error.php
similarity index 100%
rename from include/library/Cana/Stripe/Error.php
rename to include/library/Cana/_Stripe/Error.php
diff --git a/include/library/Cana/Stripe/Event.php b/include/library/Cana/_Stripe/Event.php
similarity index 100%
rename from include/library/Cana/Stripe/Event.php
rename to include/library/Cana/_Stripe/Event.php
diff --git a/include/library/Cana/Stripe/InvalidRequestError.php b/include/library/Cana/_Stripe/InvalidRequestError.php
similarity index 100%
rename from include/library/Cana/Stripe/InvalidRequestError.php
rename to include/library/Cana/_Stripe/InvalidRequestError.php
diff --git a/include/library/Cana/Stripe/Invoice.php b/include/library/Cana/_Stripe/Invoice.php
similarity index 100%
rename from include/library/Cana/Stripe/Invoice.php
rename to include/library/Cana/_Stripe/Invoice.php
diff --git a/include/library/Cana/Stripe/InvoiceItem.php b/include/library/Cana/_Stripe/InvoiceItem.php
similarity index 100%
rename from include/library/Cana/Stripe/InvoiceItem.php
rename to include/library/Cana/_Stripe/InvoiceItem.php
diff --git a/include/library/Cana/Stripe/List.php b/include/library/Cana/_Stripe/List.php
similarity index 100%
rename from include/library/Cana/Stripe/List.php
rename to include/library/Cana/_Stripe/List.php
diff --git a/include/library/Cana/Stripe/Object.php b/include/library/Cana/_Stripe/Object.php
similarity index 100%
rename from include/library/Cana/Stripe/Object.php
rename to include/library/Cana/_Stripe/Object.php
diff --git a/include/library/Cana/Stripe/Plan.php b/include/library/Cana/_Stripe/Plan.php
similarity index 100%
rename from include/library/Cana/Stripe/Plan.php
rename to include/library/Cana/_Stripe/Plan.php
diff --git a/include/library/Cana/Stripe/Recipient.php b/include/library/Cana/_Stripe/Recipient.php
similarity index 100%
rename from include/library/Cana/Stripe/Recipient.php
rename to include/library/Cana/_Stripe/Recipient.php
diff --git a/include/library/Cana/Stripe/SingletonApiResource.php b/include/library/Cana/_Stripe/SingletonApiResource.php
similarity index 100%
rename from include/library/Cana/Stripe/SingletonApiResource.php
rename to include/library/Cana/_Stripe/SingletonApiResource.php
diff --git a/include/library/Cana/Stripe/Token.php b/include/library/Cana/_Stripe/Token.php
similarity index 100%
rename from include/library/Cana/Stripe/Token.php
rename to include/library/Cana/_Stripe/Token.php
diff --git a/include/library/Cana/Stripe/Transfer.php b/include/library/Cana/_Stripe/Transfer.php
similarity index 100%
rename from include/library/Cana/Stripe/Transfer.php
rename to include/library/Cana/_Stripe/Transfer.php
diff --git a/include/library/Cana/Stripe/Util.php b/include/library/Cana/_Stripe/Util.php
similarity index 100%
rename from include/library/Cana/Stripe/Util.php
rename to include/library/Cana/_Stripe/Util.php
diff --git a/include/library/Cana/Stripe/Util/Set.php b/include/library/Cana/_Stripe/Util/Set.php
similarity index 100%
rename from include/library/Cana/Stripe/Util/Set.php
rename to include/library/Cana/_Stripe/Util/Set.php
diff --git a/include/library/Crunchbutton/App.php b/include/library/Crunchbutton/App.php
index 0f1e1f16c..18913118d 100755
--- a/include/library/Crunchbutton/App.php
+++ b/include/library/Crunchbutton/App.php
@@ -157,9 +157,6 @@ class Crunchbutton_App extends Cana_App {
->config($config)
->postInit($params);
- require_once c::config()->dirs->library . '/Cana/Stripe.php';
- Stripe::setApiKey(c::config()->stripe->dev->secret);
-
switch ($_SERVER['SERVER_NAME']) {
case 'spicywithdelivery.com':
case 'beta.spicywithdelivery.com':
@@ -462,6 +459,16 @@ class Crunchbutton_App extends Cana_App {
}
return $this->_balanced;
}
+
+ public function stripe() {
+ if (!$this->_stripe) {
+ \Stripe\Stripe::setApiKey(c::config()->stripe->{c::getEnv()}->secret);;
+ $this->_stripe = true;
+ }
+ return $this->_stripe;
+ }
+
+
public function lob($d = true) {
if (!$this->_lob) {
diff --git a/include/library/Crunchbutton/Charge/Balanced.php b/include/library/Crunchbutton/Charge/Balanced.php
index 61cec82c7..fd31d4f32 100644
--- a/include/library/Crunchbutton/Charge/Balanced.php
+++ b/include/library/Crunchbutton/Charge/Balanced.php
@@ -20,7 +20,8 @@ class Crunchbutton_Charge_Balanced extends Cana_Model {
$c = $this->_card->debits->create([
'amount' => $params['amount'] * 100,
'appears_on_statement_as' => 'Crunchbutton',
- 'description' => $params['restaurant']->name
+ 'description' => $params['restaurant']->name,
+ 'statement_descriptor' => $params['restaurant']->statementName()
]);
} catch (Exception $e) {
diff --git a/include/library/Crunchbutton/Charge/Stripe.php b/include/library/Crunchbutton/Charge/Stripe.php
index 09ab68c11..6a2d4b461 100644
--- a/include/library/Crunchbutton/Charge/Stripe.php
+++ b/include/library/Crunchbutton/Charge/Stripe.php
@@ -2,98 +2,103 @@
class Crunchbutton_Charge_Stripe extends Crunchbutton_Charge {
public function __construct($params = []) {
-
+ $this->_customer = $params['customer_id'];
+ $this->_card = $params['card_id'];
}
public function charge($params = []) {
- $env = c::getEnv();
-
- Stripe::setApiKey(c::config()->stripe->{$env}->secret);
+ c::stripe();
$success = false;
- $reason = false;
-
- $user = $params[ 'user' ];
-
- // Start with no customer id
- $customer_id = false;
// The user changed its card or it is a new one
- if( $params['card']['id'] ){
- // The first thing we need to do is check customer
- $token = $params['card']['uri'];
- // lets see if the customer exists
- if ( !$user || !$user->payment_type()->stripe_id ) {
- // if there is no user, create one
- try {
- $customer = Stripe_Customer::create( array(
- 'description' => "Crunchbutton",
- 'card' => $token
- ) );
- } catch ( Exception $e ) {
- print_r( $e );
- die('creating customer error: 1');
- }
- } elseif ( $user && $user->payment_type()->stripe_id ) {
- // if there is already a user, update it
- try {
- $customer = Stripe_Customer::retrieve( $user->payment_type()->stripe_id );
- $customer->card = $token;
- $customer->save();
- } catch ( Exception $e ) {
- print_r( $e );
- die('creating customer error: 2');
- }
- }
- $customer_id = $customer->id;
- }
- // If we don't have a card token it means the user is already a customer
- else if( $user->payment_type()->stripe_id ) {
- $customer_id = $user->payment_type()->stripe_id;
- }
-
- // yay, we have a valid customer
- if( $customer_id ){
- // Now we have to charge it
+ if ($params['card']) {
+
+ // create a customer if it doesnt exist
+ if (!$this->_customer) {
try {
- $charge = Stripe_Charge::create([
- 'amount' => $params['amount'] * 100,
- 'currency' => 'usd',
- 'customer' => $customer_id,
- 'description' => $params['restaurant']->name,
- ] );
- }
- // Shit happens
- catch(Stripe_CardError $e) {
- Log::debug( [ 'card error' => 'card declined', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
- $errors[] = 'Your card was declined. Please try again!';
- } catch (Stripe_InvalidRequestError $e) {
- Log::debug( [ 'card error' => 'invalid request', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
- $errors[] = 'Please update your credit card information.';
- } catch (Stripe_AuthenticationError $e) {
- Log::debug( [ 'card error' => 'auth error', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
- $errors[] = 'Please update your credit card information.';
- } catch (Stripe_ApiConnectionError $e) {
- Log::debug( [ 'card error' => 'api connection', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
- $errors[] = 'Please update your credit card information.';
- } catch (Stripe_Error $e) {
- Log::debug( [ 'card error' => 'api connection', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
- $errors[] = 'Please update your credit card information.';
- } catch (Exception $e) {
- $errors[] = 'Not enough card information.';
- }
+ $customer = \Stripe\Customer::create([
+ 'description' => $params['name'],
+ 'email' => $params['email'],
+ 'source' => $params['card']['uri']
+ ]);
- if ( $charge->paid && !$charge->refunded ) {
- $success = true;
- $txn = $charge->id;
- }
- }
- if (!$success && !$errors) {
- $errors[] = 'Not enough card information.';
+ } catch ( Exception $e ) {
+ $errors[] = 'Could not create customer with processor.';
+ }
+ $this->_customer = $customer->id;
+
+ // there is already a customer
+ } else {
+ try {
+ $customer = \Stripe\Customer::retrieve($this->_customer);
+ $customer->card = $params['card']['token'];
+ $customer->save();
+
+ } catch ( Exception $e ) {
+ $errors[] = 'Could not retrieve or save customer to processor.';
+ }
+ }
+
+ $this->_card = $params['card']['id'];
}
- return [ 'status' => $success, 'txn' => $txn, 'errors' => $errors, 'customer' => $customer ];
+ // Now we have to charge it
+ try {
+ $charge = \Stripe\Charge::create([
+ 'amount' => $params['amount'] * 100,
+ 'currency' => 'usd',
+ 'customer' => $this->_customer,
+ //'source' => $this->_card,
+ 'description' => $params['restaurant']->name,
+ 'capture' => c::config()->site->config('processor_payments_capture') ? true : false,
+ 'statement_descriptor' => $params['restaurant']->statementName()
+ ]);
+
+ } catch(\Stripe\Stripe_CardError $e) {
+ Log::debug( [ 'card error' => 'card declined', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
+ $errors[] = 'Your card was declined. Please try again!';
+
+ } catch (\Stripe\Stripe_InvalidRequestError $e) {
+ Log::debug( [ 'card error' => 'invalid request', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
+ $errors[] = 'Please update your credit card information.';
+
+ } catch (\Stripe\Stripe_AuthenticationError $e) {
+ Log::debug( [ 'card error' => 'auth error', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
+ $errors[] = 'Please update your credit card information.';
+
+ } catch (\Stripe\Stripe_ApiConnectionError $e) {
+ Log::debug( [ 'card error' => 'api connection', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
+ $errors[] = 'Please update your credit card information.';
+
+ } catch (\Stripe\Stripe_Error $e) {
+ Log::debug( [ 'card error' => 'api connection', 'Exception' => $e->getJsonBody(), 'type' => 'stripe error' ]);
+ $errors[] = 'Please update your credit card information.';
+
+ } catch (Exception $e) {
+ //tripe\Error\InvalidRequest
+ //Stripe\Error\Card
+ print_r($e);
+ $errors[] = 'Error processing credit card.';
+ }
+
+ if ($charge && $charge->paid && !$charge->refunded) {
+ $success = true;
+ $txn = $charge->id;
+ }
+
+ if (!$success && !$errors) {
+ $errors[] = 'Completly vague payment error. Contact support and complain. We love complaints.'."\n\n".'angrycustomers@_DOMAIN_';
+ }
+
+ return [
+ 'status' => $success,
+ 'txn' => $txn,
+ 'errors' => $errors,
+ 'customer' => $this->_customer,
+ 'card' => $this->_card
+ ];
}
}
\ No newline at end of file
diff --git a/include/library/Crunchbutton/Order.php b/include/library/Crunchbutton/Order.php
index 4b3832197..ff2f76713 100644
--- a/include/library/Crunchbutton/Order.php
+++ b/include/library/Crunchbutton/Order.php
@@ -564,11 +564,9 @@ class Crunchbutton_Order extends Crunchbutton_Order_Trackchange {
switch (Crunchbutton_User_Payment_Type::processor()) {
case 'stripe':
- $payment_type->stripe_id = $this->_customer->id;
+ $payment_type->stripe_id = $this->_paymentType;
break;
-
case 'balanced':
- default:
$payment_type->balanced_id = $this->_paymentType->id;
break;
}
@@ -949,32 +947,34 @@ class Crunchbutton_Order extends Crunchbutton_Order_Trackchange {
case 'card':
$user = c::user()->id_user ? c::user() : null;
+ $processorId = c::config()->site->config('processor_payments') == 'balanced' ? 'balanced_id' : 'stripe_id';
- if( $user ){
+ if ($user) {
$paymentType = $user->payment_type();
}
- if (!$this->_card['id'] && !$paymentType->id_user_payment_type && $user->balanced_id) {
- // user only has a balanced customer id, not a payment. copy payment type over
- $paymentType = (new User_Payment_Type([
- 'id_user' => $user->id_user,
- 'active' => 1,
-// 'stripe_id' => $user->stripe_id,
- 'balanced_id' => $user->balanced_id,
- 'card' => $user->card,
- 'card_exp_month' => $user->card_exp_month,
- 'card_exp_year' => $user->card_exp_year,
- 'date' => date('Y-m-d H:i:s')
- ]))->save();
+ // #5243 - if using stripe, get the stripe id from balanced, and update the paymenttype
+ if (c::config()->site->config('processor_payments') == 'stripe' && $paymentType->balanced_id && !$paymentType->stripe_id) {
+ $balancedCard = Crunchbutton_Balanced_Card::byId($paymentType->balanced_id);
+ print_r($balancedCard);
+ exit;
}
+ // use a stored users card and the apporiate payment type
+
if (!$this->_card['id'] && $paymentType->id_user_payment_type) {
- // use a stored users card and the apporiate payment type
- if ($paymentType->balanced_id) {
+ if (c::config()->site->config('processor_payments') == 'stripe' && $paymentType->stripe_id) {
+ $charge = new Charge_Stripe([
+ 'card_id' => $paymentType->stripe_id,
+ 'customer_id' => $user->stripe_id
+ ]);
+
+ } elseif (c::config()->site->config('processor_payments') == 'balanced' && $paymentType->balanced_id) {
if (substr($paymentType->balanced_id,0,2) != 'CC') {
// we have stored the customer and not the payment type. need to fix that
+ // @todo: i dont really understand wtf this is for - devin
$cards = Crunchbutton_Balanced_Account::byId($paymentType->balanced_id)->cards;
if (get_class($cards) == 'RESTful\Collection') {
foreach ($cards as $card) {
@@ -996,23 +996,19 @@ class Crunchbutton_Order extends Crunchbutton_Order_Trackchange {
$charge = new Charge_Balanced([
'card_id' => $paymentType->balanced_id
]);
-
- } elseif ($paymentType->stripe_id) {
- $charge = new Charge_Stripe([
- 'stripe_id' => $paymentType->stripe_id
- ]);
+ } else {
+ die('processor mismatch');
}
}
+ // create the objects with no params
if (!$charge) {
switch (Crunchbutton_User_Payment_Type::processor()) {
case 'balanced':
$charge = new Charge_Balanced();
break;
case 'stripe':
- $charge = new Charge_Stripe([
- 'stripe_id' => $user->stripe_id
- ]);
+ $charge = new Charge_Stripe();
break;
}
}
@@ -1029,6 +1025,7 @@ class Crunchbutton_Order extends Crunchbutton_Order_Trackchange {
'card' => $this->_card,
'name' => $this->name,
'address' => $this->address,
+ 'email' => $user->email,
'phone' => $this->phone,
'user' => $user,
'restaurant' => $this->restaurant()
diff --git a/include/library/Crunchbutton/Restaurant.php b/include/library/Crunchbutton/Restaurant.php
index e9f13dee9..a66d18a94 100644
--- a/include/library/Crunchbutton/Restaurant.php
+++ b/include/library/Crunchbutton/Restaurant.php
@@ -154,8 +154,17 @@ class Crunchbutton_Restaurant extends Cana_Table_Trackchange {
return $phone;
}
- public function shortName() {
- return $this->short_name ? $this->short_name : $this->name;
+ // name that appears on credit card statement
+ public function statementName() {
+ if (!isset($this->_statementName)) {
+ $name = $this->short_name ? $this->short_name : $this->name;
+ $name = preg_replace('/[^a-z ]/i','',$name);
+ if (strlen($name) > 22) {
+ $name = str_replace(' ', '', $name);
+ }
+ $this->_statementName = strtoupper(substr($name, 0, 22));
+ }
+ return $this->_statementName;
}
public function _hasOption($option, $options) {
diff --git a/include/library/Crunchbutton/User/Payment/Type.php b/include/library/Crunchbutton/User/Payment/Type.php
index b43791164..e64d29389 100644
--- a/include/library/Crunchbutton/User/Payment/Type.php
+++ b/include/library/Crunchbutton/User/Payment/Type.php
@@ -3,18 +3,27 @@
class Crunchbutton_User_Payment_Type extends Cana_Table {
public function processor() {
- return c::config()->processor;
+ return c::config()->site->config('processor_payments')->value;
}
- public function getUserPaymentType( $id_user = null ){
- $id_user = ( $id_user ) ? $id_user : c::user()->id_user;
- if( $id_user ){
- $where = ' AND ' . Crunchbutton_User_Payment_Type::processor() . '_id IS NOT NULL';
- $payment = Crunchbutton_User_Payment_Type::q( 'SELECT * FROM user_payment_type WHERE id_user = ? AND active = true ' . $where . ' ORDER BY id_user_payment_type DESC LIMIT 1', [$id_user]);
- if( $payment->id_user_payment_type ){
+ public function getUserPaymentType($id_user = null) {
+ $id_user = $id_user ? $id_user : c::user()->id_user;
+
+ if ($id_user) {
+ $payment = Crunchbutton_User_Payment_Type::q('
+ SELECT * FROM user_payment_type
+ WHERE
+ id_user = ?
+ AND active = true
+ AND ' . Crunchbutton_User_Payment_Type::processor() . '_id IS NOT NULL
+ ORDER BY id_user_payment_type DESC LIMIT 1
+ ', [$id_user]);
+
+ if ($payment->id_user_payment_type) {
return $payment;
}
}
+
return false;
}
diff --git a/include/library/Stripe/Account.php b/include/library/Stripe/Account.php
new file mode 100755
index 000000000..0684a55cb
--- /dev/null
+++ b/include/library/Stripe/Account.php
@@ -0,0 +1,62 @@
+_save();
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $opts
+ *
+ * @return Account[]
+ */
+ public static function all($params = null, $opts = null)
+ {
+ return self::_all($params, $opts);
+ }
+}
diff --git a/include/library/Stripe/ApiRequestor.php b/include/library/Stripe/ApiRequestor.php
new file mode 100755
index 000000000..c30951533
--- /dev/null
+++ b/include/library/Stripe/ApiRequestor.php
@@ -0,0 +1,471 @@
+_apiKey = $apiKey;
+ if (!$apiBase) {
+ $apiBase = Stripe::$apiBase;
+ }
+ $this->_apiBase = $apiBase;
+ }
+
+ /**
+ * @param string|mixed $value A string to UTF8-encode.
+ *
+ * @return string|mixed The UTF8-encoded string, or the object passed in if
+ * it wasn't a string.
+ */
+ public static function utf8($value)
+ {
+ if (is_string($value) && mb_detect_encoding($value, "UTF-8", true) != "UTF-8") {
+ return utf8_encode($value);
+ } else {
+ return $value;
+ }
+ }
+
+ private static function _encodeObjects($d)
+ {
+ if ($d instanceof ApiResource) {
+ return self::utf8($d->id);
+ } elseif ($d === true) {
+ return 'true';
+ } elseif ($d === false) {
+ return 'false';
+ } elseif (is_array($d)) {
+ $res = array();
+ foreach ($d as $k => $v) {
+ $res[$k] = self::_encodeObjects($v);
+ }
+ return $res;
+ } else {
+ return self::utf8($d);
+ }
+ }
+
+ /**
+ * @param array $arr An map of param keys to values.
+ * @param string|null $prefix (It doesn't look like we ever use $prefix...)
+ *
+ * @return string A querystring, essentially.
+ */
+ public static function encode($arr, $prefix = null)
+ {
+ if (!is_array($arr)) {
+ return $arr;
+ }
+
+ $r = array();
+ foreach ($arr as $k => $v) {
+ if (is_null($v)) {
+ continue;
+ }
+
+ if ($prefix && $k && !is_int($k)) {
+ $k = $prefix."[".$k."]";
+ } elseif ($prefix) {
+ $k = $prefix."[]";
+ }
+
+ if (is_array($v)) {
+ $r[] = self::encode($v, $k, true);
+ } else {
+ $r[] = urlencode($k)."=".urlencode($v);
+ }
+ }
+
+ return implode("&", $r);
+ }
+
+ /**
+ * @param string $method
+ * @param string $url
+ * @param array|null $params
+ * @param array|null $headers
+ *
+ * @return array An array whose first element is the response and second
+ * element is the API key used to make the request.
+ */
+ public function request($method, $url, $params = null, $headers = null)
+ {
+ if (!$params) {
+ $params = array();
+ }
+ if (!$headers) {
+ $headers = array();
+ }
+ list($rbody, $rcode, $myApiKey) =
+ $this->_requestRaw($method, $url, $params, $headers);
+ $resp = $this->_interpretResponse($rbody, $rcode);
+ return array($resp, $myApiKey);
+ }
+
+ /**
+ * @param string $rbody A JSON string.
+ * @param int $rcode
+ * @param array $resp
+ *
+ * @throws Error\InvalidRequest if the error is caused by the user.
+ * @throws Error\Authentication if the error is caused by a lack of
+ * permissions.
+ * @throws Error\Card if the error is the error code is 402 (payment
+ * required)
+ * @throws Error\Api otherwise.
+ */
+ public function handleApiError($rbody, $rcode, $resp)
+ {
+ if (!is_array($resp) || !isset($resp['error'])) {
+ $msg = "Invalid response object from API: $rbody "
+ . "(HTTP response code was $rcode)";
+ throw new Error\Api($msg, $rcode, $rbody, $resp);
+ }
+
+ $error = $resp['error'];
+ $msg = isset($error['message']) ? $error['message'] : null;
+ $param = isset($error['param']) ? $error['param'] : null;
+ $code = isset($error['code']) ? $error['code'] : null;
+
+ switch ($rcode) {
+ case 400:
+ if ($code == 'rate_limit') {
+ throw new Error\RateLimit($msg, $param, $rcode, $rbody, $resp);
+ }
+
+ // intentional fall-through
+ case 404:
+ throw new Error\InvalidRequest($msg, $param, $rcode, $rbody, $resp);
+ case 401:
+ throw new Error\Authentication($msg, $rcode, $rbody, $resp);
+ case 402:
+ throw new Error\Card($msg, $param, $code, $rcode, $rbody, $resp);
+ default:
+ throw new Error\Api($msg, $rcode, $rbody, $resp);
+ }
+ }
+
+ private function _requestRaw($method, $url, $params, $headers)
+ {
+ if (!array_key_exists($this->_apiBase, self::$_preFlight) ||
+ !self::$_preFlight[$this->_apiBase]) {
+ self::$_preFlight[$this->_apiBase] = $this->checkSslCert($this->_apiBase);
+ }
+
+ $myApiKey = $this->_apiKey;
+ if (!$myApiKey) {
+ $myApiKey = Stripe::$apiKey;
+ }
+
+ if (!$myApiKey) {
+ $msg = 'No API key provided. (HINT: set your API key using '
+ . '"Stripe::setApiKey()". You can generate API keys from '
+ . 'the Stripe web interface. See https://stripe.com/api for '
+ . 'details, or email support@stripe.com if you have any questions.';
+ throw new Error\Authentication($msg);
+ }
+
+ $absUrl = $this->_apiBase.$url;
+ $params = self::_encodeObjects($params);
+ $langVersion = phpversion();
+ $uname = php_uname();
+ $ua = array(
+ 'bindings_version' => Stripe::VERSION,
+ 'lang' => 'php',
+ 'lang_version' => $langVersion,
+ 'publisher' => 'stripe',
+ 'uname' => $uname,
+ );
+ $defaultHeaders = array(
+ 'X-Stripe-Client-User-Agent' => json_encode($ua),
+ 'User-Agent' => 'Stripe/v1 PhpBindings/' . Stripe::VERSION,
+ 'Authorization' => 'Bearer ' . $myApiKey,
+ );
+ if (Stripe::$apiVersion) {
+ $defaultHeaders['Stripe-Version'] = Stripe::$apiVersion;
+ }
+ $hasFile = false;
+ $hasCurlFile = class_exists('\CURLFile', false);
+ foreach ($params as $k => $v) {
+ if (is_resource($v)) {
+ $hasFile = true;
+ $params[$k] = self::_processResourceParam($v, $hasCurlFile);
+ } elseif ($hasCurlFile && $v instanceof \CURLFile) {
+ $hasFile = true;
+ }
+ }
+
+ if ($hasFile) {
+ $defaultHeaders['Content-Type'] = 'multipart/form-data';
+ } else {
+ $defaultHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+
+ $combinedHeaders = array_merge($defaultHeaders, $headers);
+ $rawHeaders = array();
+
+ foreach ($combinedHeaders as $header => $value) {
+ $rawHeaders[] = $header . ': ' . $value;
+ }
+
+ list($rbody, $rcode) = $this->_curlRequest(
+ $method,
+ $absUrl,
+ $rawHeaders,
+ $params,
+ $hasFile
+ );
+ return array($rbody, $rcode, $myApiKey);
+ }
+
+ private function _processResourceParam($resource, $hasCurlFile)
+ {
+ if (get_resource_type($resource) !== 'stream') {
+ throw new Error\Api(
+ 'Attempted to upload a resource that is not a stream'
+ );
+ }
+
+ $metaData = stream_get_meta_data($resource);
+ if ($metaData['wrapper_type'] !== 'plainfile') {
+ throw new Error\Api(
+ 'Only plainfile resource streams are supported'
+ );
+ }
+
+ if ($hasCurlFile) {
+ // We don't have the filename or mimetype, but the API doesn't care
+ return new \CURLFile($metaData['uri']);
+ } else {
+ return '@'.$metaData['uri'];
+ }
+ }
+
+ private function _interpretResponse($rbody, $rcode)
+ {
+ try {
+ $resp = json_decode($rbody, true);
+ } catch (Exception $e) {
+ $msg = "Invalid response body from API: $rbody "
+ . "(HTTP response code was $rcode)";
+ throw new Error\Api($msg, $rcode, $rbody);
+ }
+
+ if ($rcode < 200 || $rcode >= 300) {
+ $this->handleApiError($rbody, $rcode, $resp);
+ }
+ return $resp;
+ }
+
+ private function _curlRequest($method, $absUrl, $headers, $params, $hasFile)
+ {
+ $curl = curl_init();
+ $method = strtolower($method);
+ $opts = array();
+ if ($method == 'get') {
+ if ($hasFile) {
+ throw new Error\Api(
+ "Issuing a GET request with a file parameter"
+ );
+ }
+ $opts[CURLOPT_HTTPGET] = 1;
+ if (count($params) > 0) {
+ $encoded = self::encode($params);
+ $absUrl = "$absUrl?$encoded";
+ }
+ } elseif ($method == 'post') {
+ $opts[CURLOPT_POST] = 1;
+ $opts[CURLOPT_POSTFIELDS] = $hasFile ? $params : self::encode($params);
+ } elseif ($method == 'delete') {
+ $opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
+ if (count($params) > 0) {
+ $encoded = self::encode($params);
+ $absUrl = "$absUrl?$encoded";
+ }
+ } else {
+ throw new Error\Api("Unrecognized method $method");
+ }
+
+ $absUrl = self::utf8($absUrl);
+ $opts[CURLOPT_URL] = $absUrl;
+ $opts[CURLOPT_RETURNTRANSFER] = true;
+ $opts[CURLOPT_CONNECTTIMEOUT] = 30;
+ $opts[CURLOPT_TIMEOUT] = 80;
+ $opts[CURLOPT_RETURNTRANSFER] = true;
+ $opts[CURLOPT_HTTPHEADER] = $headers;
+ if (!Stripe::$verifySslCerts) {
+ $opts[CURLOPT_SSL_VERIFYPEER] = false;
+ }
+
+ curl_setopt_array($curl, $opts);
+ $rbody = curl_exec($curl);
+
+ if (!defined('CURLE_SSL_CACERT_BADFILE')) {
+ define('CURLE_SSL_CACERT_BADFILE', 77); // constant not defined in PHP
+ }
+
+ $errno = curl_errno($curl);
+ if ($errno == CURLE_SSL_CACERT ||
+ $errno == CURLE_SSL_PEER_CERTIFICATE ||
+ $errno == CURLE_SSL_CACERT_BADFILE
+ ) {
+ array_push(
+ $headers,
+ 'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}'
+ );
+ $cert = $this->caBundle();
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($curl, CURLOPT_CAINFO, $cert);
+ $rbody = curl_exec($curl);
+ }
+
+ if ($rbody === false) {
+ $errno = curl_errno($curl);
+ $message = curl_error($curl);
+ curl_close($curl);
+ $this->handleCurlError($errno, $message);
+ }
+
+ $rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ curl_close($curl);
+ return array($rbody, $rcode);
+ }
+
+ /**
+ * @param number $errno
+ * @param string $message
+ * @throws ApiConnectionError
+ */
+ public function handleCurlError($errno, $message)
+ {
+ $apiBase = $this->_apiBase;
+ switch ($errno) {
+ case CURLE_COULDNT_CONNECT:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_OPERATION_TIMEOUTED:
+ $msg = "Could not connect to Stripe ($apiBase). Please check your "
+ . "internet connection and try again. If this problem persists, "
+ . "you should check Stripe's service status at "
+ . "https://twitter.com/stripestatus, or";
+ break;
+ case CURLE_SSL_CACERT:
+ case CURLE_SSL_PEER_CERTIFICATE:
+ $msg = "Could not verify Stripe's SSL certificate. Please make sure "
+ . "that your network is not intercepting certificates. "
+ . "(Try going to $apiBase in your browser.) "
+ . "If this problem persists,";
+ break;
+ default:
+ $msg = "Unexpected error communicating with Stripe. "
+ . "If this problem persists,";
+ }
+ $msg .= " let us know at support@stripe.com.";
+
+ $msg .= "\n\n(Network error [errno $errno]: $message)";
+ throw new Error\ApiConnection($msg);
+ }
+
+ /**
+ * Preflight the SSL certificate presented by the backend. This isn't 100%
+ * bulletproof, in that we're not actually validating the transport used to
+ * communicate with Stripe, merely that the first attempt to does not use a
+ * revoked certificate.
+ *
+ * Unfortunately the interface to OpenSSL doesn't make it easy to check the
+ * certificate before sending potentially sensitive data on the wire. This
+ * approach raises the bar for an attacker significantly.
+ */
+ private function checkSslCert($url)
+ {
+ if (!function_exists('stream_context_get_params') ||
+ !function_exists('stream_socket_enable_crypto')) {
+ error_log(
+ 'Warning: This version of PHP does not support checking SSL ' .
+ 'certificates Stripe cannot guarantee that the server has a ' .
+ 'certificate which is not blacklisted.'
+ );
+ return true;
+ }
+
+ $url = parse_url($url);
+ $port = isset($url["port"]) ? $url["port"] : 443;
+ $url = "ssl://{$url["host"]}:{$port}";
+
+ $sslContext = stream_context_create(
+ array('ssl' => array(
+ 'capture_peer_cert' => true,
+ 'verify_peer' => true,
+ 'cafile' => $this->caBundle(),
+ ))
+ );
+ $result = stream_socket_client(
+ $url,
+ $errno,
+ $errstr,
+ 30,
+ STREAM_CLIENT_CONNECT,
+ $sslContext
+ );
+ if (($errno !== 0 && $errno !== null) || $result === false) {
+ throw new Error\ApiConnection(
+ 'Could not connect to Stripe (' . $url . '). Please check your ' .
+ 'internet connection and try again. If this problem persists, ' .
+ 'you should check Stripe\'s service status at ' .
+ 'https://twitter.com/stripestatus. Reason was: ' . $errstr
+ );
+ }
+
+ $params = stream_context_get_params($result);
+
+ $cert = $params['options']['ssl']['peer_certificate'];
+
+ openssl_x509_export($cert, $pemCert);
+
+ if (self::isBlackListed($pemCert)) {
+ throw new Error\ApiConnection(
+ 'Invalid server certificate. You tried to connect to a server that ' .
+ 'has a revoked SSL certificate, which means we cannot securely send ' .
+ 'data to that server. Please email support@stripe.com if you need ' .
+ 'help connecting to the correct API server.'
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a valid PEM encoded certificate is blacklisted
+ * @return boolean
+ */
+ public static function isBlackListed($certificate)
+ {
+ $certificate = trim($certificate);
+ $lines = explode("\n", $certificate);
+
+ // Kludgily remove the PEM padding
+ array_shift($lines);
+ array_pop($lines);
+
+ $derCert = base64_decode(implode("", $lines));
+ $fingerprint = sha1($derCert);
+ return in_array($fingerprint, self::$_blacklistedCerts);
+ }
+
+ private function caBundle()
+ {
+ return dirname(__FILE__) . '/../../../ssl/ca-certificates.crt';
+ }
+}
diff --git a/include/library/Stripe/ApiResource.php b/include/library/Stripe/ApiResource.php
new file mode 100755
index 000000000..f80aeb85e
--- /dev/null
+++ b/include/library/Stripe/ApiResource.php
@@ -0,0 +1,161 @@
+ true, 'Stripe-Version' => true);
+
+ public static function baseUrl()
+ {
+ return Stripe::$apiBase;
+ }
+
+ /**
+ * @return ApiResource The refreshed resource.
+ */
+ public function refresh()
+ {
+ $requestor = new ApiRequestor($this->_opts->apiKey, static::baseUrl());
+ $url = $this->instanceUrl();
+
+ list($response, $this->_opts->apiKey) = $requestor->request(
+ 'get',
+ $url,
+ $this->_retrieveOptions,
+ $this->_opts->headers
+ );
+ $this->refreshFrom($response, $this->_opts);
+ return $this;
+ }
+
+ /**
+ * @return string The name of the class, with namespacing and underscores
+ * stripped.
+ */
+ public static function className()
+ {
+ $class = get_called_class();
+ // Useful for namespaces: Foo\Charge
+ if ($postfixNamespaces = strrchr($class, '\\')) {
+ $class = substr($postfixNamespaces, 1);
+ }
+ // Useful for underscored 'namespaces': Foo_Charge
+ if ($postfixFakeNamespaces = strrchr($class, '')) {
+ $class = $postfixFakeNamespaces;
+ }
+ if (substr($class, 0, strlen('Stripe')) == 'Stripe') {
+ $class = substr($class, strlen('Stripe'));
+ }
+ $class = str_replace('_', '', $class);
+ $name = urlencode($class);
+ $name = strtolower($name);
+ return $name;
+ }
+
+ /**
+ * @return string The endpoint URL for the given class.
+ */
+ public static function classUrl()
+ {
+ $base = static::className();
+ return "/v1/${base}s";
+ }
+
+ /**
+ * @return string The full API URL for this API resource.
+ */
+ public function instanceUrl()
+ {
+ $id = $this['id'];
+ if ($id === null) {
+ $class = get_called_class();
+ $message = "Could not determine which URL to request: "
+ . "$class instance has invalid ID: $id";
+ throw new Error\InvalidRequest($message, null);
+ }
+ $id = ApiRequestor::utf8($id);
+ $base = static::classUrl();
+ $extn = urlencode($id);
+ return "$base/$extn";
+ }
+
+ private static function _validateParams($params = null)
+ {
+ if ($params && !is_array($params)) {
+ $message = "You must pass an array as the first argument to Stripe API "
+ . "method calls. (HINT: an example call to create a charge "
+ . "would be: \"Stripe\\Charge::create(array('amount' => 100, "
+ . "'currency' => 'usd', 'card' => array('number' => "
+ . "4242424242424242, 'exp_month' => 5, 'exp_year' => 2015)))\")";
+ throw new Error\Api($message);
+ }
+ }
+
+ protected function _request($method, $url, $params = array(), $options = null)
+ {
+ $opts = $this->_opts->merge($options);
+ return static::_staticRequest($method, $url, $params, $opts);
+ }
+
+ protected static function _staticRequest($method, $url, $params, $options)
+ {
+ $opts = Util\RequestOptions::parse($options);
+ $requestor = new ApiRequestor($opts->apiKey, static::baseUrl());
+ list($response, $opts->apiKey) = $requestor->request($method, $url, $params, $opts->headers);
+ foreach ($opts->headers as $k => $v) {
+ if (!array_key_exists($k, self::$HEADERS_TO_PERSIST)) {
+ unset($opts->headers[$k]);
+ }
+ }
+ return array($response, $opts);
+ }
+
+ protected static function _retrieve($id, $options = null)
+ {
+ $opts = Util\RequestOptions::parse($options);
+ $instance = new static($id, $opts);
+ $instance->refresh();
+ return $instance;
+ }
+
+ protected static function _all($params = null, $options = null)
+ {
+ self::_validateParams($params);
+ $url = static::classUrl();
+
+ list($response, $opts) = static::_staticRequest('get', $url, $params, $options);
+ return Util\Util::convertToStripeObject($response, $opts);
+ }
+
+ protected static function _create($params = null, $options = null)
+ {
+ self::_validateParams($params);
+ $base = static::baseUrl();
+ $url = static::classUrl();
+
+ list($response, $opts) = static::_staticRequest('post', $url, $params, $options);
+ return Util\Util::convertToStripeObject($response, $opts);
+ }
+
+ protected function _save($options = null)
+ {
+ $params = $this->serializeParameters();
+ if (count($params) > 0) {
+ $url = $this->instanceUrl();
+ list($response, $opts) = $this->_request('post', $url, $params, $options);
+ $this->refreshFrom($response, $opts);
+ }
+ return $this;
+ }
+
+ protected function _delete($params = null, $options = null)
+ {
+ self::_validateParams($params);
+
+ $url = $this->instanceUrl();
+ list($response, $opts) = $this->_request('delete', $url, $params, $options);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+}
diff --git a/include/library/Stripe/ApplicationFee.php b/include/library/Stripe/ApplicationFee.php
new file mode 100755
index 000000000..41674e499
--- /dev/null
+++ b/include/library/Stripe/ApplicationFee.php
@@ -0,0 +1,53 @@
+instanceUrl() . '/refund';
+ list($response, $opts) = $this->_request('post', $url, $params, $opts);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+}
diff --git a/include/library/Stripe/ApplicationFeeRefund.php b/include/library/Stripe/ApplicationFeeRefund.php
new file mode 100755
index 000000000..7f4e94ff2
--- /dev/null
+++ b/include/library/Stripe/ApplicationFeeRefund.php
@@ -0,0 +1,39 @@
+_save($opts);
+ }
+}
diff --git a/include/library/Stripe/AttachedObject.php b/include/library/Stripe/AttachedObject.php
new file mode 100755
index 000000000..be3868639
--- /dev/null
+++ b/include/library/Stripe/AttachedObject.php
@@ -0,0 +1,25 @@
+_values), array_keys($properties));
+ // Don't unset, but rather set to null so we send up '' for deletion.
+ foreach ($removed as $k) {
+ $this->$k = null;
+ }
+
+ foreach ($properties as $k => $v) {
+ $this->$k = $v;
+ }
+ }
+}
diff --git a/include/library/Stripe/Balance.php b/include/library/Stripe/Balance.php
new file mode 100755
index 000000000..d07231f6c
--- /dev/null
+++ b/include/library/Stripe/Balance.php
@@ -0,0 +1,16 @@
+_delete($params, $opts);
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return BitcoinReceiver The saved Bitcoin Receiver item.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+}
diff --git a/include/library/Stripe/BitcoinTransaction.php b/include/library/Stripe/BitcoinTransaction.php
new file mode 100755
index 000000000..a7414e3f8
--- /dev/null
+++ b/include/library/Stripe/BitcoinTransaction.php
@@ -0,0 +1,8 @@
+_delete($params, $opts);
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Card The saved card.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+}
diff --git a/include/library/Stripe/Charge.php b/include/library/Stripe/Charge.php
new file mode 100755
index 000000000..60d36151e
--- /dev/null
+++ b/include/library/Stripe/Charge.php
@@ -0,0 +1,132 @@
+_save($options);
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $options
+ *
+ * @return Charge The refunded charge.
+ */
+ public function refund($params = null, $options = null)
+ {
+ $url = $this->instanceUrl() . '/refund';
+ list($response, $opts) = $this->request('post', $url, $params, $options);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $options
+ *
+ * @return Charge The captured charge.
+ */
+ public function capture($params = null, $options = null)
+ {
+ $url = $this->instanceUrl() . '/capture';
+ list($response, $opts) = $this->_request('post', $url, $params, $options);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $options
+ *
+ * @return array The updated dispute.
+ */
+ public function updateDispute($params = null, $options = null)
+ {
+ $url = $this->instanceUrl() . '/dispute';
+ list($response, $opts) = $this->_request('post', $url, $params, $options);
+ $this->refreshFrom(array('dispute' => $response), $opts, true);
+ return $this->dispute;
+ }
+
+ /**
+ * @param array|string|null $options
+ *
+ * @return Charge The updated charge.
+ */
+ public function closeDispute($options = null)
+ {
+ $url = $this->instanceUrl() . '/dispute/close';
+ list($response, $opts) = $this->_request('post', $url, null, $options);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Charge The updated charge.
+ */
+ public function markAsFraudulent($opts = null)
+ {
+ $params = array('fraud_details' => array('user_report' => 'fraudulent'));
+ $url = $this->instanceUrl();
+ list($response, $opts) = $this->_request('post', $url, $params, $opts);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Charge The updated charge.
+ */
+ public function markAsSafe($opts = null)
+ {
+ $params = array('fraud_details' => array('user_report' => 'safe'));
+ $url = $this->instanceUrl();
+ list($response, $opts) = $this->_request('post', $url, $params, $opts);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+}
diff --git a/include/library/Stripe/Collection.php b/include/library/Stripe/Collection.php
new file mode 100755
index 000000000..a42771536
--- /dev/null
+++ b/include/library/Stripe/Collection.php
@@ -0,0 +1,56 @@
+extractPathAndUpdateParams($params);
+
+ list($response, $opts) = $this->_request('get', $url, $params, $opts);
+ return Util\Util::convertToStripeObject($response, $opts);
+ }
+
+ public function create($params = null, $opts = null)
+ {
+ list($url, $params) = $this->extractPathAndUpdateParams($params);
+
+ list($response, $opts) = $this->_request('post', $url, $params, $opts);
+ return Util\Util::convertToStripeObject($response, $opts);
+ }
+
+ public function retrieve($id, $params = null, $opts = null)
+ {
+ list($url, $params) = $this->extractPathAndUpdateParams($params);
+
+ $id = ApiRequestor::utf8($id);
+ $extn = urlencode($id);
+ list($response, $opts) = $this->_request(
+ 'get',
+ "$url/$extn",
+ $params,
+ $opts
+ );
+ return Util\Util::convertToStripeObject($response, $opts);
+ }
+
+ private function extractPathAndUpdateParams($params)
+ {
+ $url = parse_url($this->url);
+ if (!isset($url['path'])) {
+ throw new Error\Api("Could not parse list url into parts: $url");
+ }
+
+ if (isset($url['query'])) {
+ // If the URL contains a query param, parse it out into $params so they
+ // don't interact weirdly with each other.
+ $query = array();
+ parse_str($url['query'], $query);
+ // PHP 5.2 doesn't support the ?: operator :(
+ $params = array_merge($params ? $params : array(), $query);
+ }
+
+ return array($url['path'], $params);
+ }
+}
diff --git a/include/library/Stripe/Coupon.php b/include/library/Stripe/Coupon.php
new file mode 100755
index 000000000..eb2353ef8
--- /dev/null
+++ b/include/library/Stripe/Coupon.php
@@ -0,0 +1,60 @@
+_delete($params, $opts);
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Coupon The saved coupon.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $opts
+ *
+ * @return Coupon[]
+ */
+ public static function all($params = null, $opts = null)
+ {
+ return self::_all($params, $opts);
+ }
+}
diff --git a/include/library/Stripe/Customer.php b/include/library/Stripe/Customer.php
new file mode 100755
index 000000000..b759f4eb7
--- /dev/null
+++ b/include/library/Stripe/Customer.php
@@ -0,0 +1,158 @@
+_save($opts);
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $opts
+ *
+ * @return Customer The deleted customer.
+ */
+ public function delete($params = null, $opts = null)
+ {
+ return $this->_delete($params, $opts);
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return InvoiceItem The resulting invoice item.
+ */
+ public function addInvoiceItem($params = null)
+ {
+ if (!$params) {
+ $params = array();
+ }
+ $params['customer'] = $this->id;
+ $ii = InvoiceItem::create($params, $this->_opts);
+ return $ii;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return array An array of the customer's Invoices.
+ */
+ public function invoices($params = null)
+ {
+ if (!$params) {
+ $params = array();
+ }
+ $params['customer'] = $this->id;
+ $invoices = Invoice::all($params, $this->_opts);
+ return $invoices;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return array An array of the customer's InvoiceItems.
+ */
+ public function invoiceItems($params = null)
+ {
+ if (!$params) {
+ $params = array();
+ }
+ $params['customer'] = $this->id;
+ $iis = InvoiceItem::all($params, $this->_opts);
+ return $iis;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return array An array of the customer's Charges.
+ */
+ public function charges($params = null)
+ {
+ if (!$params) {
+ $params = array();
+ }
+ $params['customer'] = $this->id;
+ $charges = Charge::all($params, $this->_opts);
+ return $charges;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return Subscription The updated subscription.
+ */
+ public function updateSubscription($params = null)
+ {
+ $url = $this->instanceUrl() . '/subscription';
+ list($response, $opts) = $this->_request('post', $url, $params);
+ $this->refreshFrom(array('subscription' => $response), $opts, true);
+ return $this->subscription;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return Subscription The cancelled subscription.
+ */
+ public function cancelSubscription($params = null)
+ {
+ $url = $this->instanceUrl() . '/subscription';
+ list($response, $opts) = $this->_request('delete', $url, $params);
+ $this->refreshFrom(array('subscription' => $response), $opts, true);
+ return $this->subscription;
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return Customer The updated customer.
+ */
+ public function deleteDiscount()
+ {
+ $url = $this->instanceUrl() . '/discount';
+ list($response, $opts) = $this->_request('delete', $url);
+ $this->refreshFrom(array('discount' => null), $opts, true);
+ }
+}
diff --git a/include/library/Stripe/Error/Api.php b/include/library/Stripe/Error/Api.php
new file mode 100755
index 000000000..dc7d069ef
--- /dev/null
+++ b/include/library/Stripe/Error/Api.php
@@ -0,0 +1,7 @@
+httpStatus = $httpStatus;
+ $this->httpBody = $httpBody;
+ $this->jsonBody = $jsonBody;
+ }
+
+ public function getHttpStatus()
+ {
+ return $this->httpStatus;
+ }
+
+ public function getHttpBody()
+ {
+ return $this->httpBody;
+ }
+
+ public function getJsonBody()
+ {
+ return $this->jsonBody;
+ }
+}
diff --git a/include/library/Stripe/Error/Card.php b/include/library/Stripe/Error/Card.php
new file mode 100755
index 000000000..9f8ca2290
--- /dev/null
+++ b/include/library/Stripe/Error/Card.php
@@ -0,0 +1,19 @@
+param = $param;
+ $this->code = $code;
+ }
+}
diff --git a/include/library/Stripe/Error/InvalidRequest.php b/include/library/Stripe/Error/InvalidRequest.php
new file mode 100755
index 000000000..e29a70072
--- /dev/null
+++ b/include/library/Stripe/Error/InvalidRequest.php
@@ -0,0 +1,17 @@
+param = $param;
+ }
+}
diff --git a/include/library/Stripe/Error/RateLimit.php b/include/library/Stripe/Error/RateLimit.php
new file mode 100755
index 000000000..ebb055f55
--- /dev/null
+++ b/include/library/Stripe/Error/RateLimit.php
@@ -0,0 +1,16 @@
+_save($opts);
+ }
+
+ /**
+ * @return Invoice The paid invoice.
+ */
+ public function pay($opts = null)
+ {
+ $url = $this->instanceUrl() . '/pay';
+ list($response, $opts) = $this->_request('post', $url, null, $opts);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+}
diff --git a/include/library/Stripe/InvoiceItem.php b/include/library/Stripe/InvoiceItem.php
new file mode 100755
index 000000000..d1407b562
--- /dev/null
+++ b/include/library/Stripe/InvoiceItem.php
@@ -0,0 +1,60 @@
+_save($opts);
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $opts
+ *
+ * @return InvoiceItem The deleted invoice item.
+ */
+ public function delete($params = null, $opts = null)
+ {
+ return $this->_delete($params, $opts);
+ }
+}
diff --git a/include/library/Stripe/Object.php b/include/library/Stripe/Object.php
new file mode 100755
index 000000000..7c524c708
--- /dev/null
+++ b/include/library/Stripe/Object.php
@@ -0,0 +1,247 @@
+_opts = $opts ? $opts : new Util\RequestOptions();
+ $this->_values = array();
+ $this->_unsavedValues = new Util\Set();
+ $this->_transientValues = new Util\Set();
+
+ $this->_retrieveOptions = array();
+ if (is_array($id)) {
+ foreach ($id as $key => $value) {
+ if ($key != 'id') {
+ $this->_retrieveOptions[$key] = $value;
+ }
+ }
+ $id = $id['id'];
+ }
+
+ if ($id !== null) {
+ $this->id = $id;
+ }
+ }
+
+ // Standard accessor magic methods
+ public function __set($k, $v)
+ {
+ if ($v === "") {
+ throw new InvalidArgumentException(
+ 'You cannot set \''.$k.'\'to an empty string. '
+ .'We interpret empty strings as NULL in requests. '
+ .'You may set obj->'.$k.' = NULL to delete the property'
+ );
+ }
+
+ if (self::$nestedUpdatableAttributes->includes($k)
+ && isset($this->$k) && is_array($v)) {
+ $this->$k->replaceWith($v);
+ } else {
+ // TODO: may want to clear from $_transientValues (Won't be user-visible).
+ $this->_values[$k] = $v;
+ }
+ if (!self::$permanentAttributes->includes($k)) {
+ $this->_unsavedValues->add($k);
+ }
+ }
+
+ public function __isset($k)
+ {
+ return isset($this->_values[$k]);
+ }
+ public function __unset($k)
+ {
+ unset($this->_values[$k]);
+ $this->_transientValues->add($k);
+ $this->_unsavedValues->discard($k);
+ }
+ public function __get($k)
+ {
+ if (array_key_exists($k, $this->_values)) {
+ return $this->_values[$k];
+ } else if ($this->_transientValues->includes($k)) {
+ $class = get_class($this);
+ $attrs = join(', ', array_keys($this->_values));
+ $message = "Stripe Notice: Undefined property of $class instance: $k. "
+ . "HINT: The $k attribute was set in the past, however. "
+ . "It was then wiped when refreshing the object "
+ . "with the result returned by Stripe's API, "
+ . "probably as a result of a save(). The attributes currently "
+ . "available on this object are: $attrs";
+ error_log($message);
+ return null;
+ } else {
+ $class = get_class($this);
+ error_log("Stripe Notice: Undefined property of $class instance: $k");
+ return null;
+ }
+ }
+
+ // ArrayAccess methods
+ public function offsetSet($k, $v)
+ {
+ $this->$k = $v;
+ }
+
+ public function offsetExists($k)
+ {
+ return array_key_exists($k, $this->_values);
+ }
+
+ public function offsetUnset($k)
+ {
+ unset($this->$k);
+ }
+ public function offsetGet($k)
+ {
+ return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
+ }
+
+ public function keys()
+ {
+ return array_keys($this->_values);
+ }
+
+ /**
+ * This unfortunately needs to be public to be used in Util\Util
+ *
+ * @param array $values
+ * @param array $opts
+ *
+ * @return Object The object constructed from the given values.
+ */
+ public static function constructFrom($values, $opts)
+ {
+ $obj = new static(isset($values['id']) ? $values['id'] : null);
+ $obj->refreshFrom($values, $opts);
+ return $obj;
+ }
+
+ /**
+ * Refreshes this object using the provided values.
+ *
+ * @param array $values
+ * @param array $opts
+ * @param boolean $partial Defaults to false.
+ */
+ public function refreshFrom($values, $opts, $partial = false)
+ {
+ $this->_opts = $opts;
+
+ // Wipe old state before setting new. This is useful for e.g. updating a
+ // customer, where there is no persistent card parameter. Mark those values
+ // which don't persist as transient
+ if ($partial) {
+ $removed = new Util\Set();
+ } else {
+ $removed = array_diff(array_keys($this->_values), array_keys($values));
+ }
+
+ foreach ($removed as $k) {
+ if (self::$permanentAttributes->includes($k)) {
+ continue;
+ }
+
+ unset($this->$k);
+ }
+
+ foreach ($values as $k => $v) {
+ if (self::$permanentAttributes->includes($k) && isset($this[$k])) {
+ continue;
+ }
+
+ if (self::$nestedUpdatableAttributes->includes($k) && is_array($v)) {
+ $this->_values[$k] = AttachedObject::constructFrom($v, $opts);
+ } else {
+ $this->_values[$k] = Util\Util::convertToStripeObject($v, $opts);
+ }
+
+ $this->_transientValues->discard($k);
+ $this->_unsavedValues->discard($k);
+ }
+ }
+
+ /**
+ * @return array A recursive mapping of attributes to values for this object,
+ * including the proper value for deleted attributes.
+ */
+ public function serializeParameters()
+ {
+ $params = array();
+ if ($this->_unsavedValues) {
+ foreach ($this->_unsavedValues->toArray() as $k) {
+ $v = $this->$k;
+ if ($v === null) {
+ $v = '';
+ }
+
+ $params[$k] = $v;
+ }
+ }
+
+ // Get nested updates.
+ foreach (self::$nestedUpdatableAttributes->toArray() as $property) {
+ if (isset($this->$property) && $this->$property instanceof Object) {
+ $params[$property] = $this->$property->serializeParameters();
+ }
+ }
+
+ return $params;
+ }
+
+ public function __toJSON()
+ {
+ if (defined('JSON_PRETTY_PRINT')) {
+ return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
+ } else {
+ return json_encode($this->__toArray(true));
+ }
+ }
+
+ public function __toString()
+ {
+ $class = get_class($this);
+ return $class . ' JSON: ' . $this->__toJSON();
+ }
+
+ public function __toArray($recursive = false)
+ {
+ if ($recursive) {
+ return Util\Util::convertStripeObjectToArray($this->_values);
+ } else {
+ return $this->_values;
+ }
+ }
+}
+
+Object::init();
diff --git a/include/library/Stripe/Plan.php b/include/library/Stripe/Plan.php
new file mode 100755
index 000000000..12342d4e6
--- /dev/null
+++ b/include/library/Stripe/Plan.php
@@ -0,0 +1,60 @@
+_delete($params, $opts);
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Plan The saved plan.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+
+ /**
+ * @param array|null $params
+ * @param array|string|null $opts
+ *
+ * @return Plan[]
+ */
+ public static function all($params = null, $opts = null)
+ {
+ return self::_all($params, $opts);
+ }
+}
diff --git a/include/library/Stripe/Recipient.php b/include/library/Stripe/Recipient.php
new file mode 100755
index 000000000..cdb785cd8
--- /dev/null
+++ b/include/library/Stripe/Recipient.php
@@ -0,0 +1,75 @@
+_save($opts);
+ }
+
+ /**
+ * @param array|null $params
+ *
+ * @return Recipient The deleted recipient.
+ */
+ public function delete($params = null, $opts = null)
+ {
+ return $this->_delete($params, $opts);
+ }
+
+
+ /**
+ * @param array|null $params
+ *
+ * @return array An array of the recipient's Transfers.
+ */
+ public function transfers($params = null)
+ {
+ if ($params === null) {
+ $params = array();
+ }
+ $params['recipient'] = $this->id;
+ $transfers = Transfer::all($params, $this->_opts);
+ return $transfers;
+ }
+}
diff --git a/include/library/Stripe/Refund.php b/include/library/Stripe/Refund.php
new file mode 100755
index 000000000..d0a01aa19
--- /dev/null
+++ b/include/library/Stripe/Refund.php
@@ -0,0 +1,39 @@
+_save($opts);
+ }
+}
diff --git a/include/library/Stripe/SingletonApiResource.php b/include/library/Stripe/SingletonApiResource.php
new file mode 100755
index 000000000..6dd7910bf
--- /dev/null
+++ b/include/library/Stripe/SingletonApiResource.php
@@ -0,0 +1,31 @@
+refresh();
+ return $instance;
+ }
+
+ /**
+ * @return string The endpoint associated with this singleton class.
+ */
+ public static function classUrl()
+ {
+ $base = static::className();
+ return "/v1/${base}";
+ }
+
+ /**
+ * @return string The endpoint associated with this singleton API resource.
+ */
+ public function instanceUrl()
+ {
+ return static::classUrl();
+ }
+}
diff --git a/include/library/Stripe/Stripe.php b/include/library/Stripe/Stripe.php
new file mode 100755
index 000000000..68e6346ea
--- /dev/null
+++ b/include/library/Stripe/Stripe.php
@@ -0,0 +1,74 @@
+_delete($params, $opts);
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Subscription The saved subscription.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+
+ /**
+ * @return Subscription The updated subscription.
+ */
+ public function deleteDiscount()
+ {
+ $url = $this->instanceUrl() . '/discount';
+ list($response, $opts) = $this->_request('delete', $url);
+ $this->refreshFrom(array('discount' => null), $opts, true);
+ }
+}
diff --git a/include/library/Stripe/Token.php b/include/library/Stripe/Token.php
new file mode 100755
index 000000000..432e22bd8
--- /dev/null
+++ b/include/library/Stripe/Token.php
@@ -0,0 +1,28 @@
+instanceUrl() . '/reversals';
+ list($response, $opts) = $this->request('post', $url, $params, $options);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @return Transfer The canceled transfer.
+ */
+ public function cancel()
+ {
+ $url = $this->instanceUrl() . '/cancel';
+ list($response, $opts) = $this->_request('post', $url);
+ $this->refreshFrom($response, $opts);
+ return $this;
+ }
+
+ /**
+ * @param array|string|null $opts
+ *
+ * @return Transfer The saved transfer.
+ */
+ public function save($opts = null)
+ {
+ return $this->_save($opts);
+ }
+}
diff --git a/include/library/Stripe/TransferReversal.php b/include/library/Stripe/TransferReversal.php
new file mode 100755
index 000000000..28fb776c7
--- /dev/null
+++ b/include/library/Stripe/TransferReversal.php
@@ -0,0 +1,39 @@
+_save($opts);
+ }
+}
diff --git a/include/library/Stripe/Util/RequestOptions.php b/include/library/Stripe/Util/RequestOptions.php
new file mode 100755
index 000000000..14af2b8a0
--- /dev/null
+++ b/include/library/Stripe/Util/RequestOptions.php
@@ -0,0 +1,79 @@
+apiKey = $key;
+ $this->headers = $headers;
+ }
+
+ /**
+ * Unpacks an options array and merges it into the existing RequestOptions
+ * object.
+ * @param array|string|null $options a key => value array
+ *
+ * @return RequestOptions
+ */
+ public function merge($options)
+ {
+ $other_options = self::parse($options);
+ if ($other_options->apiKey === null) {
+ $other_options->apiKey = $this->apiKey;
+ }
+ $other_options->headers = array_merge($this->headers, $other_options->headers);
+ return $other_options;
+ }
+
+ /**
+ * Unpacks an options array into an RequestOptions object
+ * @param array|string|null $options a key => value array
+ *
+ * @return RequestOptions
+ */
+ public static function parse($options)
+ {
+ if ($options instanceof self) {
+ return $options;
+ }
+
+ if (is_null($options)) {
+ return new RequestOptions(null, array());
+ }
+
+ if (is_string($options)) {
+ return new RequestOptions($options, array());
+ }
+
+ if (is_array($options)) {
+ $headers = array();
+ $key = null;
+ if (array_key_exists('api_key', $options)) {
+ $key = $options['api_key'];
+ }
+ if (array_key_exists('idempotency_key', $options)) {
+ $headers['Idempotency-Key'] = $options['idempotency_key'];
+ }
+ if (array_key_exists('stripe_account', $options)) {
+ $headers['Stripe-Account'] = $options['stripe_account'];
+ }
+ if (array_key_exists('stripe_version', $options)) {
+ $headers['Stripe-Version'] = $options['stripe_version'];
+ }
+ return new RequestOptions($key, $headers);
+ }
+
+ $message = 'The second argument to Stripe API method calls is an '
+ . 'optional per-request apiKey, which must be a string, or '
+ . 'per-request options, which must be an array. (HINT: you can set '
+ . 'a global apiKey by "Stripe::setApiKey()")';
+ throw new Error\Api($message);
+ }
+}
diff --git a/include/library/Stripe/Util/Set.php b/include/library/Stripe/Util/Set.php
new file mode 100755
index 000000000..2a500cd63
--- /dev/null
+++ b/include/library/Stripe/Util/Set.php
@@ -0,0 +1,44 @@
+_elts = array();
+ foreach ($members as $item) {
+ $this->_elts[$item] = true;
+ }
+ }
+
+ public function includes($elt)
+ {
+ return isset($this->_elts[$elt]);
+ }
+
+ public function add($elt)
+ {
+ $this->_elts[$elt] = true;
+ }
+
+ public function discard($elt)
+ {
+ unset($this->_elts[$elt]);
+ }
+
+ public function toArray()
+ {
+ return array_keys($this->_elts);
+ }
+
+ public function getIterator()
+ {
+ return new ArrayIterator($this->toArray());
+ }
+}
diff --git a/include/library/Stripe/Util/Util.php b/include/library/Stripe/Util/Util.php
new file mode 100755
index 000000000..d52798a66
--- /dev/null
+++ b/include/library/Stripe/Util/Util.php
@@ -0,0 +1,102 @@
+ $v) {
+ // FIXME: this is an encapsulation violation
+ if ($k[0] == '_') {
+ continue;
+ }
+ if ($v instanceof Object) {
+ $results[$k] = $v->__toArray(true);
+ } elseif (is_array($v)) {
+ $results[$k] = self::convertStripeObjectToArray($v);
+ } else {
+ $results[$k] = $v;
+ }
+ }
+ return $results;
+ }
+
+ /**
+ * Converts a response from the Stripe API to the corresponding PHP object.
+ *
+ * @param array $resp The response from the Stripe API.
+ * @param array $opts
+ * @return Object|array
+ */
+ public static function convertToStripeObject($resp, $opts)
+ {
+ $types = array(
+ 'account' => 'Stripe\\Account',
+ 'card' => 'Stripe\\Card',
+ 'charge' => 'Stripe\\Charge',
+ 'coupon' => 'Stripe\\Coupon',
+ 'customer' => 'Stripe\\Customer',
+ 'list' => 'Stripe\\Collection',
+ 'invoice' => 'Stripe\\Invoice',
+ 'invoiceitem' => 'Stripe\\InvoiceItem',
+ 'event' => 'Stripe\\Event',
+ 'file' => 'Stripe\\FileUpload',
+ 'token' => 'Stripe\\Token',
+ 'transfer' => 'Stripe\\Transfer',
+ 'plan' => 'Stripe\\Plan',
+ 'recipient' => 'Stripe\\Recipient',
+ 'refund' => 'Stripe\\Refund',
+ 'subscription' => 'Stripe\\Subscription',
+ 'fee_refund' => 'Stripe\\ApplicationFeeRefund',
+ 'bitcoin_receiver' => 'Stripe\\BitcoinReceiver',
+ 'bitcoin_transaction' => 'Stripe\\BitcoinTransaction',
+ );
+ if (self::isList($resp)) {
+ $mapped = array();
+ foreach ($resp as $i) {
+ array_push($mapped, self::convertToStripeObject($i, $opts));
+ }
+ return $mapped;
+ } elseif (is_array($resp)) {
+ if (isset($resp['object']) && is_string($resp['object']) && isset($types[$resp['object']])) {
+ $class = $types[$resp['object']];
+ } else {
+ $class = 'Stripe\\Object';
+ }
+ return $class::constructFrom($resp, $opts);
+ } else {
+ return $resp;
+ }
+ }
+}
diff --git a/www/assets/js/tokenizeCard.js b/www/assets/js/tokenizeCard.js
index c3a296286..a09255e54 100644
--- a/www/assets/js/tokenizeCard.js
+++ b/www/assets/js/tokenizeCard.js
@@ -3,34 +3,33 @@ console.log('App.tokenizeCard');
var processor = ( App.config.processor && App.config.processor.type ) ? App.config.processor.type : false;
console.debug('Processor: ', processor);
- var legacy_card = {
- card_number: card.number,
- expiration_month: card.expiration_month,
- expiration_year: card.expiration_year,
- security_code: null
- };
-
- if (App.isPhoneGap) {
- //card = legacy_card;
- }
-
switch(processor) {
case 'stripe':
- App.tokenizeCard_stripe( legacy_card, complete );
+ App.tokenizeCard_stripe( card, complete );
break;
case 'balanced':
App.tokenizeCard_balanced( card, complete );
- break;
+ break;
default:
+ App.alert('There was an error communicating with our payment processor.');
console.log( 'Processor error::', App.config.processor );
- break;
+ break;
}
};
App.tokenizeCard_stripe = function( card, complete ) {
- var res = { status: false };
- var card = { number: card.card_number, exp_month: card.expiration_month, exp_year: card.expiration_year };
+ var res = {
+ status: false
+ };
+
+ var card = {
+ number: card.number,
+ exp_month: card.expiration_month,
+ exp_year: card.expiration_year
+ };
+
Stripe.card.createToken( card , function( status, response ){
+ console.debug('Recieved response from stripe: ', status, response);
if ( response.error ) {
switch( response.error.code ){
case 'incorrect_number':
@@ -70,7 +69,7 @@ App.tokenizeCard_stripe = function( card, complete ) {
id : response.card.id,
uri: response.id,
lastfour: response.card.last4,
- card_type: response.card.type,
+ card_type: response.card.brand.toLowerCase(),
month: response.card.exp_month,
year: response.card.exp_year,
status : true