From 217cad09c5d28faefc846be7bbdda26ed7ee363e Mon Sep 17 00:00:00 2001 From: David Grayston Date: Tue, 15 Oct 2024 22:29:25 +0100 Subject: [PATCH 1/2] feat: Handle notification entity serialization --- src/Client.php | 9 ++++- src/Entities/Event.php | 14 ++----- src/Notifications/Entities/Adjustment.php | 6 ++- src/Notifications/Entities/EntityFactory.php | 3 ++ .../Shared/PayoutTotalsAdjustment.php | 24 +++++++++-- .../Entities/UndefinedEntity.php | 30 ++++++++++++++ src/Notifications/Events/UndefinedEvent.php | 36 +++++++++++++++++ .../Resources/Events/EventsClientTest.php | 36 +++++++++++++++++ .../_fixtures/response/list_default.json | 8 ++++ .../Notifications/NotificationsClientTest.php | 40 +++++++++++++++++++ .../_fixtures/response/list_default.json | 22 ++++++++++ .../_fixtures/response/full_entity.json | 4 +- .../Simulations/SimulationsClientTest.php | 16 ++++++++ .../request/address_created_payload.json | 4 +- .../_fixtures/request/create_basic.json | 4 +- .../_fixtures/request/update_full.json | 1 + .../_fixtures/response/full_entity.json | 4 +- tests/Unit/Entities/EventTest.php | 21 ++++++++++ .../notification/entity/address.created.json | 4 +- 19 files changed, 260 insertions(+), 26 deletions(-) create mode 100644 src/Notifications/Entities/UndefinedEntity.php create mode 100644 src/Notifications/Events/UndefinedEvent.php diff --git a/src/Client.php b/src/Client.php index d8ab568..a4a42b2 100644 --- a/src/Client.php +++ b/src/Client.php @@ -17,6 +17,7 @@ use Http\Discovery\HttpAsyncClientDiscovery; use Http\Discovery\Psr17FactoryDiscovery; use Http\Message\Authentication\Bearer; +use Paddle\SDK\Entities\DateTime; use Paddle\SDK\Logger\Formatter; use Paddle\SDK\Resources\Addresses\AddressesClient; use Paddle\SDK\Resources\Adjustments\AdjustmentsClient; @@ -48,6 +49,7 @@ use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer; +use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; @@ -184,7 +186,12 @@ private function requestRaw(string $method, string|UriInterface $uri, array|\Jso $request = $this->requestFactory->createRequest($method, $uri); $serializer = new Serializer( - [new BackedEnumNormalizer(), new JsonSerializableNormalizer(), new ObjectNormalizer(nameConverter: new CamelCaseToSnakeCaseNameConverter())], + [ + new BackedEnumNormalizer(), + new DateTimeNormalizer([DateTimeNormalizer::FORMAT_KEY => DateTime::PADDLE_RFC3339]), + new JsonSerializableNormalizer(), + new ObjectNormalizer(nameConverter: new CamelCaseToSnakeCaseNameConverter()), + ], [new JsonEncoder()], ); diff --git a/src/Entities/Event.php b/src/Entities/Event.php index 729c2db..f5db070 100644 --- a/src/Entities/Event.php +++ b/src/Entities/Event.php @@ -6,6 +6,8 @@ use Paddle\SDK\Entities\Event\EventTypeName; use Paddle\SDK\Notifications\Entities\Entity as NotificationEntity; +use Paddle\SDK\Notifications\Entities\EntityFactory; +use Paddle\SDK\Notifications\Events\UndefinedEvent; use Psr\Http\Message\ServerRequestInterface; abstract class Event implements Entity @@ -22,28 +24,20 @@ protected function __construct( public static function from(array $data): self { $type = explode('.', (string) $data['event_type']); - $entity = $type[0] ?? 'Unknown'; $identifier = str_replace('_', '', ucwords(implode('_', $type), '_')); /** @var class-string $event */ $event = sprintf('\Paddle\SDK\Notifications\Events\%s', $identifier); if (! class_exists($event) || ! is_subclass_of($event, self::class)) { - throw new \UnexpectedValueException("Event type '{$identifier}' cannot be mapped to an object"); - } - - /** @var class-string $entity */ - $entity = sprintf('\Paddle\SDK\Notifications\Entities\%s', ucfirst($entity)); - - if (! class_exists($entity) || ! in_array(NotificationEntity::class, class_implements($entity), true)) { - throw new \UnexpectedValueException("Event type '{$identifier}' cannot be mapped to an object"); + $event = UndefinedEvent::class; } return $event::fromEvent( $data['event_id'], EventTypeName::from($data['event_type']), DateTime::from($data['occurred_at']), - $entity::from($data['data']), + EntityFactory::create($data['event_type'], $data['data']), $data['notification_id'] ?? null, ); } diff --git a/src/Notifications/Entities/Adjustment.php b/src/Notifications/Entities/Adjustment.php index ec4e291..0865628 100644 --- a/src/Notifications/Entities/Adjustment.php +++ b/src/Notifications/Entities/Adjustment.php @@ -38,7 +38,7 @@ private function __construct( public array $items, public AdjustmentTotals $totals, public PayoutTotalsAdjustment|null $payoutTotals, - public array $taxRatesUsed, + public array|null $taxRatesUsed, public \DateTimeInterface $createdAt, public \DateTimeInterface|null $updatedAt, ) { @@ -59,7 +59,9 @@ public static function from(array $data): self items: array_map(fn (array $item): AdjustmentItem => AdjustmentItem::from($item), $data['items']), totals: AdjustmentTotals::from($data['totals']), payoutTotals: isset($data['payout_totals']) ? PayoutTotalsAdjustment::from($data['payout_totals']) : null, - taxRatesUsed: array_map(fn (array $taxRateUsed): AdjustmentTaxRatesUsed => AdjustmentTaxRatesUsed::from($taxRateUsed), $data['tax_rates_used'] ?? []), + taxRatesUsed: isset($data['tax_rates_used']) + ? array_map(fn (array $taxRateUsed): AdjustmentTaxRatesUsed => AdjustmentTaxRatesUsed::from($taxRateUsed), $data['tax_rates_used'] ?? []) + : null, createdAt: DateTime::from($data['created_at']), updatedAt: isset($data['updated_at']) ? DateTime::from($data['updated_at']) : null, ); diff --git a/src/Notifications/Entities/EntityFactory.php b/src/Notifications/Entities/EntityFactory.php index 63c4a47..db0d9b8 100644 --- a/src/Notifications/Entities/EntityFactory.php +++ b/src/Notifications/Entities/EntityFactory.php @@ -14,6 +14,9 @@ public static function create(string $eventType, array $data): Entity /** @var class-string $entity */ $entity = sprintf('\Paddle\SDK\Notifications\Entities\%s', ucfirst($entity)); + if (! class_exists($entity)) { + $entity = UndefinedEntity::class; + } if (! class_exists($entity) || ! in_array(Entity::class, class_implements($entity), true)) { throw new \UnexpectedValueException("Event type '{$identifier}' cannot be mapped to an object"); diff --git a/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php b/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php index 551c994..eee9407 100644 --- a/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php +++ b/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php @@ -11,14 +11,19 @@ namespace Paddle\SDK\Notifications\Entities\Shared; -class PayoutTotalsAdjustment +use Paddle\SDK\FiltersUndefined; +use Paddle\SDK\Undefined; + +class PayoutTotalsAdjustment implements \JsonSerializable { + use FiltersUndefined; + private function __construct( public string $subtotal, public string $tax, public string $total, public string $fee, - public ChargebackFee|null $chargebackFee, + public ChargebackFee|Undefined|null $chargebackFee, public string $earnings, public CurrencyCodePayouts $currencyCode, ) { @@ -31,9 +36,22 @@ public static function from(array $data): self tax: $data['tax'], total: $data['total'], fee: $data['fee'], - chargebackFee: isset($data['chargeback_fee']) ? ChargebackFee::from($data['chargeback_fee']) : null, + chargebackFee: isset($data['chargeback_fee']) ? ChargebackFee::from($data['chargeback_fee']) : new Undefined(), earnings: $data['earnings'], currencyCode: CurrencyCodePayouts::from($data['currency_code']), ); } + + public function jsonSerialize(): array + { + return $this->filterUndefined([ + 'subtotal' => $this->subtotal, + 'tax' => $this->tax, + 'total' => $this->total, + 'fee' => $this->fee, + 'chargeback_fee' => $this->chargebackFee, + 'earnings' => $this->earnings, + 'currency_code' => $this->currencyCode, + ]); + } } diff --git a/src/Notifications/Entities/UndefinedEntity.php b/src/Notifications/Entities/UndefinedEntity.php new file mode 100644 index 0000000..abcfbaa --- /dev/null +++ b/src/Notifications/Entities/UndefinedEntity.php @@ -0,0 +1,30 @@ +data; + } +} diff --git a/src/Notifications/Events/UndefinedEvent.php b/src/Notifications/Events/UndefinedEvent.php new file mode 100644 index 0000000..7efef86 --- /dev/null +++ b/src/Notifications/Events/UndefinedEvent.php @@ -0,0 +1,36 @@ +createdAt->format(\DATE_RFC3339_EXTENDED)); self::assertSame('2023-11-24T14:12:05.528+00:00', $price1->updatedAt->format(\DATE_RFC3339_EXTENDED)); } + + /** + * @test + */ + public function list_handles_unknown_events(): void + { + $this->mockClient->addResponse(new Response(200, body: self::readRawJsonFixture('response/list_default'))); + $events = $this->client->events->list(new ListEvents()); + $request = $this->mockClient->getLastRequest(); + + self::assertInstanceOf(RequestInterface::class, $request); + self::assertEquals('GET', $request->getMethod()); + + $undefinedEvents = array_values( + array_filter( + iterator_to_array($events), + fn ($event) => (string) $event->eventType === 'unknown_entity.updated', + ), + ); + + $undefinedEvent = $undefinedEvents[0]; + self::assertInstanceOf(UndefinedEvent::class, $undefinedEvent); + self::assertSame($undefinedEvent->entity, $undefinedEvent->data); + self::assertInstanceOf(UndefinedEntity::class, $undefinedEvent->entity); + self::assertInstanceOf(UndefinedEntity::class, $undefinedEvent->data); + self::assertInstanceOf(Entity::class, $undefinedEvent->data); + self::assertEquals( + [ + 'key' => 'value', + ], + $undefinedEvent->entity->data, + ); + } } diff --git a/tests/Functional/Resources/Events/_fixtures/response/list_default.json b/tests/Functional/Resources/Events/_fixtures/response/list_default.json index 377afbd..b4eb9d6 100644 --- a/tests/Functional/Resources/Events/_fixtures/response/list_default.json +++ b/tests/Functional/Resources/Events/_fixtures/response/list_default.json @@ -2801,6 +2801,14 @@ "updated_at": "2023-11-23T15:33:19.238230688Z", "billed_at": "2023-11-23T15:33:01.930479Z" } + }, + { + "event_id": "evt_01hfyd0v4xppkwmjaca5xyzh5d", + "event_type": "unknown_entity.updated", + "occurred_at": "2023-11-23T15:33:19.645134Z", + "data": { + "key": "value" + } } ], "meta": { diff --git a/tests/Functional/Resources/Notifications/NotificationsClientTest.php b/tests/Functional/Resources/Notifications/NotificationsClientTest.php index 0e8dacc..af592e1 100644 --- a/tests/Functional/Resources/Notifications/NotificationsClientTest.php +++ b/tests/Functional/Resources/Notifications/NotificationsClientTest.php @@ -7,8 +7,12 @@ use GuzzleHttp\Psr7\Response; use Http\Mock\Client as MockClient; use Paddle\SDK\Client; +use Paddle\SDK\Entities\Notification; use Paddle\SDK\Entities\Notification\NotificationStatus; use Paddle\SDK\Environment; +use Paddle\SDK\Notifications\Entities\Entity; +use Paddle\SDK\Notifications\Entities\UndefinedEntity; +use Paddle\SDK\Notifications\Events\UndefinedEvent; use Paddle\SDK\Options; use Paddle\SDK\Resources\Notifications\Operations\ListNotifications; use Paddle\SDK\Resources\Shared\Operations\List\Pager; @@ -171,4 +175,40 @@ public function replay_hits_expected_uri(): void ); self::assertSame('ntf_01h46h1s2zabpkdks7yt4vkgkc', $replayId); } + + /** + * @test + */ + public function list_handles_unknown_events(): void + { + $this->mockClient->addResponse(new Response(200, body: self::readRawJsonFixture('response/list_default'))); + $notifications = $this->client->notifications->list(new ListNotifications()); + $request = $this->mockClient->getLastRequest(); + + self::assertInstanceOf(RequestInterface::class, $request); + self::assertEquals('GET', $request->getMethod()); + + $undefinedEventNotifications = array_values( + array_filter( + iterator_to_array($notifications), + fn (Notification $notification) => (string) $notification->type === 'unknown_entity.updated', + ), + ); + + $undefinedEventNotification = $undefinedEventNotifications[0]; + self::assertInstanceOf(Notification::class, $undefinedEventNotification); + + $undefinedEvent = $undefinedEventNotification->payload; + self::assertInstanceOf(UndefinedEvent::class, $undefinedEvent); + self::assertSame($undefinedEvent->entity, $undefinedEvent->data); + self::assertInstanceOf(Entity::class, $undefinedEvent->data); + self::assertInstanceOf(UndefinedEntity::class, $undefinedEvent->data); + self::assertInstanceOf(UndefinedEntity::class, $undefinedEvent->entity); + self::assertEquals( + [ + 'key' => 'value', + ], + $undefinedEvent->entity->data, + ); + } } diff --git a/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json b/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json index bd92d24..29b9362 100644 --- a/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json +++ b/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json @@ -452,6 +452,28 @@ "retry_at": null, "times_attempted": 1, "notification_setting_id": "ntfset_01h7zcdzf04a7wvyja9k9p1n3p" + }, + { + "id": "ntf_01h8441jz6fr97hv7zemswj8cw", + "type": "unknown_entity.updated", + "status": "delivered", + "payload": { + "data": { + "key": "value" + }, + "event_id": "evt_01h8441jx8x1q971q9ksksqh82", + "event_type": "unknown_entity.updated", + "occurred_at": "2023-08-18T10:46:18.792661Z", + "notification_id": "ntf_01h8441jz6fr97hv7zemswj8cw" + }, + "occurred_at": "2023-08-18T10:46:18.792661Z", + "delivered_at": "2023-08-18T10:46:19.396422Z", + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-18T10:46:18.887423Z", + "retry_at": null, + "times_attempted": 1, + "notification_setting_id": "ntfset_01h7zcdzf04a7wvyja9k9p1n3p" } ], "meta": { diff --git a/tests/Functional/Resources/SimulationRunEvents/_fixtures/response/full_entity.json b/tests/Functional/Resources/SimulationRunEvents/_fixtures/response/full_entity.json index 18b52cd..fe66a71 100644 --- a/tests/Functional/Resources/SimulationRunEvents/_fixtures/response/full_entity.json +++ b/tests/Functional/Resources/SimulationRunEvents/_fixtures/response/full_entity.json @@ -8,9 +8,9 @@ "city": "New York", "region": "NY", "status": "active", - "created_at": "2024-04-12T06:42:58.785Z", + "created_at": "2024-04-12T06:42:58.785000Z", "first_line": "4050 Jefferson Plaza, 41st Floor", - "updated_at": "2024-04-12T06:42:58.785Z", + "updated_at": "2024-04-12T06:42:58.785000Z", "custom_data": null, "customer_id": "ctm_01hv6y1jedq4p1n0yqn5ba3ky4", "description": "Head Office", diff --git a/tests/Functional/Resources/Simulations/SimulationsClientTest.php b/tests/Functional/Resources/Simulations/SimulationsClientTest.php index 7477ac3..aea1e7d 100644 --- a/tests/Functional/Resources/Simulations/SimulationsClientTest.php +++ b/tests/Functional/Resources/Simulations/SimulationsClientTest.php @@ -70,6 +70,22 @@ public static function createOperationsProvider(): \Generator new Response(200, body: self::readRawJsonFixture('response/full_entity')), self::readRawJsonFixture('request/create_basic'), ]; + + yield 'Undefined' => [ + new CreateSimulation( + notificationSettingId: 'ntfset_01j82d983j814ypzx7m1fw2jpz', + type: EventTypeName::from('unknown_entity.created'), + name: 'Some Simulation', + payload: EntityFactory::create('unknown_entity.created', ['some' => 'data']), + ), + new Response(200, body: self::readRawJsonFixture('response/full_entity')), + json_encode([ + 'notification_setting_id' => 'ntfset_01j82d983j814ypzx7m1fw2jpz', + 'name' => 'Some Simulation', + 'type' => 'unknown_entity.created', + 'payload' => ['some' => 'data'], + ]), + ]; } /** diff --git a/tests/Functional/Resources/Simulations/_fixtures/request/address_created_payload.json b/tests/Functional/Resources/Simulations/_fixtures/request/address_created_payload.json index 432e7b3..f160c96 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/request/address_created_payload.json +++ b/tests/Functional/Resources/Simulations/_fixtures/request/address_created_payload.json @@ -3,9 +3,9 @@ "city": "New York", "region": "NY", "status": "active", - "created_at": "2024-04-12T06:42:58.785Z", + "created_at": "2024-04-12T06:42:58.785000Z", "first_line": "4050 Jefferson Plaza, 41st Floor", - "updated_at": "2024-04-12T06:42:58.785Z", + "updated_at": "2024-04-12T06:42:58.785000Z", "custom_data": null, "customer_id": "ctm_01hv6y1jedq4p1n0yqn5ba3ky4", "description": "Head Office", diff --git a/tests/Functional/Resources/Simulations/_fixtures/request/create_basic.json b/tests/Functional/Resources/Simulations/_fixtures/request/create_basic.json index 75cfafe..6577e27 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/request/create_basic.json +++ b/tests/Functional/Resources/Simulations/_fixtures/request/create_basic.json @@ -7,9 +7,9 @@ "city": "New York", "region": "NY", "status": "active", - "created_at": "2024-04-12T06:42:58.785Z", + "created_at": "2024-04-12T06:42:58.785000Z", "first_line": "4050 Jefferson Plaza, 41st Floor", - "updated_at": "2024-04-12T06:42:58.785Z", + "updated_at": "2024-04-12T06:42:58.785000Z", "custom_data": null, "customer_id": "ctm_01hv6y1jedq4p1n0yqn5ba3ky4", "description": "Head Office", diff --git a/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json b/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json index 56b48a8..6485a62 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json +++ b/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json @@ -8,6 +8,7 @@ "action": "refund", "transaction_id": "txn_01hvcc93znj3mpqt1tenkjb04y", "subscription_id": "sub_01hvccbx32q2gb40sqx7n42430", + "tax_rates_used": null, "customer_id": "ctm_01hrffh7gvp29kc7xahm8wddwa", "reason": "error", "credit_applied_to_balance": null, diff --git a/tests/Functional/Resources/Simulations/_fixtures/response/full_entity.json b/tests/Functional/Resources/Simulations/_fixtures/response/full_entity.json index 6097b6a..379be80 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/response/full_entity.json +++ b/tests/Functional/Resources/Simulations/_fixtures/response/full_entity.json @@ -10,9 +10,9 @@ "city": "New York", "region": "NY", "status": "active", - "created_at": "2024-04-12T06:42:58.785Z", + "created_at": "2024-04-12T06:42:58.785000Z", "first_line": "4050 Jefferson Plaza, 41st Floor", - "updated_at": "2024-04-12T06:42:58.785Z", + "updated_at": "2024-04-12T06:42:58.785000Z", "custom_data": null, "customer_id": "ctm_01hv6y1jedq4p1n0yqn5ba3ky4", "description": "Head Office", diff --git a/tests/Unit/Entities/EventTest.php b/tests/Unit/Entities/EventTest.php index 6e6a046..fc83893 100644 --- a/tests/Unit/Entities/EventTest.php +++ b/tests/Unit/Entities/EventTest.php @@ -333,6 +333,27 @@ public static function eventDataProvider(): iterable } } + /** + * @test + */ + public function it_creates_event_for_undefined_entity(): void + { + $event = Event::from([ + 'event_id' => 'evt_01h8bzakzx3hm2fmen703n5q45', + 'event_type' => 'unknown_event.created', + 'occurred_at' => '2023-08-21T11:57:47.390028Z', + 'notification_id' => 'ntf_01h8bzam1z32agrxjwhjgqk8w6', + 'data' => [ + 'some' => 'data', + ], + ]); + + self::assertSame('ntf_01h8bzam1z32agrxjwhjgqk8w6', $event->notificationId); + + self::assertInstanceOf(Event::class, $event); + self::assertInstanceOf(Entity::class, $event->data); + } + /** * @test */ diff --git a/tests/Unit/Entities/_fixtures/notification/entity/address.created.json b/tests/Unit/Entities/_fixtures/notification/entity/address.created.json index 10dcb1e..6103eac 100644 --- a/tests/Unit/Entities/_fixtures/notification/entity/address.created.json +++ b/tests/Unit/Entities/_fixtures/notification/entity/address.created.json @@ -3,9 +3,9 @@ "city": "New York", "region": "NY", "status": "active", - "created_at": "2024-04-12T06:42:58.785Z", + "created_at": "2024-04-12T06:42:58.785000Z", "first_line": "4050 Jefferson Plaza, 41st Floor", - "updated_at": "2024-04-12T06:42:58.785Z", + "updated_at": "2024-04-12T06:42:58.785000Z", "custom_data": null, "customer_id": "ctm_01hv6y1jedq4p1n0yqn5ba3ky4", "description": "Head Office", From 21202d5d0594c3d3bc7eb601bbdc0a2043f8188c Mon Sep 17 00:00:00 2001 From: David Grayston Date: Wed, 16 Oct 2024 23:20:11 +0100 Subject: [PATCH 2/2] feat: Revert changes to support optional properties --- src/Notifications/Entities/Adjustment.php | 6 ++--- .../Shared/PayoutTotalsAdjustment.php | 24 +++---------------- .../request/adjustment_updated_payload.json | 7 ++++++ .../_fixtures/request/update_full.json | 9 ++++++- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/Notifications/Entities/Adjustment.php b/src/Notifications/Entities/Adjustment.php index 0865628..ec4e291 100644 --- a/src/Notifications/Entities/Adjustment.php +++ b/src/Notifications/Entities/Adjustment.php @@ -38,7 +38,7 @@ private function __construct( public array $items, public AdjustmentTotals $totals, public PayoutTotalsAdjustment|null $payoutTotals, - public array|null $taxRatesUsed, + public array $taxRatesUsed, public \DateTimeInterface $createdAt, public \DateTimeInterface|null $updatedAt, ) { @@ -59,9 +59,7 @@ public static function from(array $data): self items: array_map(fn (array $item): AdjustmentItem => AdjustmentItem::from($item), $data['items']), totals: AdjustmentTotals::from($data['totals']), payoutTotals: isset($data['payout_totals']) ? PayoutTotalsAdjustment::from($data['payout_totals']) : null, - taxRatesUsed: isset($data['tax_rates_used']) - ? array_map(fn (array $taxRateUsed): AdjustmentTaxRatesUsed => AdjustmentTaxRatesUsed::from($taxRateUsed), $data['tax_rates_used'] ?? []) - : null, + taxRatesUsed: array_map(fn (array $taxRateUsed): AdjustmentTaxRatesUsed => AdjustmentTaxRatesUsed::from($taxRateUsed), $data['tax_rates_used'] ?? []), createdAt: DateTime::from($data['created_at']), updatedAt: isset($data['updated_at']) ? DateTime::from($data['updated_at']) : null, ); diff --git a/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php b/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php index eee9407..551c994 100644 --- a/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php +++ b/src/Notifications/Entities/Shared/PayoutTotalsAdjustment.php @@ -11,19 +11,14 @@ namespace Paddle\SDK\Notifications\Entities\Shared; -use Paddle\SDK\FiltersUndefined; -use Paddle\SDK\Undefined; - -class PayoutTotalsAdjustment implements \JsonSerializable +class PayoutTotalsAdjustment { - use FiltersUndefined; - private function __construct( public string $subtotal, public string $tax, public string $total, public string $fee, - public ChargebackFee|Undefined|null $chargebackFee, + public ChargebackFee|null $chargebackFee, public string $earnings, public CurrencyCodePayouts $currencyCode, ) { @@ -36,22 +31,9 @@ public static function from(array $data): self tax: $data['tax'], total: $data['total'], fee: $data['fee'], - chargebackFee: isset($data['chargeback_fee']) ? ChargebackFee::from($data['chargeback_fee']) : new Undefined(), + chargebackFee: isset($data['chargeback_fee']) ? ChargebackFee::from($data['chargeback_fee']) : null, earnings: $data['earnings'], currencyCode: CurrencyCodePayouts::from($data['currency_code']), ); } - - public function jsonSerialize(): array - { - return $this->filterUndefined([ - 'subtotal' => $this->subtotal, - 'tax' => $this->tax, - 'total' => $this->total, - 'fee' => $this->fee, - 'chargeback_fee' => $this->chargebackFee, - 'earnings' => $this->earnings, - 'currency_code' => $this->currencyCode, - ]); - } } diff --git a/tests/Functional/Resources/Simulations/_fixtures/request/adjustment_updated_payload.json b/tests/Functional/Resources/Simulations/_fixtures/request/adjustment_updated_payload.json index 2b29687..3ec5b3d 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/request/adjustment_updated_payload.json +++ b/tests/Functional/Resources/Simulations/_fixtures/request/adjustment_updated_payload.json @@ -31,6 +31,13 @@ "currency_code": "USD" }, "payout_totals": { + "chargeback_fee": { + "amount": "1", + "original": { + "amount": "2", + "currency_code": "USD" + } + }, "subtotal": "92", "tax": "8", "total": "100", diff --git a/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json b/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json index 6485a62..d9623f3 100644 --- a/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json +++ b/tests/Functional/Resources/Simulations/_fixtures/request/update_full.json @@ -8,7 +8,7 @@ "action": "refund", "transaction_id": "txn_01hvcc93znj3mpqt1tenkjb04y", "subscription_id": "sub_01hvccbx32q2gb40sqx7n42430", - "tax_rates_used": null, + "tax_rates_used": [], "customer_id": "ctm_01hrffh7gvp29kc7xahm8wddwa", "reason": "error", "credit_applied_to_balance": null, @@ -37,6 +37,13 @@ "currency_code": "USD" }, "payout_totals": { + "chargeback_fee": { + "amount": "1", + "original": { + "amount": "2", + "currency_code": "USD" + } + }, "subtotal": "92", "tax": "8", "total": "100",