Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: API Sync #70

Merged
merged 15 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx
- Added `product` to `subscription.items[]`, see [related changelog](https://developer.paddle.com/changelog/2024/subscription-items-product?utm_source=dx&utm_medium=paddle-php-sdk)
- Added `import_meta` to `transaction`
- Support for `createdAt` and `updatedAt` on Subscription notification prices
- Support custom prices when updating and previewing subscriptions, see [related changelog](https://developer.paddle.com/changelog/2024/add-custom-items-subscription)
- `TransactionsClient::getInvoicePDF` now supports `disposition` parameter, see [related changelog](https://developer.paddle.com/changelog/2024/invoice-pdf-open-in-browser)
- Support notification settings pagination, see [related changelog](https://developer.paddle.com/changelog/2024/notification-settings-pagination)
- Support notification settings `active` filter

### Fixed

- `PreviewPrice` operation no longer allows empty `items`

## [1.1.2] - 2024-08-23

Expand Down
24 changes: 24 additions & 0 deletions src/Entities/Shared/Disposition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

/**
* |------
* | ! Generated code !
* | Altering this code will result in changes being overwritten |
* |-------------------------------------------------------------|.
*/

namespace Paddle\SDK\Entities\Shared;

use Paddle\SDK\PaddleEnum;

/**
* @method static Disposition Attachment()
* @method static Disposition Inline()
*/
final class Disposition extends PaddleEnum
{
private const Attachment = 'attachment';
private const Inline = 'inline';
}
3 changes: 3 additions & 0 deletions src/Entities/Subscription/SubscriptionNonCatalogPrice.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Paddle\SDK\Entities\Shared\Money;
use Paddle\SDK\Entities\Shared\PriceQuantity;
use Paddle\SDK\Entities\Shared\TaxMode;
use Paddle\SDK\Entities\Shared\TimePeriod;
use Paddle\SDK\Entities\Shared\UnitPriceOverride;

class SubscriptionNonCatalogPrice
Expand All @@ -31,6 +32,8 @@ public function __construct(
public array $unitPriceOverrides,
public PriceQuantity $quantity,
public CustomData|null $customData,
public TimePeriod|null $billingCycle = null,
public TimePeriod|null $trialPeriod = null,
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Paddle\SDK\Entities\Shared\Money;
use Paddle\SDK\Entities\Shared\PriceQuantity;
use Paddle\SDK\Entities\Shared\TaxMode;
use Paddle\SDK\Entities\Shared\TimePeriod;
use Paddle\SDK\Entities\Shared\UnitPriceOverride;

class SubscriptionNonCatalogPriceWithProduct
Expand All @@ -31,6 +32,8 @@ public function __construct(
public array $unitPriceOverrides,
public PriceQuantity $quantity,
public CustomData|null $customData,
public TimePeriod|null $billingCycle = null,
public TimePeriod|null $trialPeriod = null,
) {
}
}
5 changes: 5 additions & 0 deletions src/Exceptions/SdkExceptions/InvalidArgumentException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

class InvalidArgumentException extends SdkException
{
public static function arrayIsEmpty(string $field): self
{
return new self(sprintf('%s cannot be empty', $field));
}

public static function arrayContainsInvalidTypes(string $field, string $expectedType, string $given): self
{
return new self(sprintf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

use Paddle\SDK\Client;
use Paddle\SDK\Entities\Collections\NotificationSettingCollection;
use Paddle\SDK\Entities\Collections\Paginator;
use Paddle\SDK\Entities\NotificationSetting;
use Paddle\SDK\Exceptions\ApiError;
use Paddle\SDK\Exceptions\SdkExceptions\MalformedResponse;
use Paddle\SDK\Resources\NotificationSettings\Operations\CreateNotificationSetting;
use Paddle\SDK\Resources\NotificationSettings\Operations\ListNotificationSettings;
use Paddle\SDK\Resources\NotificationSettings\Operations\UpdateNotificationSetting;
use Paddle\SDK\ResponseParser;

Expand All @@ -31,14 +33,15 @@ public function __construct(
* @throws ApiError On a generic API error
* @throws MalformedResponse If the API response was not parsable
*/
public function list(): NotificationSettingCollection
public function list(ListNotificationSettings $listOperation = new ListNotificationSettings()): NotificationSettingCollection
{
$parser = new ResponseParser(
$this->client->getRaw('notification-settings'),
$this->client->getRaw('notification-settings', $listOperation),
);

return NotificationSettingCollection::from(
$parser->getData(),
new Paginator($this->client, $parser->getPagination(), NotificationSettingCollection::class),
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Paddle\SDK\Resources\NotificationSettings\Operations;

use Paddle\SDK\HasParameters;
use Paddle\SDK\Resources\Shared\Operations\List\Pager;

class ListNotificationSettings implements HasParameters
{
public function __construct(
private readonly Pager|null $pager = null,
private readonly bool|null $active = null,
) {
}

public function getParameters(): array
{
return array_merge(
$this->pager?->getParameters() ?? [],
array_filter([
'active' => isset($this->active) ? ($this->active ? 'true' : 'false') : null,
]),
);
}
}
8 changes: 8 additions & 0 deletions src/Resources/PricingPreviews/Operations/PreviewPrice.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Paddle\SDK\Entities\PricingPreview\PricePreviewItem;
use Paddle\SDK\Entities\Shared\AddressPreview;
use Paddle\SDK\Entities\Shared\CurrencyCode;
use Paddle\SDK\Exceptions\SdkExceptions\InvalidArgumentException;
use Paddle\SDK\FiltersUndefined;
use Paddle\SDK\Undefined;

Expand All @@ -27,6 +28,13 @@ public function __construct(
public readonly AddressPreview|Undefined|null $address = new Undefined(),
public readonly string|Undefined|null $customerIpAddress = new Undefined(),
) {
if (count($this->items) === 0) {
throw InvalidArgumentException::arrayIsEmpty('items');
}

if ($invalid = array_filter($this->items, fn ($value): bool => ! $value instanceof PricePreviewItem)) {
throw InvalidArgumentException::arrayContainsInvalidTypes('items', PricePreviewItem::class, implode(', ', $invalid));
}
}

public function jsonSerialize(): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Paddle\SDK\Entities\Shared\CurrencyCode;
use Paddle\SDK\Entities\Shared\CustomData;
use Paddle\SDK\Entities\Subscription\SubscriptionItems;
use Paddle\SDK\Entities\Subscription\SubscriptionItemsWithPrice;
use Paddle\SDK\Entities\Subscription\SubscriptionOnPaymentFailure;
use Paddle\SDK\Entities\Subscription\SubscriptionProrationBillingMode;
use Paddle\SDK\FiltersUndefined;
Expand All @@ -21,7 +22,7 @@ class PreviewUpdateSubscription implements \JsonSerializable
use FiltersUndefined;

/**
* @param array<SubscriptionItems> $items
* @param array<SubscriptionItems|SubscriptionItemsWithPrice> $items
*/
public function __construct(
public readonly string|Undefined $customerId = new Undefined(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Paddle\SDK\Entities\Shared\CurrencyCode;
use Paddle\SDK\Entities\Shared\CustomData;
use Paddle\SDK\Entities\Subscription\SubscriptionItems;
use Paddle\SDK\Entities\Subscription\SubscriptionItemsWithPrice;
use Paddle\SDK\Entities\Subscription\SubscriptionOnPaymentFailure;
use Paddle\SDK\Entities\Subscription\SubscriptionProrationBillingMode;
use Paddle\SDK\FiltersUndefined;
Expand All @@ -21,7 +22,7 @@ class UpdateSubscription implements \JsonSerializable
use FiltersUndefined;

/**
* @param array<SubscriptionItems> $items
* @param array<SubscriptionItems|SubscriptionItemsWithPrice> $items
*/
public function __construct(
public readonly string|Undefined $customerId = new Undefined(),
Expand Down
23 changes: 23 additions & 0 deletions src/Resources/Transactions/Operations/GetTransactionInvoice.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Paddle\SDK\Resources\Transactions\Operations;

use Paddle\SDK\Entities\Shared\Disposition;
use Paddle\SDK\HasParameters;

class GetTransactionInvoice implements HasParameters
{
public function __construct(
private readonly Disposition|null $disposition = null,
) {
}

public function getParameters(): array
{
return array_filter([
'disposition' => $this->disposition?->getValue(),
]);
}
}
5 changes: 3 additions & 2 deletions src/Resources/Transactions/TransactionsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Paddle\SDK\Exceptions\SdkExceptions\InvalidArgumentException;
use Paddle\SDK\Exceptions\SdkExceptions\MalformedResponse;
use Paddle\SDK\Resources\Transactions\Operations\CreateTransaction;
use Paddle\SDK\Resources\Transactions\Operations\GetTransactionInvoice;
use Paddle\SDK\Resources\Transactions\Operations\List\Includes;
use Paddle\SDK\Resources\Transactions\Operations\ListTransactions;
use Paddle\SDK\Resources\Transactions\Operations\PreviewTransaction;
Expand Down Expand Up @@ -128,10 +129,10 @@ public function preview(PreviewTransaction $operation): TransactionPreview
* @throws ApiError\TransactionApiError On a transaction specific API error
* @throws MalformedResponse If the API response was not parsable
*/
public function getInvoicePDF(string $id): TransactionData
public function getInvoicePDF(string $id, GetTransactionInvoice $getOperation = new GetTransactionInvoice()): TransactionData
{
$parser = new ResponseParser(
$this->client->getRaw("/transactions/{$id}/invoice"),
$this->client->getRaw("/transactions/{$id}/invoice", $getOperation),
);

return TransactionData::from($parser->getData());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
use Paddle\SDK\Environment;
use Paddle\SDK\Options;
use Paddle\SDK\Resources\NotificationSettings\Operations\CreateNotificationSetting;
use Paddle\SDK\Resources\NotificationSettings\Operations\ListNotificationSettings;
use Paddle\SDK\Resources\NotificationSettings\Operations\UpdateNotificationSetting;
use Paddle\SDK\Resources\Shared\Operations\List\OrderBy;
use Paddle\SDK\Resources\Shared\Operations\List\Pager;
use Paddle\SDK\Tests\Utils\ReadsFixtures;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestInterface;
Expand Down Expand Up @@ -173,11 +176,11 @@ public static function updateOperationsProvider(): \Generator
* @dataProvider listOperationsProvider
*/
public function list_hits_expected_uri(
ResponseInterface $response,
ListNotificationSettings $listOperation,
string $expectedUri,
): void {
$this->mockClient->addResponse($response);
$this->client->notificationSettings->list();
$this->mockClient->addResponse(new Response(200, body: self::readRawJsonFixture('response/list_default')));
$this->client->notificationSettings->list($listOperation);
$request = $this->mockClient->getLastRequest();

self::assertInstanceOf(RequestInterface::class, $request);
Expand All @@ -188,9 +191,92 @@ public function list_hits_expected_uri(
public static function listOperationsProvider(): \Generator
{
yield 'Default' => [
new Response(200, body: self::readRawJsonFixture('response/list_default')),
new ListNotificationSettings(),
sprintf('%s/notification-settings', Environment::SANDBOX->baseUrl()),
];

yield 'With active filter true' => [
new ListNotificationSettings(null, true),
sprintf('%s/notification-settings?active=true', Environment::SANDBOX->baseUrl()),
];

yield 'With active filter false' => [
new ListNotificationSettings(null, false),
sprintf('%s/notification-settings?active=false', Environment::SANDBOX->baseUrl()),
];

yield 'With default pagination' => [
new ListNotificationSettings(
new Pager(),
),
sprintf('%s/notification-settings?order_by=id[asc]&per_page=50', Environment::SANDBOX->baseUrl()),
];

yield 'With pagination after' => [
new ListNotificationSettings(
new Pager('ntfset_01gkpjp8bkm3tm53kdgkx6sms7'),
),
sprintf(
'%s/notification-settings?after=ntfset_01gkpjp8bkm3tm53kdgkx6sms7&order_by=id[asc]&per_page=50',
Environment::SANDBOX->baseUrl(),
),
];

yield 'With pagination after, order by ID asc' => [
new ListNotificationSettings(
new Pager('ntfset_02gkpjp8bkm3tm53kdgkx6sms7', OrderBy::idAscending()),
),
sprintf(
'%s/notification-settings?after=ntfset_02gkpjp8bkm3tm53kdgkx6sms7&order_by=id[asc]&per_page=50',
Environment::SANDBOX->baseUrl(),
),
];

yield 'With pagination after, order by ID desc' => [
new ListNotificationSettings(
new Pager('ntfset_03gkpjp8bkm3tm53kdgkx6sms7', OrderBy::idDescending()),
),
sprintf(
'%s/notification-settings?after=ntfset_03gkpjp8bkm3tm53kdgkx6sms7&order_by=id[desc]&per_page=50',
Environment::SANDBOX->baseUrl(),
),
];

yield 'With pagination after, order by ID asc, per page' => [
new ListNotificationSettings(
new Pager('ntfset_04gkpjp8bkm3tm53kdgkx6sms7', OrderBy::idDescending(), 10),
),
sprintf(
'%s/notification-settings?after=ntfset_04gkpjp8bkm3tm53kdgkx6sms7&order_by=id[desc]&per_page=10',
Environment::SANDBOX->baseUrl(),
),
];
}

/** @test */
public function it_can_paginate(): void
{
$this->mockClient->addResponse(new Response(200, body: self::readRawJsonFixture('response/list_paginated_page_one')));
$this->mockClient->addResponse(new Response(200, body: self::readRawJsonFixture('response/list_paginated_page_two')));

$collection = $this->client->notificationSettings->list();

$request = $this->mockClient->getLastRequest();

self::assertEquals(
Environment::SANDBOX->baseUrl() . '/notification-settings',
urldecode((string) $request->getUri()),
);

$allNotificationSettings = iterator_to_array($collection);
self::assertCount(2, $allNotificationSettings);

$request = $this->mockClient->getLastRequest();

self::assertEquals(
Environment::SANDBOX->baseUrl() . '/notification-settings?after=ntfset_01gkpjp8bkm3tm53kdgkx6sms7',
urldecode((string) $request->getUri()),
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@
}
],
"meta": {
"request_id": "cf039cbb-6c2a-485d-b244-501894b797a6"
"request_id": "cf039cbb-6c2a-485d-b244-501894b797a6",
"pagination": {
"per_page": 5,
"next": "https://api.paddle.com/notification-settings?after=ntfset_01gkpop8bkm3tm53itgkx6klk7",
"has_more": false,
"estimated_total": 5
}
}
}
Loading
Loading