From 2d110487bce253e8fba244256aa864c351ffc8b6 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 2 Aug 2022 16:00:27 +0300 Subject: [PATCH 1/7] transaction created event --- config/config.php | 4 ++ .../TransactionCreatedEventAssembler.php | 28 ++++++++++++++ ...nsactionCreatedEventAssemblerInterface.php | 13 +++++++ .../Events/TransactionCreatedEvent.php | 38 +++++++++++++++++++ .../TransactionCreatedEventInterface.php | 18 +++++++++ src/Services/TransactionService.php | 8 ++++ src/WalletServiceProvider.php | 14 +++++++ 7 files changed, 123 insertions(+) create mode 100644 src/Internal/Assembler/TransactionCreatedEventAssembler.php create mode 100644 src/Internal/Assembler/TransactionCreatedEventAssemblerInterface.php create mode 100644 src/Internal/Events/TransactionCreatedEvent.php create mode 100644 src/Internal/Events/TransactionCreatedEventInterface.php diff --git a/config/config.php b/config/config.php index 8ed1effac..522928ec9 100644 --- a/config/config.php +++ b/config/config.php @@ -6,12 +6,14 @@ use Bavix\Wallet\Internal\Assembler\BalanceUpdatedEventAssembler; use Bavix\Wallet\Internal\Assembler\ExtraDtoAssembler; use Bavix\Wallet\Internal\Assembler\OptionDtoAssembler; +use Bavix\Wallet\Internal\Assembler\TransactionCreatedEventAssembler; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionQueryAssembler; use Bavix\Wallet\Internal\Assembler\TransferDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransferQueryAssembler; use Bavix\Wallet\Internal\Events\BalanceUpdatedEvent; +use Bavix\Wallet\Internal\Events\TransactionCreatedEvent; use Bavix\Wallet\Internal\Events\WalletCreatedEvent; use Bavix\Wallet\Internal\Repository\TransactionRepository; use Bavix\Wallet\Internal\Repository\TransferRepository; @@ -139,6 +141,7 @@ 'transaction' => TransactionDtoAssembler::class, 'transfer_lazy' => TransferLazyDtoAssembler::class, 'transfer' => TransferDtoAssembler::class, + 'transaction_created_event' => TransactionCreatedEventAssembler::class, 'transaction_query' => TransactionQueryAssembler::class, 'transfer_query' => TransferQueryAssembler::class, ], @@ -149,6 +152,7 @@ 'events' => [ 'balance_updated' => BalanceUpdatedEvent::class, 'wallet_created' => WalletCreatedEvent::class, + 'transaction_created' => TransactionCreatedEvent::class, ], /** diff --git a/src/Internal/Assembler/TransactionCreatedEventAssembler.php b/src/Internal/Assembler/TransactionCreatedEventAssembler.php new file mode 100644 index 000000000..4be5cef8d --- /dev/null +++ b/src/Internal/Assembler/TransactionCreatedEventAssembler.php @@ -0,0 +1,28 @@ +getKey(), + $transaction->type, + $transaction->wallet_id, + $this->clockService->now(), + ); + } +} diff --git a/src/Internal/Assembler/TransactionCreatedEventAssemblerInterface.php b/src/Internal/Assembler/TransactionCreatedEventAssemblerInterface.php new file mode 100644 index 000000000..443582dcb --- /dev/null +++ b/src/Internal/Assembler/TransactionCreatedEventAssemblerInterface.php @@ -0,0 +1,13 @@ +id; + } + + public function getType(): string + { + return $this->type; + } + + public function getWalletId(): int + { + return $this->walletId; + } + + public function getCreatedAt(): DateTimeImmutable + { + return $this->createdAt; + } +} diff --git a/src/Internal/Events/TransactionCreatedEventInterface.php b/src/Internal/Events/TransactionCreatedEventInterface.php new file mode 100644 index 000000000..a105800cb --- /dev/null +++ b/src/Internal/Events/TransactionCreatedEventInterface.php @@ -0,0 +1,18 @@ +regulatorService->increase($object, $total); } + foreach ($transactions as $transaction) { + $this->dispatcherService->dispatch($this->transactionCreatedEventAssembler->create($transaction)); + } + return $transactions; } } diff --git a/src/WalletServiceProvider.php b/src/WalletServiceProvider.php index 788d3ba5d..8a4e0560a 100644 --- a/src/WalletServiceProvider.php +++ b/src/WalletServiceProvider.php @@ -13,6 +13,8 @@ use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\OptionDtoAssembler; use Bavix\Wallet\Internal\Assembler\OptionDtoAssemblerInterface; +use Bavix\Wallet\Internal\Assembler\TransactionCreatedEventAssembler; +use Bavix\Wallet\Internal\Assembler\TransactionCreatedEventAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionQueryAssembler; @@ -27,6 +29,8 @@ use Bavix\Wallet\Internal\Assembler\WalletCreatedEventAssemblerInterface; use Bavix\Wallet\Internal\Events\BalanceUpdatedEvent; use Bavix\Wallet\Internal\Events\BalanceUpdatedEventInterface; +use Bavix\Wallet\Internal\Events\TransactionCreatedEvent; +use Bavix\Wallet\Internal\Events\TransactionCreatedEventInterface; use Bavix\Wallet\Internal\Events\WalletCreatedEvent; use Bavix\Wallet\Internal\Events\WalletCreatedEventInterface; use Bavix\Wallet\Internal\Repository\TransactionRepository; @@ -290,6 +294,11 @@ private function assemblers(array $configure): void WalletCreatedEventAssemblerInterface::class, $configure['wallet_created_event'] ?? WalletCreatedEventAssembler::class ); + + $this->app->singleton( + TransactionCreatedEventAssemblerInterface::class, + $configure['transaction_created_event'] ?? TransactionCreatedEventAssembler::class + ); } private function transformers(array $configure): void @@ -316,6 +325,11 @@ private function events(array $configure): void WalletCreatedEventInterface::class, $configure['wallet_created'] ?? WalletCreatedEvent::class ); + + $this->app->bind( + TransactionCreatedEventInterface::class, + $configure['transaction_created'] ?? TransactionCreatedEvent::class + ); } private function bindObjects(array $configure): void From 7d18d74329f51b1b9897293c037840e27f5be38a Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 5 Aug 2022 20:30:51 +0300 Subject: [PATCH 2/7] add units --- .../TransactionCreatedThrowListener.php | 24 +++++++++++++++ tests/Units/Domain/EventTest.php | 30 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/Infra/Listeners/TransactionCreatedThrowListener.php diff --git a/tests/Infra/Listeners/TransactionCreatedThrowListener.php b/tests/Infra/Listeners/TransactionCreatedThrowListener.php new file mode 100644 index 000000000..2f12137a1 --- /dev/null +++ b/tests/Infra/Listeners/TransactionCreatedThrowListener.php @@ -0,0 +1,24 @@ +getType(); + $walletId = $transactionCreatedEvent->getWalletId(); + $createdAt = $transactionCreatedEvent->getCreatedAt() + ->format(\DateTimeInterface::ATOM) + ; + + $message = hash('sha256', $type . $walletId . $createdAt); + + throw new UnknownEventException($message, $transactionCreatedEvent->getId()); + } +} diff --git a/tests/Units/Domain/EventTest.php b/tests/Units/Domain/EventTest.php index c8e62e97c..de004004d 100644 --- a/tests/Units/Domain/EventTest.php +++ b/tests/Units/Domain/EventTest.php @@ -5,16 +5,19 @@ namespace Bavix\Wallet\Test\Units\Domain; use Bavix\Wallet\Internal\Events\BalanceUpdatedEventInterface; +use Bavix\Wallet\Internal\Events\TransactionCreatedEventInterface; use Bavix\Wallet\Internal\Events\WalletCreatedEventInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Service\ClockServiceInterface; use Bavix\Wallet\Internal\Service\DatabaseServiceInterface; use Bavix\Wallet\Internal\Service\UuidFactoryServiceInterface; +use Bavix\Wallet\Models\Transaction; use Bavix\Wallet\Test\Infra\Exceptions\UnknownEventException; use Bavix\Wallet\Test\Infra\Factories\BuyerFactory; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowDateListener; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowIdListener; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowUuidListener; +use Bavix\Wallet\Test\Infra\Listeners\TransactionCreatedThrowListener; use Bavix\Wallet\Test\Infra\Listeners\WalletCreatedThrowListener; use Bavix\Wallet\Test\Infra\Models\Buyer; use Bavix\Wallet\Test\Infra\Services\ClockFakeService; @@ -132,4 +135,31 @@ public function testBalanceNotChanged(): void self::assertSame(0, $buyer->balanceInt); self::assertCount(4, $buyer->transactions()->get()); } + + /** + * @throws ExceptionInterface + */ + public function testTransactionCreatedThrowListener(): void + { + $this->app->bind(ClockServiceInterface::class, ClockFakeService::class); + + Event::listen(TransactionCreatedEventInterface::class, TransactionCreatedThrowListener::class,); + + /** @var Buyer $buyer */ + $buyer = BuyerFactory::new()->create(); + self::assertSame(0, $buyer->wallet->balanceInt); + + $createdAt = app(ClockServiceInterface::class) + ->now() + ->format(DateTimeInterface::ATOM) + ; + + $message = hash('sha256', Transaction::TYPE_DEPOSIT . $buyer->wallet->getKey() . $createdAt); + + // unit + $this->expectException(UnknownEventException::class); + $this->expectExceptionMessage($message); + + $buyer->deposit(100); + } } From 205d62caedf3e0e7ff5f99cf7d8c89bc398d586c Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 5 Aug 2022 22:22:29 +0300 Subject: [PATCH 3/7] added check for sending multiple events --- src/Internal/Service/DispatcherService.php | 9 ++- src/Services/TransactionService.php | 1 + tests/Units/Domain/EventTest.php | 66 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/Internal/Service/DispatcherService.php b/src/Internal/Service/DispatcherService.php index 8038f7247..91ff316f7 100644 --- a/src/Internal/Service/DispatcherService.php +++ b/src/Internal/Service/DispatcherService.php @@ -27,15 +27,20 @@ public function dispatch(EventInterface $event): void public function flush(): void { - foreach (array_keys($this->events) as $event) { + foreach ($this->events as $event => $value) { $this->dispatcher->flush($event); } + + $this->dispatcher->forgetPushed(); + $this->events = []; } public function forgot(): void { - foreach (array_keys($this->events) as $event) { + foreach ($this->events as $event => $value) { $this->dispatcher->forget($event); } + + $this->events = []; } } diff --git a/src/Services/TransactionService.php b/src/Services/TransactionService.php index 854f56c41..680434010 100644 --- a/src/Services/TransactionService.php +++ b/src/Services/TransactionService.php @@ -62,6 +62,7 @@ public function apply(array $wallets, array $objects): array { $transactions = $this->atmService->makeTransactions($objects); // q1 $totals = $this->assistantService->getSums($objects); + assert(count($objects) === count($transactions)); foreach ($totals as $walletId => $total) { $wallet = $wallets[$walletId] ?? null; diff --git a/tests/Units/Domain/EventTest.php b/tests/Units/Domain/EventTest.php index de004004d..cfacc571c 100644 --- a/tests/Units/Domain/EventTest.php +++ b/tests/Units/Domain/EventTest.php @@ -12,8 +12,11 @@ use Bavix\Wallet\Internal\Service\DatabaseServiceInterface; use Bavix\Wallet\Internal\Service\UuidFactoryServiceInterface; use Bavix\Wallet\Models\Transaction; +use Bavix\Wallet\Objects\Cart; +use Bavix\Wallet\Services\PurchaseServiceInterface; use Bavix\Wallet\Test\Infra\Exceptions\UnknownEventException; use Bavix\Wallet\Test\Infra\Factories\BuyerFactory; +use Bavix\Wallet\Test\Infra\Factories\ItemFactory; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowDateListener; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowIdListener; use Bavix\Wallet\Test\Infra\Listeners\BalanceUpdatedThrowUuidListener; @@ -162,4 +165,67 @@ public function testTransactionCreatedThrowListener(): void $buyer->deposit(100); } + + /** + * @throws ExceptionInterface + */ + public function testTransactionCreatedMultiListener(): void + { + /** @var array> $transactionIds */ + /** @var array> $transactionCounts */ + $transactionIds = []; + $transactionCounts = []; + Event::listen( + TransactionCreatedEventInterface::class, + static function (TransactionCreatedEventInterface $event) use ( + &$transactionIds, + &$transactionCounts + ): void { + $transactionCounts[$event->getWalletId()] = ($transactionCounts[$event->getWalletId()] ?? 0) + 1; + $transactionIds[$event->getWalletId()][] = $event->getId(); + }, + ); + + /** @var Buyer $buyer */ + $buyer = BuyerFactory::new()->create(); + self::assertSame(0, $buyer->wallet->balanceInt); + + $products = ItemFactory::times(10)->create([ + 'quantity' => 1, + ]); + + $cart = app(Cart::class)->withItems($products); + foreach ($cart->getItems() as $product) { + self::assertSame(0, $product->getBalanceIntAttribute()); + } + + self::assertSame($buyer->balance, $buyer->wallet->balance); + + $depositTransaction = $buyer->deposit($cart->getTotal($buyer)); + self::assertNotNull($depositTransaction); // +1 + + self::assertSame($buyer->balance, $buyer->wallet->balance); + + $transfers = $buyer->payCart($cart); // +10 + self::assertCount(count($cart), $transfers); + self::assertTrue((bool) app(PurchaseServiceInterface::class)->already($buyer, $cart->getBasketDto())); + self::assertSame(0, $buyer->balanceInt); + + $resultIds = [(int) $depositTransaction->getKey()]; + $valueIds = $transactionIds[$buyer->wallet->getKey()] ?? []; + foreach ($transfers as $transfer) { + $resultIds[] = (int) $transfer->withdraw->getKey(); + self::assertSame(1, $transactionCounts[$transfer->deposit->wallet_id] ?? 0); + } + + sort($valueIds); + sort($resultIds); + + self::assertSame(1 + 10, $transactionCounts[$buyer->wallet->getKey()] ?? 0); + + self::assertCount(1 + 10, $resultIds); + self::assertCount(1 + 10, $valueIds); + + self::assertSame($valueIds, $resultIds); + } } From a42010a28996fcda1c54ea75085e99a8f85281d7 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Mon, 8 Aug 2022 13:44:21 +0300 Subject: [PATCH 4/7] fix rector --- src/Internal/Service/DispatcherService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Internal/Service/DispatcherService.php b/src/Internal/Service/DispatcherService.php index 91ff316f7..128fcdfba 100644 --- a/src/Internal/Service/DispatcherService.php +++ b/src/Internal/Service/DispatcherService.php @@ -27,7 +27,7 @@ public function dispatch(EventInterface $event): void public function flush(): void { - foreach ($this->events as $event => $value) { + foreach (array_keys($this->events) as $event) { $this->dispatcher->flush($event); } @@ -37,7 +37,7 @@ public function flush(): void public function forgot(): void { - foreach ($this->events as $event => $value) { + foreach (array_keys($this->events) as $event) { $this->dispatcher->forget($event); } From 57f13046379f8ecad34860030cdbf702393e5c65 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Mon, 8 Aug 2022 13:47:25 +0300 Subject: [PATCH 5/7] fix ecs --- src/Internal/Service/DispatcherService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Internal/Service/DispatcherService.php b/src/Internal/Service/DispatcherService.php index 128fcdfba..9b68d2d82 100644 --- a/src/Internal/Service/DispatcherService.php +++ b/src/Internal/Service/DispatcherService.php @@ -27,7 +27,7 @@ public function dispatch(EventInterface $event): void public function flush(): void { - foreach (array_keys($this->events) as $event) { + foreach (array_keys($this->events) as $event) { $this->dispatcher->flush($event); } From b15354dfa2bb676627f31cc98a58b8e653b8644f Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Mon, 8 Aug 2022 14:10:14 +0300 Subject: [PATCH 6/7] update changelog.md --- changelog.md | 10 +++++++++- docs/_sidebar.md | 1 + docs/transaction-created-event.md | 33 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docs/transaction-created-event.md diff --git a/changelog.md b/changelog.md index 1f097f8d1..b2c6111df 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [9.1.0] - 2022-08-08 +### Added +- TransactionCreatedEvent #538 + +### Fixed +- Fixed a bug with sending multiple events inside the queue. Extra events were sent. + ## [9.0.4] - 2022-07-28 ### Fixed - Add allow plugin infection by @rez1dent3 in #528 @@ -889,7 +896,8 @@ The operation is now executed in the transaction and updates the new `refund` fi - Exceptions: AmountInvalid, BalanceIsEmpty. - Models: Transfer, Transaction. -[Unreleased]: https://github.com/bavix/laravel-wallet/compare/9.0.4...develop +[Unreleased]: https://github.com/bavix/laravel-wallet/compare/9.1.0...develop +[9.1.0]: https://github.com/bavix/laravel-wallet/compare/9.0.4...9.1.0 [9.0.4]: https://github.com/bavix/laravel-wallet/compare/9.0.3...9.0.4 [9.0.3]: https://github.com/bavix/laravel-wallet/compare/9.0.2...9.0.3 [9.0.2]: https://github.com/bavix/laravel-wallet/compare/9.0.1...9.0.2 diff --git a/docs/_sidebar.md b/docs/_sidebar.md index b7b59bd07..adb4b9f9f 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -44,6 +44,7 @@ - [BalanceUpdatedEvent](balance-updated-event) - [WalletCreatedEvent](wallet-created-event) + - [TransactionCreatedEvent](transaction-created-event) - [Event Customize](event-customize) - Additions diff --git a/docs/transaction-created-event.md b/docs/transaction-created-event.md new file mode 100644 index 000000000..e0a97c8d0 --- /dev/null +++ b/docs/transaction-created-event.md @@ -0,0 +1,33 @@ +## Tracking the creation of wallet transactions + +The events are similar to the events for updating the balance, only for the creation of a wallet. A frequent case of transferring data via websockets to the front-end. + +Version 7.3 introduces an interface to which you can subscribe. +This is done using standard Laravel methods. +More information in the [documentation](https://laravel.com/docs/8.x/events). + +```php +use Bavix\Wallet\Internal\Events\TransactionCreatedEventInterface; + +protected $listen = [ + TransactionCreatedEventInterface::class => [ + MyWalletTransactionCreatedListener::class, + ], +]; +``` + +And then we create a listener. + +```php +use Bavix\Wallet\Internal\Events\TransactionCreatedEventInterface; + +class MyWalletTransactionCreatedListener +{ + public function handle(TransactionCreatedEventInterface $event): void + { + // And then the implementation... + } +} +``` + +It worked! From 4920c588ef8c144a44027348fc0f18a7a805bc48 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Mon, 8 Aug 2022 14:19:13 +0300 Subject: [PATCH 7/7] update units --- tests/Units/Domain/EventTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Units/Domain/EventTest.php b/tests/Units/Domain/EventTest.php index cfacc571c..5a6079963 100644 --- a/tests/Units/Domain/EventTest.php +++ b/tests/Units/Domain/EventTest.php @@ -221,6 +221,7 @@ static function (TransactionCreatedEventInterface $event) use ( sort($valueIds); sort($resultIds); + self::assertSame(1 + 20, array_sum($transactionCounts)); // deposit+withdraw self::assertSame(1 + 10, $transactionCounts[$buyer->wallet->getKey()] ?? 0); self::assertCount(1 + 10, $resultIds);