From 4d650f1bbaabbf32dd77818d55848ee7484e6ca0 Mon Sep 17 00:00:00 2001 From: Kajetan Nobel Date: Wed, 27 Sep 2023 00:36:27 +0200 Subject: [PATCH] feat: adds new NotificationService --- src/DTO/BaseDto.php | 4 +- .../Notifications/OneClickNotificationDto.php | 9 +++ src/Factories/Casts/PaymentDtoFactory.php | 16 ++--- .../Casts/PaymentProfileDtoFactory.php | 30 ++++----- src/Factories/Casts/TransactionDtoFactory.php | 23 +++++-- src/Factories/Factory.php | 4 ++ .../OneClickNotificationDtoFactory.php | 23 +++++++ src/Services/NotificationService.php | 62 +++++++++++++++++++ tests/Services/NotificationServiceTest.php | 21 +++++++ 9 files changed, 155 insertions(+), 37 deletions(-) create mode 100644 src/Factories/Notifications/OneClickNotificationDtoFactory.php create mode 100644 src/Services/NotificationService.php create mode 100644 tests/Services/NotificationServiceTest.php diff --git a/src/DTO/BaseDto.php b/src/DTO/BaseDto.php index a7a9de6..cbac012 100644 --- a/src/DTO/BaseDto.php +++ b/src/DTO/BaseDto.php @@ -29,7 +29,9 @@ private function castAttributes(array $attributes): array public function castAttribute(string $castType, mixed $value): mixed { if (is_a($castType, BaseDto::class, true)) { - return new $castType($value ?? []); + return $value instanceof BaseDto + ? $value + : new $castType($value ?? []); } if (enum_exists($castType)) { diff --git a/src/DTO/Notifications/OneClickNotificationDto.php b/src/DTO/Notifications/OneClickNotificationDto.php index 2bcbbdc..d9575b1 100644 --- a/src/DTO/Notifications/OneClickNotificationDto.php +++ b/src/DTO/Notifications/OneClickNotificationDto.php @@ -4,9 +4,11 @@ namespace Routegroup\Imoje\Payment\DTO\Notifications; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Routegroup\Imoje\Payment\DTO\BaseDto; use Routegroup\Imoje\Payment\DTO\Casts\PaymentDto; use Routegroup\Imoje\Payment\DTO\Casts\TransactionDto; +use Routegroup\Imoje\Payment\Factories\Notifications\OneClickNotificationDtoFactory; /** * @property-read TransactionDto $transaction @@ -14,8 +16,15 @@ */ class OneClickNotificationDto extends BaseDto { + use HasFactory; + protected array $casts = [ 'transaction' => TransactionDto::class, 'payment' => PaymentDto::class, ]; + + protected static function newFactory(): OneClickNotificationDtoFactory + { + return OneClickNotificationDtoFactory::new(); + } } diff --git a/src/Factories/Casts/PaymentDtoFactory.php b/src/Factories/Casts/PaymentDtoFactory.php index 892026c..9b48163 100644 --- a/src/Factories/Casts/PaymentDtoFactory.php +++ b/src/Factories/Casts/PaymentDtoFactory.php @@ -7,11 +7,7 @@ use Routegroup\Imoje\Payment\DTO\Casts\PaymentDto; use Routegroup\Imoje\Payment\Factories\Factory; use Routegroup\Imoje\Payment\Types\Currency; -use Routegroup\Imoje\Payment\Types\PaymentMethod; -use Routegroup\Imoje\Payment\Types\PaymentMethodCode; -use Routegroup\Imoje\Payment\Types\TransactionSource; use Routegroup\Imoje\Payment\Types\TransactionStatus; -use Routegroup\Imoje\Payment\Types\TransactionType; class PaymentDtoFactory extends Factory { @@ -23,17 +19,13 @@ public function definition(): array return [ 'id' => $this->faker->unique()->uuid, - 'type' => TransactionType::REFUND->value, - 'status' => TransactionStatus::SETTLED->value, - 'source' => TransactionSource::API->value, + 'amount' => $this->faker->numberBetween(1, 1000) * 100, + 'status' => TransactionStatus::SETTLED, 'created' => $now->timestamp, + 'orderId' => $this->faker->unique()->uuid, + 'currency' => Currency::PLN, 'modified' => $now->timestamp, 'serviceId' => config('services.imoje.service_key'), - 'amount' => $this->faker->numberBetween(1, 100) * 100, - 'currency' => Currency::PLN->value, - 'orderId' => $this->faker->unique()->uuid, - 'paymentMethod' => PaymentMethod::CARD->value, - 'paymentMethodCode' => PaymentMethodCode::ONECLICK->value, ]; } } diff --git a/src/Factories/Casts/PaymentProfileDtoFactory.php b/src/Factories/Casts/PaymentProfileDtoFactory.php index 8c307d6..d483814 100644 --- a/src/Factories/Casts/PaymentProfileDtoFactory.php +++ b/src/Factories/Casts/PaymentProfileDtoFactory.php @@ -4,14 +4,9 @@ namespace Routegroup\Imoje\Payment\Factories\Casts; +use Illuminate\Support\Str; use Routegroup\Imoje\Payment\DTO\Casts\PaymentProfileDto; use Routegroup\Imoje\Payment\Factories\Factory; -use Routegroup\Imoje\Payment\Types\Currency; -use Routegroup\Imoje\Payment\Types\PaymentMethod; -use Routegroup\Imoje\Payment\Types\PaymentMethodCode; -use Routegroup\Imoje\Payment\Types\TransactionSource; -use Routegroup\Imoje\Payment\Types\TransactionStatus; -use Routegroup\Imoje\Payment\Types\TransactionType; class PaymentProfileDtoFactory extends Factory { @@ -19,21 +14,20 @@ class PaymentProfileDtoFactory extends Factory public function definition(): array { - $now = now(); + $expirationDate = $this->faker->creditCardExpirationDate; return [ 'id' => $this->faker->unique()->uuid, - 'type' => TransactionType::REFUND->value, - 'status' => TransactionStatus::SETTLED->value, - 'source' => TransactionSource::API->value, - 'created' => $now->timestamp, - 'modified' => $now->timestamp, - 'serviceId' => config('services.imoje.service_key'), - 'amount' => $this->faker->numberBetween(1, 100) * 100, - 'currency' => Currency::PLN->value, - 'orderId' => $this->faker->unique()->uuid, - 'paymentMethod' => PaymentMethod::CARD->value, - 'paymentMethodCode' => PaymentMethodCode::ONECLICK->value, + 'merchantMid' => Str::random(), + 'merchantCustomerId' => $this->faker->unique()->numberBetween(1, 999999), + 'firstName' => $this->faker->firstName, + 'lastName' => $this->faker->lastName, + 'maskedNumber' => $this->faker->numerify('****####'), + 'month' => $expirationDate->format('m'), + 'year' => $expirationDate->format('Y'), + 'organization' => $this->faker->creditCardType, + 'isActive' => 1, + 'profile' => '', ]; } } diff --git a/src/Factories/Casts/TransactionDtoFactory.php b/src/Factories/Casts/TransactionDtoFactory.php index 8c9736b..a60f915 100644 --- a/src/Factories/Casts/TransactionDtoFactory.php +++ b/src/Factories/Casts/TransactionDtoFactory.php @@ -23,17 +23,28 @@ public function definition(): array return [ 'id' => $this->faker->unique()->uuid, - 'type' => TransactionType::REFUND->value, - 'status' => TransactionStatus::SETTLED->value, - 'source' => TransactionSource::API->value, + 'type' => TransactionType::REFUND, + 'status' => TransactionStatus::SETTLED, + 'source' => TransactionSource::API, 'created' => $now->timestamp, 'modified' => $now->timestamp, 'serviceId' => config('services.imoje.service_key'), 'amount' => $this->faker->numberBetween(1, 100) * 100, - 'currency' => Currency::PLN->value, + 'currency' => Currency::PLN, 'orderId' => $this->faker->unique()->uuid, - 'paymentMethod' => PaymentMethod::CARD->value, - 'paymentMethodCode' => PaymentMethodCode::ONECLICK->value, + 'paymentMethod' => $this->faker->randomElement(PaymentMethod::cases()), + 'paymentMethodCode' => $this->faker->randomElement(PaymentMethodCode::cases()), ]; } + + public function asOneClick(): static + { + return $this->state([ + 'type' => TransactionType::SALE, + 'status' => TransactionStatus::SETTLED, + 'source' => TransactionSource::WEB, + 'paymentMethod' => PaymentMethod::CARD, + 'paymentMethodCode' => PaymentMethodCode::ONECLICK, + ]); + } } diff --git a/src/Factories/Factory.php b/src/Factories/Factory.php index c74b8c1..d0ba96f 100644 --- a/src/Factories/Factory.php +++ b/src/Factories/Factory.php @@ -12,6 +12,10 @@ abstract class Factory extends BaseFactory { public function create($attributes = [], Model $parent = null) { + if (! empty($attributes)) { + return $this->state($attributes)->create([], $parent); + } + return $this->make($attributes, $parent); } diff --git a/src/Factories/Notifications/OneClickNotificationDtoFactory.php b/src/Factories/Notifications/OneClickNotificationDtoFactory.php new file mode 100644 index 0000000..4932f3d --- /dev/null +++ b/src/Factories/Notifications/OneClickNotificationDtoFactory.php @@ -0,0 +1,23 @@ + TransactionDto::factory()->asOneClick(), + 'payment' => PaymentDto::factory(), + ]; + } +} diff --git a/src/Services/NotificationService.php b/src/Services/NotificationService.php new file mode 100644 index 0000000..f366480 --- /dev/null +++ b/src/Services/NotificationService.php @@ -0,0 +1,62 @@ +toArray(); + + $this->validator->fromNotification($data); + + if ($this->isOneClick($data)) { + return new OneClickNotificationDto($data); + } + + throw new NotImplementedException($data); + } + + protected function isOneClick(array $data): bool + { + return $this->isEqualWithStructure($data, [ + 'transaction' => [ + 'type' => TransactionType::SALE->value, + 'source' => TransactionSource::WEB->value, + 'paymentMethod' => PaymentMethod::CARD->value, + 'paymentMethodCode' => PaymentMethodCode::ONECLICK->value, + ], + ]); + } + + protected function isEqualWithStructure(array $data, array $structure): bool + { + $structure = Arr::dot($structure); + $data = Arr::dot($data); + + return count($structure) === count(array_intersect($structure, $data)); + } +} diff --git a/tests/Services/NotificationServiceTest.php b/tests/Services/NotificationServiceTest.php new file mode 100644 index 0000000..f0ce178 --- /dev/null +++ b/tests/Services/NotificationServiceTest.php @@ -0,0 +1,21 @@ +service = app(NotificationService::class); +}); + +function mockRequest(BaseDto $dto): Request +{ + return new Request($dto->toArray()); +} + +it('returns OneClickNotification', function (): void { + $request = mockRequest(OneClickNotificationDto::factory()->make()); + $result = $this->service->resolve($request); + expect($result)->toBeInstanceOf(OneClickNotificationDto::class); +});