diff --git a/bootstrap.php b/bootstrap.php index cdc5242..c723cc3 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -8,6 +8,13 @@ use \Finix\Settings; use \Finix\Bootstrap; +$processing_url = getenv("PROCESSING_URL"); +if ($processing_url == null) { + $processing_url = "https://api-staging.finix.io/"; +} + +Fixtures::$apiUrl = $processing_url; + Settings::configure([ "root_url" => Fixtures::$apiUrl ]); diff --git a/composer.json b/composer.json index 91512ac..423aa78 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "finix/processing-php", - "version": "1.0.3", + "version": "1.0.4", "description": "A PHP HTTP Client conforming to the HAL hypermedia type for the Finix processing API", "license": "Apache2", "authors": [ diff --git a/src/Finix/Bootstrap.php b/src/Finix/Bootstrap.php index 4d979b8..33ac528 100644 --- a/src/Finix/Bootstrap.php +++ b/src/Finix/Bootstrap.php @@ -66,6 +66,8 @@ private static function initializeResources() Resources\Processor::init(); Resources\Merchant::init(); Resources\PaymentInstrument::init(); + Resources\PaymentCard::init(); + Resources\BankAccount::init(); Resources\Authorization::init(); Resources\Transfer::init(); Resources\Reversal::init(); @@ -75,6 +77,7 @@ private static function initializeResources() Resources\Verification::init(); Resources\Evidence::init(); Resources\Token::init(); + Resources\InstrumentUpdate::init(); self::$initialized = true; } diff --git a/src/Finix/Hal/HrefSpec.php b/src/Finix/Hal/HrefSpec.php index 289c2e5..04d613f 100644 --- a/src/Finix/Hal/HrefSpec.php +++ b/src/Finix/Hal/HrefSpec.php @@ -30,36 +30,4 @@ public function __construct($name, $idNames, $root = null, $override = null) } } } - - public function match($uri) - { - $parts = explode('/', rtrim($uri, "/")); - - // collection - if ($parts[count($parts) - 1] == $this->name) { - - return array( - 'collection' => true, - ); - } - - // non-member - if (count($parts) < count($this->idNames) + 1 || - $parts[count($parts) - 1 - count($this->idNames)] != $this->name - ) { - return null; - } - - // member - $ids = array_combine( - $this->idNames, - array_slice($parts, -count($this->idNames)) - ); - $result = array( - 'collection' => false, - 'ids' => $ids, - ); - - return $result; - } } diff --git a/src/Finix/Hal/Resource.php b/src/Finix/Hal/Resource.php index d2f12a7..6a65e37 100644 --- a/src/Finix/Hal/Resource.php +++ b/src/Finix/Hal/Resource.php @@ -92,6 +92,11 @@ public function getLink($rel) return $link; } + public function hasRel($rel) + { + return self::findByRel($this->links, $rel) != null; + } + /** * Finds an array of links by their relation type. * Note that there is no guarantees as to the order of the links. diff --git a/src/Finix/Pagination.php b/src/Finix/Pagination.php index f0af7b3..ed4b2f0 100644 --- a/src/Finix/Pagination.php +++ b/src/Finix/Pagination.php @@ -2,9 +2,12 @@ namespace Finix; +use Finix\Http\Request; +use Iterator; -class Pagination extends Resource +class Pagination extends Resource implements Iterator { + private $resourceClass; public function __construct(Hal\Resource $halResource, $class) { @@ -16,5 +19,40 @@ public function __construct(Hal\Resource $halResource, $class) array_push($items, new $class($resource->getState(), $resource->getAllLinks())); } $this->state->items = $items; + $this->resourceClass = $class; + } + + public function current() + { + return $this->state->items; + } + + public function next() + { + if (!$this->resource->hasRel("next")) { + $this->state->items = array(); + $page = $this->state->page; + $page["offset"] = $page["count"]; + $this->page = $page; + return; + } + $link = $this->resource->getLink('next')->getHref(); + $halResource = $this->client->sendRequest(new Request($link)); + $this->__construct($halResource, $this->resourceClass); + } + + public function key() + { + return $this->page["offset"]; + } + + public function valid() + { + return $this->page["offset"] < $this->page["count"]; + } + + public function rewind() + { + // TODO: Implement rewind() method. } } diff --git a/src/Finix/Resource.php b/src/Finix/Resource.php index ed6ca32..f3dbf40 100644 --- a/src/Finix/Resource.php +++ b/src/Finix/Resource.php @@ -10,14 +10,10 @@ abstract class Resource { - /** @var Hal\Resource $resource */ protected $resource; - /** @var ArrayProxy $state */ protected $state; - - protected static $href; protected $client; -// protected static $client; + protected static $href; protected static $registry; /** @@ -105,18 +101,29 @@ public function __isset($name) * @throws Hal\Exception\HalRedirectionException * @throws Hal\Exception\HalServerErrorException */ - public static function retrieve($id) + public static function retrieve($id_or_url) { - $uri = self::getHrefSpec()->collection_uri . '/' . $id; + + $uri = filter_var($id_or_url, FILTER_VALIDATE_URL) || (strpos($id_or_url, '/') !== false) ? + $id_or_url : self::getHrefSpec()->collection_uri . '/' . $id_or_url; $resource = Bootstrap::createClient()->sendRequest(new Request($uri)); $class = get_called_class(); - return new $class($resource->getState(), $resource->getAllLinks()); + $state = $resource->getState(); + if (sizeof($resource->getAllEmbeddedResources()) > 0) { + $items = $resource->getAllEmbeddedResources(); + $items = reset($items); + if (sizeof($items) == 1) { + $state = $items[0]->getState(); + } + } + return new $class($state, $resource->getAllLinks()); } - public static function getPagination($href) + public static function getPagination($resource) { - $resource = Bootstrap::createClient()->sendRequest(new Request($href)); - return new Pagination($resource, get_called_class()); + $cls = get_called_class(); + $halResource = Bootstrap::createClient()->sendRequest(new Request($resource->getHref($cls::getHrefSpec()->name))); + return new Pagination($halResource, $cls); } public function refresh() diff --git a/src/Finix/Resources/Authorization.php b/src/Finix/Resources/Authorization.php index ea29b91..d34a948 100644 --- a/src/Finix/Resources/Authorization.php +++ b/src/Finix/Resources/Authorization.php @@ -11,14 +11,15 @@ public static function init() self::getRegistry()->add(get_called_class(), new HrefSpec('authorizations', 'id', '/')); } - public function capture($amount, $fee = 0) + public function capture(array $cap = []) { - $this->state["capture_amount"] = $amount; - $this->state["fee"] = $fee; + foreach ($cap as $key => $value) { + $this->state[$key] = $value; + } return $this->save(); } - public function void($voidMe) + public function void($voidMe = true) { $this->state["void_me"] = $voidMe; return $this->save(); diff --git a/src/Finix/Resources/BankAccount.php b/src/Finix/Resources/BankAccount.php index 84cdc0a..086f34b 100644 --- a/src/Finix/Resources/BankAccount.php +++ b/src/Finix/Resources/BankAccount.php @@ -2,6 +2,7 @@ namespace Finix\Resources; +use Finix\Hal\HrefSpec; class BankAccount extends PaymentInstrument { @@ -10,4 +11,9 @@ public function __construct(array $state = [], array $links = null) $state["type"] = "BANK_ACCOUNT"; parent::__construct($state, $links); } + + public static function init() + { + self::getRegistry()->add(get_called_class(), new HrefSpec('payment_instruments', 'id', '/')); + } } diff --git a/src/Finix/Resources/Identity.php b/src/Finix/Resources/Identity.php index 3caa385..833ad37 100644 --- a/src/Finix/Resources/Identity.php +++ b/src/Finix/Resources/Identity.php @@ -11,6 +11,11 @@ public static function init() self::getRegistry()->add(get_called_class(), new HrefSpec('identities', 'id', '/')); } + public function createMerchantUser(User $user) + { + return $user->create($this->resource->getLink("users")->getHref()); + } + public function provisionMerchantOn(Merchant $merchant) { return $merchant->create($this->resource->getLink("merchants")->getHref()); diff --git a/src/Finix/Resources/InstrumentUpdate.php b/src/Finix/Resources/InstrumentUpdate.php new file mode 100644 index 0000000..2845dd8 --- /dev/null +++ b/src/Finix/Resources/InstrumentUpdate.php @@ -0,0 +1,14 @@ +add(get_called_class(), new HrefSpec('updates', 'id', '/')); + } +} \ No newline at end of file diff --git a/src/Finix/Resources/PaymentCard.php b/src/Finix/Resources/PaymentCard.php index ee95e9c..dc6be1b 100644 --- a/src/Finix/Resources/PaymentCard.php +++ b/src/Finix/Resources/PaymentCard.php @@ -2,6 +2,8 @@ namespace Finix\Resources; +use Finix\Hal\HrefSpec; + class PaymentCard extends PaymentInstrument { @@ -11,4 +13,20 @@ public function __construct(array $state = [], array $links = null) $state["type"] = "PAYMENT_CARD"; parent::__construct($state, $links); } + + public static function init() + { + self::getRegistry()->add(get_called_class(), new HrefSpec('payment_instruments', 'id', '/')); + } + + public function createUpdate(InstrumentUpdate $action) + { + return $action->create($this->resource->getLink("updates")->getHref()); + } + + public static function getUpdateUri($card_id, $update_id) + { + // TODO move this to Registry + return "/" . self::getHrefSpec()->name . "/" . $card_id . "/" . InstrumentUpdate::getHrefSpec()->name . "?id=" . $update_id; + } } diff --git a/src/Finix/Resources/PaymentInstrument.php b/src/Finix/Resources/PaymentInstrument.php index 04d7875..23a68a3 100644 --- a/src/Finix/Resources/PaymentInstrument.php +++ b/src/Finix/Resources/PaymentInstrument.php @@ -6,9 +6,9 @@ abstract class PaymentInstrument extends Resource { + public static function init() { - self::getRegistry()->add(get_called_class(), - new HrefSpec('payment_instruments', 'id', '/')); + self::getRegistry()->add(get_called_class(), new HrefSpec('payment_instruments', 'id', '/')); } } diff --git a/tests/Finix/Fixtures.php b/tests/Finix/Fixtures.php index 9bd48c3..bf987a2 100644 --- a/tests/Finix/Fixtures.php +++ b/tests/Finix/Fixtures.php @@ -18,12 +18,12 @@ class Fixtures extends \PHPUnit_Framework_TestCase { - public static $apiUrl = "https://api-staging.finix.io/"; + public static $apiUrl; public static $disputeAmount = 888888; public static function createAdminUser() { - $user = new User(["enabled" => true]); + $user = new User(["enabled" => true, "role" => "ROLE_ADMIN"]); $user = $user->save(); self::assertNotEmpty($user->id); self::assertNotEmpty($user->password); diff --git a/tests/Finix/ScenariosTest.php b/tests/Finix/ScenariosTest.php index b287a97..6327c96 100644 --- a/tests/Finix/ScenariosTest.php +++ b/tests/Finix/ScenariosTest.php @@ -3,7 +3,13 @@ use Finix\Resources\Dispute; +use Finix\Resources\Identity; +use Finix\Resources\Transfer; use Finix\Resources\Verification; +use Finix\Resources\PaymentCard; +use Finix\Resources\BankAccount; +use Finix\Resources\User; +use Finix\Resources\InstrumentUpdate; use Finix\Settings; class ScenariosTest extends \PHPUnit_Framework_TestCase @@ -41,16 +47,55 @@ protected function setUp() Settings::configure(["username" => $this->partnerUser->id, "password" => $this->partnerUser->password]); $this->identity = Fixtures::createIdentity(); - -// $entity = $this->identity->entity; -// $entity["last_name"] = "serna"; -// $this->identity->entity = $entity; -// $this->identity->save(); - + $this->bankAccount = Fixtures::createBankAccount($this->identity); $this->merchant = Fixtures::provisionMerchant($this->identity); $this->card = Fixtures::createCard($this->identity); } + + public function testRetrieveIdentity() + { + $identity = Identity::retrieve($this->identity->id); + $this->assertEquals($this->identity->id, $identity->id); + } + + public function testCreateMerchantUser() { + $this->markTestSkipped("https://github.com/verygoodgroup/api-spec/issues/333"); + $user = $this->identity->createMerchantUser(new User([["enabled" => true]])); + self::assertNotNull($user->id); + } + + public function testCreateBankAccountDirectly() { + $bankAccount = new BankAccount( + array( + "account_type"=> "SAVINGS", + "name"=> "Fran Lemke", + "tags"=> array( + "Bank Account"=> "Company Account" + ), + "country"=> "USA", + "bank_code"=> "123123123", + "account_number"=> "123123123", + "type"=> "BANK_ACCOUNT", + "identity"=> $this->identity->id + )); + $bankAccount = $bankAccount->save(); + self::assertNotNull($bankAccount->id, "Invalid bank account"); + } + + public function testCreatePaymentCardDirectly() { + $card = new PaymentCard([ + "name" => "Joe Doe", + "expiration_month" => 12, + "expiration_year" => 2030, + "number" => "4111 1111 1111 1111", + "security_code" => 231, + "identity"=> $this->identity->id + ]); + $card = $card->save(); + self::assertNotNull($card->id, "Invalid card"); + } + public function testCreateWebhook() { $webhook = Fixtures::createWebhook("https://tools.ietf.org/html/rfc2606"); self::assertNotNull($webhook->id); @@ -89,7 +134,10 @@ public function testDebitTransfer() { public function testCaptureAuthorization() { $authorization = Fixtures::createAuthorization($this->card, 100); - $authorization = $authorization->capture(50, 10); + $authorization = $authorization->capture([ + "capture_amount"=> 100, + "fee"=> 10 + ]); self::assertEquals($authorization->state, "SUCCEEDED", "Capture amount $10 of '" . $this->card->id . "' not succeeded"); } @@ -137,9 +185,51 @@ public function testSettlement() public function testDispute() { $transfer = $this->testDebitTransfer(); - $disputePage = Dispute::getPagination($transfer->getHref("disputes")); + $disputePage = Dispute::getPagination($transfer); $dispute = $disputePage->items[0]; $file = $dispute->uploadEvidence($this->receiptImage); $this->assertEquals($file->dispute, $dispute->id); } + + public function testCreateAndFetchInstrumentUpdate() + { + $identity = Fixtures::createIdentity(); + Fixtures::createBankAccount($identity); + $merchant = Fixtures::provisionMerchant($identity); + $update = $this->card->createUpdate(new InstrumentUpdate(["merchant" => $merchant->id])); + $this->assertEquals($this->application->id, $update->application); + + $fetchUpdate = InstrumentUpdate::retrieve(PaymentCard::getUpdateUri($this->card->id, $update->id)); + $this->assertEquals($update->id, $fetchUpdate->id); + } + + public function testGetAllInstrumentUpdates() + { + $this->testCreateAndFetchInstrumentUpdate(); + $instrumentUpdatePage = InstrumentUpdate::getPagination($this->card); + foreach ($instrumentUpdatePage as $indexPage => $instrumentUpdates) { + foreach ($instrumentUpdates as $index => $instrumentUpdate) { // read the first page + $this->assertEquals($this->application->id, $instrumentUpdate->application); + } + } + } + + public function testIterateAllTransfers() + { + for ($i = 0; $i <= 41; $i++) { + Fixtures::createTransfer([ + "identity" => $this->card->identity, + "amount" => Fixtures::$disputeAmount, + "source" => $this->card->id, + "tags" => ["_source" => "php_client"] + ]); + } + + $transferPage = Transfer::getPagination($this->card); + foreach ($transferPage as $indexPage => $items) { + foreach ($items as $index => $transfer) { // read the first page + $this->assertTrue($transfer->amount > 0); + } + } + } }