From 5040cea97cb478e1b594529b2d2860d24901086b Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Sat, 16 Apr 2022 10:39:36 +0300 Subject: [PATCH 01/61] Split product interface --- src/Interfaces/Customer.php | 22 +++++++++--------- src/Interfaces/Product.php | 26 ++++++++-------------- src/Interfaces/ProductInterface.php | 18 +++++++++++++++ src/Interfaces/ProductLimitedInterface.php | 15 +++++++++++++ src/Internal/Dto/BasketDto.php | 4 ++-- src/Internal/Dto/BasketDtoInterface.php | 4 ++-- src/Internal/Dto/ItemDto.php | 8 +++---- src/Internal/Dto/ItemDtoInterface.php | 6 ++--- src/Objects/Cart.php | 21 ++++++++--------- src/Services/BasketService.php | 8 ++++++- src/Services/MetaServiceLegacy.php | 4 ++-- src/Traits/CanPay.php | 22 +++++++++--------- src/Traits/CartPay.php | 4 ++-- src/Traits/HasGift.php | 8 +++---- 14 files changed, 99 insertions(+), 71 deletions(-) create mode 100644 src/Interfaces/ProductInterface.php create mode 100644 src/Interfaces/ProductLimitedInterface.php diff --git a/src/Interfaces/Customer.php b/src/Interfaces/Customer.php index 708ee3931..06171fb25 100644 --- a/src/Interfaces/Customer.php +++ b/src/Interfaces/Customer.php @@ -27,9 +27,9 @@ interface Customer extends Wallet * @throws TransactionFailedException * @throws ExceptionInterface */ - public function payFree(Product $product): Transfer; + public function payFree(ProductInterface $product): Transfer; - public function safePay(Product $product, bool $force = false): ?Transfer; + public function safePay(ProductInterface $product, bool $force = false): ?Transfer; /** * @throws ProductEnded @@ -41,7 +41,7 @@ public function safePay(Product $product, bool $force = false): ?Transfer; * @throws TransactionFailedException * @throws ExceptionInterface */ - public function pay(Product $product, bool $force = false): Transfer; + public function pay(ProductInterface $product, bool $force = false): Transfer; /** * @throws ProductEnded @@ -51,9 +51,9 @@ public function pay(Product $product, bool $force = false): Transfer; * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forcePay(Product $product): Transfer; + public function forcePay(ProductInterface $product): Transfer; - public function safeRefund(Product $product, bool $force = false, bool $gifts = false): bool; + public function safeRefund(ProductInterface $product, bool $force = false, bool $gifts = false): bool; /** * @throws BalanceIsEmpty @@ -65,7 +65,7 @@ public function safeRefund(Product $product, bool $force = false, bool $gifts = * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function refund(Product $product, bool $force = false, bool $gifts = false): bool; + public function refund(ProductInterface $product, bool $force = false, bool $gifts = false): bool; /** * @throws LockProviderNotFoundException @@ -75,9 +75,9 @@ public function refund(Product $product, bool $force = false, bool $gifts = fals * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function forceRefund(Product $product, bool $gifts = false): bool; + public function forceRefund(ProductInterface $product, bool $gifts = false): bool; - public function safeRefundGift(Product $product, bool $force = false): bool; + public function safeRefundGift(ProductInterface $product, bool $force = false): bool; /** * @throws BalanceIsEmpty @@ -89,7 +89,7 @@ public function safeRefundGift(Product $product, bool $force = false): bool; * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function refundGift(Product $product, bool $force = false): bool; + public function refundGift(ProductInterface $product, bool $force = false): bool; /** * @throws LockProviderNotFoundException @@ -99,7 +99,7 @@ public function refundGift(Product $product, bool $force = false): bool; * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function forceRefundGift(Product $product): bool; + public function forceRefundGift(ProductInterface $product): bool; /** * @throws ProductEnded @@ -199,5 +199,5 @@ public function forceRefundGiftCart(CartInterface $cart): bool; * * @deprecated The method is slow and will be removed in the future */ - public function paid(Product $product, bool $gifts = false): ?Transfer; + public function paid(ProductInterface $product, bool $gifts = false): ?Transfer; } diff --git a/src/Interfaces/Product.php b/src/Interfaces/Product.php index 503abaaf6..df5ec2b82 100644 --- a/src/Interfaces/Product.php +++ b/src/Interfaces/Product.php @@ -4,22 +4,14 @@ namespace Bavix\Wallet\Interfaces; -interface Product extends Wallet +/** + * If the product is always in stock, then the ProductInterface must be used. If the product may not be available, then + * there is a need to use the ProductLimitedInterface. + * + * @deprecated The class is deprecated. Will be removed in the future. + * @see ProductInterface + * @see ProductLimitedInterface + */ +interface Product extends ProductLimitedInterface { - /** - * The method is only needed for simple projects. For more complex projects, deprecate this method and redefine the - * "BasketServiceInterface" interface. Typically, in projects, this method always returns false, and the presence - * interface goes to the microservice and receives data on products. - */ - public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool; - - /** - * @return float|int|string - */ - public function getAmountProduct(Customer $customer); - - /** - * @return array - */ - public function getMetaProduct(): ?array; } diff --git a/src/Interfaces/ProductInterface.php b/src/Interfaces/ProductInterface.php new file mode 100644 index 000000000..fc5a01555 --- /dev/null +++ b/src/Interfaces/ProductInterface.php @@ -0,0 +1,18 @@ + + * @return Generator */ public function cursor(): Generator { diff --git a/src/Internal/Dto/BasketDtoInterface.php b/src/Internal/Dto/BasketDtoInterface.php index 8e9f53295..577df3f5e 100644 --- a/src/Internal/Dto/BasketDtoInterface.php +++ b/src/Internal/Dto/BasketDtoInterface.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Internal\Dto; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Countable; use Generator; @@ -20,7 +20,7 @@ public function meta(): array; public function items(): array; /** - * @return Generator + * @return Generator */ public function cursor(): Generator; } diff --git a/src/Internal/Dto/ItemDto.php b/src/Internal/Dto/ItemDto.php index 83b6e8818..b2c2dd4b6 100644 --- a/src/Internal/Dto/ItemDto.php +++ b/src/Internal/Dto/ItemDto.php @@ -4,26 +4,26 @@ namespace Bavix\Wallet\Internal\Dto; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; /** @psalm-immutable */ final class ItemDto implements ItemDtoInterface { public function __construct( - private Product $product, + private ProductInterface $product, private int $quantity ) { } /** - * @return Product[] + * @return ProductInterface[] */ public function items(): array { return array_fill(0, $this->quantity, $this->product); } - public function product(): Product + public function product(): ProductInterface { return $this->product; } diff --git a/src/Internal/Dto/ItemDtoInterface.php b/src/Internal/Dto/ItemDtoInterface.php index 91d10f421..79765b8b7 100644 --- a/src/Internal/Dto/ItemDtoInterface.php +++ b/src/Internal/Dto/ItemDtoInterface.php @@ -4,17 +4,17 @@ namespace Bavix\Wallet\Internal\Dto; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Countable; interface ItemDtoInterface extends Countable { /** - * @return Product[] + * @return ProductInterface[] */ public function items(): array; public function count(): int; - public function product(): Product; + public function product(): ProductInterface; } diff --git a/src/Objects/Cart.php b/src/Objects/Cart.php index 58bd8b8bd..b1fc3268e 100644 --- a/src/Objects/Cart.php +++ b/src/Objects/Cart.php @@ -6,7 +6,7 @@ use Bavix\Wallet\Interfaces\CartInterface; use Bavix\Wallet\Interfaces\Customer; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Internal\Dto\BasketDto; use Bavix\Wallet\Internal\Dto\BasketDtoInterface; use Bavix\Wallet\Internal\Dto\ItemDto; @@ -21,7 +21,7 @@ final class Cart implements Countable, CartInterface { /** - * @var Product[] + * @var ProductInterface[] */ private array $items = []; @@ -64,7 +64,7 @@ public function setMeta(array $meta): self return $this; } - public function withItem(Product $product, int $quantity = 1): self + public function withItem(ProductInterface $product, int $quantity = 1): self { $self = clone $this; @@ -82,7 +82,7 @@ public function withItem(Product $product, int $quantity = 1): self * @deprecated * @see withItem */ - public function addItem(Product $product, int $quantity = 1): self + public function addItem(ProductInterface $product, int $quantity = 1): self { $productId = $this->productId($product); @@ -118,7 +118,7 @@ public function addItems(iterable $products): self } /** - * @return Product[] + * @return ProductInterface[] */ public function getItems(): array { @@ -134,10 +134,7 @@ public function getItems(): array } /** - * @return Product[] - * - * @deprecated Will be removed in 9.x - * @see getItems + * @return ProductInterface[] */ public function getUniqueItems(): array { @@ -160,7 +157,7 @@ public function count(): int return count($this->items); } - public function getQuantity(Product $product): int + public function getQuantity(ProductInterface $product): int { return $this->quantity[$this->productId($product)] ?? 0; } @@ -171,7 +168,7 @@ public function getQuantity(Product $product): int public function getBasketDto(): BasketDtoInterface { $items = array_map( - fn (Product $product): ItemDtoInterface => new ItemDto($product, $this->getQuantity($product)), + fn (ProductInterface $product): ItemDtoInterface => new ItemDto($product, $this->getQuantity($product)), $this->getUniqueItems() ); @@ -182,7 +179,7 @@ public function getBasketDto(): BasketDtoInterface return new BasketDto($items, $this->getMeta()); } - private function productId(Product $product): string + private function productId(ProductInterface $product): string { return $product::class.':'.$this->castService->getModel($product)->getKey(); } diff --git a/src/Services/BasketService.php b/src/Services/BasketService.php index 16ac142ab..bdc5c456b 100644 --- a/src/Services/BasketService.php +++ b/src/Services/BasketService.php @@ -4,6 +4,7 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\Internal\Dto\AvailabilityDtoInterface; final class BasketService implements BasketServiceInterface @@ -13,7 +14,12 @@ public function availability(AvailabilityDtoInterface $availabilityDto): bool $basketDto = $availabilityDto->getBasketDto(); $customer = $availabilityDto->getCustomer(); foreach ($basketDto->items() as $itemDto) { - if (!$itemDto->product()->canBuy($customer, $itemDto->count(), $availabilityDto->isForce())) { + $product = $itemDto->product(); + if ($product instanceof ProductLimitedInterface && !$product->canBuy( + $customer, + $itemDto->count(), + $availabilityDto->isForce() + )) { return false; } } diff --git a/src/Services/MetaServiceLegacy.php b/src/Services/MetaServiceLegacy.php index 78c1b362c..587383462 100644 --- a/src/Services/MetaServiceLegacy.php +++ b/src/Services/MetaServiceLegacy.php @@ -5,12 +5,12 @@ namespace Bavix\Wallet\Services; use Bavix\Wallet\Interfaces\CartInterface; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; /** @deprecated */ final class MetaServiceLegacy { - public function getMeta(CartInterface $cart, Product $product): ?array + public function getMeta(CartInterface $cart, ProductInterface $product): ?array { $metaCart = $cart->getBasketDto() ->meta() diff --git a/src/Traits/CanPay.php b/src/Traits/CanPay.php index 4039eed38..627d2e739 100644 --- a/src/Traits/CanPay.php +++ b/src/Traits/CanPay.php @@ -7,7 +7,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; use Bavix\Wallet\Exceptions\ProductEnded; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\ModelNotFoundException; @@ -36,12 +36,12 @@ trait CanPay * @throws TransactionFailedException * @throws ExceptionInterface */ - public function payFree(Product $product): Transfer + public function payFree(ProductInterface $product): Transfer { return current($this->payFreeCart(app(Cart::class)->withItem($product))); } - public function safePay(Product $product, bool $force = false): ?Transfer + public function safePay(ProductInterface $product, bool $force = false): ?Transfer { return current($this->safePayCart(app(Cart::class)->withItem($product), $force)) ?: null; } @@ -56,7 +56,7 @@ public function safePay(Product $product, bool $force = false): ?Transfer * @throws TransactionFailedException * @throws ExceptionInterface */ - public function pay(Product $product, bool $force = false): Transfer + public function pay(ProductInterface $product, bool $force = false): Transfer { return current($this->payCart(app(Cart::class)->withItem($product), $force)); } @@ -69,12 +69,12 @@ public function pay(Product $product, bool $force = false): Transfer * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forcePay(Product $product): Transfer + public function forcePay(ProductInterface $product): Transfer { return current($this->forcePayCart(app(Cart::class)->withItem($product))); } - public function safeRefund(Product $product, bool $force = false, bool $gifts = false): bool + public function safeRefund(ProductInterface $product, bool $force = false, bool $gifts = false): bool { return $this->safeRefundCart(app(Cart::class)->withItem($product), $force, $gifts); } @@ -89,7 +89,7 @@ public function safeRefund(Product $product, bool $force = false, bool $gifts = * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function refund(Product $product, bool $force = false, bool $gifts = false): bool + public function refund(ProductInterface $product, bool $force = false, bool $gifts = false): bool { return $this->refundCart(app(Cart::class)->withItem($product), $force, $gifts); } @@ -102,12 +102,12 @@ public function refund(Product $product, bool $force = false, bool $gifts = fals * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function forceRefund(Product $product, bool $gifts = false): bool + public function forceRefund(ProductInterface $product, bool $gifts = false): bool { return $this->forceRefundCart(app(Cart::class)->withItem($product), $gifts); } - public function safeRefundGift(Product $product, bool $force = false): bool + public function safeRefundGift(ProductInterface $product, bool $force = false): bool { return $this->safeRefundGiftCart(app(Cart::class)->withItem($product), $force); } @@ -122,7 +122,7 @@ public function safeRefundGift(Product $product, bool $force = false): bool * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function refundGift(Product $product, bool $force = false): bool + public function refundGift(ProductInterface $product, bool $force = false): bool { return $this->refundGiftCart(app(Cart::class)->withItem($product), $force); } @@ -135,7 +135,7 @@ public function refundGift(Product $product, bool $force = false): bool * @throws ModelNotFoundException * @throws ExceptionInterface */ - public function forceRefundGift(Product $product): bool + public function forceRefundGift(ProductInterface $product): bool { return $this->forceRefundGiftCart(app(Cart::class)->withItem($product)); } diff --git a/src/Traits/CartPay.php b/src/Traits/CartPay.php index 81c2f1df2..cb22bd0c8 100644 --- a/src/Traits/CartPay.php +++ b/src/Traits/CartPay.php @@ -9,7 +9,7 @@ use Bavix\Wallet\Exceptions\InsufficientFunds; use Bavix\Wallet\Exceptions\ProductEnded; use Bavix\Wallet\Interfaces\CartInterface; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Internal\Assembler\AvailabilityDtoAssemblerInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; @@ -273,7 +273,7 @@ public function forceRefundGiftCart(CartInterface $cart): bool * * @deprecated The method is slow and will be removed in the future */ - public function paid(Product $product, bool $gifts = false): ?Transfer + public function paid(ProductInterface $product, bool $gifts = false): ?Transfer { $cart = app(Cart::class)->withItem($product); $purchases = app(PurchaseServiceInterface::class) diff --git a/src/Traits/HasGift.php b/src/Traits/HasGift.php index d7ea425b0..a91afb663 100644 --- a/src/Traits/HasGift.php +++ b/src/Traits/HasGift.php @@ -7,7 +7,7 @@ use function app; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\TransferDtoAssemblerInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; @@ -35,7 +35,7 @@ trait HasGift /** * Give the goods safely. */ - public function safeGift(Wallet $to, Product $product, bool $force = false): ?Transfer + public function safeGift(Wallet $to, ProductInterface $product, bool $force = false): ?Transfer { try { return $this->gift($to, $product, $force); @@ -55,7 +55,7 @@ public function safeGift(Wallet $to, Product $product, bool $force = false): ?Tr * @throws TransactionFailedException * @throws ExceptionInterface */ - public function gift(Wallet $to, Product $product, bool $force = false): Transfer + public function gift(Wallet $to, ProductInterface $product, bool $force = false): Transfer { return app(AtomicServiceInterface::class)->block($this, function () use ($to, $product, $force): Transfer { $mathService = app(MathServiceInterface::class); @@ -103,7 +103,7 @@ public function gift(Wallet $to, Product $product, bool $force = false): Transfe * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceGift(Wallet $to, Product $product): Transfer + public function forceGift(Wallet $to, ProductInterface $product): Transfer { return $this->gift($to, $product, true); } From ef750e5e159211356ae9110a8ee9d742390fc5ad Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Sat, 16 Apr 2022 11:04:47 +0300 Subject: [PATCH 02/61] fix units --- tests/Infra/Models/Item.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Infra/Models/Item.php b/tests/Infra/Models/Item.php index 21b7fd2cd..f35534564 100644 --- a/tests/Infra/Models/Item.php +++ b/tests/Infra/Models/Item.php @@ -5,7 +5,7 @@ namespace Bavix\Wallet\Test\Infra\Models; use Bavix\Wallet\Interfaces\Customer; -use Bavix\Wallet\Interfaces\Product; +use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\Models\Transfer; use Bavix\Wallet\Models\Wallet; use Bavix\Wallet\Services\CastService; @@ -20,7 +20,7 @@ * @property int $quantity * @property int $price */ -class Item extends Model implements Product +class Item extends Model implements ProductLimitedInterface { use HasWallet; From 593060ea4e6090f13b4645221946e80a7d6a5684 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Sat, 16 Apr 2022 11:36:03 +0300 Subject: [PATCH 03/61] remove @internal --- src/Interfaces/ProductInterface.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Interfaces/ProductInterface.php b/src/Interfaces/ProductInterface.php index fc5a01555..c471bd036 100644 --- a/src/Interfaces/ProductInterface.php +++ b/src/Interfaces/ProductInterface.php @@ -4,9 +4,6 @@ namespace Bavix\Wallet\Interfaces; -/** - * @internal - */ interface ProductInterface extends Wallet { /** From b502e403dc3517e7a3fd195dda8f4fbd72cda55d Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 18:05:41 +0300 Subject: [PATCH 04/61] ExtraDtoInterface --- config/config.php | 4 + src/Interfaces/Exchangeable.php | 7 +- src/Interfaces/Wallet.php | 7 +- src/Interfaces/WalletFloat.php | 7 +- src/Internal/Assembler/ExtraDtoAssembler.php | 26 +++++ .../Assembler/ExtraDtoAssemblerInterface.php | 12 +++ src/Internal/Assembler/OptionDtoAssembler.php | 16 +++ .../Assembler/OptionDtoAssemblerInterface.php | 12 +++ src/Internal/Dto/ExtraDto.php | 25 +++++ src/Internal/Dto/ExtraDtoInterface.php | 12 +++ src/Internal/Dto/OptionDto.php | 19 ++++ src/Internal/Dto/OptionDtoInterface.php | 10 ++ src/Objects/Extra.php | 30 ++++++ src/Objects/Option.php | 20 ++++ src/Services/CommonServiceLegacy.php | 19 +++- src/Services/PrepareService.php | 10 +- src/Services/PrepareServiceInterface.php | 3 +- src/Traits/CanExchange.php | 20 +++- src/Traits/HasWallet.php | 14 ++- src/Traits/HasWalletFloat.php | 7 +- src/WalletServiceProvider.php | 11 +++ tests/Units/Domain/EagerLoadingTest.php | 21 ++++ tests/Units/Domain/ExtraTest.php | 97 +++++++++++++++++++ 23 files changed, 380 insertions(+), 29 deletions(-) create mode 100644 src/Internal/Assembler/ExtraDtoAssembler.php create mode 100644 src/Internal/Assembler/ExtraDtoAssemblerInterface.php create mode 100644 src/Internal/Assembler/OptionDtoAssembler.php create mode 100644 src/Internal/Assembler/OptionDtoAssemblerInterface.php create mode 100644 src/Internal/Dto/ExtraDto.php create mode 100644 src/Internal/Dto/ExtraDtoInterface.php create mode 100644 src/Internal/Dto/OptionDto.php create mode 100644 src/Internal/Dto/OptionDtoInterface.php create mode 100644 src/Objects/Extra.php create mode 100644 src/Objects/Option.php create mode 100644 tests/Units/Domain/ExtraTest.php diff --git a/config/config.php b/config/config.php index 27aadf324..7cb2c53ed 100644 --- a/config/config.php +++ b/config/config.php @@ -4,6 +4,8 @@ use Bavix\Wallet\Internal\Assembler\AvailabilityDtoAssembler; use Bavix\Wallet\Internal\Assembler\BalanceUpdatedEventAssembler; +use Bavix\Wallet\Internal\Assembler\ExtraDtoAssembler; +use Bavix\Wallet\Internal\Assembler\OptionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionQueryAssembler; use Bavix\Wallet\Internal\Assembler\TransferDtoAssembler; @@ -126,6 +128,8 @@ 'assemblers' => [ 'availability' => AvailabilityDtoAssembler::class, 'balance_updated_event' => BalanceUpdatedEventAssembler::class, + 'extra' => ExtraDtoAssembler::class, + 'option' => OptionDtoAssembler::class, 'transaction' => TransactionDtoAssembler::class, 'transfer_lazy' => TransferLazyDtoAssembler::class, 'transfer' => TransferDtoAssembler::class, diff --git a/src/Interfaces/Exchangeable.php b/src/Interfaces/Exchangeable.php index 5d177bbe6..27de92e7b 100644 --- a/src/Interfaces/Exchangeable.php +++ b/src/Interfaces/Exchangeable.php @@ -6,6 +6,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; @@ -26,12 +27,12 @@ interface Exchangeable * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, ?array $meta = null): Transfer; + public function exchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; /** * @param int|string $amount */ - public function safeExchange(Wallet $to, $amount, ?array $meta = null): ?Transfer; + public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer; /** * @param int|string $amount @@ -42,5 +43,5 @@ public function safeExchange(Wallet $to, $amount, ?array $meta = null): ?Transfe * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, ?array $meta = null): Transfer; + public function forceExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; } diff --git a/src/Interfaces/Wallet.php b/src/Interfaces/Wallet.php index 09bbd52c6..09c7634eb 100644 --- a/src/Interfaces/Wallet.php +++ b/src/Interfaces/Wallet.php @@ -7,6 +7,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; @@ -64,12 +65,12 @@ public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = tr * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(self $wallet, $amount, ?array $meta = null): Transfer; + public function transfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer; /** * @param int|string $amount */ - public function safeTransfer(self $wallet, $amount, ?array $meta = null): ?Transfer; + public function safeTransfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): ?Transfer; /** * @param int|string $amount @@ -80,7 +81,7 @@ public function safeTransfer(self $wallet, $amount, ?array $meta = null): ?Trans * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(self $wallet, $amount, ?array $meta = null): Transfer; + public function forceTransfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer; /** * @param int|string $amount diff --git a/src/Interfaces/WalletFloat.php b/src/Interfaces/WalletFloat.php index c369919aa..b80091d5d 100644 --- a/src/Interfaces/WalletFloat.php +++ b/src/Interfaces/WalletFloat.php @@ -7,6 +7,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; @@ -62,12 +63,12 @@ public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, ?array $meta = null): Transfer; + public function transferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; /** * @param float|string $amount */ - public function safeTransferFloat(Wallet $wallet, $amount, ?array $meta = null): ?Transfer; + public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer; /** * @param float|string $amount @@ -78,7 +79,7 @@ public function safeTransferFloat(Wallet $wallet, $amount, ?array $meta = null): * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, ?array $meta = null): Transfer; + public function forceTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; /** * @param float|string $amount diff --git a/src/Internal/Assembler/ExtraDtoAssembler.php b/src/Internal/Assembler/ExtraDtoAssembler.php new file mode 100644 index 000000000..504c5fc58 --- /dev/null +++ b/src/Internal/Assembler/ExtraDtoAssembler.php @@ -0,0 +1,26 @@ +optionDtoAssembler->create($data); + + return new ExtraDto($option, $option); + } +} diff --git a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php new file mode 100644 index 000000000..f3631a317 --- /dev/null +++ b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php @@ -0,0 +1,12 @@ +deposit; + } + + public function getWithdrawExtra(): OptionDtoInterface + { + return $this->withdraw; + } +} diff --git a/src/Internal/Dto/ExtraDtoInterface.php b/src/Internal/Dto/ExtraDtoInterface.php new file mode 100644 index 000000000..604d5071e --- /dev/null +++ b/src/Internal/Dto/ExtraDtoInterface.php @@ -0,0 +1,12 @@ +meta; + } +} diff --git a/src/Internal/Dto/OptionDtoInterface.php b/src/Internal/Dto/OptionDtoInterface.php new file mode 100644 index 000000000..aba4e2621 --- /dev/null +++ b/src/Internal/Dto/OptionDtoInterface.php @@ -0,0 +1,10 @@ +deposit = new Option($deposit); + $this->withdraw = new Option($withdraw); + } + + public function getDepositExtra(): OptionDtoInterface + { + return $this->deposit; + } + + public function getWithdrawExtra(): OptionDtoInterface + { + return $this->withdraw; + } +} diff --git a/src/Objects/Option.php b/src/Objects/Option.php new file mode 100644 index 000000000..cf8de7231 --- /dev/null +++ b/src/Objects/Option.php @@ -0,0 +1,20 @@ +meta; + } +} diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 3bbe53389..9d6a03a70 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -6,6 +6,7 @@ use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\TransferDtoAssemblerInterface; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; @@ -44,7 +45,7 @@ public function forceTransfer( Wallet $from, Wallet $to, $amount, - ?array $meta = null, + array|null|ExtraDtoInterface $meta = null, string $status = Transfer::STATUS_TRANSFER ): Transfer { $transferLazyDto = $this->prepareService->transferLazy($from, $to, $status, $amount, $meta); @@ -82,6 +83,7 @@ public function applyTransfers(array $objects): array $transactions = $this->applyTransactions($wallets, $operations); + $links = []; $transfers = []; foreach ($objects as $object) { $withdraw = $transactions[$object->getWithdrawDto()->getUuid()] ?? null; @@ -90,6 +92,9 @@ public function applyTransfers(array $objects): array $deposit = $transactions[$object->getDepositDto()->getUuid()] ?? null; assert($deposit !== null); + $links[$deposit->getKey()] = $deposit; + $links[$withdraw->getKey()] = $withdraw; + $transfers[] = $this->transferDtoAssembler->create( $deposit->getKey(), $withdraw->getKey(), @@ -101,7 +106,15 @@ public function applyTransfers(array $objects): array ); } - return $this->atmService->makeTransfers($transfers); + $models = $this->atmService->makeTransfers($transfers); + foreach ($models as $model) { + if (isset($links[$model->deposit_id], $links[$model->withdraw_id])) { + $model->setRelation('withdraw', $links[$model->withdraw_id]); + $model->setRelation('deposit', $links[$model->deposit_id]); + } + } + + return $models; }); } @@ -115,7 +128,7 @@ public function makeTransaction( Wallet $wallet, string $type, $amount, - ?array $meta, + array|null|ExtraDtoInterface $meta, bool $confirmed = true ): Transaction { assert(in_array($type, [Transaction::TYPE_DEPOSIT, Transaction::TYPE_WITHDRAW], true)); diff --git a/src/Services/PrepareService.php b/src/Services/PrepareService.php index 357019cf6..be98ebd89 100644 --- a/src/Services/PrepareService.php +++ b/src/Services/PrepareService.php @@ -6,8 +6,10 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Interfaces\Wallet; +use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssemblerInterface; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; use Bavix\Wallet\Internal\Service\MathServiceInterface; @@ -20,6 +22,7 @@ public function __construct( private TransactionDtoAssemblerInterface $transactionDtoAssembler, private DiscountServiceInterface $personalDiscountService, private ConsistencyServiceInterface $consistencyService, + private ExtraDtoAssemblerInterface $extraDtoAssembler, private CastServiceInterface $castService, private MathServiceInterface $mathService, private TaxServiceInterface $taxService @@ -80,7 +83,7 @@ public function transferLazy( Wallet $to, string $status, $amount, - ?array $meta = null + array|ExtraDtoInterface|null $meta = null ): TransferLazyDtoInterface { $discount = $this->personalDiscountService->getDiscount($from, $to); $toWallet = $this->castService->getWallet($to); @@ -90,14 +93,15 @@ public function transferLazy( $amountWithoutDiscount = $this->mathService->sub($amount, $discount, $toWallet->decimal_places); $depositAmount = $this->mathService->compare($amountWithoutDiscount, 0) === -1 ? '0' : $amountWithoutDiscount; $withdrawAmount = $this->mathService->add($depositAmount, $fee, $from->decimal_places); + $extra = $this->extraDtoAssembler->create($meta); return $this->transferLazyDtoAssembler->create( $from, $to, $discount, $fee, - $this->withdraw($from, $withdrawAmount, $meta), - $this->deposit($to, $depositAmount, $meta), + $this->withdraw($from, $withdrawAmount, $extra->getWithdrawExtra()->getMeta()), + $this->deposit($to, $depositAmount, $extra->getDepositExtra()->getMeta()), $status ); } diff --git a/src/Services/PrepareServiceInterface.php b/src/Services/PrepareServiceInterface.php index 7eb2d0291..e3d1626cf 100644 --- a/src/Services/PrepareServiceInterface.php +++ b/src/Services/PrepareServiceInterface.php @@ -6,6 +6,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Interfaces\Wallet; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; @@ -41,6 +42,6 @@ public function transferLazy( Wallet $to, string $status, $amount, - ?array $meta = null + array|null|ExtraDtoInterface $meta = null ): TransferLazyDtoInterface; } diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index 89e3cc0ef..e0e127143 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -7,7 +7,9 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; use Bavix\Wallet\Interfaces\Wallet; +use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssemblerInterface; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; @@ -39,7 +41,7 @@ trait CanExchange * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, ?array $meta = null): Transfer + public function exchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer { $wallet = app(CastServiceInterface::class)->getWallet($this); @@ -51,7 +53,7 @@ public function exchange(Wallet $to, $amount, ?array $meta = null): Transfer /** * @param int|string $amount */ - public function safeExchange(Wallet $to, $amount, ?array $meta = null): ?Transfer + public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer { try { return $this->exchange($to, $amount, $meta); @@ -69,9 +71,10 @@ public function safeExchange(Wallet $to, $amount, ?array $meta = null): ?Transfe * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, ?array $meta = null): Transfer + public function forceExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer { return app(AtomicServiceInterface::class)->block($this, function () use ($to, $amount, $meta) { + $extraAssembler = app(ExtraDtoAssemblerInterface::class); $prepareService = app(PrepareServiceInterface::class); $mathService = app(MathServiceInterface::class); $castService = app(CastServiceInterface::class); @@ -85,11 +88,18 @@ public function forceExchange(Wallet $to, $amount, ?array $meta = null): Transfe 1 ); - $withdrawDto = $prepareService->withdraw($this, $mathService->add($amount, $fee), $meta); + $extraDto = $extraAssembler->create($meta); + $withdrawDto = $prepareService->withdraw( + $this, + $mathService->add($amount, $fee), + $extraDto->getWithdrawExtra() + ->getMeta() + ); $depositDto = $prepareService->deposit( $to, $mathService->floor($mathService->mul($amount, $rate, 1)), - $meta + $extraDto->getDepositExtra() + ->getMeta() ); $transferLazyDto = app(TransferLazyDtoAssemblerInterface::class)->create( $this, diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index 01102d459..b3d244246 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -9,6 +9,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; use Bavix\Wallet\Interfaces\Wallet; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; @@ -103,7 +104,7 @@ public function transactions(): MorphMany * * @param int|string $amount */ - public function safeTransfer(Wallet $wallet, $amount, ?array $meta = null): ?Transfer + public function safeTransfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): ?Transfer { try { return $this->transfer($wallet, $amount, $meta); @@ -125,7 +126,7 @@ public function safeTransfer(Wallet $wallet, $amount, ?array $meta = null): ?Tra * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(Wallet $wallet, $amount, ?array $meta = null): Transfer + public function transfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer { /** @var Wallet $this */ app(ConsistencyServiceInterface::class)->checkPotential($this, $amount); @@ -179,8 +180,11 @@ public function canWithdraw($amount, bool $allowZero = false): bool * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction - { + public function forceWithdraw( + $amount, + array|null|ExtraDtoInterface $meta = null, + bool $confirmed = true + ): Transaction { return app(AtomicServiceInterface::class)->block( $this, fn () => app(CommonServiceLegacy::class) @@ -200,7 +204,7 @@ public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = tr * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(Wallet $wallet, $amount, ?array $meta = null): Transfer + public function forceTransfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer { return app(AtomicServiceInterface::class)->block( $this, diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index 6a6712877..d2063557d 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -8,6 +8,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; use Bavix\Wallet\Interfaces\Wallet; +use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; @@ -111,7 +112,7 @@ public function canWithdrawFloat($amount): bool * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, ?array $meta = null): Transfer + public function transferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -124,7 +125,7 @@ public function transferFloat(Wallet $wallet, $amount, ?array $meta = null): Tra /** * @param float|string $amount */ - public function safeTransferFloat(Wallet $wallet, $amount, ?array $meta = null): ?Transfer + public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -143,7 +144,7 @@ public function safeTransferFloat(Wallet $wallet, $amount, ?array $meta = null): * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, ?array $meta = null): Transfer + public function forceTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; diff --git a/src/WalletServiceProvider.php b/src/WalletServiceProvider.php index d34c796e7..903b07ce8 100644 --- a/src/WalletServiceProvider.php +++ b/src/WalletServiceProvider.php @@ -8,6 +8,10 @@ use Bavix\Wallet\Internal\Assembler\AvailabilityDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\BalanceUpdatedEventAssembler; use Bavix\Wallet\Internal\Assembler\BalanceUpdatedEventAssemblerInterface; +use Bavix\Wallet\Internal\Assembler\ExtraDtoAssembler; +use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; +use Bavix\Wallet\Internal\Assembler\OptionDtoAssembler; +use Bavix\Wallet\Internal\Assembler\OptionDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionQueryAssembler; @@ -236,6 +240,13 @@ private function assemblers(array $configure): void $configure['balance_updated_event'] ?? BalanceUpdatedEventAssembler::class ); + $this->app->singleton(ExtraDtoAssemblerInterface::class, $configure['extra'] ?? ExtraDtoAssembler::class); + + $this->app->singleton( + OptionDtoAssemblerInterface::class, + $configure['option'] ?? OptionDtoAssembler::class + ); + $this->app->singleton( TransactionDtoAssemblerInterface::class, $configure['transaction'] ?? TransactionDtoAssembler::class diff --git a/tests/Units/Domain/EagerLoadingTest.php b/tests/Units/Domain/EagerLoadingTest.php index fb0720eb4..80bee7c33 100644 --- a/tests/Units/Domain/EagerLoadingTest.php +++ b/tests/Units/Domain/EagerLoadingTest.php @@ -7,6 +7,7 @@ use Bavix\Wallet\Test\Infra\Factories\BuyerFactory; use Bavix\Wallet\Test\Infra\Models\Buyer; use Bavix\Wallet\Test\Infra\TestCase; +use Illuminate\Database\Eloquent\Collection; /** * @internal @@ -15,7 +16,11 @@ final class EagerLoadingTest extends TestCase { public function testUuidDuplicate(): void { + /** @var Buyer[]|Collection $buyerTimes */ $buyerTimes = BuyerFactory::times(10)->create(); + foreach ($buyerTimes as $buyerTime) { + $buyerTime->deposit(100); + } /** @var Buyer[] $buyers */ $buyers = Buyer::with('wallet') @@ -26,6 +31,8 @@ public function testUuidDuplicate(): void $uuids = []; $balances = []; foreach ($buyers as $buyer) { + self::assertTrue($buyer->relationLoaded('wallet')); + $uuids[] = $buyer->wallet->uuid; $balances[] = $buyer->wallet->balanceInt; } @@ -33,4 +40,18 @@ public function testUuidDuplicate(): void self::assertCount(10, array_unique($uuids)); self::assertCount(1, array_unique($balances)); } + + public function testTransferTransactions(): void + { + /** @var Buyer $user1 */ + /** @var Buyer $user2 */ + [$user1, $user2] = BuyerFactory::times(2)->create(); + + $user1->deposit(1000); + self::assertSame(1000, $user1->balanceInt); + + $transfer = $user1->transfer($user2, 500); + self::assertTrue($transfer->relationLoaded('withdraw')); + self::assertTrue($transfer->relationLoaded('deposit')); + } } diff --git a/tests/Units/Domain/ExtraTest.php b/tests/Units/Domain/ExtraTest.php new file mode 100644 index 000000000..2eb1c31a1 --- /dev/null +++ b/tests/Units/Domain/ExtraTest.php @@ -0,0 +1,97 @@ +create(); + + $user1->deposit(1000); + self::assertSame(1000, $user1->balanceInt); + + $transfer = $user1->transfer( + $user2, + 500, + new Extra( + deposit: [ + 'type' => 'extra-deposit', + ], + withdraw: [ + 'type' => 'extra-withdraw', + ], + ) + ); + + self::assertSame(500, $user1->balanceInt); + self::assertSame(500, $user2->balanceInt); + self::assertNotNull($transfer); + + self::assertSame([ + 'type' => 'extra-deposit', + ], $transfer->deposit->meta); + self::assertSame([ + 'type' => 'extra-withdraw', + ], $transfer->withdraw->meta); + } + + public function testExtraExchange(): void + { + /** @var UserMulti $user */ + $user = UserMultiFactory::new()->create(); + $usd = $user->createWallet([ + 'name' => 'My USD', + 'slug' => 'usd', + ]); + + $rub = $user->createWallet([ + 'name' => 'My RUB', + 'slug' => 'rub', + ]); + + self::assertSame(0, $rub->balanceInt); + self::assertSame(0, $usd->balanceInt); + + $rub->deposit(10000); + + self::assertSame(10000, $rub->balanceInt); + self::assertSame(0, $usd->balanceInt); + + $transfer = $rub->exchange($usd, 10000, new Extra( + deposit: [ + 'message' => 'We credit to the dollar account', + ], + withdraw: [ + 'message' => 'Write off from the ruble account', + ] + )); + + self::assertSame(0, $rub->balanceInt); + self::assertSame(147, $usd->balanceInt); + self::assertSame(1.47, (float) $usd->balanceFloat); // $1.47 + self::assertSame(0, (int) $transfer->fee); + self::assertSame(Transfer::STATUS_EXCHANGE, $transfer->status); + self::assertSame([ + 'message' => 'We credit to the dollar account', + ], $transfer->deposit->meta); + self::assertSame([ + 'message' => 'Write off from the ruble account', + ], $transfer->withdraw->meta); + } +} From effdf595b4d9c5d2ca42c19d3b7e98d709b45725 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 18:14:21 +0300 Subject: [PATCH 05/61] fix deptrac --- depfile.yaml | 2 ++ src/{Internal/Dto => External}/ExtraDtoInterface.php | 2 +- src/{Internal/Dto => External}/OptionDtoInterface.php | 2 +- src/Interfaces/Exchangeable.php | 2 +- src/Interfaces/Wallet.php | 2 +- src/Interfaces/WalletFloat.php | 2 +- src/Internal/Assembler/ExtraDtoAssembler.php | 2 +- src/Internal/Assembler/ExtraDtoAssemblerInterface.php | 2 +- src/Internal/Assembler/OptionDtoAssembler.php | 2 +- src/Internal/Assembler/OptionDtoAssemblerInterface.php | 2 +- src/Internal/Dto/ExtraDto.php | 3 +++ src/Internal/Dto/OptionDto.php | 2 ++ src/Objects/Extra.php | 4 ++-- src/Objects/Option.php | 2 +- src/Services/CommonServiceLegacy.php | 2 +- src/Services/PrepareService.php | 2 +- src/Services/PrepareServiceInterface.php | 2 +- src/Traits/CanExchange.php | 2 +- src/Traits/HasWallet.php | 6 +++--- src/Traits/HasWalletFloat.php | 2 +- 20 files changed, 27 insertions(+), 20 deletions(-) rename src/{Internal/Dto => External}/ExtraDtoInterface.php (83%) rename src/{Internal/Dto => External}/OptionDtoInterface.php (74%) diff --git a/depfile.yaml b/depfile.yaml index 797b6bc80..d755a9e15 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -13,6 +13,8 @@ layers: collectors: - type: className regex: ^Bavix\\Wallet\\Interfaces\\.* + - type: className + regex: ^Bavix\\Wallet\\External\\.* - name: UI collectors: diff --git a/src/Internal/Dto/ExtraDtoInterface.php b/src/External/ExtraDtoInterface.php similarity index 83% rename from src/Internal/Dto/ExtraDtoInterface.php rename to src/External/ExtraDtoInterface.php index 604d5071e..53ceb95e5 100644 --- a/src/Internal/Dto/ExtraDtoInterface.php +++ b/src/External/ExtraDtoInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bavix\Wallet\Internal\Dto; +namespace Bavix\Wallet\External; interface ExtraDtoInterface { diff --git a/src/Internal/Dto/OptionDtoInterface.php b/src/External/OptionDtoInterface.php similarity index 74% rename from src/Internal/Dto/OptionDtoInterface.php rename to src/External/OptionDtoInterface.php index aba4e2621..e123f0b5c 100644 --- a/src/Internal/Dto/OptionDtoInterface.php +++ b/src/External/OptionDtoInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bavix\Wallet\Internal\Dto; +namespace Bavix\Wallet\External; interface OptionDtoInterface { diff --git a/src/Interfaces/Exchangeable.php b/src/Interfaces/Exchangeable.php index 27de92e7b..f7442485f 100644 --- a/src/Interfaces/Exchangeable.php +++ b/src/Interfaces/Exchangeable.php @@ -6,7 +6,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; diff --git a/src/Interfaces/Wallet.php b/src/Interfaces/Wallet.php index 09c7634eb..836bc6cd5 100644 --- a/src/Interfaces/Wallet.php +++ b/src/Interfaces/Wallet.php @@ -7,7 +7,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; diff --git a/src/Interfaces/WalletFloat.php b/src/Interfaces/WalletFloat.php index b80091d5d..8f89510cc 100644 --- a/src/Interfaces/WalletFloat.php +++ b/src/Interfaces/WalletFloat.php @@ -7,7 +7,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; diff --git a/src/Internal/Assembler/ExtraDtoAssembler.php b/src/Internal/Assembler/ExtraDtoAssembler.php index 504c5fc58..b149a6994 100644 --- a/src/Internal/Assembler/ExtraDtoAssembler.php +++ b/src/Internal/Assembler/ExtraDtoAssembler.php @@ -4,8 +4,8 @@ namespace Bavix\Wallet\Internal\Assembler; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\ExtraDto; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; final class ExtraDtoAssembler implements ExtraDtoAssemblerInterface { diff --git a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php index f3631a317..b31e91b51 100644 --- a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php +++ b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Internal\Assembler; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; +use Bavix\Wallet\External\ExtraDtoInterface; interface ExtraDtoAssemblerInterface { diff --git a/src/Internal/Assembler/OptionDtoAssembler.php b/src/Internal/Assembler/OptionDtoAssembler.php index 768f1b5e5..92e08eccc 100644 --- a/src/Internal/Assembler/OptionDtoAssembler.php +++ b/src/Internal/Assembler/OptionDtoAssembler.php @@ -4,8 +4,8 @@ namespace Bavix\Wallet\Internal\Assembler; +use Bavix\Wallet\External\OptionDtoInterface; use Bavix\Wallet\Internal\Dto\OptionDto; -use Bavix\Wallet\Internal\Dto\OptionDtoInterface; final class OptionDtoAssembler implements OptionDtoAssemblerInterface { diff --git a/src/Internal/Assembler/OptionDtoAssemblerInterface.php b/src/Internal/Assembler/OptionDtoAssemblerInterface.php index 6ed850ea6..adde9a390 100644 --- a/src/Internal/Assembler/OptionDtoAssemblerInterface.php +++ b/src/Internal/Assembler/OptionDtoAssemblerInterface.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Internal\Assembler; -use Bavix\Wallet\Internal\Dto\OptionDtoInterface; +use Bavix\Wallet\External\OptionDtoInterface; interface OptionDtoAssemblerInterface { diff --git a/src/Internal/Dto/ExtraDto.php b/src/Internal/Dto/ExtraDto.php index 47801ab10..4dc046d2c 100644 --- a/src/Internal/Dto/ExtraDto.php +++ b/src/Internal/Dto/ExtraDto.php @@ -4,6 +4,9 @@ namespace Bavix\Wallet\Internal\Dto; +use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\OptionDtoInterface; + /** @internal */ final class ExtraDto implements ExtraDtoInterface { diff --git a/src/Internal/Dto/OptionDto.php b/src/Internal/Dto/OptionDto.php index d47c8dc83..49c14bce0 100644 --- a/src/Internal/Dto/OptionDto.php +++ b/src/Internal/Dto/OptionDto.php @@ -4,6 +4,8 @@ namespace Bavix\Wallet\Internal\Dto; +use Bavix\Wallet\External\OptionDtoInterface; + /** @internal */ final class OptionDto implements OptionDtoInterface { diff --git a/src/Objects/Extra.php b/src/Objects/Extra.php index cecff2a60..7f8101e75 100644 --- a/src/Objects/Extra.php +++ b/src/Objects/Extra.php @@ -4,8 +4,8 @@ namespace Bavix\Wallet\Objects; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; -use Bavix\Wallet\Internal\Dto\OptionDtoInterface; +use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\OptionDtoInterface; final class Extra implements ExtraDtoInterface { diff --git a/src/Objects/Option.php b/src/Objects/Option.php index cf8de7231..940e86635 100644 --- a/src/Objects/Option.php +++ b/src/Objects/Option.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Objects; -use Bavix\Wallet\Internal\Dto\OptionDtoInterface; +use Bavix\Wallet\External\OptionDtoInterface; final class Option implements OptionDtoInterface { diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 9d6a03a70..6fbb13c80 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -4,9 +4,9 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\TransferDtoAssemblerInterface; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; diff --git a/src/Services/PrepareService.php b/src/Services/PrepareService.php index be98ebd89..58777951d 100644 --- a/src/Services/PrepareService.php +++ b/src/Services/PrepareService.php @@ -5,11 +5,11 @@ namespace Bavix\Wallet\Services; use Bavix\Wallet\Exceptions\AmountInvalid; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssemblerInterface; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; use Bavix\Wallet\Internal\Service\MathServiceInterface; diff --git a/src/Services/PrepareServiceInterface.php b/src/Services/PrepareServiceInterface.php index e3d1626cf..bfe178c8b 100644 --- a/src/Services/PrepareServiceInterface.php +++ b/src/Services/PrepareServiceInterface.php @@ -5,8 +5,8 @@ namespace Bavix\Wallet\Services; use Bavix\Wallet\Exceptions\AmountInvalid; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index e0e127143..6b86a58d4 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -6,10 +6,10 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssemblerInterface; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index b3d244246..007fd3903 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -4,12 +4,11 @@ namespace Bavix\Wallet\Traits; -use function app; use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; @@ -22,11 +21,12 @@ use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\RegulatorServiceInterface; -use function config; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\RecordsNotFoundException; use Illuminate\Support\Collection; +use function app; +use function config; /** * Trait HasWallet. diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index d2063557d..5647175fd 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -7,8 +7,8 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; +use Bavix\Wallet\External\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; -use Bavix\Wallet\Internal\Dto\ExtraDtoInterface; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; From 619610068916e8c6a080cf30b8570bfcf1806435 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 18:23:11 +0300 Subject: [PATCH 06/61] fix phpstan --- src/Internal/Dto/OptionDto.php | 2 +- src/Objects/Extra.php | 4 ++-- src/Objects/Option.php | 2 +- src/Services/CommonServiceLegacy.php | 20 ++++++++++---------- src/Traits/HasWallet.php | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Internal/Dto/OptionDto.php b/src/Internal/Dto/OptionDto.php index 49c14bce0..cbadc6e59 100644 --- a/src/Internal/Dto/OptionDto.php +++ b/src/Internal/Dto/OptionDto.php @@ -10,7 +10,7 @@ final class OptionDto implements OptionDtoInterface { public function __construct( - private ?array $meta = null + private ?array $meta ) { } diff --git a/src/Objects/Extra.php b/src/Objects/Extra.php index 7f8101e75..9b9167be7 100644 --- a/src/Objects/Extra.php +++ b/src/Objects/Extra.php @@ -14,8 +14,8 @@ final class Extra implements ExtraDtoInterface public function __construct(array|OptionDtoInterface|null $deposit, array|OptionDtoInterface|null $withdraw) { - $this->deposit = new Option($deposit); - $this->withdraw = new Option($withdraw); + $this->deposit = $deposit instanceof OptionDtoInterface ? $deposit : new Option($deposit); + $this->withdraw = $withdraw instanceof OptionDtoInterface ? $withdraw : new Option($withdraw); } public function getDepositExtra(): OptionDtoInterface diff --git a/src/Objects/Option.php b/src/Objects/Option.php index 940e86635..86892b316 100644 --- a/src/Objects/Option.php +++ b/src/Objects/Option.php @@ -9,7 +9,7 @@ final class Option implements OptionDtoInterface { public function __construct( - private ?array $meta = null + private ?array $meta ) { } diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 6fbb13c80..68acc31db 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -92,10 +92,7 @@ public function applyTransfers(array $objects): array $deposit = $transactions[$object->getDepositDto()->getUuid()] ?? null; assert($deposit !== null); - $links[$deposit->getKey()] = $deposit; - $links[$withdraw->getKey()] = $withdraw; - - $transfers[] = $this->transferDtoAssembler->create( + $transfer = $this->transferDtoAssembler->create( $deposit->getKey(), $withdraw->getKey(), $object->getStatus(), @@ -104,14 +101,17 @@ public function applyTransfers(array $objects): array $object->getDiscount(), $object->getFee() ); + + $transfers[] = $transfer; + $links[$transfer->getUuid()] = [ + 'deposit' => $deposit, + 'withdraw' => $withdraw, + ]; } $models = $this->atmService->makeTransfers($transfers); foreach ($models as $model) { - if (isset($links[$model->deposit_id], $links[$model->withdraw_id])) { - $model->setRelation('withdraw', $links[$model->withdraw_id]); - $model->setRelation('deposit', $links[$model->deposit_id]); - } + $model->setRelations($links[$model->uuid] ?? []); } return $models; @@ -128,7 +128,7 @@ public function makeTransaction( Wallet $wallet, string $type, $amount, - array|null|ExtraDtoInterface $meta, + ?array $meta, bool $confirmed = true ): Transaction { assert(in_array($type, [Transaction::TYPE_DEPOSIT, Transaction::TYPE_WITHDRAW], true)); @@ -141,7 +141,7 @@ public function makeTransaction( $transactions = $this->applyTransactions([ $dto->getWalletId() => $wallet, - ], [$dto],); + ], [$dto]); return current($transactions); } diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index 007fd3903..5f912e30f 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -4,6 +4,7 @@ namespace Bavix\Wallet\Traits; +use function app; use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; @@ -21,12 +22,11 @@ use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\RegulatorServiceInterface; +use function config; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\RecordsNotFoundException; use Illuminate\Support\Collection; -use function app; -use function config; /** * Trait HasWallet. From 66ff7275d98967d4c8155680e2ed43ebae11ab89 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 20:45:01 +0300 Subject: [PATCH 07/61] add confirmed in exchange/transfer --- depfile.yaml | 251 ----------------- deptrac.yaml | 252 ++++++++++++++++++ phpstan-baseline.neon | 5 + src/External/Contracts/ExtraDtoInterface.php | 12 + .../{ => Contracts}/OptionDtoInterface.php | 4 +- src/{Objects => External/Dto}/Extra.php | 10 +- src/External/Dto/Option.php | 26 ++ src/External/ExtraDtoInterface.php | 12 - src/Interfaces/Exchangeable.php | 2 +- src/Interfaces/Wallet.php | 2 +- src/Interfaces/WalletFloat.php | 2 +- src/Internal/Assembler/ExtraDtoAssembler.php | 6 +- .../Assembler/ExtraDtoAssemblerInterface.php | 2 +- src/Internal/Assembler/OptionDtoAssembler.php | 6 +- .../Assembler/OptionDtoAssemblerInterface.php | 2 +- src/Internal/Dto/ExtraDto.php | 28 -- src/Internal/Dto/OptionDto.php | 21 -- src/Objects/Option.php | 20 -- src/Services/CommonServiceLegacy.php | 2 +- src/Services/PrepareService.php | 8 +- src/Services/PrepareServiceInterface.php | 2 +- src/Traits/CanExchange.php | 12 +- src/Traits/HasWallet.php | 2 +- src/Traits/HasWalletFloat.php | 2 +- tests/Units/Domain/ExtraTest.php | 108 +++++++- 25 files changed, 429 insertions(+), 370 deletions(-) delete mode 100644 depfile.yaml create mode 100644 deptrac.yaml create mode 100644 src/External/Contracts/ExtraDtoInterface.php rename src/External/{ => Contracts}/OptionDtoInterface.php (55%) rename src/{Objects => External/Dto}/Extra.php (68%) create mode 100644 src/External/Dto/Option.php delete mode 100644 src/External/ExtraDtoInterface.php delete mode 100644 src/Internal/Dto/ExtraDto.php delete mode 100644 src/Internal/Dto/OptionDto.php delete mode 100644 src/Objects/Option.php diff --git a/depfile.yaml b/depfile.yaml deleted file mode 100644 index d755a9e15..000000000 --- a/depfile.yaml +++ /dev/null @@ -1,251 +0,0 @@ -paths: - - ./src - -layers: - - name: Legacy - collectors: - - type: className - regex: ^Bavix\\.*Legacy$ - - type: className - regex: ^Bavix\\.*\\Objects\\Cart$ - - - name: Contract - collectors: - - type: className - regex: ^Bavix\\Wallet\\Interfaces\\.* - - type: className - regex: ^Bavix\\Wallet\\External\\.* - - - name: UI - collectors: - - type: className - regex: ^Bavix\\.*\\Traits\\.* - - - name: UIException - collectors: - - type: className - regex: ^Illuminate\\Database\\Eloquent\\ModelNotFoundException$ - - type: className - regex: ^Bavix\\Wallet\\Exceptions\\.* - - # internal - - name: InternalException - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Exceptions\\.* - - - name: Event - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Events\\.*Event$ - - - name: EventInterface - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Events\\.*EventInterface$ - - - name: Dto - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Dto\\.*Dto$ - - - name: DtoInterface - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Dto\\.*DtoInterface$ - - - name: AssemblerDto - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Assembler\\.*DtoAssembler$ - - - name: AssemblerDtoInterface - collectors: - - type: className - regex: ^Bavix\\.*\\Internal\\Assembler\\.*DtoAssemblerInterface$ - - - name: QueryInterface - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Query\\.*QueryInterface$ - - - name: Query - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Query\\.*Query$ - - - name: RepositoryInterface - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Repository\\.*RepositoryInterface$ - - - name: Repository - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Repository\\.*Repository$ - - - name: Transform - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Transform\\.*DtoTransformer$ - - - name: TransformInterface - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Transform\\.*DtoTransformerInterface$ - - - name: Infra - collectors: - - type: className - regex: ^Bavix\\.*Internal\\Service\\.*Service$ - - # contracts - - name: Model - collectors: - - type: className - regex: ^Bavix\\.*Models\\Transaction$ - - type: className - regex: ^Bavix\\.*Models\\Transfer$ - - type: className - regex: ^Bavix\\.*Models\\Wallet$ - - - name: Service - collectors: - - type: className - regex: ^Bavix\\.*Services\\.*Service$ - - - name: ServiceInterface - collectors: - - type: className - regex: ^Bavix\\.*Service\\.*ServiceInterface$ - - type: className - regex: ^Bavix\\.*Services\\.*ServiceInterface$ - - # framework - - name: EloquentModel - collectors: - - type: className - regex: ^Illuminate\\Database\\Eloquent\\Model$ - - - name: Config - collectors: - - type: className - regex: ^Illuminate\\Config\\Repository$ - - - name: Cache - collectors: - - type: className - regex: ^Illuminate\\Contracts\\Cache\\Repository$ - -ruleset: - Contract: - - InternalException - - DtoInterface - - UIException - - Model - - UI: - - AssemblerDtoInterface # delete as soon as possible - - InternalException - - ServiceInterface - - UIException - - Contract - - Model - - Legacy # delete as soon as possible - - UIException: - - InternalException - - Infra: - - InternalException - - ServiceInterface - - EventInterface - - Config - - Cache - - EventInterface: - Event: - - EventInterface - - DtoInterface: - - Contract - Dto: - - DtoInterface - - Contract - - Model: - - AssemblerDtoInterface - - InternalException - - ServiceInterface - - EloquentModel - - UIException - - Contract - - Legacy - - UI - - TransformInterface: - - DtoInterface - Transform: - - TransformInterface - - DtoInterface - - QueryInterface: - Query: - - QueryInterface - - RepositoryInterface: - - InternalException - - QueryInterface - - DtoInterface - - Model - Repository: - - RepositoryInterface - - TransformInterface - - InternalException - - ServiceInterface # json service only - - QueryInterface - - DtoInterface - - UIException - - Model - - ServiceInterface: - - InternalException - - EventInterface - - EloquentModel - - DtoInterface - - UIException - - Contract - - Model - Service: - - AssemblerDtoInterface - - RepositoryInterface - - InternalException - - ServiceInterface - - EloquentModel - - DtoInterface - - UIException - - Contract - - Model - - AssemblerDtoInterface: - - EloquentModel - - DtoInterface - - Contract - AssemblerDto: - - AssemblerDtoInterface - - QueryInterface - - ServiceInterface # UUID - - EloquentModel - - DtoInterface - - Contract - - Dto - - Legacy: - - AssemblerDtoInterface - - InternalException - - ServiceInterface - - DtoInterface - - UIException - - Contract - - Model - - Dto # Cart from objects diff --git a/deptrac.yaml b/deptrac.yaml new file mode 100644 index 000000000..3b21d6fe2 --- /dev/null +++ b/deptrac.yaml @@ -0,0 +1,252 @@ +parameters: + paths: + - ./src + + layers: + - name: Legacy + collectors: + - type: className + regex: ^Bavix\\.*Legacy$ + - type: className + regex: ^Bavix\\.*\\Objects\\Cart$ + + - name: Contract + collectors: + - type: className + regex: ^Bavix\\Wallet\\Interfaces\\.* + - type: className + regex: ^Bavix\\Wallet\\External\\.* + + - name: UI + collectors: + - type: className + regex: ^Bavix\\.*\\Traits\\.* + + - name: UIException + collectors: + - type: className + regex: ^Illuminate\\Database\\Eloquent\\ModelNotFoundException$ + - type: className + regex: ^Bavix\\Wallet\\Exceptions\\.* + + # internal + - name: InternalException + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Exceptions\\.* + + - name: Event + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Events\\.*Event$ + + - name: EventInterface + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Events\\.*EventInterface$ + + - name: Dto + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Dto\\.*Dto$ + + - name: DtoInterface + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Dto\\.*DtoInterface$ + + - name: AssemblerDto + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Assembler\\.*DtoAssembler$ + + - name: AssemblerDtoInterface + collectors: + - type: className + regex: ^Bavix\\.*\\Internal\\Assembler\\.*DtoAssemblerInterface$ + + - name: QueryInterface + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Query\\.*QueryInterface$ + + - name: Query + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Query\\.*Query$ + + - name: RepositoryInterface + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Repository\\.*RepositoryInterface$ + + - name: Repository + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Repository\\.*Repository$ + + - name: Transform + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Transform\\.*DtoTransformer$ + + - name: TransformInterface + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Transform\\.*DtoTransformerInterface$ + + - name: Infra + collectors: + - type: className + regex: ^Bavix\\.*Internal\\Service\\.*Service$ + + # contracts + - name: Model + collectors: + - type: className + regex: ^Bavix\\.*Models\\Transaction$ + - type: className + regex: ^Bavix\\.*Models\\Transfer$ + - type: className + regex: ^Bavix\\.*Models\\Wallet$ + + - name: Service + collectors: + - type: className + regex: ^Bavix\\.*Services\\.*Service$ + + - name: ServiceInterface + collectors: + - type: className + regex: ^Bavix\\.*Service\\.*ServiceInterface$ + - type: className + regex: ^Bavix\\.*Services\\.*ServiceInterface$ + + # framework + - name: EloquentModel + collectors: + - type: className + regex: ^Illuminate\\Database\\Eloquent\\Model$ + + - name: Config + collectors: + - type: className + regex: ^Illuminate\\Config\\Repository$ + + - name: Cache + collectors: + - type: className + regex: ^Illuminate\\Contracts\\Cache\\Repository$ + + ruleset: + Contract: + - InternalException + - DtoInterface + - UIException + - Model + + UI: + - AssemblerDtoInterface # delete as soon as possible + - InternalException + - ServiceInterface + - UIException + - Contract + - Model + - Legacy # delete as soon as possible + + UIException: + - InternalException + + Infra: + - InternalException + - ServiceInterface + - EventInterface + - Config + - Cache + + EventInterface: + Event: + - EventInterface + + DtoInterface: + - Contract + Dto: + - DtoInterface + - Contract + + Model: + - AssemblerDtoInterface + - InternalException + - ServiceInterface + - EloquentModel + - UIException + - Contract + - Legacy + - UI + + TransformInterface: + - DtoInterface + Transform: + - TransformInterface + - DtoInterface + + QueryInterface: + Query: + - QueryInterface + + RepositoryInterface: + - InternalException + - QueryInterface + - DtoInterface + - Model + Repository: + - RepositoryInterface + - TransformInterface + - InternalException + - ServiceInterface # json service only + - QueryInterface + - DtoInterface + - UIException + - Model + + ServiceInterface: + - InternalException + - EventInterface + - EloquentModel + - DtoInterface + - UIException + - Contract + - Model + Service: + - AssemblerDtoInterface + - RepositoryInterface + - InternalException + - ServiceInterface + - EloquentModel + - DtoInterface + - UIException + - Contract + - Model + + AssemblerDtoInterface: + - EloquentModel + - DtoInterface + - Contract + AssemblerDto: + - AssemblerDtoInterface + - QueryInterface + - ServiceInterface # UUID + - EloquentModel + - DtoInterface + - Contract + - Dto + + Legacy: + - AssemblerDtoInterface + - InternalException + - ServiceInterface + - DtoInterface + - UIException + - Contract + - Model + - Dto # Cart from objects diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 93d4b8cc6..63e2bdc53 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,10 @@ parameters: ignoreErrors: + - + message: "#^Constructor in Bavix\\\\Wallet\\\\External\\\\Dto\\\\Option has parameter \\$confirmed with default value\\.$#" + count: 1 + path: src/External/Dto/Option.php + - message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\:\\:where\\(\\)\\.$#" count: 1 diff --git a/src/External/Contracts/ExtraDtoInterface.php b/src/External/Contracts/ExtraDtoInterface.php new file mode 100644 index 000000000..03749daef --- /dev/null +++ b/src/External/Contracts/ExtraDtoInterface.php @@ -0,0 +1,12 @@ +withdraw = $withdraw instanceof OptionDtoInterface ? $withdraw : new Option($withdraw); } - public function getDepositExtra(): OptionDtoInterface + public function getDepositOption(): OptionDtoInterface { return $this->deposit; } - public function getWithdrawExtra(): OptionDtoInterface + public function getWithdrawOption(): OptionDtoInterface { return $this->withdraw; } diff --git a/src/External/Dto/Option.php b/src/External/Dto/Option.php new file mode 100644 index 000000000..4a1cccfd2 --- /dev/null +++ b/src/External/Dto/Option.php @@ -0,0 +1,26 @@ +meta; + } + + public function isConfirmed(): bool + { + return $this->confirmed; + } +} diff --git a/src/External/ExtraDtoInterface.php b/src/External/ExtraDtoInterface.php deleted file mode 100644 index 53ceb95e5..000000000 --- a/src/External/ExtraDtoInterface.php +++ /dev/null @@ -1,12 +0,0 @@ -optionDtoAssembler->create($data); - return new ExtraDto($option, $option); + return new Extra($option, $option); } } diff --git a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php index b31e91b51..b04cbba5e 100644 --- a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php +++ b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Internal\Assembler; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; interface ExtraDtoAssemblerInterface { diff --git a/src/Internal/Assembler/OptionDtoAssembler.php b/src/Internal/Assembler/OptionDtoAssembler.php index 92e08eccc..88782924e 100644 --- a/src/Internal/Assembler/OptionDtoAssembler.php +++ b/src/Internal/Assembler/OptionDtoAssembler.php @@ -4,13 +4,13 @@ namespace Bavix\Wallet\Internal\Assembler; -use Bavix\Wallet\External\OptionDtoInterface; -use Bavix\Wallet\Internal\Dto\OptionDto; +use Bavix\Wallet\External\Contracts\OptionDtoInterface; +use Bavix\Wallet\External\Dto\Option; final class OptionDtoAssembler implements OptionDtoAssemblerInterface { public function create(array|null $data): OptionDtoInterface { - return new OptionDto($data); + return new Option($data); } } diff --git a/src/Internal/Assembler/OptionDtoAssemblerInterface.php b/src/Internal/Assembler/OptionDtoAssemblerInterface.php index adde9a390..8d1684be0 100644 --- a/src/Internal/Assembler/OptionDtoAssemblerInterface.php +++ b/src/Internal/Assembler/OptionDtoAssemblerInterface.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Internal\Assembler; -use Bavix\Wallet\External\OptionDtoInterface; +use Bavix\Wallet\External\Contracts\OptionDtoInterface; interface OptionDtoAssemblerInterface { diff --git a/src/Internal/Dto/ExtraDto.php b/src/Internal/Dto/ExtraDto.php deleted file mode 100644 index 4dc046d2c..000000000 --- a/src/Internal/Dto/ExtraDto.php +++ /dev/null @@ -1,28 +0,0 @@ -deposit; - } - - public function getWithdrawExtra(): OptionDtoInterface - { - return $this->withdraw; - } -} diff --git a/src/Internal/Dto/OptionDto.php b/src/Internal/Dto/OptionDto.php deleted file mode 100644 index cbadc6e59..000000000 --- a/src/Internal/Dto/OptionDto.php +++ /dev/null @@ -1,21 +0,0 @@ -meta; - } -} diff --git a/src/Objects/Option.php b/src/Objects/Option.php deleted file mode 100644 index 86892b316..000000000 --- a/src/Objects/Option.php +++ /dev/null @@ -1,20 +0,0 @@ -meta; - } -} diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 68acc31db..1c4715d30 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -4,7 +4,7 @@ namespace Bavix\Wallet\Services; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\TransferDtoAssemblerInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; diff --git a/src/Services/PrepareService.php b/src/Services/PrepareService.php index 58777951d..c27492d01 100644 --- a/src/Services/PrepareService.php +++ b/src/Services/PrepareService.php @@ -5,7 +5,7 @@ namespace Bavix\Wallet\Services; use Bavix\Wallet\Exceptions\AmountInvalid; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; @@ -94,14 +94,16 @@ public function transferLazy( $depositAmount = $this->mathService->compare($amountWithoutDiscount, 0) === -1 ? '0' : $amountWithoutDiscount; $withdrawAmount = $this->mathService->add($depositAmount, $fee, $from->decimal_places); $extra = $this->extraDtoAssembler->create($meta); + $withdrawOption = $extra->getWithdrawOption(); + $depositOption = $extra->getDepositOption(); return $this->transferLazyDtoAssembler->create( $from, $to, $discount, $fee, - $this->withdraw($from, $withdrawAmount, $extra->getWithdrawExtra()->getMeta()), - $this->deposit($to, $depositAmount, $extra->getDepositExtra()->getMeta()), + $this->withdraw($from, $withdrawAmount, $withdrawOption->getMeta(), $withdrawOption->isConfirmed()), + $this->deposit($to, $depositAmount, $depositOption->getMeta(), $depositOption->isConfirmed()), $status ); } diff --git a/src/Services/PrepareServiceInterface.php b/src/Services/PrepareServiceInterface.php index bfe178c8b..683b2daba 100644 --- a/src/Services/PrepareServiceInterface.php +++ b/src/Services/PrepareServiceInterface.php @@ -5,7 +5,7 @@ namespace Bavix\Wallet\Services; use Bavix\Wallet\Exceptions\AmountInvalid; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index 6b86a58d4..163e78d4e 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -6,7 +6,7 @@ use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Assembler\ExtraDtoAssemblerInterface; use Bavix\Wallet\Internal\Assembler\TransferLazyDtoAssemblerInterface; @@ -89,17 +89,19 @@ public function forceExchange(Wallet $to, $amount, array|ExtraDtoInterface|null ); $extraDto = $extraAssembler->create($meta); + $withdrawOption = $extraDto->getWithdrawOption(); + $depositOption = $extraDto->getDepositOption(); $withdrawDto = $prepareService->withdraw( $this, $mathService->add($amount, $fee), - $extraDto->getWithdrawExtra() - ->getMeta() + $withdrawOption->getMeta(), + $withdrawOption->isConfirmed(), ); $depositDto = $prepareService->deposit( $to, $mathService->floor($mathService->mul($amount, $rate, 1)), - $extraDto->getDepositExtra() - ->getMeta() + $depositOption->getMeta(), + $depositOption->isConfirmed(), ); $transferLazyDto = app(TransferLazyDtoAssemblerInterface::class)->create( $this, diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index 5f912e30f..11cada932 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -8,7 +8,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index 5647175fd..fccb76539 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -7,7 +7,7 @@ use Bavix\Wallet\Exceptions\AmountInvalid; use Bavix\Wallet\Exceptions\BalanceIsEmpty; use Bavix\Wallet\Exceptions\InsufficientFunds; -use Bavix\Wallet\External\ExtraDtoInterface; +use Bavix\Wallet\External\Contracts\ExtraDtoInterface; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; diff --git a/tests/Units/Domain/ExtraTest.php b/tests/Units/Domain/ExtraTest.php index 2eb1c31a1..e6c3731e0 100644 --- a/tests/Units/Domain/ExtraTest.php +++ b/tests/Units/Domain/ExtraTest.php @@ -4,8 +4,9 @@ namespace Bavix\Wallet\Test\Units\Domain; +use Bavix\Wallet\External\Dto\Extra; +use Bavix\Wallet\External\Dto\Option; use Bavix\Wallet\Models\Transfer; -use Bavix\Wallet\Objects\Extra; use Bavix\Wallet\Test\Infra\Factories\BuyerFactory; use Bavix\Wallet\Test\Infra\Factories\UserMultiFactory; use Bavix\Wallet\Test\Infra\Models\Buyer; @@ -17,7 +18,7 @@ */ final class ExtraTest extends TestCase { - public function testExtraTransfer(): void + public function testExtraTransferWithdraw(): void { /** @var Buyer $user1 */ /** @var Buyer $user2 */ @@ -33,6 +34,46 @@ public function testExtraTransfer(): void deposit: [ 'type' => 'extra-deposit', ], + withdraw: new Option( + [ + 'type' => 'extra-withdraw', + ], + false + ), + ) + ); + + self::assertSame(1000, $user1->balanceInt); + self::assertSame(500, $user2->balanceInt); + self::assertNotNull($transfer); + + self::assertSame([ + 'type' => 'extra-deposit', + ], $transfer->deposit->meta); + self::assertSame([ + 'type' => 'extra-withdraw', + ], $transfer->withdraw->meta); + } + + public function testExtraTransferDeposit(): void + { + /** @var Buyer $user1 */ + /** @var Buyer $user2 */ + [$user1, $user2] = BuyerFactory::times(2)->create(); + + $user1->deposit(1000); + self::assertSame(1000, $user1->balanceInt); + + $transfer = $user1->transfer( + $user2, + 500, + new Extra( + deposit: new Option( + [ + 'type' => 'extra-deposit', + ], + false + ), withdraw: [ 'type' => 'extra-withdraw', ], @@ -40,7 +81,7 @@ public function testExtraTransfer(): void ); self::assertSame(500, $user1->balanceInt); - self::assertSame(500, $user2->balanceInt); + self::assertSame(0, $user2->balanceInt); self::assertNotNull($transfer); self::assertSame([ @@ -51,7 +92,7 @@ public function testExtraTransfer(): void ], $transfer->withdraw->meta); } - public function testExtraExchange(): void + public function testExtraExchangeDeposit(): void { /** @var UserMulti $user */ $user = UserMultiFactory::new()->create(); @@ -68,23 +109,72 @@ public function testExtraExchange(): void self::assertSame(0, $rub->balanceInt); self::assertSame(0, $usd->balanceInt); - $rub->deposit(10000); + $rub->deposit(10_000); - self::assertSame(10000, $rub->balanceInt); + self::assertSame(10_000, $rub->balanceInt); self::assertSame(0, $usd->balanceInt); $transfer = $rub->exchange($usd, 10000, new Extra( deposit: [ 'message' => 'We credit to the dollar account', ], + withdraw: new Option( + [ + 'message' => 'Write off from the ruble account', + ], + false + ) + )); + + self::assertSame(10_000, $rub->balanceInt); + self::assertSame(147, $usd->balanceInt); + self::assertSame(1.47, (float) $usd->balanceFloat); // $1.47 + self::assertSame(0, (int) $transfer->fee); + self::assertSame(Transfer::STATUS_EXCHANGE, $transfer->status); + self::assertSame([ + 'message' => 'We credit to the dollar account', + ], $transfer->deposit->meta); + self::assertSame([ + 'message' => 'Write off from the ruble account', + ], $transfer->withdraw->meta); + } + + public function testExtraExchangeWithdraw(): void + { + /** @var UserMulti $user */ + $user = UserMultiFactory::new()->create(); + $usd = $user->createWallet([ + 'name' => 'My USD', + 'slug' => 'usd', + ]); + + $rub = $user->createWallet([ + 'name' => 'My RUB', + 'slug' => 'rub', + ]); + + self::assertSame(0, $rub->balanceInt); + self::assertSame(0, $usd->balanceInt); + + $rub->deposit(10_000); + + self::assertSame(10_000, $rub->balanceInt); + self::assertSame(0, $usd->balanceInt); + + $transfer = $rub->exchange($usd, 10000, new Extra( + deposit: new Option( + [ + 'message' => 'We credit to the dollar account', + ], + false + ), withdraw: [ 'message' => 'Write off from the ruble account', - ] + ], )); self::assertSame(0, $rub->balanceInt); - self::assertSame(147, $usd->balanceInt); - self::assertSame(1.47, (float) $usd->balanceFloat); // $1.47 + self::assertSame(0, $usd->balanceInt); self::assertSame(0, (int) $transfer->fee); self::assertSame(Transfer::STATUS_EXCHANGE, $transfer->status); self::assertSame([ From 7da55b757c19408ec3a8ee5cf666582e19ade3be Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 23:28:06 +0300 Subject: [PATCH 08/61] sort union types --- src/External/Dto/Extra.php | 2 +- src/Interfaces/Exchangeable.php | 6 +++--- src/Interfaces/WalletFloat.php | 6 +++--- src/Internal/Assembler/ExtraDtoAssemblerInterface.php | 2 +- src/Services/PrepareService.php | 2 +- src/Traits/CanExchange.php | 6 +++--- src/Traits/HasWalletFloat.php | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/External/Dto/Extra.php b/src/External/Dto/Extra.php index 26f9e7894..4f2138840 100644 --- a/src/External/Dto/Extra.php +++ b/src/External/Dto/Extra.php @@ -12,7 +12,7 @@ final class Extra implements ExtraDtoInterface private OptionDtoInterface $deposit; private OptionDtoInterface $withdraw; - public function __construct(array|OptionDtoInterface|null $deposit, array|OptionDtoInterface|null $withdraw) + public function __construct(OptionDtoInterface|array|null $deposit, OptionDtoInterface|array|null $withdraw) { $this->deposit = $deposit instanceof OptionDtoInterface ? $deposit : new Option($deposit); $this->withdraw = $withdraw instanceof OptionDtoInterface ? $withdraw : new Option($withdraw); diff --git a/src/Interfaces/Exchangeable.php b/src/Interfaces/Exchangeable.php index ed04c5401..4e60163db 100644 --- a/src/Interfaces/Exchangeable.php +++ b/src/Interfaces/Exchangeable.php @@ -27,12 +27,12 @@ interface Exchangeable * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; + public function exchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; /** * @param int|string $amount */ - public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer; + public function safeExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; /** * @param int|string $amount @@ -43,5 +43,5 @@ public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $ * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; + public function forceExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; } diff --git a/src/Interfaces/WalletFloat.php b/src/Interfaces/WalletFloat.php index a5a0b5642..0fe6ce550 100644 --- a/src/Interfaces/WalletFloat.php +++ b/src/Interfaces/WalletFloat.php @@ -63,12 +63,12 @@ public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; + public function transferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; /** * @param float|string $amount */ - public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer; + public function safeTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; /** * @param float|string $amount @@ -79,7 +79,7 @@ public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterfa * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer; + public function forceTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; /** * @param float|string $amount diff --git a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php index b04cbba5e..824d21853 100644 --- a/src/Internal/Assembler/ExtraDtoAssemblerInterface.php +++ b/src/Internal/Assembler/ExtraDtoAssemblerInterface.php @@ -8,5 +8,5 @@ interface ExtraDtoAssemblerInterface { - public function create(array|ExtraDtoInterface|null $data): ExtraDtoInterface; + public function create(ExtraDtoInterface|array|null $data): ExtraDtoInterface; } diff --git a/src/Services/PrepareService.php b/src/Services/PrepareService.php index c27492d01..acd886905 100644 --- a/src/Services/PrepareService.php +++ b/src/Services/PrepareService.php @@ -83,7 +83,7 @@ public function transferLazy( Wallet $to, string $status, $amount, - array|ExtraDtoInterface|null $meta = null + ExtraDtoInterface|array|null $meta = null ): TransferLazyDtoInterface { $discount = $this->personalDiscountService->getDiscount($from, $to); $toWallet = $this->castService->getWallet($to); diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index 163e78d4e..dbc2bfd83 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -41,7 +41,7 @@ trait CanExchange * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer + public function exchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { $wallet = app(CastServiceInterface::class)->getWallet($this); @@ -53,7 +53,7 @@ public function exchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta /** * @param int|string $amount */ - public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer + public function safeExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer { try { return $this->exchange($to, $amount, $meta); @@ -71,7 +71,7 @@ public function safeExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $ * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, array|ExtraDtoInterface|null $meta = null): Transfer + public function forceExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { return app(AtomicServiceInterface::class)->block($this, function () use ($to, $amount, $meta) { $extraAssembler = app(ExtraDtoAssemblerInterface::class); diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index fccb76539..d2188fc92 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -112,7 +112,7 @@ public function canWithdrawFloat($amount): bool * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer + public function transferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -125,7 +125,7 @@ public function transferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|n /** * @param float|string $amount */ - public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): ?Transfer + public function safeTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -144,7 +144,7 @@ public function safeTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterfa * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, array|ExtraDtoInterface|null $meta = null): Transfer + public function forceTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; From d8927c237ce26ae38e5c10c321d2b54635db4bcc Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 23:33:05 +0300 Subject: [PATCH 09/61] sort union types --- src/Interfaces/Wallet.php | 6 +++--- src/Services/CommonServiceLegacy.php | 2 +- src/Services/PrepareServiceInterface.php | 2 +- src/Traits/HasWallet.php | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Interfaces/Wallet.php b/src/Interfaces/Wallet.php index bae15c26c..84307de1d 100644 --- a/src/Interfaces/Wallet.php +++ b/src/Interfaces/Wallet.php @@ -65,12 +65,12 @@ public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = tr * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer; + public function transfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; /** * @param int|string $amount */ - public function safeTransfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): ?Transfer; + public function safeTransfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; /** * @param int|string $amount @@ -81,7 +81,7 @@ public function safeTransfer(self $wallet, $amount, array|null|ExtraDtoInterface * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(self $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer; + public function forceTransfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; /** * @param int|string $amount diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 1c4715d30..9ddaf86c1 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -45,7 +45,7 @@ public function forceTransfer( Wallet $from, Wallet $to, $amount, - array|null|ExtraDtoInterface $meta = null, + ExtraDtoInterface|array|null $meta = null, string $status = Transfer::STATUS_TRANSFER ): Transfer { $transferLazyDto = $this->prepareService->transferLazy($from, $to, $status, $amount, $meta); diff --git a/src/Services/PrepareServiceInterface.php b/src/Services/PrepareServiceInterface.php index 683b2daba..498c76187 100644 --- a/src/Services/PrepareServiceInterface.php +++ b/src/Services/PrepareServiceInterface.php @@ -42,6 +42,6 @@ public function transferLazy( Wallet $to, string $status, $amount, - array|null|ExtraDtoInterface $meta = null + ExtraDtoInterface|array|null $meta = null ): TransferLazyDtoInterface; } diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index 11cada932..3fe5c9162 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -104,7 +104,7 @@ public function transactions(): MorphMany * * @param int|string $amount */ - public function safeTransfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): ?Transfer + public function safeTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer { try { return $this->transfer($wallet, $amount, $meta); @@ -126,7 +126,7 @@ public function safeTransfer(Wallet $wallet, $amount, array|null|ExtraDtoInterfa * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer + public function transfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { /** @var Wallet $this */ app(ConsistencyServiceInterface::class)->checkPotential($this, $amount); @@ -182,7 +182,7 @@ public function canWithdraw($amount, bool $allowZero = false): bool */ public function forceWithdraw( $amount, - array|null|ExtraDtoInterface $meta = null, + ExtraDtoInterface|array|null $meta = null, bool $confirmed = true ): Transaction { return app(AtomicServiceInterface::class)->block( @@ -204,7 +204,7 @@ public function forceWithdraw( * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(Wallet $wallet, $amount, array|null|ExtraDtoInterface $meta = null): Transfer + public function forceTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer { return app(AtomicServiceInterface::class)->block( $this, From a30306c84cd85c79edfb3128954ed45728e3dcf8 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Tue, 19 Apr 2022 23:54:13 +0300 Subject: [PATCH 10/61] micro optimize --- src/Traits/HasWallets.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Traits/HasWallets.php b/src/Traits/HasWallets.php index de46935e0..3cedfe814 100644 --- a/src/Traits/HasWallets.php +++ b/src/Traits/HasWallets.php @@ -23,11 +23,11 @@ trait HasWallets /** * The variable is used for the cache, so as not to request wallets many times. WalletProxy keeps the money wallets * in the memory to avoid errors when you purchase/transfer, etc. + * + * @var WalletModel[] */ private array $_wallets = []; - private bool $_loadedWallets = false; - /** * Get wallet by slug. * @@ -59,16 +59,19 @@ public function getWallet(string $slug): ?WalletModel */ public function getWalletOrFail(string $slug): WalletModel { - if (!$this->_loadedWallets && $this->relationLoaded('wallets')) { - $this->_loadedWallets = true; - $wallets = $this->getRelation('wallets'); - foreach ($wallets as $wallet) { + if ($this->_wallets === [] && $this->relationLoaded('wallets')) { + /** @var WalletModel $wallet */ + foreach ($this->getRelation('wallets') as $wallet) { + $wallet->setRelation('holder', $this); $this->_wallets[$wallet->slug] = $wallet; } } if (!array_key_exists($slug, $this->_wallets)) { - $this->_wallets[$slug] = app(WalletServiceInterface::class)->getBySlug($this, $slug); + $wallet = app(WalletServiceInterface::class)->getBySlug($this, $slug); + $wallet->setRelation('holder', $this); + + $this->_wallets[$slug] = $wallet; } return $this->_wallets[$slug]; @@ -86,6 +89,7 @@ public function createWallet(array $data): WalletModel { $wallet = app(WalletServiceInterface::class)->create($this, $data); $this->_wallets[$wallet->slug] = $wallet; + $wallet->setRelation('holder', $this); return $wallet; } From 725bfa7070118d2af6db7bdd7e2602b114feee93 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 00:00:26 +0300 Subject: [PATCH 11/61] add unit --- tests/Units/Domain/EagerLoadingTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Units/Domain/EagerLoadingTest.php b/tests/Units/Domain/EagerLoadingTest.php index 80bee7c33..9fa3868b3 100644 --- a/tests/Units/Domain/EagerLoadingTest.php +++ b/tests/Units/Domain/EagerLoadingTest.php @@ -5,7 +5,9 @@ namespace Bavix\Wallet\Test\Units\Domain; use Bavix\Wallet\Test\Infra\Factories\BuyerFactory; +use Bavix\Wallet\Test\Infra\Factories\UserMultiFactory; use Bavix\Wallet\Test\Infra\Models\Buyer; +use Bavix\Wallet\Test\Infra\Models\UserMulti; use Bavix\Wallet\Test\Infra\TestCase; use Illuminate\Database\Eloquent\Collection; @@ -54,4 +56,23 @@ public function testTransferTransactions(): void self::assertTrue($transfer->relationLoaded('withdraw')); self::assertTrue($transfer->relationLoaded('deposit')); } + + public function testMultiWallets(): void + { + /** @var UserMulti $multi */ + $multi = UserMultiFactory::new()->create(); + $multi->createWallet([ + 'name' => 'Hello', + ]); + + $multi->createWallet([ + 'name' => 'World', + ]); + + /** @var UserMulti $user */ + $user = UserMulti::with('wallets')->find($multi->getKey()); + self::assertTrue($user->relationLoaded('wallets')); + self::assertNotNull($user->getWallet('hello')); + self::assertNotNull($user->getWallet('world')); + } } From ccd2dec9b1ee697a86f79ba975dc611d3b8b10c3 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 22:39:33 +0300 Subject: [PATCH 12/61] Improved eager loading. Quick refund goods --- config/config.php | 2 ++ .../Repository/TransferRepository.php | 15 +++++++++++++ .../TransferRepositoryInterface.php | 5 +++++ src/Models/Transfer.php | 1 + src/Services/TransferService.php | 22 +++++++++++++++++++ src/Services/TransferServiceInterface.php | 13 +++++++++++ src/Traits/CartPay.php | 17 +++++--------- src/Traits/MorphOneWallet.php | 18 ++++++++++----- src/WalletServiceProvider.php | 3 +++ tests/Units/Domain/CartTest.php | 2 ++ tests/Units/Domain/EagerLoadingTest.php | 5 +++++ 11 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 src/Services/TransferService.php create mode 100644 src/Services/TransferServiceInterface.php diff --git a/config/config.php b/config/config.php index 7cb2c53ed..341500b4c 100644 --- a/config/config.php +++ b/config/config.php @@ -43,6 +43,7 @@ use Bavix\Wallet\Services\PurchaseService; use Bavix\Wallet\Services\RegulatorService; use Bavix\Wallet\Services\TaxService; +use Bavix\Wallet\Services\TransferService; use Bavix\Wallet\Services\WalletService; return [ @@ -102,6 +103,7 @@ 'prepare' => PrepareService::class, 'purchase' => PurchaseService::class, 'tax' => TaxService::class, + 'transfer' => TransferService::class, 'wallet' => WalletService::class, ], diff --git a/src/Internal/Repository/TransferRepository.php b/src/Internal/Repository/TransferRepository.php index 5b9fd5cb4..61a123439 100644 --- a/src/Internal/Repository/TransferRepository.php +++ b/src/Internal/Repository/TransferRepository.php @@ -8,6 +8,7 @@ use Bavix\Wallet\Internal\Query\TransferQueryInterface; use Bavix\Wallet\Internal\Transform\TransferDtoTransformerInterface; use Bavix\Wallet\Models\Transfer; +use Illuminate\Support\Facades\DB; final class TransferRepository implements TransferRepositoryInterface { @@ -48,4 +49,18 @@ public function findBy(TransferQueryInterface $query): array ->all() ; } + + /** + * @param non-empty-array $ids + */ + public function updateStatusByIds(string $status, array $ids): int + { + return $this->transfer->newQuery() + ->whereKey($ids) + ->update([ + 'status' => $status, + 'status_last' => DB::raw('status'), + ]) + ; + } } diff --git a/src/Internal/Repository/TransferRepositoryInterface.php b/src/Internal/Repository/TransferRepositoryInterface.php index 50498b4e8..bc7207a69 100644 --- a/src/Internal/Repository/TransferRepositoryInterface.php +++ b/src/Internal/Repository/TransferRepositoryInterface.php @@ -21,4 +21,9 @@ public function insertOne(TransferDtoInterface $dto): Transfer; * @return Transfer[] */ public function findBy(TransferQueryInterface $query): array; + + /** + * @param non-empty-array $ids + */ + public function updateStatusByIds(string $status, array $ids): int; } diff --git a/src/Models/Transfer.php b/src/Models/Transfer.php index 39843ab54..fc9304a28 100644 --- a/src/Models/Transfer.php +++ b/src/Models/Transfer.php @@ -13,6 +13,7 @@ * Class Transfer. * * @property string $status + * @property string $status_last * @property string $discount * @property int $deposit_id * @property int $withdraw_id diff --git a/src/Services/TransferService.php b/src/Services/TransferService.php new file mode 100644 index 000000000..5864ccac5 --- /dev/null +++ b/src/Services/TransferService.php @@ -0,0 +1,22 @@ +repository->updateStatusByIds($status, $ids); + } +} diff --git a/src/Services/TransferServiceInterface.php b/src/Services/TransferServiceInterface.php new file mode 100644 index 000000000..abf01c7da --- /dev/null +++ b/src/Services/TransferServiceInterface.php @@ -0,0 +1,13 @@ +block($this, function () use ($cart, $force, $gifts) { - $results = []; $transfers = app(PurchaseServiceInterface::class)->already($this, $cart->getBasketDto(), $gifts); if (count($transfers) !== $cart->getBasketDto()->total()) { throw new ModelNotFoundException( @@ -186,9 +185,11 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts $index = 0; $objects = []; + $transferIds = []; $transfers = array_values($transfers); $prepareService = app(PrepareServiceInterface::class); foreach ($cart->getBasketDto()->cursor() as $product) { + $transferIds[] = $transfers[$index]->getKey(); $objects[] = $prepareService->transferLazy( $product, $transfers[$index]->withdraw->wallet, @@ -206,15 +207,9 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts app(CommonServiceLegacy::class)->applyTransfers($objects); - // fixme: one query update for - foreach ($transfers as $transfer) { - $results[] = $transfer->update([ - 'status' => Transfer::STATUS_REFUND, - 'status_last' => $transfer->status, - ]); - } - - return count(array_unique($results)) === 1; + return app(TransferServiceInterface::class) + ->updateStatusByIds(Transfer::STATUS_REFUND, $transferIds) + ; }); } diff --git a/src/Traits/MorphOneWallet.php b/src/Traits/MorphOneWallet.php index 4dbf2a5d0..c10d94c75 100644 --- a/src/Traits/MorphOneWallet.php +++ b/src/Traits/MorphOneWallet.php @@ -25,12 +25,18 @@ public function wallet(): MorphOne ->getHolder($this) ->morphOne(config('wallet.wallet.model', WalletModel::class), 'holder') ->where('slug', config('wallet.wallet.default.slug', 'default')) - ->withDefault(array_merge(config('wallet.wallet.creating', []), [ - 'name' => config('wallet.wallet.default.name', 'Default Wallet'), - 'slug' => config('wallet.wallet.default.slug', 'default'), - 'meta' => config('wallet.wallet.default.meta', []), - 'balance' => 0, - ])) + ->withDefault(static function (WalletModel $wallet, object $holder) { + $wallet->forceFill(array_merge(config('wallet.wallet.creating', []), [ + 'name' => config('wallet.wallet.default.name', 'Default Wallet'), + 'slug' => config('wallet.wallet.default.slug', 'default'), + 'meta' => config('wallet.wallet.default.meta', []), + 'balance' => 0, + ])); + + if (property_exists($holder, 'exists') && $holder->exists) { + $wallet->setRelation('holder', $holder); + } + }) ; } } diff --git a/src/WalletServiceProvider.php b/src/WalletServiceProvider.php index 903b07ce8..0ac542186 100644 --- a/src/WalletServiceProvider.php +++ b/src/WalletServiceProvider.php @@ -87,6 +87,8 @@ use Bavix\Wallet\Services\RegulatorServiceInterface; use Bavix\Wallet\Services\TaxService; use Bavix\Wallet\Services\TaxServiceInterface; +use Bavix\Wallet\Services\TransferService; +use Bavix\Wallet\Services\TransferServiceInterface; use Bavix\Wallet\Services\WalletService; use Bavix\Wallet\Services\WalletServiceInterface; use function config; @@ -199,6 +201,7 @@ private function services(array $configure, array $cache): void $this->app->singleton(PrepareServiceInterface::class, $configure['prepare'] ?? PrepareService::class); $this->app->singleton(PurchaseServiceInterface::class, $configure['purchase'] ?? PurchaseService::class); $this->app->singleton(TaxServiceInterface::class, $configure['tax'] ?? TaxService::class); + $this->app->singleton(TransferServiceInterface::class, $configure['transfer'] ?? TransferService::class); $this->app->singleton(WalletServiceInterface::class, $configure['wallet'] ?? WalletService::class); $this->app->singleton(BookkeeperServiceInterface::class, fn () => $this->app->make( diff --git a/tests/Units/Domain/CartTest.php b/tests/Units/Domain/CartTest.php index fde6d948d..3647b8979 100644 --- a/tests/Units/Domain/CartTest.php +++ b/tests/Units/Domain/CartTest.php @@ -133,6 +133,7 @@ public function testPay(): void foreach ($transfers as $transfer) { self::assertSame(Transfer::STATUS_PAID, $transfer->status); + self::assertNull($transfer->status_last); } foreach ($cart->getItems() as $product) { @@ -143,6 +144,7 @@ public function testPay(): void foreach ($transfers as $transfer) { $transfer->refresh(); self::assertSame(Transfer::STATUS_REFUND, $transfer->status); + self::assertSame(Transfer::STATUS_PAID, $transfer->status_last); } } diff --git a/tests/Units/Domain/EagerLoadingTest.php b/tests/Units/Domain/EagerLoadingTest.php index 9fa3868b3..c75693392 100644 --- a/tests/Units/Domain/EagerLoadingTest.php +++ b/tests/Units/Domain/EagerLoadingTest.php @@ -21,6 +21,7 @@ public function testUuidDuplicate(): void /** @var Buyer[]|Collection $buyerTimes */ $buyerTimes = BuyerFactory::times(10)->create(); foreach ($buyerTimes as $buyerTime) { + self::assertTrue($buyerTime->wallet->relationLoaded('holder')); $buyerTime->deposit(100); } @@ -34,6 +35,8 @@ public function testUuidDuplicate(): void $balances = []; foreach ($buyers as $buyer) { self::assertTrue($buyer->relationLoaded('wallet')); + // self::assertTrue($buyer->wallet->relationLoaded('holder')); + // fixme: I did not find a way to load the buyer, maybe someday I will get there. $uuids[] = $buyer->wallet->uuid; $balances[] = $buyer->wallet->balanceInt; @@ -74,5 +77,7 @@ public function testMultiWallets(): void self::assertTrue($user->relationLoaded('wallets')); self::assertNotNull($user->getWallet('hello')); self::assertNotNull($user->getWallet('world')); + self::assertTrue($user->getWallet('hello')->relationLoaded('holder')); + self::assertSame($user, $user->getWallet('hello')->holder); } } From 853b524ff6a6a587ce7af3fa7b36c1a90cbfc21b Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 22:50:43 +0300 Subject: [PATCH 13/61] fix query --- src/Internal/Repository/TransferRepository.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Internal/Repository/TransferRepository.php b/src/Internal/Repository/TransferRepository.php index 61a123439..846e3b4e3 100644 --- a/src/Internal/Repository/TransferRepository.php +++ b/src/Internal/Repository/TransferRepository.php @@ -56,10 +56,11 @@ public function findBy(TransferQueryInterface $query): array public function updateStatusByIds(string $status, array $ids): int { return $this->transfer->newQuery() - ->whereKey($ids) + ->toBase() + ->whereIn($this->transfer->getKeyName(), $ids) ->update([ - 'status' => $status, 'status_last' => DB::raw('status'), + 'status' => $status, ]) ; } From 1c762d1b7b93376b96795588b7e9ccc742dc846f Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 23:22:17 +0300 Subject: [PATCH 14/61] PHP 8+ Union types --- rector.php | 4 -- src/Interfaces/Discount.php | 5 +- src/Interfaces/Exchangeable.php | 13 ++--- src/Interfaces/MaximalTaxable.php | 5 +- src/Interfaces/MinimalTaxable.php | 5 +- src/Interfaces/ProductInterface.php | 5 +- src/Interfaces/Taxable.php | 4 +- src/Interfaces/Wallet.php | 43 ++++++---------- src/Interfaces/WalletFloat.php | 48 +++++++++--------- src/Models/Transaction.php | 5 +- src/Models/Wallet.php | 5 +- src/Services/CommonServiceLegacy.php | 8 +-- src/Services/ConsistencyServiceInterface.php | 14 ++---- src/Traits/CanExchange.php | 13 ++--- src/Traits/HasWallet.php | 42 ++++++---------- src/Traits/HasWalletFloat.php | 52 +++++++++----------- tests/Infra/Models/Item.php | 2 +- tests/Infra/Models/ItemTax.php | 4 +- 18 files changed, 100 insertions(+), 177 deletions(-) diff --git a/rector.php b/rector.php index e37e6bfa8..868b562f1 100644 --- a/rector.php +++ b/rector.php @@ -18,10 +18,6 @@ __DIR__ . '/tests', ]); - $parameters->set(Option::SKIP, [ - UnionTypesRector::class - ]); - // Define what rule sets will be applied $containerConfigurator->import(PHPUnitSetList::PHPUNIT_91); $containerConfigurator->import(LaravelSetList::LARAVEL_80); diff --git a/src/Interfaces/Discount.php b/src/Interfaces/Discount.php index 3c06dd597..fc57c4846 100644 --- a/src/Interfaces/Discount.php +++ b/src/Interfaces/Discount.php @@ -6,8 +6,5 @@ interface Discount { - /** - * @return float|int - */ - public function getPersonalDiscount(Customer $customer); + public function getPersonalDiscount(Customer $customer): float|int; } diff --git a/src/Interfaces/Exchangeable.php b/src/Interfaces/Exchangeable.php index 4e60163db..b85c835d1 100644 --- a/src/Interfaces/Exchangeable.php +++ b/src/Interfaces/Exchangeable.php @@ -17,8 +17,6 @@ interface Exchangeable { /** - * @param int|string $amount - * * @throws BalanceIsEmpty * @throws InsufficientFunds * @throws LockProviderNotFoundException @@ -27,21 +25,16 @@ interface Exchangeable * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function exchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer; - /** - * @param int|string $amount - */ - public function safeExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; + public function safeExchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; /** - * @param int|string $amount - * * @throws LockProviderNotFoundException * @throws RecordNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function forceExchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer; } diff --git a/src/Interfaces/MaximalTaxable.php b/src/Interfaces/MaximalTaxable.php index 4ae1495d9..c06daa052 100644 --- a/src/Interfaces/MaximalTaxable.php +++ b/src/Interfaces/MaximalTaxable.php @@ -6,8 +6,5 @@ interface MaximalTaxable extends Taxable { - /** - * @return float|int - */ - public function getMaximalFee(); + public function getMaximalFee(): float|int; } diff --git a/src/Interfaces/MinimalTaxable.php b/src/Interfaces/MinimalTaxable.php index 472af7dc2..900400c62 100644 --- a/src/Interfaces/MinimalTaxable.php +++ b/src/Interfaces/MinimalTaxable.php @@ -6,8 +6,5 @@ interface MinimalTaxable extends Taxable { - /** - * @return float|int - */ - public function getMinimalFee(); + public function getMinimalFee(): float|int; } diff --git a/src/Interfaces/ProductInterface.php b/src/Interfaces/ProductInterface.php index c471bd036..d2062231c 100644 --- a/src/Interfaces/ProductInterface.php +++ b/src/Interfaces/ProductInterface.php @@ -6,10 +6,7 @@ interface ProductInterface extends Wallet { - /** - * @return float|int|string - */ - public function getAmountProduct(Customer $customer); + public function getAmountProduct(Customer $customer): float|int|string; public function getMetaProduct(): ?array; } diff --git a/src/Interfaces/Taxable.php b/src/Interfaces/Taxable.php index e59fb0ea5..ad291d595 100644 --- a/src/Interfaces/Taxable.php +++ b/src/Interfaces/Taxable.php @@ -10,8 +10,6 @@ interface Taxable * Specify the percentage of the amount. For example, the product costs $100, the equivalent of 15%. That's $115. * * Minimum 0; Maximum 100 Example: return 7.5; // 7.5% - * - * @return float|int */ - public function getFeePercent(); + public function getFeePercent(): float|int; } diff --git a/src/Interfaces/Wallet.php b/src/Interfaces/Wallet.php index 84307de1d..cc16b307d 100644 --- a/src/Interfaces/Wallet.php +++ b/src/Interfaces/Wallet.php @@ -20,19 +20,15 @@ interface Wallet { /** - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function deposit($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function deposit(int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction; /** - * @param int|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -41,22 +37,18 @@ public function deposit($amount, ?array $meta = null, bool $confirmed = true): T * @throws TransactionFailedException * @throws ExceptionInterface */ - public function withdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function withdraw(int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction; /** - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function forceWithdraw(int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction; /** - * @param int|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -65,33 +57,30 @@ public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = tr * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function transfer(self $wallet, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer; - /** - * @param int|string $amount - */ - public function safeTransfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; + public function safeTransfer( + self $wallet, + int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): ?Transfer; /** - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(self $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function forceTransfer( + self $wallet, + int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer; - /** - * @param int|string $amount - */ - public function canWithdraw($amount, bool $allowZero = false): bool; + public function canWithdraw(int|string $amount, bool $allowZero = false): bool; - /** - * @return float|int - */ - public function getBalanceAttribute(); + public function getBalanceAttribute(): string; public function getBalanceIntAttribute(): int; diff --git a/src/Interfaces/WalletFloat.php b/src/Interfaces/WalletFloat.php index 0fe6ce550..6f954495c 100644 --- a/src/Interfaces/WalletFloat.php +++ b/src/Interfaces/WalletFloat.php @@ -18,19 +18,15 @@ interface WalletFloat { /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function depositFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function depositFloat(float|int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction; /** - * @param float|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -39,22 +35,22 @@ public function depositFloat($amount, ?array $meta = null, bool $confirmed = tru * @throws TransactionFailedException * @throws ExceptionInterface */ - public function withdrawFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function withdrawFloat(float|int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction; /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction; + public function forceWithdrawFloat( + float|int|string $amount, + ?array $meta = null, + bool $confirmed = true + ): Transaction; /** - * @param float|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -63,31 +59,35 @@ public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function transferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer; - /** - * @param float|string $amount - */ - public function safeTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer; + public function safeTransferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): ?Transfer; /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer; + public function forceTransferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer; - /** - * @param float|string $amount - */ - public function canWithdrawFloat($amount): bool; + public function canWithdrawFloat(float|int|string $amount): bool; /** - * @return float|int|string + * @return string */ public function getBalanceFloatAttribute(); } diff --git a/src/Models/Transaction.php b/src/Models/Transaction.php index f2f88a4b5..7726eaba8 100644 --- a/src/Models/Transaction.php +++ b/src/Models/Transaction.php @@ -92,10 +92,7 @@ public function getAmountFloatAttribute(): string return $math->div($this->amount, $decimalPlaces); } - /** - * @param float|int|string $amount - */ - public function setAmountFloatAttribute($amount): void + public function setAmountFloatAttribute(float|int|string $amount): void { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class) diff --git a/src/Models/Wallet.php b/src/Models/Wallet.php index 5f4163433..7f8938b48 100644 --- a/src/Models/Wallet.php +++ b/src/Models/Wallet.php @@ -124,10 +124,7 @@ public function getOriginalBalanceAttribute(): string return (string) $this->getRawOriginal('balance', 0); } - /** - * @return float|int|string - */ - public function getAvailableBalanceAttribute() + public function getAvailableBalanceAttribute(): float|int|string { return $this->walletTransactions() ->where('confirmed', true) diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php index 9ddaf86c1..c15ac1b28 100644 --- a/src/Services/CommonServiceLegacy.php +++ b/src/Services/CommonServiceLegacy.php @@ -33,8 +33,6 @@ public function __construct( } /** - * @param int|string $amount - * * @throws LockProviderNotFoundException * @throws RecordNotFoundException * @throws RecordsNotFoundException @@ -44,7 +42,7 @@ public function __construct( public function forceTransfer( Wallet $from, Wallet $to, - $amount, + int|string $amount, ExtraDtoInterface|array|null $meta = null, string $status = Transfer::STATUS_TRANSFER ): Transfer { @@ -119,15 +117,13 @@ public function applyTransfers(array $objects): array } /** - * @param float|int|string $amount - * * @throws LockProviderNotFoundException * @throws RecordNotFoundException */ public function makeTransaction( Wallet $wallet, string $type, - $amount, + float|int|string $amount, ?array $meta, bool $confirmed = true ): Transaction { diff --git a/src/Services/ConsistencyServiceInterface.php b/src/Services/ConsistencyServiceInterface.php index e6b9aa127..8ae66c519 100644 --- a/src/Services/ConsistencyServiceInterface.php +++ b/src/Services/ConsistencyServiceInterface.php @@ -13,25 +13,17 @@ interface ConsistencyServiceInterface { /** - * @param float|int|string $amount - * * @throws AmountInvalid */ - public function checkPositive($amount): void; + public function checkPositive(float|int|string $amount): void; /** - * @param float|int|string $amount - * * @throws BalanceIsEmpty * @throws InsufficientFunds */ - public function checkPotential(Wallet $object, $amount, bool $allowZero = false): void; + public function checkPotential(Wallet $object, float|int|string $amount, bool $allowZero = false): void; - /** - * @param float|int|string $balance - * @param float|int|string $amount - */ - public function canWithdraw($balance, $amount, bool $allowZero = false): bool; + public function canWithdraw(int|string $balance, int|string $amount, bool $allowZero = false): bool; /** * @param TransferLazyDtoInterface[] $objects diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index dbc2bfd83..270c27066 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -31,8 +31,6 @@ trait CanExchange { /** - * @param int|string $amount - * * @throws BalanceIsEmpty * @throws InsufficientFunds * @throws LockProviderNotFoundException @@ -41,7 +39,7 @@ trait CanExchange * @throws TransactionFailedException * @throws ExceptionInterface */ - public function exchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer + public function exchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer { $wallet = app(CastServiceInterface::class)->getWallet($this); @@ -50,10 +48,7 @@ public function exchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta return $this->forceExchange($to, $amount, $meta); } - /** - * @param int|string $amount - */ - public function safeExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer + public function safeExchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer { try { return $this->exchange($to, $amount, $meta); @@ -63,15 +58,13 @@ public function safeExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $ } /** - * @param int|string $amount - * * @throws LockProviderNotFoundException * @throws RecordNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceExchange(Wallet $to, $amount, ExtraDtoInterface|array|null $meta = null): Transfer + public function forceExchange(Wallet $to, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer { return app(AtomicServiceInterface::class)->block($this, function () use ($to, $amount, $meta) { $extraAssembler = app(ExtraDtoAssemblerInterface::class); diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index 3fe5c9162..fda3b728a 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -44,15 +44,13 @@ trait HasWallet /** * The input means in the system. * - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function deposit($amount, ?array $meta = null, bool $confirmed = true): Transaction + public function deposit(int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction { return app(AtomicServiceInterface::class)->block( $this, @@ -63,10 +61,8 @@ public function deposit($amount, ?array $meta = null, bool $confirmed = true): T /** * Magic laravel framework method, makes it possible to call property balance. - * - * @return float|int|string */ - public function getBalanceAttribute() + public function getBalanceAttribute(): string { /** @var Wallet $this */ return app(RegulatorServiceInterface::class)->amount(app(CastServiceInterface::class)->getWallet($this)); @@ -101,11 +97,12 @@ public function transactions(): MorphMany /** * This method ignores errors that occur when transferring funds. - * - * @param int|string $amount */ - public function safeTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer - { + public function safeTransfer( + Wallet $wallet, + int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): ?Transfer { try { return $this->transfer($wallet, $amount, $meta); } catch (ExceptionInterface) { @@ -116,8 +113,6 @@ public function safeTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|nu /** * A method that transfers funds from host to host. * - * @param int|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -126,7 +121,7 @@ public function safeTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|nu * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer + public function transfer(Wallet $wallet, int|string $amount, ExtraDtoInterface|array|null $meta = null): Transfer { /** @var Wallet $this */ app(ConsistencyServiceInterface::class)->checkPotential($this, $amount); @@ -137,8 +132,6 @@ public function transfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $ /** * Withdrawals from the system. * - * @param int|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -147,7 +140,7 @@ public function transfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $ * @throws TransactionFailedException * @throws ExceptionInterface */ - public function withdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction + public function withdraw(int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction { /** @var Wallet $this */ app(ConsistencyServiceInterface::class)->checkPotential($this, $amount); @@ -157,10 +150,8 @@ public function withdraw($amount, ?array $meta = null, bool $confirmed = true): /** * Checks if you can withdraw funds. - * - * @param float|int|string $amount */ - public function canWithdraw($amount, bool $allowZero = false): bool + public function canWithdraw(int|string $amount, bool $allowZero = false): bool { $mathService = app(MathServiceInterface::class); $wallet = app(CastServiceInterface::class)->getWallet($this); @@ -172,8 +163,6 @@ public function canWithdraw($amount, bool $allowZero = false): bool /** * Forced to withdraw funds from system. * - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException @@ -181,7 +170,7 @@ public function canWithdraw($amount, bool $allowZero = false): bool * @throws ExceptionInterface */ public function forceWithdraw( - $amount, + int|string $amount, ExtraDtoInterface|array|null $meta = null, bool $confirmed = true ): Transaction { @@ -196,16 +185,17 @@ public function forceWithdraw( * the forced transfer is needed when the user does not have the money, and we drive it. Sometimes you do. Depends * on business logic. * - * @param int|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransfer(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer - { + public function forceTransfer( + Wallet $wallet, + int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer { return app(AtomicServiceInterface::class)->block( $this, fn () => app(CommonServiceLegacy::class) diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index d2188fc92..97d5e1ab0 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -30,16 +30,17 @@ trait HasWalletFloat use HasWallet; /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction - { + public function forceWithdrawFloat( + float|int|string $amount, + ?array $meta = null, + bool $confirmed = true + ): Transaction { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; $decimalPlaces = $math->powTen($decimalPlacesValue); @@ -49,15 +50,13 @@ public function forceWithdrawFloat($amount, ?array $meta = null, bool $confirmed } /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function depositFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction + public function depositFloat(float|int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -68,8 +67,6 @@ public function depositFloat($amount, ?array $meta = null, bool $confirmed = tru } /** - * @param float|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -78,7 +75,7 @@ public function depositFloat($amount, ?array $meta = null, bool $confirmed = tru * @throws TransactionFailedException * @throws ExceptionInterface */ - public function withdrawFloat($amount, ?array $meta = null, bool $confirmed = true): Transaction + public function withdrawFloat(float|int|string $amount, ?array $meta = null, bool $confirmed = true): Transaction { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -88,10 +85,7 @@ public function withdrawFloat($amount, ?array $meta = null, bool $confirmed = tr return $this->withdraw($result, $meta, $confirmed); } - /** - * @param float|string $amount - */ - public function canWithdrawFloat($amount): bool + public function canWithdrawFloat(float|int|string $amount): bool { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; @@ -102,8 +96,6 @@ public function canWithdrawFloat($amount): bool } /** - * @param float|string $amount - * * @throws AmountInvalid * @throws BalanceIsEmpty * @throws InsufficientFunds @@ -112,8 +104,11 @@ public function canWithdrawFloat($amount): bool * @throws TransactionFailedException * @throws ExceptionInterface */ - public function transferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer - { + public function transferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; $decimalPlaces = $math->powTen($decimalPlacesValue); @@ -122,11 +117,11 @@ public function transferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|n return $this->transfer($wallet, $result, $meta); } - /** - * @param float|string $amount - */ - public function safeTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): ?Transfer - { + public function safeTransferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): ?Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; $decimalPlaces = $math->powTen($decimalPlacesValue); @@ -136,16 +131,17 @@ public function safeTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|arr } /** - * @param float|string $amount - * * @throws AmountInvalid * @throws LockProviderNotFoundException * @throws RecordsNotFoundException * @throws TransactionFailedException * @throws ExceptionInterface */ - public function forceTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|array|null $meta = null): Transfer - { + public function forceTransferFloat( + Wallet $wallet, + float|int|string $amount, + ExtraDtoInterface|array|null $meta = null + ): Transfer { $math = app(MathServiceInterface::class); $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places; $decimalPlaces = $math->powTen($decimalPlacesValue); @@ -155,7 +151,7 @@ public function forceTransferFloat(Wallet $wallet, $amount, ExtraDtoInterface|ar } /** - * @return float|int|string + * @return string */ public function getBalanceFloatAttribute() { diff --git a/tests/Infra/Models/Item.php b/tests/Infra/Models/Item.php index f35534564..260601cdc 100644 --- a/tests/Infra/Models/Item.php +++ b/tests/Infra/Models/Item.php @@ -37,7 +37,7 @@ public function canBuy(Customer $customer, int $quantity = 1, bool $force = fals return $result && !$customer->paid($this); } - public function getAmountProduct(Customer $customer) + public function getAmountProduct(Customer $customer): float|int|string { /** @var Wallet $wallet */ $wallet = app(CastService::class)->getWallet($customer); diff --git a/tests/Infra/Models/ItemTax.php b/tests/Infra/Models/ItemTax.php index fe74e6d23..ffb6efa79 100644 --- a/tests/Infra/Models/ItemTax.php +++ b/tests/Infra/Models/ItemTax.php @@ -17,10 +17,8 @@ public function getTable(): string * Specify the percentage of the amount. For example, the product costs $100, the equivalent of 15%. That's $115. * * Minimum 0; Maximum 100 Example: return 7.5; // 7.5% - * - * @return float|int */ - public function getFeePercent() + public function getFeePercent(): float|int { return 7.5; } From e65664a5e091b5c5266bee96e1cf401cf81a595d Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 23:45:50 +0300 Subject: [PATCH 15/61] fix contract --- src/Interfaces/ProductInterface.php | 2 +- tests/Infra/Models/Item.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Interfaces/ProductInterface.php b/src/Interfaces/ProductInterface.php index d2062231c..3354a70fc 100644 --- a/src/Interfaces/ProductInterface.php +++ b/src/Interfaces/ProductInterface.php @@ -6,7 +6,7 @@ interface ProductInterface extends Wallet { - public function getAmountProduct(Customer $customer): float|int|string; + public function getAmountProduct(Customer $customer): int|string; public function getMetaProduct(): ?array; } diff --git a/tests/Infra/Models/Item.php b/tests/Infra/Models/Item.php index 260601cdc..0a20cf480 100644 --- a/tests/Infra/Models/Item.php +++ b/tests/Infra/Models/Item.php @@ -37,7 +37,7 @@ public function canBuy(Customer $customer, int $quantity = 1, bool $force = fals return $result && !$customer->paid($this); } - public function getAmountProduct(Customer $customer): float|int|string + public function getAmountProduct(Customer $customer): int|string { /** @var Wallet $wallet */ $wallet = app(CastService::class)->getWallet($customer); From 7518b841df5a2c83f8e51a41620e94a0d6702fb0 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 23:49:24 +0300 Subject: [PATCH 16/61] fix contract --- src/Interfaces/WalletFloat.php | 5 +---- src/Traits/HasWalletFloat.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Interfaces/WalletFloat.php b/src/Interfaces/WalletFloat.php index 6f954495c..bfd09ce15 100644 --- a/src/Interfaces/WalletFloat.php +++ b/src/Interfaces/WalletFloat.php @@ -86,8 +86,5 @@ public function forceTransferFloat( public function canWithdrawFloat(float|int|string $amount): bool; - /** - * @return string - */ - public function getBalanceFloatAttribute(); + public function getBalanceFloatAttribute(): string; } diff --git a/src/Traits/HasWalletFloat.php b/src/Traits/HasWalletFloat.php index 97d5e1ab0..ee42b7595 100644 --- a/src/Traits/HasWalletFloat.php +++ b/src/Traits/HasWalletFloat.php @@ -150,10 +150,7 @@ public function forceTransferFloat( return $this->forceTransfer($wallet, $result, $meta); } - /** - * @return string - */ - public function getBalanceFloatAttribute() + public function getBalanceFloatAttribute(): string { $math = app(MathServiceInterface::class); $wallet = app(CastServiceInterface::class)->getWallet($this); From 2e0ef6c80a5999f1ec5ccf3201bc2dafcf0b6500 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 23:50:58 +0300 Subject: [PATCH 17/61] drop legacy methods --- src/Objects/Cart.php | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/Objects/Cart.php b/src/Objects/Cart.php index b1fc3268e..d2154dae1 100644 --- a/src/Objects/Cart.php +++ b/src/Objects/Cart.php @@ -51,19 +51,6 @@ public function withMeta(array $meta): self return $self; } - /** - * @codeCoverageIgnore - * - * @deprecated - * @see withMeta - */ - public function setMeta(array $meta): self - { - $this->meta = $meta; - - return $this; - } - public function withItem(ProductInterface $product, int $quantity = 1): self { $self = clone $this; @@ -76,22 +63,6 @@ public function withItem(ProductInterface $product, int $quantity = 1): self return $self; } - /** - * @codeCoverageIgnore - * - * @deprecated - * @see withItem - */ - public function addItem(ProductInterface $product, int $quantity = 1): self - { - $productId = $this->productId($product); - - $this->quantity[$productId] = $this->getQuantity($product) + $quantity; - $this->items[$productId] = $product; - - return $this; - } - public function withItems(iterable $products): self { $self = clone $this; @@ -102,21 +73,6 @@ public function withItems(iterable $products): self return $self; } - /** - * @codeCoverageIgnore - * - * @deprecated - * @see withItems - */ - public function addItems(iterable $products): self - { - foreach ($products as $product) { - $this->addItem($product); - } - - return $this; - } - /** * @return ProductInterface[] */ From fd04208006aa3c40fc2ab5c328d283f3419d5bf1 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Wed, 20 Apr 2022 23:58:09 +0300 Subject: [PATCH 18/61] delete MetaServiceLegacy --- .phpstorm.meta.php | 2 -- src/Services/AssistantService.php | 20 +++++++++++++++ src/Services/AssistantServiceInterface.php | 4 +++ src/Services/MetaServiceLegacy.php | 30 ---------------------- src/Traits/CartPay.php | 13 +++++----- src/WalletServiceProvider.php | 2 -- 6 files changed, 31 insertions(+), 40 deletions(-) delete mode 100644 src/Services/MetaServiceLegacy.php diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index af06931ac..f946484ef 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -37,7 +37,6 @@ use Bavix\Wallet\Internal\Service\UuidFactoryServiceInterface; use Bavix\Wallet\Objects\Cart; use Bavix\Wallet\Services\CommonServiceLegacy; - use Bavix\Wallet\Services\MetaServiceLegacy; use Bavix\Wallet\Services\TaxServiceInterface; override(\app(0), map([ @@ -91,7 +90,6 @@ // lagacy.services CommonServiceLegacy::class => CommonServiceLegacy::class, - MetaServiceLegacy::class => MetaServiceLegacy::class, ])); } diff --git a/src/Services/AssistantService.php b/src/Services/AssistantService.php index 698890f77..5494c6f3f 100644 --- a/src/Services/AssistantService.php +++ b/src/Services/AssistantService.php @@ -4,6 +4,8 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\Interfaces\CartInterface; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferDtoInterface; use Bavix\Wallet\Internal\Service\MathServiceInterface; @@ -44,4 +46,22 @@ public function getSums(array $transactions): array return array_filter($amounts, fn (string $amount): bool => $this->mathService->compare($amount, 0) !== 0); } + + public function getMeta(CartInterface $cart, ProductInterface $product): ?array + { + $metaCart = $cart->getBasketDto() + ->meta() + ; + $metaProduct = $product->getMetaProduct(); + + if ($metaProduct !== null) { + return array_merge($metaCart, $metaProduct); + } + + if (count($metaCart) > 0) { + return $metaCart; + } + + return null; + } } diff --git a/src/Services/AssistantServiceInterface.php b/src/Services/AssistantServiceInterface.php index d467d1175..070ade021 100644 --- a/src/Services/AssistantServiceInterface.php +++ b/src/Services/AssistantServiceInterface.php @@ -4,6 +4,8 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\Interfaces\CartInterface; +use Bavix\Wallet\Interfaces\ProductInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Dto\TransferDtoInterface; @@ -22,4 +24,6 @@ public function getUuids(array $objects): array; * @return array */ public function getSums(array $transactions): array; + + public function getMeta(CartInterface $cart, ProductInterface $product): ?array; } diff --git a/src/Services/MetaServiceLegacy.php b/src/Services/MetaServiceLegacy.php deleted file mode 100644 index 587383462..000000000 --- a/src/Services/MetaServiceLegacy.php +++ /dev/null @@ -1,30 +0,0 @@ -getBasketDto() - ->meta() - ; - $metaProduct = $product->getMetaProduct(); - - if ($metaProduct !== null) { - return array_merge($metaCart, $metaProduct); - } - - if (count($metaCart) > 0) { - return $metaCart; - } - - return null; - } -} diff --git a/src/Traits/CartPay.php b/src/Traits/CartPay.php index 1f0dde05d..1a2308239 100644 --- a/src/Traits/CartPay.php +++ b/src/Traits/CartPay.php @@ -18,11 +18,11 @@ use Bavix\Wallet\Internal\Service\TranslatorServiceInterface; use Bavix\Wallet\Models\Transfer; use Bavix\Wallet\Objects\Cart; +use Bavix\Wallet\Services\AssistantServiceInterface; use Bavix\Wallet\Services\AtomicServiceInterface; use Bavix\Wallet\Services\BasketServiceInterface; use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; -use Bavix\Wallet\Services\MetaServiceLegacy; use Bavix\Wallet\Services\PrepareServiceInterface; use Bavix\Wallet\Services\PurchaseServiceInterface; use Bavix\Wallet\Services\TransferServiceInterface; @@ -65,14 +65,14 @@ public function payFreeCart(CartInterface $cart): array $transfers = []; $prepareService = app(PrepareServiceInterface::class); - $metaService = app(MetaServiceLegacy::class); + $assistantService = app(AssistantServiceInterface::class); foreach ($cart->getBasketDto()->cursor() as $product) { $transfers[] = $prepareService->transferLazy( $this, $product, Transfer::STATUS_PAID, 0, - $metaService->getMeta($cart, $product) + $assistantService->getMeta($cart, $product) ); } @@ -118,14 +118,14 @@ public function payCart(CartInterface $cart, bool $force = false): array $transfers = []; $prepareService = app(PrepareServiceInterface::class); - $metaService = app(MetaServiceLegacy::class); + $assistantService = app(AssistantServiceInterface::class); foreach ($cart->getBasketDto()->cursor() as $product) { $transfers[] = $prepareService->transferLazy( $this, $product, Transfer::STATUS_PAID, $product->getAmountProduct($this), - $metaService->getMeta($cart, $product) + $assistantService->getMeta($cart, $product) ); } @@ -188,6 +188,7 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts $transferIds = []; $transfers = array_values($transfers); $prepareService = app(PrepareServiceInterface::class); + $assistantService = app(AssistantServiceInterface::class); foreach ($cart->getBasketDto()->cursor() as $product) { $transferIds[] = $transfers[$index]->getKey(); $objects[] = $prepareService->transferLazy( @@ -195,7 +196,7 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts $transfers[$index]->withdraw->wallet, Transfer::STATUS_TRANSFER, $transfers[$index]->deposit->amount, - app(MetaServiceLegacy::class)->getMeta($cart, $product) + $assistantService->getMeta($cart, $product) ); ++$index; diff --git a/src/WalletServiceProvider.php b/src/WalletServiceProvider.php index 0ac542186..7b3b3fe84 100644 --- a/src/WalletServiceProvider.php +++ b/src/WalletServiceProvider.php @@ -78,7 +78,6 @@ use Bavix\Wallet\Services\DiscountServiceInterface; use Bavix\Wallet\Services\ExchangeService; use Bavix\Wallet\Services\ExchangeServiceInterface; -use Bavix\Wallet\Services\MetaServiceLegacy; use Bavix\Wallet\Services\PrepareService; use Bavix\Wallet\Services\PrepareServiceInterface; use Bavix\Wallet\Services\PurchaseService; @@ -310,7 +309,6 @@ private function events(array $configure): void private function legacySingleton(): void { $this->app->singleton(CommonServiceLegacy::class); - $this->app->singleton(MetaServiceLegacy::class); } private function bindObjects(array $configure): void From cf18d5b2006ac42975e5d14171ad4be0fe94a569 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 00:28:35 +0300 Subject: [PATCH 19/61] delete CommonServiceLegacy --- .phpstorm.meta.php | 3 - config/config.php | 2 + deptrac.yaml | 5 - src/Services/CommonServiceLegacy.php | 171 ------------------- src/Services/TransactionService.php | 76 +++++++++ src/Services/TransactionServiceInterface.php | 37 ++++ src/Services/TransferService.php | 85 ++++++++- src/Services/TransferServiceInterface.php | 21 +++ src/Traits/CanExchange.php | 4 +- src/Traits/CartPay.php | 11 +- src/Traits/HasGift.php | 8 +- src/Traits/HasWallet.php | 26 +-- src/WalletServiceProvider.php | 13 +- tests/Units/Service/SingletonTest.php | 6 - 14 files changed, 252 insertions(+), 216 deletions(-) delete mode 100644 src/Services/CommonServiceLegacy.php create mode 100644 src/Services/TransactionService.php create mode 100644 src/Services/TransactionServiceInterface.php diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index f946484ef..649569c78 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -87,9 +87,6 @@ PrepareServiceInterface::class => PrepareServiceInterface::class, PurchaseServiceInterface::class => PurchaseServiceInterface::class, TaxServiceInterface::class => TaxServiceInterface::class, - - // lagacy.services - CommonServiceLegacy::class => CommonServiceLegacy::class, ])); } diff --git a/config/config.php b/config/config.php index 341500b4c..39e8add48 100644 --- a/config/config.php +++ b/config/config.php @@ -43,6 +43,7 @@ use Bavix\Wallet\Services\PurchaseService; use Bavix\Wallet\Services\RegulatorService; use Bavix\Wallet\Services\TaxService; +use Bavix\Wallet\Services\TransactionService; use Bavix\Wallet\Services\TransferService; use Bavix\Wallet\Services\WalletService; @@ -103,6 +104,7 @@ 'prepare' => PrepareService::class, 'purchase' => PurchaseService::class, 'tax' => TaxService::class, + 'transaction' => TransactionService::class, 'transfer' => TransferService::class, 'wallet' => WalletService::class, ], diff --git a/deptrac.yaml b/deptrac.yaml index 3b21d6fe2..e549ce5f0 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -5,8 +5,6 @@ parameters: layers: - name: Legacy collectors: - - type: className - regex: ^Bavix\\.*Legacy$ - type: className regex: ^Bavix\\.*\\Objects\\Cart$ @@ -242,11 +240,8 @@ parameters: - Dto Legacy: - - AssemblerDtoInterface - InternalException - ServiceInterface - DtoInterface - - UIException - Contract - - Model - Dto # Cart from objects diff --git a/src/Services/CommonServiceLegacy.php b/src/Services/CommonServiceLegacy.php deleted file mode 100644 index c15ac1b28..000000000 --- a/src/Services/CommonServiceLegacy.php +++ /dev/null @@ -1,171 +0,0 @@ -prepareService->transferLazy($from, $to, $status, $amount, $meta); - $transfers = $this->applyTransfers([$transferLazyDto]); - - return current($transfers); - } - - /** - * @param non-empty-array $objects - * - * @throws LockProviderNotFoundException - * @throws RecordNotFoundException - * @throws RecordsNotFoundException - * @throws TransactionFailedException - * @throws ExceptionInterface - * - * @return non-empty-array - */ - public function applyTransfers(array $objects): array - { - return $this->databaseService->transaction(function () use ($objects): array { - $wallets = []; - $operations = []; - foreach ($objects as $object) { - $fromWallet = $this->castService->getWallet($object->getFromWallet()); - $wallets[$fromWallet->getKey()] = $fromWallet; - - $toWallet = $this->castService->getWallet($object->getToWallet()); - $wallets[$toWallet->getKey()] = $toWallet; - - $operations[] = $object->getWithdrawDto(); - $operations[] = $object->getDepositDto(); - } - - $transactions = $this->applyTransactions($wallets, $operations); - - $links = []; - $transfers = []; - foreach ($objects as $object) { - $withdraw = $transactions[$object->getWithdrawDto()->getUuid()] ?? null; - assert($withdraw !== null); - - $deposit = $transactions[$object->getDepositDto()->getUuid()] ?? null; - assert($deposit !== null); - - $transfer = $this->transferDtoAssembler->create( - $deposit->getKey(), - $withdraw->getKey(), - $object->getStatus(), - $this->castService->getModel($object->getFromWallet()), - $this->castService->getModel($object->getToWallet()), - $object->getDiscount(), - $object->getFee() - ); - - $transfers[] = $transfer; - $links[$transfer->getUuid()] = [ - 'deposit' => $deposit, - 'withdraw' => $withdraw, - ]; - } - - $models = $this->atmService->makeTransfers($transfers); - foreach ($models as $model) { - $model->setRelations($links[$model->uuid] ?? []); - } - - return $models; - }); - } - - /** - * @throws LockProviderNotFoundException - * @throws RecordNotFoundException - */ - public function makeTransaction( - Wallet $wallet, - string $type, - float|int|string $amount, - ?array $meta, - bool $confirmed = true - ): Transaction { - assert(in_array($type, [Transaction::TYPE_DEPOSIT, Transaction::TYPE_WITHDRAW], true)); - - if ($type === Transaction::TYPE_DEPOSIT) { - $dto = $this->prepareService->deposit($wallet, (string) $amount, $meta, $confirmed); - } else { - $dto = $this->prepareService->withdraw($wallet, (string) $amount, $meta, $confirmed); - } - - $transactions = $this->applyTransactions([ - $dto->getWalletId() => $wallet, - ], [$dto]); - - return current($transactions); - } - - /** - * @param non-empty-array $wallets - * @param non-empty-array $objects - * - * @throws LockProviderNotFoundException - * @throws RecordNotFoundException - * - * @return non-empty-array - */ - public function applyTransactions(array $wallets, array $objects): array - { - $transactions = $this->atmService->makeTransactions($objects); // q1 - $totals = $this->assistantService->getSums($objects); - - foreach ($totals as $walletId => $total) { - $wallet = $wallets[$walletId] ?? null; - assert($wallet !== null); - - $object = $this->castService->getWallet($wallet); - assert((int) $object->getKey() === $walletId); - - $this->regulatorService->increase($object, $total); - } - - return $transactions; - } -} diff --git a/src/Services/TransactionService.php b/src/Services/TransactionService.php new file mode 100644 index 000000000..69009cbf3 --- /dev/null +++ b/src/Services/TransactionService.php @@ -0,0 +1,76 @@ +prepareService->deposit($wallet, (string) $amount, $meta, $confirmed); + } else { + $dto = $this->prepareService->withdraw($wallet, (string) $amount, $meta, $confirmed); + } + + $transactions = $this->apply([ + $dto->getWalletId() => $wallet, + ], [$dto]); + + return current($transactions); + } + + /** + * @param non-empty-array $wallets + * @param non-empty-array $objects + * + * @throws LockProviderNotFoundException + * @throws RecordNotFoundException + * + * @return non-empty-array + */ + public function apply(array $wallets, array $objects): array + { + $transactions = $this->atmService->makeTransactions($objects); // q1 + $totals = $this->assistantService->getSums($objects); + + foreach ($totals as $walletId => $total) { + $wallet = $wallets[$walletId] ?? null; + assert($wallet !== null); + + $object = $this->castService->getWallet($wallet); + assert((int) $object->getKey() === $walletId); + + $this->regulatorService->increase($object, $total); + } + + return $transactions; + } +} diff --git a/src/Services/TransactionServiceInterface.php b/src/Services/TransactionServiceInterface.php new file mode 100644 index 000000000..8e42608d3 --- /dev/null +++ b/src/Services/TransactionServiceInterface.php @@ -0,0 +1,37 @@ + $wallets + * @param non-empty-array $objects + * + * @throws LockProviderNotFoundException + * @throws RecordNotFoundException + * + * @return non-empty-array + */ + public function apply(array $wallets, array $objects): array; +} diff --git a/src/Services/TransferService.php b/src/Services/TransferService.php index 5864ccac5..e24655a06 100644 --- a/src/Services/TransferService.php +++ b/src/Services/TransferService.php @@ -4,12 +4,27 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\Internal\Assembler\TransferDtoAssemblerInterface; +use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; +use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; +use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; +use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; +use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; use Bavix\Wallet\Internal\Repository\TransferRepositoryInterface; +use Bavix\Wallet\Internal\Service\DatabaseServiceInterface; +use Bavix\Wallet\Models\Transfer; +use Illuminate\Database\RecordsNotFoundException; final class TransferService implements TransferServiceInterface { - public function __construct(private TransferRepositoryInterface $repository) - { + public function __construct( + private TransferDtoAssemblerInterface $transferDtoAssembler, + private TransferRepositoryInterface $transferRepository, + private TransactionServiceInterface $transactionService, + private DatabaseServiceInterface $databaseService, + private CastServiceInterface $castService, + private AtmServiceInterface $atmService, + ) { } /** @@ -17,6 +32,70 @@ public function __construct(private TransferRepositoryInterface $repository) */ public function updateStatusByIds(string $status, array $ids): bool { - return count($ids) !== 0 && count($ids) === $this->repository->updateStatusByIds($status, $ids); + return count($ids) !== 0 && count($ids) === $this->transferRepository->updateStatusByIds($status, $ids); + } + + /** + * @param non-empty-array $objects + * + * @throws LockProviderNotFoundException + * @throws RecordNotFoundException + * @throws RecordsNotFoundException + * @throws TransactionFailedException + * @throws ExceptionInterface + * + * @return non-empty-array + */ + public function apply(array $objects): array + { + return $this->databaseService->transaction(function () use ($objects): array { + $wallets = []; + $operations = []; + foreach ($objects as $object) { + $fromWallet = $this->castService->getWallet($object->getFromWallet()); + $wallets[$fromWallet->getKey()] = $fromWallet; + + $toWallet = $this->castService->getWallet($object->getToWallet()); + $wallets[$toWallet->getKey()] = $toWallet; + + $operations[] = $object->getWithdrawDto(); + $operations[] = $object->getDepositDto(); + } + + $transactions = $this->transactionService->apply($wallets, $operations); + + $links = []; + $transfers = []; + foreach ($objects as $object) { + $withdraw = $transactions[$object->getWithdrawDto()->getUuid()] ?? null; + assert($withdraw !== null); + + $deposit = $transactions[$object->getDepositDto()->getUuid()] ?? null; + assert($deposit !== null); + + $transfer = $this->transferDtoAssembler->create( + $deposit->getKey(), + $withdraw->getKey(), + $object->getStatus(), + $this->castService->getModel($object->getFromWallet()), + $this->castService->getModel($object->getToWallet()), + $object->getDiscount(), + $object->getFee() + ); + + $transfers[] = $transfer; + $links[$transfer->getUuid()] = [ + 'deposit' => $deposit, + 'withdraw' => $withdraw, + ]; + } + + $models = $this->atmService->makeTransfers($transfers); + foreach ($models as $model) { + $model->setRelations($links[$model->uuid] ?? []); + } + + return $models; + }); } } diff --git a/src/Services/TransferServiceInterface.php b/src/Services/TransferServiceInterface.php index abf01c7da..f1731ae9a 100644 --- a/src/Services/TransferServiceInterface.php +++ b/src/Services/TransferServiceInterface.php @@ -4,10 +4,31 @@ namespace Bavix\Wallet\Services; +use Bavix\Wallet\Internal\Dto\TransferLazyDtoInterface; +use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; +use Bavix\Wallet\Internal\Exceptions\LockProviderNotFoundException; +use Bavix\Wallet\Internal\Exceptions\RecordNotFoundException; +use Bavix\Wallet\Internal\Exceptions\TransactionFailedException; +use Bavix\Wallet\Models\Transfer; +use Illuminate\Database\RecordsNotFoundException; + interface TransferServiceInterface { /** * @param int[] $ids */ public function updateStatusByIds(string $status, array $ids): bool; + + /** + * @param non-empty-array $objects + * + * @throws LockProviderNotFoundException + * @throws RecordNotFoundException + * @throws RecordsNotFoundException + * @throws TransactionFailedException + * @throws ExceptionInterface + * + * @return non-empty-array + */ + public function apply(array $objects): array; } diff --git a/src/Traits/CanExchange.php b/src/Traits/CanExchange.php index 270c27066..13e9f4688 100644 --- a/src/Traits/CanExchange.php +++ b/src/Traits/CanExchange.php @@ -18,11 +18,11 @@ use Bavix\Wallet\Models\Transfer; use Bavix\Wallet\Services\AtomicServiceInterface; use Bavix\Wallet\Services\CastServiceInterface; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\ExchangeServiceInterface; use Bavix\Wallet\Services\PrepareServiceInterface; use Bavix\Wallet\Services\TaxServiceInterface; +use Bavix\Wallet\Services\TransferServiceInterface; use Illuminate\Database\RecordsNotFoundException; /** @@ -106,7 +106,7 @@ public function forceExchange(Wallet $to, int|string $amount, ExtraDtoInterface| Transfer::STATUS_EXCHANGE, ); - $transfers = app(CommonServiceLegacy::class)->applyTransfers([$transferLazyDto]); + $transfers = app(TransferServiceInterface::class)->apply([$transferLazyDto]); return current($transfers); }); diff --git a/src/Traits/CartPay.php b/src/Traits/CartPay.php index 1a2308239..806e73782 100644 --- a/src/Traits/CartPay.php +++ b/src/Traits/CartPay.php @@ -21,7 +21,6 @@ use Bavix\Wallet\Services\AssistantServiceInterface; use Bavix\Wallet\Services\AtomicServiceInterface; use Bavix\Wallet\Services\BasketServiceInterface; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\PrepareServiceInterface; use Bavix\Wallet\Services\PurchaseServiceInterface; @@ -76,7 +75,7 @@ public function payFreeCart(CartInterface $cart): array ); } - return app(CommonServiceLegacy::class)->applyTransfers($transfers); + return app(TransferServiceInterface::class)->apply($transfers); }); } @@ -133,7 +132,7 @@ public function payCart(CartInterface $cart, bool $force = false): array app(ConsistencyServiceInterface::class)->checkTransfer($transfers); } - return app(CommonServiceLegacy::class)->applyTransfers($transfers); + return app(TransferServiceInterface::class)->apply($transfers); }); } @@ -206,9 +205,11 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts app(ConsistencyServiceInterface::class)->checkTransfer($objects); } - app(CommonServiceLegacy::class)->applyTransfers($objects); + $transferService = app(TransferServiceInterface::class); - return app(TransferServiceInterface::class) + $transferService->apply($objects); + + return $transferService ->updateStatusByIds(Transfer::STATUS_REFUND, $transferIds) ; }); diff --git a/src/Traits/HasGift.php b/src/Traits/HasGift.php index a91afb663..acb010916 100644 --- a/src/Traits/HasGift.php +++ b/src/Traits/HasGift.php @@ -19,10 +19,10 @@ use Bavix\Wallet\Services\AtmServiceInterface; use Bavix\Wallet\Services\AtomicServiceInterface; use Bavix\Wallet\Services\CastServiceInterface; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\DiscountServiceInterface; use Bavix\Wallet\Services\TaxServiceInterface; +use Bavix\Wallet\Services\TransactionServiceInterface; use Illuminate\Database\RecordsNotFoundException; /** @@ -67,15 +67,15 @@ public function gift(Wallet $to, ProductInterface $product, bool $force = false) app(ConsistencyServiceInterface::class)->checkPotential($this, $mathService->add($amount, $fee)); } - $commonService = app(CommonServiceLegacy::class); + $transactionService = app(TransactionServiceInterface::class); $metaProduct = $product->getMetaProduct(); - $withdraw = $commonService->makeTransaction( + $withdraw = $transactionService->makeOne( $this, Transaction::TYPE_WITHDRAW, $mathService->add($amount, $fee), $metaProduct ); - $deposit = $commonService->makeTransaction($product, Transaction::TYPE_DEPOSIT, $amount, $metaProduct); + $deposit = $transactionService->makeOne($product, Transaction::TYPE_DEPOSIT, $amount, $metaProduct); $castService = app(CastServiceInterface::class); diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index fda3b728a..bb6ba9a28 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -19,9 +19,11 @@ use Bavix\Wallet\Models\Wallet as WalletModel; use Bavix\Wallet\Services\AtomicServiceInterface; use Bavix\Wallet\Services\CastServiceInterface; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyServiceInterface; +use Bavix\Wallet\Services\PrepareServiceInterface; use Bavix\Wallet\Services\RegulatorServiceInterface; +use Bavix\Wallet\Services\TransactionServiceInterface; +use Bavix\Wallet\Services\TransferServiceInterface; use function config; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; @@ -54,8 +56,8 @@ public function deposit(int|string $amount, ?array $meta = null, bool $confirmed { return app(AtomicServiceInterface::class)->block( $this, - fn () => app(CommonServiceLegacy::class) - ->makeTransaction($this, Transaction::TYPE_DEPOSIT, $amount, $meta, $confirmed) + fn () => app(TransactionServiceInterface::class) + ->makeOne($this, Transaction::TYPE_DEPOSIT, $amount, $meta, $confirmed) ); } @@ -176,8 +178,8 @@ public function forceWithdraw( ): Transaction { return app(AtomicServiceInterface::class)->block( $this, - fn () => app(CommonServiceLegacy::class) - ->makeTransaction($this, Transaction::TYPE_WITHDRAW, $amount, $meta, $confirmed) + fn () => app(TransactionServiceInterface::class) + ->makeOne($this, Transaction::TYPE_WITHDRAW, $amount, $meta, $confirmed) ); } @@ -196,11 +198,15 @@ public function forceTransfer( int|string $amount, ExtraDtoInterface|array|null $meta = null ): Transfer { - return app(AtomicServiceInterface::class)->block( - $this, - fn () => app(CommonServiceLegacy::class) - ->forceTransfer($this, $wallet, $amount, $meta) - ); + return app(AtomicServiceInterface::class)->block($this, function () use ($wallet, $amount, $meta) { + $transferLazyDto = app(PrepareServiceInterface::class) + ->transferLazy($this, $wallet, Transfer::STATUS_TRANSFER, $amount, $meta) + ; + + $transfers = app(TransferServiceInterface::class)->apply([$transferLazyDto]); + + return current($transfers); + }); } /** diff --git a/src/WalletServiceProvider.php b/src/WalletServiceProvider.php index 7b3b3fe84..0b2742d85 100644 --- a/src/WalletServiceProvider.php +++ b/src/WalletServiceProvider.php @@ -71,7 +71,6 @@ use Bavix\Wallet\Services\BookkeeperServiceInterface; use Bavix\Wallet\Services\CastService; use Bavix\Wallet\Services\CastServiceInterface; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Services\ConsistencyService; use Bavix\Wallet\Services\ConsistencyServiceInterface; use Bavix\Wallet\Services\DiscountService; @@ -86,6 +85,8 @@ use Bavix\Wallet\Services\RegulatorServiceInterface; use Bavix\Wallet\Services\TaxService; use Bavix\Wallet\Services\TaxServiceInterface; +use Bavix\Wallet\Services\TransactionService; +use Bavix\Wallet\Services\TransactionServiceInterface; use Bavix\Wallet\Services\TransferService; use Bavix\Wallet\Services\TransferServiceInterface; use Bavix\Wallet\Services\WalletService; @@ -137,7 +138,6 @@ public function register(): void $this->internal($configure['internal'] ?? []); $this->services($configure['services'] ?? [], $configure['cache'] ?? []); - $this->legacySingleton(); // without configuration $this->repositories($configure['repositories'] ?? []); $this->transformers($configure['transformers'] ?? []); @@ -200,6 +200,10 @@ private function services(array $configure, array $cache): void $this->app->singleton(PrepareServiceInterface::class, $configure['prepare'] ?? PrepareService::class); $this->app->singleton(PurchaseServiceInterface::class, $configure['purchase'] ?? PurchaseService::class); $this->app->singleton(TaxServiceInterface::class, $configure['tax'] ?? TaxService::class); + $this->app->singleton( + TransactionServiceInterface::class, + $configure['transaction'] ?? TransactionService::class + ); $this->app->singleton(TransferServiceInterface::class, $configure['transfer'] ?? TransferService::class); $this->app->singleton(WalletServiceInterface::class, $configure['wallet'] ?? WalletService::class); @@ -306,11 +310,6 @@ private function events(array $configure): void ); } - private function legacySingleton(): void - { - $this->app->singleton(CommonServiceLegacy::class); - } - private function bindObjects(array $configure): void { $this->app->bind(Transaction::class, $configure['transaction']['model'] ?? null); diff --git a/tests/Units/Service/SingletonTest.php b/tests/Units/Service/SingletonTest.php index f71b0652c..6cb44475c 100644 --- a/tests/Units/Service/SingletonTest.php +++ b/tests/Units/Service/SingletonTest.php @@ -7,7 +7,6 @@ use Bavix\Wallet\Internal\Service\DatabaseServiceInterface; use Bavix\Wallet\Internal\Service\MathServiceInterface; use Bavix\Wallet\Objects\Cart; -use Bavix\Wallet\Services\CommonServiceLegacy; use Bavix\Wallet\Test\Infra\PackageModels\Transaction; use Bavix\Wallet\Test\Infra\PackageModels\Transfer; use Bavix\Wallet\Test\Infra\PackageModels\Wallet; @@ -43,11 +42,6 @@ public function testWallet(): void self::assertNotSame($this->getRefId(Wallet::class), $this->getRefId(Wallet::class)); } - public function testCommonService(): void - { - self::assertSame($this->getRefId(CommonServiceLegacy::class), $this->getRefId(CommonServiceLegacy::class)); - } - public function testDatabaseService(): void { self::assertSame( From 9e5f790ad70e9dfe28077e8799b53d78ce011bc0 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 19:59:19 +0300 Subject: [PATCH 20/61] Increased the severity of code style. Preparing to work with a binary string --- rector.php | 5 +- .../Assembler/TransactionDtoAssembler.php | 2 +- .../TransactionDtoAssemblerInterface.php | 2 +- src/Internal/Dto/TransactionDto.php | 4 +- src/Internal/Dto/TransactionDtoInterface.php | 2 +- src/Internal/Repository/WalletRepository.php | 5 +- src/Internal/Service/DispatcherService.php | 4 +- src/Internal/Service/MathService.php | 60 ++++------------- src/Internal/Service/MathServiceInterface.php | 66 ++++--------------- src/Internal/Service/UuidFactoryService.php | 5 ++ .../Service/UuidFactoryServiceInterface.php | 2 + src/Models/Transaction.php | 2 +- src/Models/Transfer.php | 2 +- src/Models/Wallet.php | 2 +- src/Objects/Cart.php | 2 +- src/Services/AtmService.php | 4 +- src/Services/PrepareService.php | 8 +-- src/Services/PrepareServiceInterface.php | 8 +-- src/Services/TransferService.php | 2 +- src/Traits/CartPay.php | 4 +- src/Traits/HasGift.php | 2 +- .../Infra/PackageModels/TransactionMoney.php | 2 +- tests/Units/Domain/CartTest.php | 6 +- tests/Units/Domain/MultiWalletTest.php | 5 +- 24 files changed, 70 insertions(+), 136 deletions(-) diff --git a/rector.php b/rector.php index 868b562f1..2c4692543 100644 --- a/rector.php +++ b/rector.php @@ -2,10 +2,10 @@ declare(strict_types=1); +use Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector; use Rector\Core\Configuration\Option; use Rector\Laravel\Set\LaravelSetList; use Rector\Php74\Rector\Property\TypedPropertyRector; -use Rector\Php80\Rector\FunctionLike\UnionTypesRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\SetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -18,9 +18,12 @@ __DIR__ . '/tests', ]); + $parameters->set(Option::SKIP, [ExplicitMethodCallOverMagicGetSetRector::class]); + // Define what rule sets will be applied $containerConfigurator->import(PHPUnitSetList::PHPUNIT_91); $containerConfigurator->import(LaravelSetList::LARAVEL_80); + $containerConfigurator->import(SetList::CODE_QUALITY); $containerConfigurator->import(SetList::DEAD_CODE); $containerConfigurator->import(SetList::PHP_80); diff --git a/src/Internal/Assembler/TransactionDtoAssembler.php b/src/Internal/Assembler/TransactionDtoAssembler.php index 0dd35eb1b..84ff10be6 100644 --- a/src/Internal/Assembler/TransactionDtoAssembler.php +++ b/src/Internal/Assembler/TransactionDtoAssembler.php @@ -20,7 +20,7 @@ public function create( Model $payable, int $walletId, string $type, - string $amount, + float|int|string $amount, bool $confirmed, ?array $meta ): TransactionDtoInterface { diff --git a/src/Internal/Assembler/TransactionDtoAssemblerInterface.php b/src/Internal/Assembler/TransactionDtoAssemblerInterface.php index 74dae0fbe..d7588a7b1 100644 --- a/src/Internal/Assembler/TransactionDtoAssemblerInterface.php +++ b/src/Internal/Assembler/TransactionDtoAssemblerInterface.php @@ -13,7 +13,7 @@ public function create( Model $payable, int $walletId, string $type, - string $amount, + float|int|string $amount, bool $confirmed, ?array $meta ): TransactionDtoInterface; diff --git a/src/Internal/Dto/TransactionDto.php b/src/Internal/Dto/TransactionDto.php index 09e5caaab..6ea1d399b 100644 --- a/src/Internal/Dto/TransactionDto.php +++ b/src/Internal/Dto/TransactionDto.php @@ -18,7 +18,7 @@ public function __construct( private int|string $payableId, private int $walletId, private string $type, - private string $amount, + private float|int|string $amount, private bool $confirmed, private ?array $meta ) { @@ -51,7 +51,7 @@ public function getType(): string return $this->type; } - public function getAmount(): string + public function getAmount(): float|int|string { return $this->amount; } diff --git a/src/Internal/Dto/TransactionDtoInterface.php b/src/Internal/Dto/TransactionDtoInterface.php index 28506bd45..71cc1e3d3 100644 --- a/src/Internal/Dto/TransactionDtoInterface.php +++ b/src/Internal/Dto/TransactionDtoInterface.php @@ -18,7 +18,7 @@ public function getWalletId(): int; public function getType(): string; - public function getAmount(): string; + public function getAmount(): float|int|string; public function isConfirmed(): bool; diff --git a/src/Internal/Repository/WalletRepository.php b/src/Internal/Repository/WalletRepository.php index e7a0f0019..28076de36 100644 --- a/src/Internal/Repository/WalletRepository.php +++ b/src/Internal/Repository/WalletRepository.php @@ -6,12 +6,15 @@ use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\ModelNotFoundException; +use Bavix\Wallet\Internal\Service\UuidFactoryService; +use Bavix\Wallet\Internal\Service\UuidFactoryServiceInterface; use Bavix\Wallet\Models\Wallet; use Illuminate\Database\Eloquent\ModelNotFoundException as EloquentModelNotFoundException; final class WalletRepository implements WalletRepositoryInterface { public function __construct( + private UuidFactoryServiceInterface $uuidFactoryService, private Wallet $wallet ) { } @@ -67,7 +70,7 @@ public function getById(int $id): Wallet public function getByUuid(string $uuid): Wallet { return $this->getBy([ - 'uuid' => $uuid, + 'uuid' => $this->uuidFactoryService->cast($uuid), ]); } diff --git a/src/Internal/Service/DispatcherService.php b/src/Internal/Service/DispatcherService.php index 5ed0b6b1e..8038f7247 100644 --- a/src/Internal/Service/DispatcherService.php +++ b/src/Internal/Service/DispatcherService.php @@ -27,14 +27,14 @@ 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); } } public function forgot(): void { - foreach ($this->events as $event => $value) { + foreach (array_keys($this->events) as $event) { $this->dispatcher->forget($event); } } diff --git a/src/Internal/Service/MathService.php b/src/Internal/Service/MathService.php index 4997d5e2e..cc3e51191 100644 --- a/src/Internal/Service/MathService.php +++ b/src/Internal/Service/MathService.php @@ -17,10 +17,7 @@ public function __construct(ConfigRepository $config) $this->scale = (int) $config->get('wallet.math.scale', 64); } - /** - * {@inheritdoc} - */ - public function add($first, $second, ?int $scale = null): string + public function add(float|int|string $first, float|int|string $second, ?int $scale = null): string { return (string) BigDecimal::of($first) ->plus(BigDecimal::of($second)) @@ -28,10 +25,7 @@ public function add($first, $second, ?int $scale = null): string ; } - /** - * {@inheritdoc} - */ - public function sub($first, $second, ?int $scale = null): string + public function sub(float|int|string $first, float|int|string $second, ?int $scale = null): string { return (string) BigDecimal::of($first) ->minus(BigDecimal::of($second)) @@ -39,20 +33,14 @@ public function sub($first, $second, ?int $scale = null): string ; } - /** - * {@inheritdoc} - */ - public function div($first, $second, ?int $scale = null): string + public function div(float|int|string $first, float|int|string $second, ?int $scale = null): string { return (string) BigDecimal::of($first) ->dividedBy(BigDecimal::of($second), $scale ?? $this->scale, RoundingMode::DOWN) ; } - /** - * {@inheritdoc} - */ - public function mul($first, $second, ?int $scale = null): string + public function mul(float|int|string $first, float|int|string $second, ?int $scale = null): string { return (string) BigDecimal::of($first) ->multipliedBy(BigDecimal::of($second)) @@ -60,10 +48,7 @@ public function mul($first, $second, ?int $scale = null): string ; } - /** - * {@inheritdoc} - */ - public function pow($first, $second, ?int $scale = null): string + public function pow(float|int|string $first, float|int|string $second, ?int $scale = null): string { return (string) BigDecimal::of($first) ->power((int) $second) @@ -71,64 +56,43 @@ public function pow($first, $second, ?int $scale = null): string ; } - /** - * {@inheritdoc} - */ - public function powTen($number): string + public function powTen(float|int|string $number): string { return $this->pow(10, $number); } - /** - * {@inheritdoc} - */ - public function ceil($number): string + public function ceil(float|int|string $number): string { return (string) BigDecimal::of($number) ->dividedBy(BigDecimal::one(), 0, RoundingMode::CEILING) ; } - /** - * {@inheritdoc} - */ - public function floor($number): string + public function floor(float|int|string $number): string { return (string) BigDecimal::of($number) ->dividedBy(BigDecimal::one(), 0, RoundingMode::FLOOR) ; } - /** - * {@inheritdoc} - */ - public function round($number, int $precision = 0): string + public function round(float|int|string $number, int $precision = 0): string { return (string) BigDecimal::of($number) ->dividedBy(BigDecimal::one(), $precision, RoundingMode::HALF_UP) ; } - /** - * {@inheritdoc} - */ - public function abs($number): string + public function abs(float|int|string $number): string { return (string) BigDecimal::of($number)->abs(); } - /** - * {@inheritdoc} - */ - public function negative($number): string + public function negative(float|int|string $number): string { return (string) BigDecimal::of($number)->negated(); } - /** - * {@inheritdoc} - */ - public function compare($first, $second): int + public function compare(float|int|string $first, float|int|string $second): int { return BigDecimal::of($first)->compareTo(BigDecimal::of($second)); } diff --git a/src/Internal/Service/MathServiceInterface.php b/src/Internal/Service/MathServiceInterface.php index 41e84e27b..cbb4dd26d 100644 --- a/src/Internal/Service/MathServiceInterface.php +++ b/src/Internal/Service/MathServiceInterface.php @@ -6,69 +6,27 @@ interface MathServiceInterface { - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function add($first, $second, ?int $scale = null): string; + public function add(float|int|string $first, float|int|string $second, ?int $scale = null): string; - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function sub($first, $second, ?int $scale = null): string; + public function sub(float|int|string $first, float|int|string $second, ?int $scale = null): string; - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function div($first, $second, ?int $scale = null): string; + public function div(float|int|string $first, float|int|string $second, ?int $scale = null): string; - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function mul($first, $second, ?int $scale = null): string; + public function mul(float|int|string $first, float|int|string $second, ?int $scale = null): string; - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function pow($first, $second, ?int $scale = null): string; + public function pow(float|int|string $first, float|int|string $second, ?int $scale = null): string; - /** - * @param float|int|string $number - */ - public function powTen($number): string; + public function powTen(float|int|string $number): string; - /** - * @param float|int|string $number - */ - public function round($number, int $precision = 0): string; + public function round(float|int|string $number, int $precision = 0): string; - /** - * @param float|int|string $number - */ - public function floor($number): string; + public function floor(float|int|string $number): string; - /** - * @param float|int|string $number - */ - public function ceil($number): string; + public function ceil(float|int|string $number): string; - /** - * @param float|int|string $number - */ - public function abs($number): string; + public function abs(float|int|string $number): string; - /** - * @param float|int|string $number - */ - public function negative($number): string; + public function negative(float|int|string $number): string; - /** - * @param float|int|string $first - * @param float|int|string $second - */ - public function compare($first, $second): int; + public function compare(float|int|string $first, float|int|string $second): int; } diff --git a/src/Internal/Service/UuidFactoryService.php b/src/Internal/Service/UuidFactoryService.php index 965fcd28c..a48e50b78 100644 --- a/src/Internal/Service/UuidFactoryService.php +++ b/src/Internal/Service/UuidFactoryService.php @@ -19,4 +19,9 @@ public function uuid4(): string ->toString() ; } + + public function cast(string $uuid): string + { + return $uuid; + } } diff --git a/src/Internal/Service/UuidFactoryServiceInterface.php b/src/Internal/Service/UuidFactoryServiceInterface.php index bdfbbf8d4..3f58b1664 100644 --- a/src/Internal/Service/UuidFactoryServiceInterface.php +++ b/src/Internal/Service/UuidFactoryServiceInterface.php @@ -7,4 +7,6 @@ interface UuidFactoryServiceInterface { public function uuid4(): string; + + public function cast(string $uuid): string; } diff --git a/src/Models/Transaction.php b/src/Models/Transaction.php index 7726eaba8..66d208857 100644 --- a/src/Models/Transaction.php +++ b/src/Models/Transaction.php @@ -59,7 +59,7 @@ class Transaction extends Model public function getTable(): string { - if (!$this->table) { + if ((string) $this->table === '') { $this->table = config('wallet.transaction.table', 'transactions'); } diff --git a/src/Models/Transfer.php b/src/Models/Transfer.php index fc9304a28..3729ad2aa 100644 --- a/src/Models/Transfer.php +++ b/src/Models/Transfer.php @@ -60,7 +60,7 @@ class Transfer extends Model public function getTable(): string { - if (!$this->table) { + if ((string) $this->table === '') { $this->table = config('wallet.transfer.table', 'transfers'); } diff --git a/src/Models/Wallet.php b/src/Models/Wallet.php index 7f8938b48..8b80dfe3a 100644 --- a/src/Models/Wallet.php +++ b/src/Models/Wallet.php @@ -79,7 +79,7 @@ class Wallet extends Model implements Customer, WalletFloat, Confirmable, Exchan public function getTable(): string { - if (!$this->table) { + if ((string) $this->table === '') { $this->table = config('wallet.wallet.table', 'wallets'); } diff --git a/src/Objects/Cart.php b/src/Objects/Cart.php index d2154dae1..0ee4e2978 100644 --- a/src/Objects/Cart.php +++ b/src/Objects/Cart.php @@ -128,7 +128,7 @@ public function getBasketDto(): BasketDtoInterface $this->getUniqueItems() ); - if (count($items) === 0) { + if ($items === []) { throw new CartEmptyException('Cart is empty', ExceptionInterface::CART_EMPTY); } diff --git a/src/Services/AtmService.php b/src/Services/AtmService.php index d3c0de68a..8e257070b 100644 --- a/src/Services/AtmService.php +++ b/src/Services/AtmService.php @@ -41,7 +41,7 @@ public function makeTransactions(array $objects): array $items = $this->transactionRepository->findBy($query); } - assert(count($items) > 0); + assert($items !== []); $results = []; foreach ($items as $item) { @@ -67,7 +67,7 @@ public function makeTransfers(array $objects): array $items = $this->transferRepository->findBy($query); } - assert(count($items) > 0); + assert($items !== []); $results = []; foreach ($items as $item) { diff --git a/src/Services/PrepareService.php b/src/Services/PrepareService.php index acd886905..75008e67a 100644 --- a/src/Services/PrepareService.php +++ b/src/Services/PrepareService.php @@ -34,7 +34,7 @@ public function __construct( */ public function deposit( Wallet $wallet, - string $amount, + float|int|string $amount, ?array $meta, bool $confirmed = true ): TransactionDtoInterface { @@ -56,7 +56,7 @@ public function deposit( */ public function withdraw( Wallet $wallet, - string $amount, + float|int|string $amount, ?array $meta, bool $confirmed = true ): TransactionDtoInterface { @@ -74,15 +74,13 @@ public function withdraw( } /** - * @param float|int|string $amount - * * @throws AmountInvalid */ public function transferLazy( Wallet $from, Wallet $to, string $status, - $amount, + float|int|string $amount, ExtraDtoInterface|array|null $meta = null ): TransferLazyDtoInterface { $discount = $this->personalDiscountService->getDiscount($from, $to); diff --git a/src/Services/PrepareServiceInterface.php b/src/Services/PrepareServiceInterface.php index 498c76187..6b954c68d 100644 --- a/src/Services/PrepareServiceInterface.php +++ b/src/Services/PrepareServiceInterface.php @@ -17,7 +17,7 @@ interface PrepareServiceInterface */ public function deposit( Wallet $wallet, - string $amount, + float|int|string $amount, ?array $meta, bool $confirmed = true ): TransactionDtoInterface; @@ -27,21 +27,19 @@ public function deposit( */ public function withdraw( Wallet $wallet, - string $amount, + float|int|string $amount, ?array $meta, bool $confirmed = true ): TransactionDtoInterface; /** - * @param float|int|string $amount - * * @throws AmountInvalid */ public function transferLazy( Wallet $from, Wallet $to, string $status, - $amount, + float|int|string $amount, ExtraDtoInterface|array|null $meta = null ): TransferLazyDtoInterface; } diff --git a/src/Services/TransferService.php b/src/Services/TransferService.php index e24655a06..b0587d528 100644 --- a/src/Services/TransferService.php +++ b/src/Services/TransferService.php @@ -32,7 +32,7 @@ public function __construct( */ public function updateStatusByIds(string $status, array $ids): bool { - return count($ids) !== 0 && count($ids) === $this->transferRepository->updateStatusByIds($status, $ids); + return $ids !== [] && count($ids) === $this->transferRepository->updateStatusByIds($status, $ids); } /** diff --git a/src/Traits/CartPay.php b/src/Traits/CartPay.php index 806e73782..425711a2e 100644 --- a/src/Traits/CartPay.php +++ b/src/Traits/CartPay.php @@ -128,7 +128,7 @@ public function payCart(CartInterface $cart, bool $force = false): array ); } - if ($force === false) { + if (!$force) { app(ConsistencyServiceInterface::class)->checkTransfer($transfers); } @@ -201,7 +201,7 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts ++$index; } - if ($force === false) { + if (!$force) { app(ConsistencyServiceInterface::class)->checkTransfer($objects); } diff --git a/src/Traits/HasGift.php b/src/Traits/HasGift.php index acb010916..8dfcacc8d 100644 --- a/src/Traits/HasGift.php +++ b/src/Traits/HasGift.php @@ -63,7 +63,7 @@ public function gift(Wallet $to, ProductInterface $product, bool $force = false) $amount = $mathService->sub($product->getAmountProduct($this), $discount); $fee = app(TaxServiceInterface::class)->getFee($product, $amount); - if ($force === false) { + if (!$force) { app(ConsistencyServiceInterface::class)->checkPotential($this, $mathService->add($amount, $fee)); } diff --git a/tests/Infra/PackageModels/TransactionMoney.php b/tests/Infra/PackageModels/TransactionMoney.php index b8197f795..9e25f573d 100644 --- a/tests/Infra/PackageModels/TransactionMoney.php +++ b/tests/Infra/PackageModels/TransactionMoney.php @@ -17,7 +17,7 @@ class TransactionMoney extends \Bavix\Wallet\Models\Transaction public function getCurrencyAttribute(): Money { - if (!$this->currency) { + if ($this->currency === null) { $this->currency = \money($this->amount, $this->meta['currency'] ?? 'USD'); } diff --git a/tests/Units/Domain/CartTest.php b/tests/Units/Domain/CartTest.php index 3647b8979..8b3d1d652 100644 --- a/tests/Units/Domain/CartTest.php +++ b/tests/Units/Domain/CartTest.php @@ -165,7 +165,8 @@ public function testCartQuantity(): void $cart = app(Cart::class); $amount = 0; $price = 0; - for ($i = 0; $i < count($products) - 1; ++$i) { + $productsCount = count($products); + for ($i = 0; $i < $productsCount - 1; ++$i) { $rnd = random_int(1, 5); $cart = $cart->withItem($products[$i], $rnd); $price += $products[$i]->getAmountProduct($buyer) * $rnd; @@ -199,7 +200,8 @@ public function testModelNotFoundException(): void $cart = app(Cart::class); $total = 0; - for ($i = 0; $i < count($products) - 1; ++$i) { + $productsCount = count($products); + for ($i = 0; $i < $productsCount - 1; ++$i) { $rnd = random_int(1, 5); $cart = $cart->withItem($products[$i], $rnd); $buyer->deposit($products[$i]->getAmountProduct($buyer) * $rnd); diff --git a/tests/Units/Domain/MultiWalletTest.php b/tests/Units/Domain/MultiWalletTest.php index 7c2299b05..6c9c32f46 100644 --- a/tests/Units/Domain/MultiWalletTest.php +++ b/tests/Units/Domain/MultiWalletTest.php @@ -23,7 +23,6 @@ use Bavix\Wallet\Test\Infra\Models\UserMulti; use Bavix\Wallet\Test\Infra\PackageModels\Wallet; use Bavix\Wallet\Test\Infra\TestCase; -use function compact; use Illuminate\Database\QueryException; use function range; use Throwable; @@ -447,7 +446,9 @@ public function testGetWalletOptimize(): void $user = UserMultiFactory::new()->create(); $names = range('a', 'z'); foreach ($names as $name) { - $user->createWallet(compact('name')); + $user->createWallet([ + 'name' => $name, + ]); } $user->load('wallets'); // optimize From 9f278d1a90b1eb628dd3fbc61d7a6657a2380c75 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 20:04:17 +0300 Subject: [PATCH 21/61] phpdoc --- src/Interfaces/Customer.php | 1 + src/Internal/Repository/WalletRepository.php | 1 - src/Traits/CartPay.php | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Interfaces/Customer.php b/src/Interfaces/Customer.php index 06171fb25..13afff121 100644 --- a/src/Interfaces/Customer.php +++ b/src/Interfaces/Customer.php @@ -198,6 +198,7 @@ public function forceRefundGiftCart(CartInterface $cart): bool; * Checks acquired product your wallet. * * @deprecated The method is slow and will be removed in the future + * @see PurchaseServiceInterface */ public function paid(ProductInterface $product, bool $gifts = false): ?Transfer; } diff --git a/src/Internal/Repository/WalletRepository.php b/src/Internal/Repository/WalletRepository.php index 28076de36..336a042dd 100644 --- a/src/Internal/Repository/WalletRepository.php +++ b/src/Internal/Repository/WalletRepository.php @@ -6,7 +6,6 @@ use Bavix\Wallet\Internal\Exceptions\ExceptionInterface; use Bavix\Wallet\Internal\Exceptions\ModelNotFoundException; -use Bavix\Wallet\Internal\Service\UuidFactoryService; use Bavix\Wallet\Internal\Service\UuidFactoryServiceInterface; use Bavix\Wallet\Models\Wallet; use Illuminate\Database\Eloquent\ModelNotFoundException as EloquentModelNotFoundException; diff --git a/src/Traits/CartPay.php b/src/Traits/CartPay.php index 425711a2e..2b1c1f226 100644 --- a/src/Traits/CartPay.php +++ b/src/Traits/CartPay.php @@ -269,6 +269,7 @@ public function forceRefundGiftCart(CartInterface $cart): bool * Checks acquired product your wallet. * * @deprecated The method is slow and will be removed in the future + * @see PurchaseServiceInterface */ public function paid(ProductInterface $product, bool $gifts = false): ?Transfer { From bc085c5c6f3d834133b51ec28ab8dc25ca591839 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 20:12:36 +0300 Subject: [PATCH 22/61] rector --- src/Services/AssistantService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/AssistantService.php b/src/Services/AssistantService.php index 5494c6f3f..655a7450a 100644 --- a/src/Services/AssistantService.php +++ b/src/Services/AssistantService.php @@ -58,7 +58,7 @@ public function getMeta(CartInterface $cart, ProductInterface $product): ?array return array_merge($metaCart, $metaProduct); } - if (count($metaCart) > 0) { + if ($metaCart !== []) { return $metaCart; } From 1b9389012dc3c254c02f82a6830b84fb9aa6f4ad Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 20:56:58 +0300 Subject: [PATCH 23/61] fix .phpstorm.meta.php --- .phpstorm.meta.php | 87 +--------------------------------------------- 1 file changed, 1 insertion(+), 86 deletions(-) diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index 649569c78..4890e9f4a 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -1,92 +1,7 @@ AvailabilityDtoAssemblerInterface::class, - TransactionDtoAssemblerInterface::class => TransactionDtoAssemblerInterface::class, - TransferDtoAssemblerInterface::class => TransferDtoAssemblerInterface::class, - TransferLazyDtoAssemblerInterface::class => TransferLazyDtoAssemblerInterface::class, - // internal.query in assembler - TransactionQueryAssemblerInterface::class => TransactionQueryAssemblerInterface::class, - TransferQueryAssemblerInterface::class => TransferQueryAssemblerInterface::class, - - // internal.repositories - TransactionRepositoryInterface::class => TransactionRepositoryInterface::class, - TransferRepositoryInterface::class => TransferRepositoryInterface::class, - - // internal.service - DatabaseServiceInterface::class => DatabaseServiceInterface::class, - JsonServiceInterface::class => JsonServiceInterface::class, - LockServiceInterface::class => LockServiceInterface::class, - MathServiceInterface::class => MathServiceInterface::class, - StorageServiceInterface::class => StorageServiceInterface::class, - TranslatorServiceInterface::class => TranslatorServiceInterface::class, - UuidFactoryServiceInterface::class => UuidFactoryServiceInterface::class, - - // internal.transform - TransactionDtoTransformerInterface::class => TransactionDtoTransformerInterface::class, - TransferDtoTransformerInterface::class => TransferDtoTransformerInterface::class, - - // legacy.models - Wallet::class => Wallet::class, - Transfer::class => Transfer::class, - Transaction::class => Transaction::class, - - // legacy.objects - Cart::class => Cart::class, - - // services - AssistantServiceInterface::class => AssistantServiceInterface::class, - AtmServiceInterface::class => AtmServiceInterface::class, - AtomicServiceInterface::class => AtomicServiceInterface::class, - BasketServiceInterface::class => BasketServiceInterface::class, - BookkeeperServiceInterface::class => BookkeeperServiceInterface::class, - CastServiceInterface::class => CastServiceInterface::class, - ConsistencyServiceInterface::class => ConsistencyServiceInterface::class, - DiscountServiceInterface::class => DiscountServiceInterface::class, - ExchangeServiceInterface::class => ExchangeServiceInterface::class, - PrepareServiceInterface::class => PrepareServiceInterface::class, - PurchaseServiceInterface::class => PurchaseServiceInterface::class, - TaxServiceInterface::class => TaxServiceInterface::class, + '' => '@', ])); - } From 08122fdbfb8edf73643cedc86ae57fabd0a8529b Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Thu, 21 Apr 2022 21:16:02 +0300 Subject: [PATCH 24/61] gtag --- docs/dist/bundle.js | 2 +- docs/src/gtag.js | 36 ++++++++++++++++++++++++++++++++++++ docs/src/index.js | 3 ++- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 docs/src/gtag.js diff --git a/docs/dist/bundle.js b/docs/dist/bundle.js index d812fc5d8..267140860 100644 --- a/docs/dist/bundle.js +++ b/docs/dist/bundle.js @@ -1,2 +1,2 @@ /*! For license information please see bundle.js.LICENSE.txt */ -(()=>{var e={669:(e,n,t)=>{e.exports=t(609)},448:(e,n,t)=>{"use strict";var r=t(867),i=t(26),o=t(372),a=t(327),u=t(97),c=t(109),f=t(985),s=t(61);e.exports=function(e){return new Promise((function(n,t){var l=e.data,d=e.headers,p=e.responseType;r.isFormData(l)&&delete d["Content-Type"];var h=new XMLHttpRequest;if(e.auth){var g=e.auth.username||"",m=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";d.Authorization="Basic "+btoa(g+":"+m)}var _=u(e.baseURL,e.url);function b(){if(h){var r="getAllResponseHeaders"in h?c(h.getAllResponseHeaders()):null,o={data:p&&"text"!==p&&"json"!==p?h.response:h.responseText,status:h.status,statusText:h.statusText,headers:r,config:e,request:h};i(n,t,o),h=null}}if(h.open(e.method.toUpperCase(),a(_,e.params,e.paramsSerializer),!0),h.timeout=e.timeout,"onloadend"in h?h.onloadend=b:h.onreadystatechange=function(){h&&4===h.readyState&&(0!==h.status||h.responseURL&&0===h.responseURL.indexOf("file:"))&&setTimeout(b)},h.onabort=function(){h&&(t(s("Request aborted",e,"ECONNABORTED",h)),h=null)},h.onerror=function(){t(s("Network Error",e,null,h)),h=null},h.ontimeout=function(){var n="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(n=e.timeoutErrorMessage),t(s(n,e,e.transitional&&e.transitional.clarifyTimeoutError?"ETIMEDOUT":"ECONNABORTED",h)),h=null},r.isStandardBrowserEnv()){var v=(e.withCredentials||f(_))&&e.xsrfCookieName?o.read(e.xsrfCookieName):void 0;v&&(d[e.xsrfHeaderName]=v)}"setRequestHeader"in h&&r.forEach(d,(function(e,n){void 0===l&&"content-type"===n.toLowerCase()?delete d[n]:h.setRequestHeader(n,e)})),r.isUndefined(e.withCredentials)||(h.withCredentials=!!e.withCredentials),p&&"json"!==p&&(h.responseType=e.responseType),"function"==typeof e.onDownloadProgress&&h.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&h.upload&&h.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then((function(e){h&&(h.abort(),t(e),h=null)})),l||(l=null),h.send(l)}))}},609:(e,n,t)=>{"use strict";var r=t(867),i=t(849),o=t(321),a=t(185);function u(e){var n=new o(e),t=i(o.prototype.request,n);return r.extend(t,o.prototype,n),r.extend(t,n),t}var c=u(t(655));c.Axios=o,c.create=function(e){return u(a(c.defaults,e))},c.Cancel=t(263),c.CancelToken=t(972),c.isCancel=t(502),c.all=function(e){return Promise.all(e)},c.spread=t(713),c.isAxiosError=t(268),e.exports=c,e.exports.default=c},263:e=>{"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},972:(e,n,t)=>{"use strict";var r=t(263);function i(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var n;this.promise=new Promise((function(e){n=e}));var t=this;e((function(e){t.reason||(t.reason=new r(e),n(t.reason))}))}i.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},i.source=function(){var e;return{token:new i((function(n){e=n})),cancel:e}},e.exports=i},502:e=>{"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},321:(e,n,t)=>{"use strict";var r=t(867),i=t(327),o=t(782),a=t(572),u=t(185),c=t(875),f=c.validators;function s(e){this.defaults=e,this.interceptors={request:new o,response:new o}}s.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{}).url=arguments[0]:e=e||{},(e=u(this.defaults,e)).method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var n=e.transitional;void 0!==n&&c.assertOptions(n,{silentJSONParsing:f.transitional(f.boolean,"1.0.0"),forcedJSONParsing:f.transitional(f.boolean,"1.0.0"),clarifyTimeoutError:f.transitional(f.boolean,"1.0.0")},!1);var t=[],r=!0;this.interceptors.request.forEach((function(n){"function"==typeof n.runWhen&&!1===n.runWhen(e)||(r=r&&n.synchronous,t.unshift(n.fulfilled,n.rejected))}));var i,o=[];if(this.interceptors.response.forEach((function(e){o.push(e.fulfilled,e.rejected)})),!r){var s=[a,void 0];for(Array.prototype.unshift.apply(s,t),s=s.concat(o),i=Promise.resolve(e);s.length;)i=i.then(s.shift(),s.shift());return i}for(var l=e;t.length;){var d=t.shift(),p=t.shift();try{l=d(l)}catch(e){p(e);break}}try{i=a(l)}catch(e){return Promise.reject(e)}for(;o.length;)i=i.then(o.shift(),o.shift());return i},s.prototype.getUri=function(e){return e=u(this.defaults,e),i(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},r.forEach(["delete","get","head","options"],(function(e){s.prototype[e]=function(n,t){return this.request(u(t||{},{method:e,url:n,data:(t||{}).data}))}})),r.forEach(["post","put","patch"],(function(e){s.prototype[e]=function(n,t,r){return this.request(u(r||{},{method:e,url:n,data:t}))}})),e.exports=s},782:(e,n,t)=>{"use strict";var r=t(867);function i(){this.handlers=[]}i.prototype.use=function(e,n,t){return this.handlers.push({fulfilled:e,rejected:n,synchronous:!!t&&t.synchronous,runWhen:t?t.runWhen:null}),this.handlers.length-1},i.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},i.prototype.forEach=function(e){r.forEach(this.handlers,(function(n){null!==n&&e(n)}))},e.exports=i},97:(e,n,t)=>{"use strict";var r=t(793),i=t(303);e.exports=function(e,n){return e&&!r(n)?i(e,n):n}},61:(e,n,t)=>{"use strict";var r=t(481);e.exports=function(e,n,t,i,o){var a=new Error(e);return r(a,n,t,i,o)}},572:(e,n,t)=>{"use strict";var r=t(867),i=t(527),o=t(502),a=t(655);function u(e){e.cancelToken&&e.cancelToken.throwIfRequested()}e.exports=function(e){return u(e),e.headers=e.headers||{},e.data=i.call(e,e.data,e.headers,e.transformRequest),e.headers=r.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),r.forEach(["delete","get","head","post","put","patch","common"],(function(n){delete e.headers[n]})),(e.adapter||a.adapter)(e).then((function(n){return u(e),n.data=i.call(e,n.data,n.headers,e.transformResponse),n}),(function(n){return o(n)||(u(e),n&&n.response&&(n.response.data=i.call(e,n.response.data,n.response.headers,e.transformResponse))),Promise.reject(n)}))}},481:e=>{"use strict";e.exports=function(e,n,t,r,i){return e.config=n,t&&(e.code=t),e.request=r,e.response=i,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},185:(e,n,t)=>{"use strict";var r=t(867);e.exports=function(e,n){n=n||{};var t={},i=["url","method","data"],o=["headers","auth","proxy","params"],a=["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","timeoutMessage","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","decompress","maxContentLength","maxBodyLength","maxRedirects","transport","httpAgent","httpsAgent","cancelToken","socketPath","responseEncoding"],u=["validateStatus"];function c(e,n){return r.isPlainObject(e)&&r.isPlainObject(n)?r.merge(e,n):r.isPlainObject(n)?r.merge({},n):r.isArray(n)?n.slice():n}function f(i){r.isUndefined(n[i])?r.isUndefined(e[i])||(t[i]=c(void 0,e[i])):t[i]=c(e[i],n[i])}r.forEach(i,(function(e){r.isUndefined(n[e])||(t[e]=c(void 0,n[e]))})),r.forEach(o,f),r.forEach(a,(function(i){r.isUndefined(n[i])?r.isUndefined(e[i])||(t[i]=c(void 0,e[i])):t[i]=c(void 0,n[i])})),r.forEach(u,(function(r){r in n?t[r]=c(e[r],n[r]):r in e&&(t[r]=c(void 0,e[r]))}));var s=i.concat(o).concat(a).concat(u),l=Object.keys(e).concat(Object.keys(n)).filter((function(e){return-1===s.indexOf(e)}));return r.forEach(l,f),t}},26:(e,n,t)=>{"use strict";var r=t(61);e.exports=function(e,n,t){var i=t.config.validateStatus;t.status&&i&&!i(t.status)?n(r("Request failed with status code "+t.status,t.config,null,t.request,t)):e(t)}},527:(e,n,t)=>{"use strict";var r=t(867),i=t(655);e.exports=function(e,n,t){var o=this||i;return r.forEach(t,(function(t){e=t.call(o,e,n)})),e}},655:(e,n,t)=>{"use strict";var r=t(867),i=t(16),o=t(481),a={"Content-Type":"application/x-www-form-urlencoded"};function u(e,n){!r.isUndefined(e)&&r.isUndefined(e["Content-Type"])&&(e["Content-Type"]=n)}var c,f={transitional:{silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},adapter:(("undefined"!=typeof XMLHttpRequest||"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process))&&(c=t(448)),c),transformRequest:[function(e,n){return i(n,"Accept"),i(n,"Content-Type"),r.isFormData(e)||r.isArrayBuffer(e)||r.isBuffer(e)||r.isStream(e)||r.isFile(e)||r.isBlob(e)?e:r.isArrayBufferView(e)?e.buffer:r.isURLSearchParams(e)?(u(n,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):r.isObject(e)||n&&"application/json"===n["Content-Type"]?(u(n,"application/json"),function(e,n,t){if(r.isString(e))try{return(0,JSON.parse)(e),r.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(0,JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var n=this.transitional,t=n&&n.silentJSONParsing,i=n&&n.forcedJSONParsing,a=!t&&"json"===this.responseType;if(a||i&&r.isString(e)&&e.length)try{return JSON.parse(e)}catch(e){if(a){if("SyntaxError"===e.name)throw o(e,this,"E_JSON_PARSE");throw e}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){f.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){f.headers[e]=r.merge(a)})),e.exports=f},849:e=>{"use strict";e.exports=function(e,n){return function(){for(var t=new Array(arguments.length),r=0;r{"use strict";var r=t(867);function i(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,n,t){if(!n)return e;var o;if(t)o=t(n);else if(r.isURLSearchParams(n))o=n.toString();else{var a=[];r.forEach(n,(function(e,n){null!=e&&(r.isArray(e)?n+="[]":e=[e],r.forEach(e,(function(e){r.isDate(e)?e=e.toISOString():r.isObject(e)&&(e=JSON.stringify(e)),a.push(i(n)+"="+i(e))})))})),o=a.join("&")}if(o){var u=e.indexOf("#");-1!==u&&(e=e.slice(0,u)),e+=(-1===e.indexOf("?")?"?":"&")+o}return e}},303:e=>{"use strict";e.exports=function(e,n){return n?e.replace(/\/+$/,"")+"/"+n.replace(/^\/+/,""):e}},372:(e,n,t)=>{"use strict";var r=t(867);e.exports=r.isStandardBrowserEnv()?{write:function(e,n,t,i,o,a){var u=[];u.push(e+"="+encodeURIComponent(n)),r.isNumber(t)&&u.push("expires="+new Date(t).toGMTString()),r.isString(i)&&u.push("path="+i),r.isString(o)&&u.push("domain="+o),!0===a&&u.push("secure"),document.cookie=u.join("; ")},read:function(e){var n=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return n?decodeURIComponent(n[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},793:e=>{"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},268:e=>{"use strict";e.exports=function(e){return"object"==typeof e&&!0===e.isAxiosError}},985:(e,n,t)=>{"use strict";var r=t(867);e.exports=r.isStandardBrowserEnv()?function(){var e,n=/(msie|trident)/i.test(navigator.userAgent),t=document.createElement("a");function i(e){var r=e;return n&&(t.setAttribute("href",r),r=t.href),t.setAttribute("href",r),{href:t.href,protocol:t.protocol?t.protocol.replace(/:$/,""):"",host:t.host,search:t.search?t.search.replace(/^\?/,""):"",hash:t.hash?t.hash.replace(/^#/,""):"",hostname:t.hostname,port:t.port,pathname:"/"===t.pathname.charAt(0)?t.pathname:"/"+t.pathname}}return e=i(window.location.href),function(n){var t=r.isString(n)?i(n):n;return t.protocol===e.protocol&&t.host===e.host}}():function(){return!0}},16:(e,n,t)=>{"use strict";var r=t(867);e.exports=function(e,n){r.forEach(e,(function(t,r){r!==n&&r.toUpperCase()===n.toUpperCase()&&(e[n]=t,delete e[r])}))}},109:(e,n,t)=>{"use strict";var r=t(867),i=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var n,t,o,a={};return e?(r.forEach(e.split("\n"),(function(e){if(o=e.indexOf(":"),n=r.trim(e.substr(0,o)).toLowerCase(),t=r.trim(e.substr(o+1)),n){if(a[n]&&i.indexOf(n)>=0)return;a[n]="set-cookie"===n?(a[n]?a[n]:[]).concat([t]):a[n]?a[n]+", "+t:t}})),a):a}},713:e=>{"use strict";e.exports=function(e){return function(n){return e.apply(null,n)}}},875:(e,n,t)=>{"use strict";var r=t(593),i={};["object","boolean","number","function","string","symbol"].forEach((function(e,n){i[e]=function(t){return typeof t===e||"a"+(n<1?"n ":" ")+e}}));var o={},a=r.version.split(".");function u(e,n){for(var t=n?n.split("."):a,r=e.split("."),i=0;i<3;i++){if(t[i]>r[i])return!0;if(t[i]0;){var o=r[i],a=n[o];if(a){var u=e[o],c=void 0===u||a(u,o,e);if(!0!==c)throw new TypeError("option "+o+" must be "+c)}else if(!0!==t)throw Error("Unknown option "+o)}},validators:i}},867:(e,n,t)=>{"use strict";var r=t(849),i=Object.prototype.toString;function o(e){return"[object Array]"===i.call(e)}function a(e){return void 0===e}function u(e){return null!==e&&"object"==typeof e}function c(e){if("[object Object]"!==i.call(e))return!1;var n=Object.getPrototypeOf(e);return null===n||n===Object.prototype}function f(e){return"[object Function]"===i.call(e)}function s(e,n){if(null!=e)if("object"!=typeof e&&(e=[e]),o(e))for(var t=0,r=e.length;t{!function(){function e(e){var n=Object.create(null);return function(t){var r=o(t)?t:JSON.stringify(t);return n[r]||(n[r]=e(t))}}var n=e((function(e){return e.replace(/([A-Z])/g,(function(e){return"-"+e.toLowerCase()}))})),r=Object.prototype.hasOwnProperty,i=Object.assign||function(e){for(var n=arguments,t=1;t0&&n[1].toLowerCase()!==location.protocol||"string"==typeof n[2]&&n[2].length>0&&n[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"),"")!==location.host}var f=document.body.clientWidth<=600,s=window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),l={};function d(e,n){if(void 0===n&&(n=!1),"string"==typeof e){if(void 0!==window.Vue)return m(e);e=n?m(e):l[e]||(l[e]=m(e))}return e}var p=document,h=p.body,g=p.head;function m(e,n){return n?e.querySelector(n):p.querySelector(e)}function _(e,n){return[].slice.call(n?e.querySelectorAll(n):p.querySelectorAll(e))}function b(e,n){return e=p.createElement(e),n&&(e.innerHTML=n),e}function v(e,n){return e.appendChild(n)}function y(e,n){return e.insertBefore(n,e.children[0])}function w(e,n,t){u(n)?window.addEventListener(e,n):e.addEventListener(n,t)}function k(e,n,t){u(n)?window.removeEventListener(e,n):e.removeEventListener(n,t)}function x(e,n,t){e&&e.classList[t?n:"toggle"](t||n)}function S(e,n){void 0===n&&(n=document);var t=n.readyState;if("complete"===t||"interactive"===t)return setTimeout(e,0);n.addEventListener("DOMContentLoaded",e)}var A=Object.freeze({__proto__:null,getNode:d,$:p,body:h,head:g,find:m,findAll:_,create:b,appendTo:v,before:y,on:w,off:k,toggleClass:x,style:function(e){v(g,b("style",e))},documentReady:S}),E=decodeURIComponent,T=encodeURIComponent;function O(e){var n={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("=");n[t[0]]=t[1]&&E(t[1])})),n):n}function R(e,n){void 0===n&&(n=[]);var t=[];for(var r in e)n.indexOf(r)>-1||t.push(e[r]?(T(r)+"="+T(e[r])).toLowerCase():T(r));return t.length?"?"+t.join("&"):""}var z=e((function(e){return/(:|(\/{2}))/g.test(e)})),j=e((function(e){return e.split(/[?#]/)[0]})),C=e((function(e){if(/\/$/g.test(e))return e;var n=e.match(/(\S*\/)[^/]+$/);return n?n[1]:""})),L=e((function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")})),N=e((function(e){for(var n=e.replace(/^\//,"").split("/"),t=[],r=0,i=n.length;r=0?n:0)+"#"+e)}q.prototype.getBasePath=function(){return this.config.basePath},q.prototype.getFile=function(e,n){void 0===e&&(e=this.getCurrentPath());var t=this.config,r=this.getBasePath(),i="string"==typeof t.ext?t.ext:".md";return e=function(e,n){return new RegExp("\\.("+n.replace(/^\./,"")+"|html)$","g").test(e)?e:/\/$/g.test(e)?e+"README"+n:""+e+n}(e=t.alias?M(e,t.alias):e,i),e=e==="/README"+i&&t.homepage||e,e=z(e)?e:I(r,e),n&&(e=e.replace(new RegExp("^"+r),"")),e},q.prototype.onchange=function(e){void 0===e&&(e=a),e()},q.prototype.getCurrentPath=function(){},q.prototype.normalize=function(){},q.prototype.parse=function(){},q.prototype.toURL=function(e,n,t){var r=t&&"#"===e[0],o=this.parse(D(e));if(o.query=i({},o.query,n),e=(e=o.path+R(o.query)).replace(/\.md(\?)|\.md$/,"$1"),r){var a=t.indexOf("?");e=(a>0?t.substring(0,a):t)+e}if(this.config.relativePath&&0!==e.indexOf("/")){var u=t.substring(0,t.lastIndexOf("/")+1);return L(N(u+e))}return L("/"+e)};var B=function(e){function n(n){e.call(this,n),this.mode="hash"}return e&&(n.__proto__=e),n.prototype=Object.create(e&&e.prototype),n.prototype.constructor=n,n.prototype.getBasePath=function(){var e=window.location.pathname||"",n=this.config.basePath,t=P(e,".html")?e+"#/"+n:e+"/"+n;return/^(\/|https?:)/g.test(n)?n:L(t)},n.prototype.getCurrentPath=function(){var e=location.href,n=e.indexOf("#");return-1===n?"":e.slice(n+1)},n.prototype.onchange=function(e){void 0===e&&(e=a);var n=!1;w("click",(function(e){var t="A"===e.target.tagName?e.target:e.target.parentNode;t&&"A"===t.tagName&&!/_blank/.test(t.target)&&(n=!0)})),w("hashchange",(function(t){var r=n?"navigate":"history";n=!1,e({event:t,source:r})}))},n.prototype.normalize=function(){var e=this.getCurrentPath();if("/"===(e=D(e)).charAt(0))return U(e);U("/"+e)},n.prototype.parse=function(e){void 0===e&&(e=location.href);var n="",t=e.indexOf("#");t>=0&&(e=e.slice(t+1));var r=e.indexOf("?");return r>=0&&(n=e.slice(r+1),e=e.slice(0,r)),{path:e,file:this.getFile(e,!0),query:O(n)}},n.prototype.toURL=function(n,t,r){return"#"+e.prototype.toURL.call(this,n,t,r)},n}(q),H=function(e){function n(n){e.call(this,n),this.mode="history"}return e&&(n.__proto__=e),n.prototype=Object.create(e&&e.prototype),n.prototype.constructor=n,n.prototype.getCurrentPath=function(){var e=this.getBasePath(),n=window.location.pathname;return e&&0===n.indexOf(e)&&(n=n.slice(e.length)),(n||"/")+window.location.search+window.location.hash},n.prototype.onchange=function(e){var n=this;void 0===e&&(e=a),w("click",(function(t){var r="A"===t.target.tagName?t.target:t.target.parentNode;if(r&&"A"===r.tagName&&!/_blank/.test(r.target)){t.preventDefault();var i=r.href;-1!==n.config.crossOriginLinks.indexOf(i)?window.open(i,"_self"):window.history.pushState({key:i},"",i),e({event:t,source:"navigate"})}})),w("popstate",(function(n){e({event:n,source:"history"})}))},n.prototype.parse=function(e){void 0===e&&(e=location.href);var n="",t=e.indexOf("?");t>=0&&(n=e.slice(t+1),e=e.slice(0,t));var r=I(location.origin),i=e.indexOf(r);return i>-1&&(e=e.slice(i+r.length)),{path:e,file:this.getFile(e),query:O(n)}},n}(q),W={},G=/([^{]*?)\w(?=\})/g,Z={YYYY:"getFullYear",YY:"getYear",MM:function(e){return e.getMonth()+1},DD:"getDate",HH:"getHours",mm:"getMinutes",ss:"getSeconds",fff:"getMilliseconds"},V=Object.hasOwnProperty,Y=Object.setPrototypeOf,X=Object.isFrozen,J=Object.getPrototypeOf,K=Object.getOwnPropertyDescriptor,Q=Object.freeze,ee=Object.seal,ne=Object.create,te="undefined"!=typeof Reflect&&Reflect,re=te.apply,ie=te.construct;re||(re=function(e,n,t){return e.apply(n,t)}),Q||(Q=function(e){return e}),ee||(ee=function(e){return e}),ie||(ie=function(e,n){return new(Function.prototype.bind.apply(e,[null].concat(function(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n1?r-1:0),o=1;o/gm),Le=ee(/^data-[\-\w.\u00B7-\uFFFF]/),Ne=ee(/^aria-[\-\w]+$/),$e=ee(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Ie=ee(/^(?:\w+script|data):/i),De=ee(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Pe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function Fe(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n0&&void 0!==arguments[0]?arguments[0]:Ue(),t=function(n){return e(n)};if(t.version="2.3.1",t.removed=[],!n||!n.document||9!==n.document.nodeType)return t.isSupported=!1,t;var r=n.document,i=n.document,o=n.DocumentFragment,a=n.HTMLTemplateElement,u=n.Node,c=n.Element,f=n.NodeFilter,s=n.NamedNodeMap,l=void 0===s?n.NamedNodeMap||n.MozNamedAttrMap:s,d=n.Text,p=n.Comment,h=n.DOMParser,g=n.trustedTypes,m=c.prototype,_=ve(m,"cloneNode"),b=ve(m,"nextSibling"),v=ve(m,"childNodes"),y=ve(m,"parentNode");if("function"==typeof a){var w=i.createElement("template");w.content&&w.content.ownerDocument&&(i=w.content.ownerDocument)}var k=Be(g,r),x=k&&te?k.createHTML(""):"",S=i,A=S.implementation,E=S.createNodeIterator,T=S.createDocumentFragment,O=S.getElementsByTagName,R=r.importNode,z={};try{z=be(i).documentMode?i.documentMode:{}}catch(e){}var j={};t.isSupported="function"==typeof y&&A&&void 0!==A.createHTMLDocument&&9!==z;var C=je,L=Ce,N=Le,$=Ne,I=Ie,D=De,P=$e,F=null,M=_e({},[].concat(Fe(ye),Fe(we),Fe(ke),Fe(Se),Fe(Ee))),q=null,U=_e({},[].concat(Fe(Te),Fe(Oe),Fe(Re),Fe(ze))),B=null,H=null,W=!0,G=!0,Z=!1,V=!1,Y=!1,X=!1,J=!1,K=!1,ee=!1,ne=!0,te=!1,re=!0,ie=!0,oe=!1,me={},Me=null,qe=_e({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),He=null,We=_e({},["audio","video","img","source","image","track"]),Ge=null,Ze=_e({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ve="http://www.w3.org/1998/Math/MathML",Ye="http://www.w3.org/2000/svg",Xe="http://www.w3.org/1999/xhtml",Je=Xe,Ke=!1,Qe=null,en=i.createElement("form"),nn=function(e){Qe&&Qe===e||(e&&"object"===(void 0===e?"undefined":Pe(e))||(e={}),e=be(e),F="ALLOWED_TAGS"in e?_e({},e.ALLOWED_TAGS):M,q="ALLOWED_ATTR"in e?_e({},e.ALLOWED_ATTR):U,Ge="ADD_URI_SAFE_ATTR"in e?_e(be(Ze),e.ADD_URI_SAFE_ATTR):Ze,He="ADD_DATA_URI_TAGS"in e?_e(be(We),e.ADD_DATA_URI_TAGS):We,Me="FORBID_CONTENTS"in e?_e({},e.FORBID_CONTENTS):qe,B="FORBID_TAGS"in e?_e({},e.FORBID_TAGS):{},H="FORBID_ATTR"in e?_e({},e.FORBID_ATTR):{},me="USE_PROFILES"in e&&e.USE_PROFILES,W=!1!==e.ALLOW_ARIA_ATTR,G=!1!==e.ALLOW_DATA_ATTR,Z=e.ALLOW_UNKNOWN_PROTOCOLS||!1,V=e.SAFE_FOR_TEMPLATES||!1,Y=e.WHOLE_DOCUMENT||!1,K=e.RETURN_DOM||!1,ee=e.RETURN_DOM_FRAGMENT||!1,ne=!1!==e.RETURN_DOM_IMPORT,te=e.RETURN_TRUSTED_TYPE||!1,J=e.FORCE_BODY||!1,re=!1!==e.SANITIZE_DOM,ie=!1!==e.KEEP_CONTENT,oe=e.IN_PLACE||!1,P=e.ALLOWED_URI_REGEXP||P,Je=e.NAMESPACE||Xe,V&&(G=!1),ee&&(K=!0),me&&(F=_e({},[].concat(Fe(Ee))),q=[],!0===me.html&&(_e(F,ye),_e(q,Te)),!0===me.svg&&(_e(F,we),_e(q,Oe),_e(q,ze)),!0===me.svgFilters&&(_e(F,ke),_e(q,Oe),_e(q,ze)),!0===me.mathMl&&(_e(F,Se),_e(q,Re),_e(q,ze))),e.ADD_TAGS&&(F===M&&(F=be(F)),_e(F,e.ADD_TAGS)),e.ADD_ATTR&&(q===U&&(q=be(q)),_e(q,e.ADD_ATTR)),e.ADD_URI_SAFE_ATTR&&_e(Ge,e.ADD_URI_SAFE_ATTR),e.FORBID_CONTENTS&&(Me===qe&&(Me=be(Me)),_e(Me,e.FORBID_CONTENTS)),ie&&(F["#text"]=!0),Y&&_e(F,["html","head","body"]),F.table&&(_e(F,["tbody"]),delete B.tbody),Q&&Q(e),Qe=e)},tn=_e({},["mi","mo","mn","ms","mtext"]),rn=_e({},["foreignobject","desc","title","annotation-xml"]),on=_e({},we);_e(on,ke),_e(on,xe);var an=_e({},Se);_e(an,Ae);var un=function(e){var n=y(e);n&&n.tagName||(n={namespaceURI:Xe,tagName:"template"});var t=fe(e.tagName),r=fe(n.tagName);if(e.namespaceURI===Ye)return n.namespaceURI===Xe?"svg"===t:n.namespaceURI===Ve?"svg"===t&&("annotation-xml"===r||tn[r]):Boolean(on[t]);if(e.namespaceURI===Ve)return n.namespaceURI===Xe?"math"===t:n.namespaceURI===Ye?"math"===t&&rn[r]:Boolean(an[t]);if(e.namespaceURI===Xe){if(n.namespaceURI===Ye&&!rn[r])return!1;if(n.namespaceURI===Ve&&!tn[r])return!1;var i=_e({},["title","style","font","a","script"]);return!an[t]&&(i[t]||!on[t])}return!1},cn=function(e){ce(t.removed,{element:e});try{e.parentNode.removeChild(e)}catch(n){try{e.outerHTML=x}catch(n){e.remove()}}},fn=function(e,n){try{ce(t.removed,{attribute:n.getAttributeNode(e),from:n})}catch(e){ce(t.removed,{attribute:null,from:n})}if(n.removeAttribute(e),"is"===e&&!q[e])if(K||ee)try{cn(n)}catch(e){}else try{n.setAttribute(e,"")}catch(e){}},sn=function(e){var n=void 0,t=void 0;if(J)e=""+e;else{var r=se(e,/^[\r\n\t ]+/);t=r&&r[0]}var o=k?k.createHTML(e):e;if(Je===Xe)try{n=(new h).parseFromString(o,"text/html")}catch(e){}if(!n||!n.documentElement){n=A.createDocument(Je,"template",null);try{n.documentElement.innerHTML=Ke?"":o}catch(e){}}var a=n.body||n.documentElement;return e&&t&&a.insertBefore(i.createTextNode(t),a.childNodes[0]||null),Je===Xe?O.call(n,Y?"html":"body")[0]:Y?n.documentElement:a},ln=function(e){return E.call(e.ownerDocument||e,e,f.SHOW_ELEMENT|f.SHOW_COMMENT|f.SHOW_TEXT,null,!1)},dn=function(e){return!(e instanceof d||e instanceof p||"string"==typeof e.nodeName&&"string"==typeof e.textContent&&"function"==typeof e.removeChild&&e.attributes instanceof l&&"function"==typeof e.removeAttribute&&"function"==typeof e.setAttribute&&"string"==typeof e.namespaceURI&&"function"==typeof e.insertBefore)},pn=function(e){return"object"===(void 0===u?"undefined":Pe(u))?e instanceof u:e&&"object"===(void 0===e?"undefined":Pe(e))&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},hn=function(e,n,r){j[e]&&ae(j[e],(function(e){e.call(t,n,r,Qe)}))},gn=function(e){var n=void 0;if(hn("beforeSanitizeElements",e,null),dn(e))return cn(e),!0;if(se(e.nodeName,/[\u0080-\uFFFF]/))return cn(e),!0;var r=fe(e.nodeName);if(hn("uponSanitizeElement",e,{tagName:r,allowedTags:F}),!pn(e.firstElementChild)&&(!pn(e.content)||!pn(e.content.firstElementChild))&&he(/<[/\w]/g,e.innerHTML)&&he(/<[/\w]/g,e.textContent))return cn(e),!0;if("select"===r&&he(/