diff --git a/init.php b/init.php index 2fd6c48a9c..de7bc53f4b 100644 --- a/init.php +++ b/init.php @@ -157,6 +157,7 @@ // Services require __DIR__ . '/lib/Service/AbstractService.php'; require __DIR__ . '/lib/Service/CouponService.php'; +require __DIR__ . '/lib/Service/CustomerService.php'; require __DIR__ . '/lib/Service/FileService.php'; require __DIR__ . '/lib/Service/Issuing/CardService.php'; require __DIR__ . '/lib/Service/PaymentIntentService.php'; diff --git a/lib/Service/AbstractService.php b/lib/Service/AbstractService.php index e0311e4d3b..3c43735857 100644 --- a/lib/Service/AbstractService.php +++ b/lib/Service/AbstractService.php @@ -45,31 +45,61 @@ protected function allObjects($params, $opts) return $this->request('get', $this->basePath(), $params, $opts); } + protected function allNestedObjects($nestedPath, $parentId, $params, $opts) + { + return $this->request('get', $this->baseNestedPath($parentId, $nestedPath), $params, $opts); + } + protected function createObject($params, $opts) { return $this->request('post', $this->basePath(), $params, $opts); } + protected function createNestedObject($nestedPath, $parentId, $params, $opts) + { + return $this->request('post', $this->baseNestedPath($parentId, $nestedPath), $params, $opts); + } + protected function deleteObject($id, $params, $opts) { return $this->request('delete', $this->instancePath($id), $params, $opts); } + protected function deleteNestedObject($nestedPath, $parentId, $id, $params, $opts) + { + return $this->request('delete', $this->instanceNestedPath($parentId, $nestedPath, $id), $params, $opts); + } + protected function retrieveObject($id, $params, $opts) { return $this->request('get', $this->instancePath($id), $params, $opts); } + protected function retrieveNestedObject($nestedPath, $parentId, $id, $params, $opts) + { + return $this->request('get', $this->instanceNestedPath($parentId, $nestedPath, $id), $params, $opts); + } + protected function updateObject($id, $params, $opts) { return $this->request('post', $this->instancePath($id), $params, $opts); } + protected function updateNestedObject($nestedPath, $parentId, $id, $params, $opts) + { + return $this->request('post', $this->instanceNestedPath($parentId, $nestedPath, $id), $params, $opts); + } + protected function request($method, $path, $params, $opts) { return $this->getClient()->request($method, $path, $params, $opts); } + protected function baseNestedPath($parentId, $nestedPath) + { + return $this->instancePath($parentId) . '/' . $nestedPath; + } + protected function instancePath($id) { if (null === $id || '' === \trim($id)) { @@ -80,4 +110,15 @@ protected function instancePath($id) return $this->basePath() . '/' . \urlencode($id); } + + protected function instanceNestedPath($parentId, $nestedPath, $id) + { + if (null === $id || '' === \trim($id)) { + $msg = 'The resource ID cannot be null or whitespace.'; + + throw new \Stripe\Exception\InvalidArgumentException($msg); + } + + return $this->baseNestedPath($parentId, $nestedPath) . '/' . \urlencode($id); + } } diff --git a/lib/Service/CustomerService.php b/lib/Service/CustomerService.php new file mode 100644 index 0000000000..0a9707afa8 --- /dev/null +++ b/lib/Service/CustomerService.php @@ -0,0 +1,306 @@ +allObjects($params, $opts); + } + + /** + * List customer balance transactions. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\Collection + */ + public function allBalanceTransactions($customerId, $params = [], $opts = []) + { + return $this->allNestedObjects(self::BALANCE_TRANSACTIONS, $customerId, $params, $opts); + } + + /** + * List all sources. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\Collection + */ + public function allSources($customerId, $params = [], $opts = []) + { + return $this->allNestedObjects(self::SOURCES, $customerId, $params, $opts); + } + + /** + * List all tax IDs. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\Collection + */ + public function allTaxIds($customerId, $params = [], $opts = []) + { + return $this->allNestedObjects(self::TAX_IDS, $customerId, $params, $opts); + } + + /** + * Create a customer. + * + * @param array $params + * @param array $opts + * + * @return \Stripe\Customer + */ + public function create($params = [], $opts = []) + { + return $this->createObject($params, $opts); + } + + /** + * Create a balance transaction. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\CustomerBalanceTransaction + */ + public function createBalanceTransaction($customerId, $params = [], $opts = []) + { + return $this->createNestedObject(self::BALANCE_TRANSACTIONS, $customerId, $params, $opts); + } + + /** + * Create a source. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\BankAccount|\Stripe\Card|\Stripe\Source + */ + public function createSource($customerId, $params = [], $opts = []) + { + return $this->createNestedObject(self::SOURCES, $customerId, $params, $opts); + } + + /** + * Create a tax ID. + * + * @param string $customerId + * @param array $params + * @param array $opts + * + * @return \Stripe\TaxId + */ + public function createTaxId($customerId, $params = [], $opts = []) + { + return $this->createNestedObject(self::TAX_IDS, $customerId, $params, $opts); + } + + /** + * Delete a customer. + * + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\Customer + */ + public function delete($id, $params = [], $opts = []) + { + return $this->deleteObject($id, $params, $opts); + } + + /** + * Delete a customer discount. + * + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\Discount + */ + public function deleteDiscount($id, $params = [], $opts = []) + { + return $this->request('delete', $this->instancePath($id) . '/discount', $params, $opts); + } + + /** + * Delete a source. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\BankAccount|\Stripe\Card|\Stripe\Source + */ + public function deleteSource($customerId, $id, $params = [], $opts = []) + { + return $this->deleteNestedObject(self::SOURCES, $customerId, $id, $params, $opts); + } + + /** + * Delete a tax ID. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\TaxId + */ + public function deleteTaxId($customerId, $id, $params = [], $opts = []) + { + return $this->deleteNestedObject(self::TAX_IDS, $customerId, $id, $params, $opts); + } + + /** + * Retrieve a customer. + * + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\Customer + */ + public function retrieve($id, $params = [], $opts = []) + { + return $this->retrieveObject($id, $params, $opts); + } + + /** + * Retrieve a balance transaction. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\CustomerBalanceTransaction + */ + public function retrieveBalanceTransaction($customerId, $id, $params = [], $opts = []) + { + return $this->retrieveNestedObject(self::BALANCE_TRANSACTIONS, $customerId, $id, $params, $opts); + } + + /** + * Retrieve a source. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\BankAccount|\Stripe\Card|\Stripe\Source + */ + public function retrieveSource($customerId, $id, $params = [], $opts = []) + { + return $this->retrieveNestedObject(self::SOURCES, $customerId, $id, $params, $opts); + } + + /** + * Retrieve a tax ID. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\TaxId + */ + public function retrieveTaxId($customerId, $id, $params = [], $opts = []) + { + return $this->retrieveNestedObject(self::TAX_IDS, $customerId, $id, $params, $opts); + } + + /** + * Update a customer. + * + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\Customer + */ + public function update($id, $params = [], $opts = []) + { + return $this->updateObject($id, $params, $opts); + } + + /** + * Update a balance transaction. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\CustomerBalanceTransaction + */ + public function updateBalanceTransaction($customerId, $id, $params = [], $opts = []) + { + return $this->updateNestedObject(self::BALANCE_TRANSACTIONS, $customerId, $id, $params, $opts); + } + + /** + * Update a source. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\BankAccount|\Stripe\Card|\Stripe\Source + */ + public function updateSource($customerId, $id, $params = [], $opts = []) + { + return $this->updateNestedObject(self::SOURCES, $customerId, $id, $params, $opts); + } + + /** + * Verify a source. + * + * @param string $customerId + * @param string $id + * @param array $params + * @param array $opts + * + * @return \Stripe\BankAccount + */ + public function verifySource($customerId, $id, $params = [], $opts = []) + { + return $this->request( + 'post', + $this->instanceNestedPath($customerId, self::SOURCES, $id) . '/verify', + $params, + $opts + ); + } +} diff --git a/tests/Stripe/Service/CustomerServiceTest.php b/tests/Stripe/Service/CustomerServiceTest.php new file mode 100644 index 0000000000..79b2e68361 --- /dev/null +++ b/tests/Stripe/Service/CustomerServiceTest.php @@ -0,0 +1,243 @@ +client = new \Stripe\StripeClient('sk_test_123', null, MOCK_URL); + $this->service = new CustomerService($this->client); + } + + public function testAll() + { + $this->expectsRequest( + 'get', + '/v1/customers' + ); + $resources = $this->service->all(); + static::assertInternalType('array', $resources->data); + static::assertInstanceOf(\Stripe\Customer::class, $resources->data[0]); + } + + public function testAllBalanceTransactions() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/balance_transactions' + ); + $resources = $this->service->allBalanceTransactions(self::TEST_RESOURCE_ID); + static::assertInternalType('array', $resources->data); + static::assertInstanceOf(\Stripe\CustomerBalanceTransaction::class, $resources->data[0]); + } + + public function testAllSources() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources' + ); + $resources = $this->service->allSources(self::TEST_RESOURCE_ID); + static::assertInternalType('array', $resources->data); + } + + public function testAllTaxIds() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/tax_ids' + ); + $resources = $this->service->allTaxIds(self::TEST_RESOURCE_ID); + static::assertInternalType('array', $resources->data); + static::assertInstanceOf(\Stripe\TaxId::class, $resources->data[0]); + } + + public function testCreate() + { + $this->expectsRequest( + 'post', + '/v1/customers' + ); + $resource = $this->service->create(); + static::assertInstanceOf(\Stripe\Customer::class, $resource); + } + + public function testCreateBalanceTransaction() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/balance_transactions' + ); + $resource = $this->service->createBalanceTransaction(self::TEST_RESOURCE_ID, [ + 'amount' => 1234, + 'currency' => 'usd', + ]); + static::assertInstanceOf(\Stripe\CustomerBalanceTransaction::class, $resource); + } + + public function testCreateSource() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources' + ); + $resource = $this->service->createSource(self::TEST_RESOURCE_ID, ['source' => 'tok_123']); + } + + public function testCreateTaxId() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/tax_ids' + ); + $resource = $this->service->createTaxId(self::TEST_RESOURCE_ID, [ + 'type' => \Stripe\TaxId::TYPE_EU_VAT, + 'value' => '11111', + ]); + static::assertInstanceOf(\Stripe\TaxId::class, $resource); + } + + public function testDelete() + { + $this->expectsRequest( + 'delete', + '/v1/customers/' . self::TEST_RESOURCE_ID + ); + $resource = $this->service->delete(self::TEST_RESOURCE_ID); + static::assertInstanceOf(\Stripe\Customer::class, $resource); + } + + public function testDeleteDiscount() + { + $this->expectsRequest( + 'delete', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/discount' + ); + $resource = $this->service->deleteDiscount(self::TEST_RESOURCE_ID); + static::assertInstanceOf(\Stripe\Discount::class, $resource); + } + + public function testDeleteSource() + { + $this->expectsRequest( + 'delete', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources/' . self::TEST_SOURCE_ID + ); + $resource = $this->service->deleteSource(self::TEST_RESOURCE_ID, self::TEST_SOURCE_ID); + } + + public function testDeleteTaxId() + { + $this->expectsRequest( + 'delete', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/tax_ids/' . self::TEST_TAX_ID_ID + ); + $resource = $this->service->deleteTaxId(self::TEST_RESOURCE_ID, self::TEST_TAX_ID_ID); + static::assertInstanceOf(\Stripe\TaxId::class, $resource); + } + + public function testRetrieve() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID + ); + $resource = $this->service->retrieve(self::TEST_RESOURCE_ID); + static::assertInstanceOf(\Stripe\Customer::class, $resource); + } + + public function testRetrieveBalanceTransaction() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/balance_transactions/' + . self::TEST_CUSTOMER_BALANCE_TRANSACTION_ID + ); + $resource = $this->service->retrieveBalanceTransaction( + self::TEST_RESOURCE_ID, + self::TEST_CUSTOMER_BALANCE_TRANSACTION_ID + ); + static::assertInstanceOf(\Stripe\CustomerBalanceTransaction::class, $resource); + } + + public function testRetrieveSource() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources/' . self::TEST_SOURCE_ID + ); + $resource = $this->service->retrieveSource(self::TEST_RESOURCE_ID, self::TEST_SOURCE_ID); + } + + public function testRetrieveTaxId() + { + $this->expectsRequest( + 'get', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/tax_ids/' . self::TEST_TAX_ID_ID + ); + $resource = $this->service->retrieveTaxId(self::TEST_RESOURCE_ID, self::TEST_TAX_ID_ID); + static::assertInstanceOf(\Stripe\TaxId::class, $resource); + } + + public function testUpdate() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID + ); + $resource = $this->service->update(self::TEST_RESOURCE_ID, [ + 'metadata' => ['key' => 'value'], + ]); + static::assertInstanceOf(\Stripe\Customer::class, $resource); + } + + public function testUpdateBalanceTransaction() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/balance_transactions/' + . self::TEST_CUSTOMER_BALANCE_TRANSACTION_ID + ); + $resource = $this->service->updateBalanceTransaction( + self::TEST_RESOURCE_ID, + self::TEST_CUSTOMER_BALANCE_TRANSACTION_ID, + ['description' => 'new'] + ); + static::assertInstanceOf(\Stripe\CustomerBalanceTransaction::class, $resource); + } + + public function testUpdateSource() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources/' . self::TEST_SOURCE_ID + ); + $resource = $this->service->updateSource(self::TEST_RESOURCE_ID, self::TEST_SOURCE_ID, ['name' => 'name']); + } + + public function testVerifySource() + { + $this->expectsRequest( + 'post', + '/v1/customers/' . self::TEST_RESOURCE_ID . '/sources/' . self::TEST_SOURCE_ID . '/verify' + ); + $resource = $this->service->verifySource(self::TEST_RESOURCE_ID, self::TEST_SOURCE_ID, ['amounts' => [32, 45]]); + } +}