diff --git a/src/GhostZero/BitinflowAccounts/ApiOperations/Delete.php b/src/GhostZero/BitinflowAccounts/ApiOperations/Delete.php index 68d7393..d9926a4 100644 --- a/src/GhostZero/BitinflowAccounts/ApiOperations/Delete.php +++ b/src/GhostZero/BitinflowAccounts/ApiOperations/Delete.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace GhostZero\BitinflowAccounts\ApiOperations; use GhostZero\BitinflowAccounts\Helpers\Paginator; +use GhostZero\BitinflowAccounts\Result; /** * @author René Preuß @@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator; trait Delete { - abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null); + abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null): Result; } \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/ApiOperations/Get.php b/src/GhostZero/BitinflowAccounts/ApiOperations/Get.php index 6816961..ef2f1a3 100644 --- a/src/GhostZero/BitinflowAccounts/ApiOperations/Get.php +++ b/src/GhostZero/BitinflowAccounts/ApiOperations/Get.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace GhostZero\BitinflowAccounts\ApiOperations; use GhostZero\BitinflowAccounts\Helpers\Paginator; +use GhostZero\BitinflowAccounts\Result; /** * @author René Preuß @@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator; trait Get { - abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null); + abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null): Result; } \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/ApiOperations/Post.php b/src/GhostZero/BitinflowAccounts/ApiOperations/Post.php index 56c4c35..de10830 100644 --- a/src/GhostZero/BitinflowAccounts/ApiOperations/Post.php +++ b/src/GhostZero/BitinflowAccounts/ApiOperations/Post.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace GhostZero\BitinflowAccounts\ApiOperations; use GhostZero\BitinflowAccounts\Helpers\Paginator; +use GhostZero\BitinflowAccounts\Result; /** * @author René Preuß @@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator; trait Post { - abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null); + abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null): Result; } \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/ApiOperations/Put.php b/src/GhostZero/BitinflowAccounts/ApiOperations/Put.php index 03fc532..cb0f525 100644 --- a/src/GhostZero/BitinflowAccounts/ApiOperations/Put.php +++ b/src/GhostZero/BitinflowAccounts/ApiOperations/Put.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace GhostZero\BitinflowAccounts\ApiOperations; use GhostZero\BitinflowAccounts\Helpers\Paginator; +use GhostZero\BitinflowAccounts\Result; /** * @author René Preuß @@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator; trait Put { - abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null); + abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null): Result; } \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/BitinflowAccounts.php b/src/GhostZero/BitinflowAccounts/BitinflowAccounts.php index 43de378..1ea695d 100644 --- a/src/GhostZero/BitinflowAccounts/BitinflowAccounts.php +++ b/src/GhostZero/BitinflowAccounts/BitinflowAccounts.php @@ -18,12 +18,13 @@ class BitinflowAccounts { use Traits\ChargesTrait; - use Traits\CheckoutSessionsTrait; + use Traits\DocumentsTrait; + use Traits\PaymentIntentsTrait; use Traits\SshKeysTrait; use Traits\UsersTrait; - const BASE_URI = 'https://accounts.bitinflow.com/api/'; - const OAUTH_BASE_URI = 'https://accounts.bitinflow.com/api/'; + private const BASE_URI = 'https://accounts.bitinflow.com/api/'; + private const OAUTH_BASE_URI = 'https://accounts.bitinflow.com/api/'; /** * Guzzle is used to make http requests. diff --git a/src/GhostZero/BitinflowAccounts/Enums/DocumentType.php b/src/GhostZero/BitinflowAccounts/Enums/DocumentType.php new file mode 100644 index 0000000..fe53985 --- /dev/null +++ b/src/GhostZero/BitinflowAccounts/Enums/DocumentType.php @@ -0,0 +1,17 @@ + + */ +class DocumentType +{ + // Read authorized user´s email address. + public const TYPE_PDF_INVOICE = 'pdf.invoice'; + + // Manage a authorized user object. + public const TYPE_PDF_ORDER = 'pdf.order'; +} \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/Enums/Scope.php b/src/GhostZero/BitinflowAccounts/Enums/Scope.php index 0329c89..1e69375 100644 --- a/src/GhostZero/BitinflowAccounts/Enums/Scope.php +++ b/src/GhostZero/BitinflowAccounts/Enums/Scope.php @@ -15,24 +15,24 @@ class Scope */ // Deprecated scope. - const API = 'api'; + public const API = 'api'; // Read nonpublic user information, including email address. - const READ_USER = 'read_user'; + public const READ_USER = 'read_user'; /* * v1 API */ // Read authorized user´s email address. - const USERS_READ_EMAIL = 'users:read:email'; + public const USERS_READ_EMAIL = 'users:read:email'; // Manage a authorized user object. - const USERS_EDIT = 'users:edit'; + public const USERS_EDIT = 'users:edit'; // Read authorized user´s transactions. - const TRANSACTIONS_READ = 'transactions:read'; + public const TRANSACTIONS_READ = 'transactions:read'; // Create a new charge for the authorized user. - const CHARGES_CREATE = 'charges:create'; + public const CHARGES_CREATE = 'charges:create'; } \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/Traits/DocumentsTrait.php b/src/GhostZero/BitinflowAccounts/Traits/DocumentsTrait.php new file mode 100644 index 0000000..5a7273e --- /dev/null +++ b/src/GhostZero/BitinflowAccounts/Traits/DocumentsTrait.php @@ -0,0 +1,48 @@ + + */ +trait DocumentsTrait +{ + + use Get, Post; + + /** + * Create a Documents object + * + * @param array $parameters + * + * @return Result + */ + public function createDocument(array $parameters): Result + { + return $this->post('documents', $parameters); + } + + /** + * Create a Documents download url + * + * @param mixed $identifier + * @param CarbonInterface|null $expiresAt + * + * @return Result + */ + public function createDocumentDownloadUrl($identifier, ?CarbonInterface $expiresAt = null): Result + { + return $this->post("documents/$identifier/download-url", [ + 'expires_at' => $expiresAt + ? $expiresAt->toDateTimeString() + : now()->addHour()->toDateTimeString(), + ]); + } +} \ No newline at end of file diff --git a/src/GhostZero/BitinflowAccounts/Traits/CheckoutSessionsTrait.php b/src/GhostZero/BitinflowAccounts/Traits/PaymentIntentsTrait.php similarity index 60% rename from src/GhostZero/BitinflowAccounts/Traits/CheckoutSessionsTrait.php rename to src/GhostZero/BitinflowAccounts/Traits/PaymentIntentsTrait.php index bd1dfbb..15e0410 100644 --- a/src/GhostZero/BitinflowAccounts/Traits/CheckoutSessionsTrait.php +++ b/src/GhostZero/BitinflowAccounts/Traits/PaymentIntentsTrait.php @@ -11,32 +11,32 @@ use GhostZero\BitinflowAccounts\Result; /** * @author René Preuß */ -trait CheckoutSessionsTrait +trait PaymentIntentsTrait { use Get, Post; /** - * Get a Session object + * Get a Payment Intent object * * @param string $id * * @return Result Result object */ - public function getCheckoutSession(string $id): Result + public function getPaymentIntent(string $id): Result { - return $this->get("checkout/sessions/$id"); + return $this->get("payment-intents/$id"); } /** - * Create a Session object + * Create a Payment Intent object * * @param array $parameters * * @return Result */ - public function createCheckoutSession(array $parameters): Result + public function createPaymentIntent(array $parameters): Result { - return $this->post('payments/sessions', $parameters); + return $this->post('payment-intents', $parameters); } } \ No newline at end of file diff --git a/tests/GhostZero/BitinflowAccounts/ApiChargesTest.php b/tests/GhostZero/BitinflowAccounts/ApiChargesTest.php new file mode 100644 index 0000000..6904319 --- /dev/null +++ b/tests/GhostZero/BitinflowAccounts/ApiChargesTest.php @@ -0,0 +1,62 @@ + + */ +class ApiChargesTest extends ApiTestCase +{ + + public function testCaptureWithoutCapture(): void + { + $this->getClient()->withToken($this->getToken()); + + $result = $this->getClient()->createCharge([ + 'amount' => 2000, + 'currency' => 'usd', + 'source' => 'tok_visa', + 'description' => 'Charge for jenny.rosen@example.com', + ]); + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertEquals(2000, $result->data()->amount); + $this->assertTrue($result->data()->captured); + } + + public function testChargeWithCapture(): void + { + $this->getClient()->withToken($this->getToken()); + + $result = $this->getClient()->createCharge([ + 'amount' => 2000, + 'currency' => 'usd', + 'source' => 'tok_visa', + 'description' => 'Charge for jenny.rosen@example.com', + 'capture' => false, // default is true for instant capture + 'metadata' => [ + 'foo' => 'bar', + ], + 'receipt_email' => 'rene+unittest@bitinflow.com', + ]); + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertEquals(2000, $result->data()->amount); + $this->assertFalse($result->data()->captured); + + $charge = $result->data(); + + $result = $this->getClient()->captureCharge($charge->id); + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertEquals(2000, $result->data()->amount); + $this->assertTrue($result->data()->captured); + } +} \ No newline at end of file diff --git a/tests/GhostZero/BitinflowAccounts/ApiDocumentsTest.php b/tests/GhostZero/BitinflowAccounts/ApiDocumentsTest.php new file mode 100644 index 0000000..630c127 --- /dev/null +++ b/tests/GhostZero/BitinflowAccounts/ApiDocumentsTest.php @@ -0,0 +1,87 @@ + + */ +class ApiDocumentsTest extends ApiTestCase +{ + + public function testCreateDocument(): void + { + $this->getClient()->withToken($this->getToken()); + + $result = $this->getClient()->createDocument([ + 'branding' => [ + 'primary_color' => '#8284df', + 'watermark_url' => 'https://fbs.streamkit.gg/img/pdf/wm.png', + 'logo_url' => 'https://fbs.streamkit.gg/img/pdf/logo_dark_small.png', + ], + 'locale' => 'de', + 'type' => DocumentType::TYPE_PDF_INVOICE, + 'data' => $this->createDummyInvoiceData(), + 'receipt_email' => 'rene+unittest@bitinflow.com', + ]); + + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertArrayHasKey('download_url', $result->data()); + $this->assertEquals( + 'rene+unittest@bitinflow.com', + $result->data()->receipt_email + ); + } + + public function testGenerateDocumentStoragePath(): void + { + $this->getClient()->withToken($this->getToken()); + + $expiresAt = now()->addHours(2); + + $result = $this->getClient()->createDocumentDownloadUrl(1, $expiresAt); + + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('download_url', $result->data()); + $this->assertEquals( + $expiresAt->toDateTimeString(), + $result->data()->expires_at + ); + } + + private function createDummyInvoiceData(): array + { + return [ + 'id' => 'FBS-IN-1337', + 'customer' => [ + 'name' => 'GhostZero', + 'email' => 'rene@preuss.io', + 'address' => [ + 'Example Street 123', + '50733 Cologne', + 'GERMANY', + ], + ], + 'line_items' => [ + [ + 'name' => 'T-shirt', + 'description' => 'Comfortable cotton t-shirt', + 'unit' => 'T-shirt', // optional unit name + 'amount' => 1500, + 'currency' => 'usd', + 'quantity' => 2, + ], + ], + 'legal_notice' => 'According to the German §19 UStG no sales tax is calculated. However, the product is a digital good delivered via Internet we generally offer no refunds. The delivery date corresponds to the invoice date.', + 'already_paid' => true, + 'created_at' => now()->format('d.m.Y'), + ]; + } +} \ No newline at end of file diff --git a/tests/GhostZero/BitinflowAccounts/ApiPaymentIntentsTest.php b/tests/GhostZero/BitinflowAccounts/ApiPaymentIntentsTest.php new file mode 100644 index 0000000..c611a16 --- /dev/null +++ b/tests/GhostZero/BitinflowAccounts/ApiPaymentIntentsTest.php @@ -0,0 +1,46 @@ + + */ +class ApiPaymentIntentsTest extends ApiTestCase +{ + private $paymentIntent; + + public function testCreatePaymentIntent(): void + { + $this->getClient()->withToken($this->getToken()); + + $result = $this->getClient()->createPaymentIntent([ + 'payment_method_types' => ['card'], + 'amount' => 1000, + 'currency' => 'usd', + 'application_fee_amount' => 123, + ]); + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertArrayHasKey('redirect_url', $result->data()); + $this->assertEquals(1000, $result->data()->amount); + + // use this payment intent for our next tests + $this->paymentIntent = $result->data(); + } + + public function testGetPaymentIntent(): void + { + $this->getClient()->withToken($this->getToken()); + + $result = $this->getClient()->getPaymentIntent($this->paymentIntent->id); + $this->registerResult($result); + $this->assertTrue($result->success()); + $this->assertArrayHasKey('id', $result->data()); + $this->assertEquals(1000, $result->data()->amount); + } +} \ No newline at end of file diff --git a/tests/GhostZero/BitinflowAccounts/ApiSshKeysTest.php b/tests/GhostZero/BitinflowAccounts/ApiSshKeysTest.php index 16c08e7..9383e5b 100644 --- a/tests/GhostZero/BitinflowAccounts/ApiSshKeysTest.php +++ b/tests/GhostZero/BitinflowAccounts/ApiSshKeysTest.php @@ -13,15 +13,14 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase; class ApiSshKeysTest extends ApiTestCase { - public function testGetSshKeyByUserId() + public function testGetSshKeyByUserId(): void { $this->registerResult($result = $this->getClient()->getSshKeysByUserId(38)); - $this->assertInstanceOf(Result::class, $result); $this->assertEquals('rene.preuss@check24.de', $result->shift()->name); $this->assertGreaterThanOrEqual(2, $result->count()); } - public function testSshKeyManagement() + public function testSshKeyManagement(): void { $customName = 'Hello World!'; $publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3H7sYVrVCwwYIuRm3on3S9n/BCd2mBJrgCk6xTerbNmt0RyUZ+RtGsK6UYkgnRR2WWq9/Pv2s3RXJXPxbsIEYmKCcTdLUvDk56x9385cIVUX4w016mpe/8lyu+mIdqWYKsJMoab0oReCDX8Y9qBcaffDh8AgmYVN+86gXgoP1ITe9BDYrFiR6U571VyLDVN3OYOYPMF3/L9f0knMfM0T4LrS8oi6faVBCxZHRoBGtGmsTBkE0KwplYQFN2aa4Mxab+rTUFmJr3LYEcJF0J8wNJ3eEDFNOR0254jrjbGGAXGsc+cxJoNzech+GBkRMKMpNU0lds6VxP0ZB25VfzjEmQ== René Preuß'; diff --git a/tests/GhostZero/BitinflowAccounts/ApiUsersTest.php b/tests/GhostZero/BitinflowAccounts/ApiUsersTest.php index f239a6f..735671a 100644 --- a/tests/GhostZero/BitinflowAccounts/ApiUsersTest.php +++ b/tests/GhostZero/BitinflowAccounts/ApiUsersTest.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace GhostZero\BitinflowAccounts\Tests; -use GhostZero\BitinflowAccounts\Result; use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase; /** @@ -13,11 +12,10 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase; class ApiUsersTest extends ApiTestCase { - public function testGetAuthedUser() + public function testGetAuthedUser(): void { $this->getClient()->withToken($this->getToken()); $this->registerResult($result = $this->getClient()->getAuthedUser()); - $this->assertInstanceOf(Result::class, $result); $this->assertEquals('rene@preuss.io', $result->data()->email); } } \ No newline at end of file diff --git a/tests/GhostZero/BitinflowAccounts/ServiceInstantiationTest.php b/tests/GhostZero/BitinflowAccounts/ServiceInstantiationTest.php index 293dac8..c9165d3 100644 --- a/tests/GhostZero/BitinflowAccounts/ServiceInstantiationTest.php +++ b/tests/GhostZero/BitinflowAccounts/ServiceInstantiationTest.php @@ -14,12 +14,12 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\TestCase; class ServiceInstantiationTest extends TestCase { - public function testInstance() + public function testInstance(): void { $this->assertInstanceOf(BitinflowAccounts::class, app(BitinflowAccounts::class)); } - public function testFacade() + public function testFacade(): void { $this->assertInstanceOf(BitinflowAccounts::class, BitinflowAccountsFacade::getFacadeRoot()); }