diff --git a/stripejs/config.xml b/stripejs/config.xml index 031eacd..ea5f1c3 100644 --- a/stripejs/config.xml +++ b/stripejs/config.xml @@ -2,9 +2,9 @@ stripejs - + - + Warning: all the Stripe customers credit cards and transaction details saved in your database will be deleted. Are you sure you want uninstall this module? 1 diff --git a/stripejs/lib/Stripe.php b/stripejs/lib/Stripe.php index 6a9de16..8a9f589 100644 --- a/stripejs/lib/Stripe.php +++ b/stripejs/lib/Stripe.php @@ -1,19 +1,22 @@ id; + return self::utf8($d->id); } else if ($d === true) { return 'true'; } else if ($d === false) { @@ -34,16 +34,36 @@ private static function _encodeObjects($d) } else if (is_array($d)) { $res = array(); foreach ($d as $k => $v) - $res[$k] = self::_encodeObjects($v); + $res[$k] = self::_encodeObjects($v); return $res; } else { - return $d; + return self::utf8($d); } } - public static function encode($d) + public static function encode($arr, $prefix=null) { - return http_build_query($d, 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."]"; + else if ($prefix) + $k = $prefix."[]"; + + if (is_array($v)) { + $r[] = self::encode($v, $k, true); + } else { + $r[] = urlencode($k)."=".urlencode($v); + } + } + + return implode("&", $r); } public function request($meth, $url, $params=null) @@ -96,9 +116,10 @@ private function _requestRaw($meth, $url, $params) 'publisher' => 'stripe', 'uname' => $uname); $headers = array('X-Stripe-Client-User-Agent: ' . Tools::jsonEncode($ua), /* PrestaShop */ - 'X-Stripe-Application: ca_0ZCKiqjiWpOYdxqHZPKaKQlRDnNPhd9P', - 'User-Agent: Stripe/v1 PhpBindings/' . Stripe::VERSION, - 'Authorization: Bearer ' . $myApiKey); + 'User-Agent: Stripe/v1 PhpBindings/' . Stripe::VERSION, + 'Authorization: Bearer ' . $myApiKey); + if (Stripe::$apiVersion) + $headers[] = 'Stripe-Version: ' . Stripe::$apiVersion; list($rbody, $rcode) = $this->_curlRequest($meth, $absUrl, $headers, $params); return array($rbody, $rcode, $myApiKey); } @@ -106,12 +127,7 @@ private function _requestRaw($meth, $url, $params) private function _interpretResponse($rbody, $rcode) { try { - $rbody = trim($rbody, '"'); - $rbody = str_replace('\n', '', $rbody); - $rbody = str_replace("\n", '', $rbody); - $rbody = str_replace("\\", '', $rbody); - - $resp = json_decode($rbody, true); /* PrestaShop */ + $resp = json_decode($rbody, true); } catch (Exception $e) { throw new Stripe_ApiError("Invalid response body from API: $rbody (HTTP response code was $rcode)", $rcode, $rbody); } diff --git a/stripejs/lib/Stripe/ApiResource.php b/stripejs/lib/Stripe/ApiResource.php index 7781f9d..6f0af57 100644 --- a/stripejs/lib/Stripe/ApiResource.php +++ b/stripejs/lib/Stripe/ApiResource.php @@ -13,7 +13,8 @@ public function refresh() { $requestor = new Stripe_ApiRequestor($this->_apiKey); $url = $this->instanceUrl(); - list($response, $apiKey) = $requestor->request('get', $url); + + list($response, $apiKey) = $requestor->request('get', $url, $this->_retrieveOptions); $this->refreshFrom($response, $apiKey); return $this; } @@ -33,8 +34,8 @@ public static function className($class) public static function classUrl($class) { - $base = self::className($class); - return "/${base}s"; + $base = self::_scopedLsb($class, 'className', $class); + return "/v1/${base}s"; } public function instanceUrl() @@ -45,7 +46,7 @@ public function instanceUrl() throw new Stripe_InvalidRequestError("Could not determine which URL to request: $class instance has invalid ID: $id", null); } $id = Stripe_ApiRequestor::utf8($id); - $base = self::classUrl($class); + $base = $this->_lsb('classUrl', $class); $extn = urlencode($id); return "$base/$extn"; } @@ -62,7 +63,7 @@ protected static function _scopedAll($class, $params=null, $apiKey=null) { self::_validateCall('all', $params, $apiKey); $requestor = new Stripe_ApiRequestor($apiKey); - $url = self::classUrl($class); + $url = self::_scopedLsb($class, 'classUrl', $class); list($response, $apiKey) = $requestor->request('get', $url, $params); return Stripe_Util::convertToStripeObject($response, $apiKey); } @@ -71,7 +72,7 @@ protected static function _scopedCreate($class, $params=null, $apiKey=null) { self::_validateCall('create', $params, $apiKey); $requestor = new Stripe_ApiRequestor($apiKey); - $url = self::classUrl($class); + $url = self::_scopedLsb($class, 'classUrl', $class); list($response, $apiKey) = $requestor->request('post', $url, $params); return Stripe_Util::convertToStripeObject($response, $apiKey); } @@ -79,11 +80,10 @@ protected static function _scopedCreate($class, $params=null, $apiKey=null) protected function _scopedSave($class) { self::_validateCall('save'); - if ($this->_unsavedValues) { - $requestor = new Stripe_ApiRequestor($this->_apiKey); - $params = array(); - foreach ($this->_unsavedValues->toArray() as $k) - $params[$k] = $this->$k; + $requestor = new Stripe_ApiRequestor($this->_apiKey); + $params = $this->serializeParameters(); + + if (count($params) > 0) { $url = $this->instanceUrl(); list($response, $apiKey) = $requestor->request('post', $url, $params); $this->refreshFrom($response, $apiKey); diff --git a/stripejs/lib/Stripe/ApplicationFee.php b/stripejs/lib/Stripe/ApplicationFee.php new file mode 100644 index 0000000..79a76fb --- /dev/null +++ b/stripejs/lib/Stripe/ApplicationFee.php @@ -0,0 +1,36 @@ +_apiKey); + $url = $this->instanceUrl() . '/refund'; + list($response, $apiKey) = $requestor->request('post', $url, $params); + $this->refreshFrom($response, $apiKey); + return $this; + } +} diff --git a/stripejs/lib/Stripe/AttachedObject.php b/stripejs/lib/Stripe/AttachedObject.php new file mode 100644 index 0000000..81d8381 --- /dev/null +++ b/stripejs/lib/Stripe/AttachedObject.php @@ -0,0 +1,17 @@ +_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/stripejs/lib/Stripe/Balance.php b/stripejs/lib/Stripe/Balance.php new file mode 100644 index 0000000..93e0552 --- /dev/null +++ b/stripejs/lib/Stripe/Balance.php @@ -0,0 +1,16 @@ +_apiKey); @@ -43,4 +49,22 @@ public function capture($params=null) $this->refreshFrom($response, $apiKey); return $this; } + + public function updateDispute($params=null) + { + $requestor = new Stripe_ApiRequestor($this->_apiKey); + $url = $this->instanceUrl() . '/dispute'; + list($response, $apiKey) = $requestor->request('post', $url, $params); + $this->refreshFrom(array('dispute' => $response), $apiKey, true); + return $this->dispute; + } + + public function closeDispute() + { + $requestor = new Stripe_ApiRequestor($this->_apiKey); + $url = $this->instanceUrl() . '/dispute/close'; + list($response, $apiKey) = $requestor->request('post', $url); + $this->refreshFrom($response, $apiKey); + return $this; + } } diff --git a/stripejs/lib/Stripe/Invoice.php b/stripejs/lib/Stripe/Invoice.php index cc581b0..458643e 100644 --- a/stripejs/lib/Stripe/Invoice.php +++ b/stripejs/lib/Stripe/Invoice.php @@ -8,6 +8,12 @@ public static function constructFrom($values, $apiKey=null) return self::scopedConstructFrom($class, $values, $apiKey); } + public static function create($params=null, $apiKey=null) + { + $class = get_class(); + return self::_scopedCreate($class, $params, $apiKey); + } + public static function retrieve($id, $apiKey=null) { $class = get_class(); diff --git a/stripejs/lib/Stripe/List.php b/stripejs/lib/Stripe/List.php new file mode 100644 index 0000000..a9bbe08 --- /dev/null +++ b/stripejs/lib/Stripe/List.php @@ -0,0 +1,35 @@ +_apiKey); + list($response, $apiKey) = $requestor->request('get', $this['url'], $params); + return Stripe_Util::convertToStripeObject($response, $apiKey); + } + + public function create($params=null) + { + $requestor = new Stripe_ApiRequestor($this->_apiKey); + list($response, $apiKey) = $requestor->request('post', $this['url'], $params); + return Stripe_Util::convertToStripeObject($response, $apiKey); + } + + public function retrieve($id, $params=null) + { + $requestor = new Stripe_ApiRequestor($this->_apiKey); + $base = $this['url']; + $id = Stripe_ApiRequestor::utf8($id); + $extn = urlencode($id); + list($response, $apiKey) = $requestor->request('get', "$base/$extn", $params); + return Stripe_Util::convertToStripeObject($response, $apiKey); + } + +} diff --git a/stripejs/lib/Stripe/Object.php b/stripejs/lib/Stripe/Object.php index 949174b..32acc25 100644 --- a/stripejs/lib/Stripe/Object.php +++ b/stripejs/lib/Stripe/Object.php @@ -3,16 +3,19 @@ class Stripe_Object implements ArrayAccess { public static $_permanentAttributes; + public static $_nestedUpdatableAttributes; public static function init() { - self::$_permanentAttributes = new Stripe_Util_Set(array('_apiKey')); + self::$_permanentAttributes = new Stripe_Util_Set(array('_apiKey', 'id')); + self::$_nestedUpdatableAttributes = new Stripe_Util_Set(array('metadata')); } protected $_apiKey; protected $_values; protected $_unsavedValues; protected $_transientValues; + protected $_retrieveOptions; public function __construct($id=null, $apiKey=null) { @@ -20,6 +23,16 @@ public function __construct($id=null, $apiKey=null) $this->_values = array(); $this->_unsavedValues = new Stripe_Util_Set(); $this->_transientValues = new Stripe_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) $this->id = $id; } @@ -27,8 +40,19 @@ public function __construct($id=null, $apiKey=null) // Standard accessor magic methods public function __set($k, $v) { - // TODO: may want to clear from $_transientValues. (Won't be user-visible.) - $this->_values[$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); } @@ -44,7 +68,7 @@ public function __unset($k) } public function __get($k) { - if (isset($this->_values[$k])) { + if (array_key_exists($k, $this->_values)) { return $this->_values[$k]; } else if ($this->_transientValues->includes($k)) { $class = get_class($this); @@ -63,17 +87,24 @@ public function offsetSet($k, $v) { $this->$k = $v; } + public function offsetExists($k) { - return isset($this->$k); + return array_key_exists($k, $this->_values); } + public function offsetUnset($k) { unset($this->$k); } public function offsetGet($k) { - return isset($this->_values[$k]) ? $this->_values[$k] : null; + 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.php @@ -93,6 +124,7 @@ public static function constructFrom($values, $apiKey=null) public function refreshFrom($values, $apiKey, $partial=false) { $this->_apiKey = $apiKey; + // 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 @@ -110,15 +142,55 @@ public function refreshFrom($values, $apiKey, $partial=false) foreach ($values as $k => $v) { if (self::$_permanentAttributes->includes($k)) continue; - $this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey); + + if (self::$_nestedUpdatableAttributes->includes($k) && is_array($v)) + $this->_values[$k] = Stripe_Object::scopedConstructFrom('Stripe_AttachedObject', $v, $apiKey); + else + $this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey); + $this->_transientValues->discard($k); $this->_unsavedValues->discard($k); } } + 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 Stripe_Object) { + $params[$property] = $this->$property->serializeParameters(); + } + } + return $params; + } + + // Pretend to have late static bindings, even in PHP 5.2 + protected function _lsb($method) + { + $class = get_class($this); + $args = array_slice(func_get_args(), 1); + return call_user_func_array(array($class, $method), $args); + } + protected static function _scopedLsb($class, $method) + { + $args = array_slice(func_get_args(), 2); + return call_user_func_array(array($class, $method), $args); + } + public function __toJSON() { - return Tools::jsonEncode($this->__toArray(true)); /* PrestaShop */ + return Tools::jsonEncode($this->__toArray(true)); /* PrestaShop */ } public function __toString() diff --git a/stripejs/lib/Stripe/Recipient.php b/stripejs/lib/Stripe/Recipient.php new file mode 100644 index 0000000..98a5149 --- /dev/null +++ b/stripejs/lib/Stripe/Recipient.php @@ -0,0 +1,50 @@ +id; + $transfers = Stripe_Transfer::all($params, $this->_apiKey); + return $transfers; + } +} diff --git a/stripejs/lib/Stripe/SingletonApiResource.php b/stripejs/lib/Stripe/SingletonApiResource.php index 40d317e..84d8c8b 100644 --- a/stripejs/lib/Stripe/SingletonApiResource.php +++ b/stripejs/lib/Stripe/SingletonApiResource.php @@ -12,7 +12,7 @@ protected static function _scopedSingletonRetrieve($class, $apiKey=null) public static function classUrl($class) { $base = self::className($class); - return "/${base}"; + return "/v1/${base}"; } public function instanceUrl() diff --git a/stripejs/lib/Stripe/Stripe.php b/stripejs/lib/Stripe/Stripe.php new file mode 100644 index 0000000..a0c5a4e --- /dev/null +++ b/stripejs/lib/Stripe/Stripe.php @@ -0,0 +1,38 @@ +_apiKey); + $url = $this->instanceUrl() . '/discount'; + list($response, $apiKey) = $requestor->request('delete', $url); + $this->refreshFrom(array('discount' => null), $apiKey, true); + } +} diff --git a/stripejs/lib/Stripe/Transfer.php b/stripejs/lib/Stripe/Transfer.php index ece862a..f3b7773 100644 --- a/stripejs/lib/Stripe/Transfer.php +++ b/stripejs/lib/Stripe/Transfer.php @@ -20,11 +20,16 @@ public static function all($params=null, $apiKey=null) return self::_scopedAll($class, $params, $apiKey); } - public function transactions($params=null) + public static function create($params=null, $apiKey=null) { - $requestor = new Stripe_ApiRequestor($this->_apiKey); - $url = $this->instanceUrl() . '/transactions'; - list($response, $apiKey) = $requestor->request('get', $url, $params); - return Stripe_Util::convertToStripeObject($response, $apiKey); + $class = get_class(); + return self::_scopedCreate($class, $params, $apiKey); + } + + public function save() + { + $class = get_class(); + return self::_scopedSave($class); } + } diff --git a/stripejs/lib/Stripe/Util.php b/stripejs/lib/Stripe/Util.php index e032606..8687dae 100644 --- a/stripejs/lib/Stripe/Util.php +++ b/stripejs/lib/Stripe/Util.php @@ -6,6 +6,7 @@ public static function isList($array) { if (!is_array($array)) return false; + // TODO: this isn't actually correct in general, but it's correct given Stripe's responses foreach (array_keys($array) as $k) { if (!is_numeric($k)) @@ -19,7 +20,7 @@ public static function convertStripeObjectToArray($values) $results = array(); foreach ($values as $k => $v) { // FIXME: this is an encapsulation violation - if (Stripe_Object::$_permanentAttributes->includes($k)) { + if ($k[0] == '_') { continue; } if ($v instanceof Stripe_Object) { @@ -37,11 +38,19 @@ public static function convertStripeObjectToArray($values) public static function convertToStripeObject($resp, $apiKey) { - $types = array('charge' => 'Stripe_Charge', - 'customer' => 'Stripe_Customer', - 'invoice' => 'Stripe_Invoice', - 'invoiceitem' => 'Stripe_InvoiceItem', 'event' => 'Stripe_Event', - 'transfer' => 'Stripe_Transfer'); + $types = array( + 'card' => 'Stripe_Card', + 'charge' => 'Stripe_Charge', + 'customer' => 'Stripe_Customer', + 'list' => 'Stripe_List', + 'invoice' => 'Stripe_Invoice', + 'invoiceitem' => 'Stripe_InvoiceItem', + 'event' => 'Stripe_Event', + 'transfer' => 'Stripe_Transfer', + 'plan' => 'Stripe_Plan', + 'recipient' => 'Stripe_Recipient', + 'subscription' => 'Stripe_Subscription' + ); if (self::isList($resp)) { $mapped = array(); foreach ($resp as $i) diff --git a/stripejs/stripejs.php b/stripejs/stripejs.php index 636eadc..9fd7120 100644 --- a/stripejs/stripejs.php +++ b/stripejs/stripejs.php @@ -12,17 +12,12 @@ * obtain it through the world-wide-web, please send an email * to license@prestashop.com so we can send you a copy immediately. * -* DISCLAIMER -* -* Do not edit or add to this file if you wish to upgrade PrestaShop to newer -* versions in the future. If you wish to customize PrestaShop for your -* needs please refer to http://www.prestashop.com for more information. -* * @author PrestaShop SA * @copyright 2007-2013 PrestaShop SA * @version Release: $Revision: 7040 $ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA +* Further Updates by @olliemcfarlane */ if (!defined('_PS_VERSION_')) @@ -38,8 +33,8 @@ public function __construct() { $this->name = 'stripejs'; $this->tab = 'payments_gateways'; - $this->version = '0.9.7'; - $this->author = 'PrestaShop'; + $this->version = '0.9.8'; + $this->author = 'PrestaShop + Ollie'; $this->need_instance = 0; parent::__construct();