3 Commits

Author SHA1 Message Date
d447a88430 add mode
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-29 21:33:02 +02:00
d9a330222b update billable
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-28 17:26:02 +02:00
21946e3a22 update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-28 05:32:44 +02:00
10 changed files with 253 additions and 47 deletions

View File

@@ -9,12 +9,11 @@ PHP Anikeen ID API Client for Laravel 11+
## Table of contents
1. [Installation](#installation)
2. [Event Listener](#event-listener)
3. [Configuration](#configuration)
4. [General](#general)
5. [Examples](#examples)
6. [Documentation](#documentation)
7. [Development](#Development)
2. [Configuration](#configuration)
3. [General](#general)
4. [Examples](#examples)
5. [Documentation](#documentation)
6. [Development](#Development)
## Installation
@@ -22,19 +21,9 @@ PHP Anikeen ID API Client for Laravel 11+
composer require anikeen/id
```
## Event Listener
In Laravel 11, the default EventServiceProvider provider was removed. Instead, add the listener using the listen method on the Event facade, in your `AppServiceProvider`
```
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('anikeen-id', \Anikeen\Id\Socialite\Provider::class);
});
```
## Configuration
Add environmental variables to your `.env`
Add environmental variables to your `.env` file:
```
ANIKEEN_ID_KEY=
@@ -42,12 +31,19 @@ ANIKEEN_ID_SECRET=
ANIKEEN_ID_CALLBACK_URL=http://localhost/auth/callback
```
To switch from `production` to `staging` use following variable:
```
ANIKEEN_ID_MODE=staging
```
You will need to add an entry to the services configuration file so that after config files are cached for usage in production environment (Laravel command `artisan config:cache`) all config is still available.
**Add to `config/services.php`:**
Add to `config/services.php` file:
```php
'anikeen' => [
'mode' => env('ANIKEEN_ID_MODE'),
'client_id' => env('ANIKEEN_ID_KEY'),
'client_secret' => env('ANIKEEN_ID_SECRET'),
'redirect' => env('ANIKEEN_ID_CALLBACK_URL'),
@@ -55,6 +51,19 @@ You will need to add an entry to the services configuration file so that after c
],
```
### Event Listener
In Laravel 11, the default EventServiceProvider provider was removed. Instead, add the listener using the listen method on the Event facade, in your `AppServiceProvider` boot method:
```php
public function boot(): void
{
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('anikeen-id', \Anikeen\Id\Socialite\Provider::class);
});
}
```
### Registering Middleware
Append it to the global middleware stack in your application's `bootstrap/app.php` file:
@@ -86,7 +95,7 @@ then, you can use the `Billable` trait methods in your user model.
### Change the default access token / refresh token field name
If you access / refresh token fields differs from the default `anikeen_id_access_token` / `anikeen_id_refresh_token`, you can specify the field name in the 'AppServiceProvider' boot method:
If you access / refresh token fields differs from the default `anikeen_id_access_token` / `anikeen_id_refresh_token`, you can specify the field name in the `AppServiceProvider` boot method:
```php
use Anikeen\Id\AnikeenId;
@@ -301,6 +310,16 @@ public function isEmailExisting(string $email): Result
## Billable
### ManagesAddresses
```php
public function addresses(): Result
public function createAddress(array $attributes = []): Result
public function address(string $addressId): Result
public function updateAddress(string $addressId, array $attributes = []): Result
public function deleteAddress(string $addressId): Result
```
### ManagesBalance
```php
@@ -314,7 +333,7 @@ public function charge(float $amount, string $paymentMethodId, array $options =
```php
public function invoices(): Result
public function invoice(string $invoiceId): Result
public function getInvoiceDownloadUrl(string $invoiceId): string
public function getInvoiceTemporaryUrl(string $invoiceId): string
```
### ManagesOrders
@@ -354,6 +373,7 @@ public function createSubscription(array $attributes): Result
public function checkoutSubscription(string $subscriptionId): Result
public function revokeSubscription(string $subscriptionId): Result
public function resumeSubscription(string $subscriptionId): Result
public function deleteSubscription(string $subscriptionId): Result
```
### ManagesTaxation

View File

@@ -9,12 +9,11 @@ PHP Anikeen ID API Client for Laravel 11+
## Table of contents
1. [Installation](#installation)
2. [Event Listener](#event-listener)
3. [Configuration](#configuration)
4. [General](#general)
5. [Examples](#examples)
6. [Documentation](#documentation)
7. [Development](#Development)
2. [Configuration](#configuration)
3. [General](#general)
4. [Examples](#examples)
5. [Documentation](#documentation)
6. [Development](#Development)
## Installation
@@ -22,19 +21,9 @@ PHP Anikeen ID API Client for Laravel 11+
composer require anikeen/id
```
## Event Listener
In Laravel 11, the default EventServiceProvider provider was removed. Instead, add the listener using the listen method on the Event facade, in your `AppServiceProvider`
```
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('anikeen-id', \Anikeen\Id\Socialite\Provider::class);
});
```
## Configuration
Add environmental variables to your `.env`
Add environmental variables to your `.env` file:
```
ANIKEEN_ID_KEY=
@@ -42,12 +31,19 @@ ANIKEEN_ID_SECRET=
ANIKEEN_ID_CALLBACK_URL=http://localhost/auth/callback
```
To switch from `production` to `staging` use following variable:
```
ANIKEEN_ID_MODE=staging
```
You will need to add an entry to the services configuration file so that after config files are cached for usage in production environment (Laravel command `artisan config:cache`) all config is still available.
**Add to `config/services.php`:**
Add to `config/services.php` file:
```php
'anikeen' => [
'mode' => env('ANIKEEN_ID_MODE'),
'client_id' => env('ANIKEEN_ID_KEY'),
'client_secret' => env('ANIKEEN_ID_SECRET'),
'redirect' => env('ANIKEEN_ID_CALLBACK_URL'),
@@ -55,6 +51,19 @@ You will need to add an entry to the services configuration file so that after c
],
```
### Event Listener
In Laravel 11, the default EventServiceProvider provider was removed. Instead, add the listener using the listen method on the Event facade, in your `AppServiceProvider` boot method:
```php
public function boot(): void
{
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('anikeen-id', \Anikeen\Id\Socialite\Provider::class);
});
}
```
### Registering Middleware
Append it to the global middleware stack in your application's `bootstrap/app.php` file:
@@ -86,7 +95,7 @@ then, you can use the `Billable` trait methods in your user model.
### Change the default access token / refresh token field name
If you access / refresh token fields differs from the default `anikeen_id_access_token` / `anikeen_id_refresh_token`, you can specify the field name in the 'AppServiceProvider' boot method:
If you access / refresh token fields differs from the default `anikeen_id_access_token` / `anikeen_id_refresh_token`, you can specify the field name in the `AppServiceProvider` boot method:
```php
use Anikeen\Id\AnikeenId;

View File

@@ -51,6 +51,11 @@ class AnikeenId
*/
private static string $baseUrl = 'https://id.anikeen.com/api/';
/**
* The staging base URL for Anikeen ID API.
*/
private static string $stagingBaseUrl = 'https://staging.id.anikeen.com/api/';
/**
* The key for the access token.
*/
@@ -105,6 +110,9 @@ class AnikeenId
if ($redirectUri = config('services.anikeen.redirect')) {
$this->setRedirectUri($redirectUri);
}
if (config('services.anikeen.mode') === 'staging') {
self::setBaseUrl(self::$stagingBaseUrl);
}
if ($baseUrl = config('services.anikeen.base_url')) {
self::setBaseUrl($baseUrl);
}

View File

@@ -3,6 +3,7 @@
namespace Anikeen\Id;
use Anikeen\Id\ApiOperations\Request;
use Anikeen\Id\Concerns\ManagesAddresses;
use Anikeen\Id\Concerns\ManagesBalance;
use Anikeen\Id\Concerns\ManagesInvoices;
use Anikeen\Id\Concerns\ManagesOrders;
@@ -17,6 +18,7 @@ use stdClass;
trait Billable
{
use ManagesAddresses;
use ManagesBalance;
use ManagesInvoices;
use ManagesOrders;

View File

@@ -0,0 +1,132 @@
<?php
namespace Anikeen\Id\Concerns;
use Anikeen\Id\ApiOperations\Request;
use Anikeen\Id\Exceptions\RequestRequiresClientIdException;
use Anikeen\Id\Result;
use GuzzleHttp\Exception\GuzzleException;
trait ManagesAddresses
{
use Request;
/**
* Get addresses from the current user.
*
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function addresses(): Result
{
return $this->request('GET', 'v1/addresses');
}
/**
* Creates a new address for the current user.
*
* @param array{
* company_name: null|string,
* first_name: string,
* last_name: string,
* address: string,
* address_2: null|string,
* house_number: null|string,
* postal_code: string,
* city: string,
* state: null|string,
* country_iso: string,
* phone_number: null|string,
* email: null|string,
* primary: bool,
* primary_billing_address: bool
* } $attributes The address data:
*   - company_name: Company name (optional)
*   - first_name: First name
*   - last_name: Last name
*   - address: Address line 1 (e.g. street address, P.O. Box, etc.)
*   - address_2: Address line 2 (optional, e.g. apartment number, c/o, etc.)
*   - house_number: House number (optional)
*   - postal_code: Postal code
*   - city: City
*   - state: State (optional, e.g. province, region, etc.)
*   - country_iso: Country ISO code (e.g. US, CA, etc.)
*   - phone_number: Phone number (optional)
*   - email: Email address (optional, e.g. for delivery notifications)
*   - primary: Whether this address should be the primary address (optional)
*   - primary_billing_address: Whether this address should be the primary billing address (optional)
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function createAddress(array $attributes = []): Result
{
return $this->request('POST', 'v1/addresses', $attributes);
}
/**
* Get given address from the current user.
*
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function address(string $addressId): Result
{
return $this->request('GET', sprintf('v1/addresses/%s', $addressId));
}
/**
* Update given address from the current user.
*
* VAT is calculated based on the billing address and shown in the address response.
*
* @param string $addressId The address ID.
* @param array{
* company_name: null|string,
* first_name: string,
* last_name: string,
* address_2: null|string,
* address: string,
* house_number: null|string,
* postal_code: string,
* city: string,
* state: null|string,
* country_iso: string,
* phone_number: null|string,
* email: null|string,
* primary: bool,
* primary_billing_address: bool
* } $attributes The address data:
* - company_name: Company name (optional)
* - first_name: First name (required when set)
* - last_name: Last name (required when set)
* - address: Address line 1 (e.g. street address, P.O. Box, etc.)
* - address_2: Address line 2 (optional, e.g. apartment number, c/o, etc.)
* - house_number: House number (optional)
* - postal_code: Postal code (required when set)
* - city: City (required when set)
* - state: State (optional, e.g. province, region, etc.)
* - country_iso: Country ISO code (required when set, e.g. US, CA, etc.)
* - phone_number: Phone number (optional)
* - email: Email address (optional, e.g. for delivery notifications)
* - primary: Whether this address should be the primary address (optional)
* - primary_billing_address: Whether this address should be the primary billing address (optional)
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function updateAddress(string $addressId, array $attributes = []): Result
{
return $this->request('PUT', sprintf('v1/addresses/%s', $addressId), $attributes);
}
/**
* Delete given address from the current user.
*
* @param string $addressId The address ID.
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function deleteAddress(string $addressId): Result
{
return $this->request('DELETE', sprintf('v1/addresses/%s', $addressId));
}
}

View File

@@ -35,14 +35,14 @@ trait ManagesInvoices
}
/**
* Get download url from given invoice.
* Get temporary download url from given invoice.
*
* @param string $invoiceId The invoice ID
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function getInvoiceDownloadUrl(string $invoiceId): string
public function getInvoiceTemporaryUrl(string $invoiceId): string
{
return $this->request('PUT', sprintf('v1/invoices/%s', $invoiceId))->data->download_url;
return $this->request('PUT', sprintf('v1/invoices/%s', $invoiceId))->data->temporary_url;
}
}

View File

@@ -27,6 +27,11 @@ trait ManagesOrders
*
* VAT is calculated based on the billing address and shown in the order response.
*
* The billing and shipping addresses are each persisted as standalone Address entities
* in the database, but are also embedded (deep-copied) into the Order object itself
* rather than merely referenced. This guarantees that the order retains its own snapshot
* of both addresses for future reference.
*
* @param array{
* billing_address: array{
* company_name: null|string,
@@ -92,6 +97,11 @@ trait ManagesOrders
*
* VAT is calculated based on the billing address and shown in the order response.
*
* The billing and shipping addresses are each persisted as standalone Address entities
* in the database, but are also embedded (deep-copied) into the Order object itself
* rather than merely referenced. This guarantees that the order retains its own snapshot
* of both addresses for future reference.
*
* @param string $orderId The order ID.
* @param array{
* billing_address: array{

View File

@@ -41,7 +41,7 @@ trait ManagesPaymentMethods
*/
public function hasDefaultPaymentMethod(): bool
{
return $this->defaultPaymentMethod()->count() > 0;
return (bool)$this->defaultPaymentMethod()->data;
}
/**
@@ -65,7 +65,7 @@ trait ManagesPaymentMethods
*/
public function billingPortalUrl(string $returnUrl, array $options): string
{
return $this->request('POST', 'v1/stripe/billing-portal', [
return $this->request('POST', 'v1/billing/portal', [
'return_url' => $returnUrl,
'options' => $options,
])->data->url;

View File

@@ -100,4 +100,16 @@ trait ManagesSubscriptions
{
return $this->request('PUT', sprintf('v1/subscriptions/%s/resume', $subscriptionId));
}
/**
* Delete a given subscription from the current user.
*
* @param string $subscriptionId The subscription ID.
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function deleteSubscription(string $subscriptionId): Result
{
return $this->request('DELETE', sprintf('v1/subscriptions/%s', $subscriptionId));
}
}

View File

@@ -4,6 +4,7 @@ namespace Anikeen\Id\Socialite;
use Anikeen\Id\Enums\Scope;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Laravel\Socialite\Two\ProviderInterface;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
@@ -26,13 +27,25 @@ class Provider extends AbstractProvider implements ProviderInterface
*/
protected $scopeSeparator = ' ';
/**
* Get the base URL for the API.
*/
protected function getBaseUrl(): string
{
$mode = $this->config['mode'] ?? 'production';
return $mode === 'staging'
? 'https://staging.id.anikeen.com'
: 'https://id.anikeen.com';
}
/**
* {@inheritdoc}
*/
protected function getAuthUrl($state): string
{
return $this->buildAuthUrlFromBase(
'https://id.anikeen.com/oauth/authorize', $state
$this->getBaseUrl() . '/oauth/authorize', $state
);
}
@@ -41,7 +54,7 @@ class Provider extends AbstractProvider implements ProviderInterface
*/
protected function getTokenUrl(): string
{
return 'https://id.anikeen.com/oauth/token';
return $this->getBaseUrl() . '/oauth/token';
}
/**
@@ -52,7 +65,7 @@ class Provider extends AbstractProvider implements ProviderInterface
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get(
'https://id.anikeen.com/api/v1/user', [
$this->getBaseUrl() . '/api/v1/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,