Skip to content

Commit

Permalink
Feature: API Sync (#70)
Browse files Browse the repository at this point in the history
* Feature: Support disposition query parameter

* Feature: Support custom prices when updating and previewing subscriptions

* Fix: Add validation for pricing preview items

* Feature: Support notification settings pagination and active filter
  • Loading branch information
davidgrayston-paddle authored Sep 13, 2024
1 parent a148262 commit af2dfb0
Show file tree
Hide file tree
Showing 22 changed files with 725 additions and 15 deletions.
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

0 comments on commit af2dfb0

Please sign in to comment.