Skip to content

Commit 5c2fe25

Browse files
committed
Custom price with shopping cart
1 parent a78bfd4 commit 5c2fe25

File tree

6 files changed

+75
-43
lines changed

6 files changed

+75
-43
lines changed

src/Internal/Dto/ItemDto.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ final class ItemDto implements ItemDtoInterface
1111
{
1212
public function __construct(
1313
private ProductInterface $product,
14-
private int $quantity
14+
private int $quantity,
15+
private int|string|null $price,
1516
) {
1617
}
1718

@@ -23,6 +24,11 @@ public function items(): array
2324
return array_fill(0, $this->quantity, $this->product);
2425
}
2526

27+
public function getPrice(): int|string|null
28+
{
29+
return $this->price;
30+
}
31+
2632
public function product(): ProductInterface
2733
{
2834
return $this->product;

src/Internal/Dto/ItemDtoInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ public function items(): array;
1616

1717
public function count(): int;
1818

19+
public function getPrice(): int|string|null;
20+
1921
public function product(): ProductInterface;
2022
}

src/Objects/Cart.php

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,10 @@
2121
final class Cart implements Countable, CartInterface
2222
{
2323
/**
24-
* @var ProductInterface[]
24+
* @var array<string, ItemDtoInterface[]>
2525
*/
2626
private array $items = [];
2727

28-
/**
29-
* @var array<string, int>
30-
*/
31-
private array $quantity = [];
32-
3328
private array $meta = [];
3429

3530
public function __construct(
@@ -51,14 +46,16 @@ public function withMeta(array $meta): self
5146
return $self;
5247
}
5348

54-
public function withItem(ProductInterface $product, int $quantity = 1): self
49+
public function withItem(ProductInterface $product, int $quantity = 1, int|string|null $price = null): self
5550
{
5651
$self = clone $this;
5752

5853
$productId = $self->productId($product);
54+
if (!isset($self->items[$productId])) {
55+
$self->items[$productId] = [];
56+
}
5957

60-
$self->quantity[$productId] = $self->getQuantity($product) + $quantity;
61-
$self->items[$productId] = $product;
58+
$self->items[$productId][] = new ItemDto($product, $quantity, $price);
6259

6360
return $self;
6461
}
@@ -80,29 +77,28 @@ public function getItems(): array
8077
{
8178
$items = [];
8279
foreach ($this->items as $item) {
83-
$count = $this->getQuantity($item);
84-
for ($i = 0; $i < $count; ++$i) {
85-
$items[] = $item;
80+
foreach ($item as $datum) {
81+
$items[] = $datum->items();
8682
}
8783
}
8884

89-
return $items;
90-
}
91-
92-
/**
93-
* @return ProductInterface[]
94-
*/
95-
public function getUniqueItems(): array
96-
{
97-
return $this->items;
85+
return array_merge(...$items);
9886
}
9987

10088
public function getTotal(Customer $customer): string
10189
{
10290
$result = 0;
103-
foreach ($this->items as $item) {
104-
$price = $this->math->mul($this->getQuantity($item), $item->getAmountProduct($customer));
105-
$result = $this->math->add($result, $price);
91+
$prices = [];
92+
foreach ($this->items as $productId => $_items) {
93+
foreach ($_items as $item) {
94+
$product = $item->product();
95+
$prices[$productId] = $item->getPrice()
96+
?? $prices[$productId]
97+
?? $item->product()->getAmountProduct($customer);
98+
99+
$price = $this->math->mul($this->getQuantity($product), $prices[$productId]);
100+
$result = $this->math->add($result, $price);
101+
}
106102
}
107103

108104
return (string) $result;
@@ -115,24 +111,26 @@ public function count(): int
115111

116112
public function getQuantity(ProductInterface $product): int
117113
{
118-
return $this->quantity[$this->productId($product)] ?? 0;
114+
/** @var ItemDtoInterface[] $items */
115+
$quantity = 0;
116+
$items = $this->items[$this->productId($product)] ?? [];
117+
foreach ($items as $item) {
118+
$quantity += $item->count();
119+
}
120+
121+
return $quantity;
119122
}
120123

121124
/**
122125
* @throws CartEmptyException
123126
*/
124127
public function getBasketDto(): BasketDtoInterface
125128
{
126-
$items = array_map(
127-
fn (ProductInterface $product): ItemDtoInterface => new ItemDto($product, $this->getQuantity($product)),
128-
$this->getUniqueItems()
129-
);
130-
131-
if ($items === []) {
129+
if ($this->items === []) {
132130
throw new CartEmptyException('Cart is empty', ExceptionInterface::CART_EMPTY);
133131
}
134132

135-
return new BasketDto($items, $this->getMeta());
133+
return new BasketDto(array_merge(...array_values($this->items)), $this->getMeta());
136134
}
137135

138136
private function productId(ProductInterface $product): string

src/Traits/CartPay.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,17 @@ public function payCart(CartInterface $cart, bool $force = false): array
120120
$basketDto = $cart->getBasketDto();
121121
$prepareService = app(PrepareServiceInterface::class);
122122
$assistantService = app(AssistantServiceInterface::class);
123-
foreach ($cart->getBasketDto()->cursor() as $product) {
124-
$transfers[] = $prepareService->transferLazy(
125-
$this,
126-
$product,
127-
Transfer::STATUS_PAID,
128-
$product->getAmountProduct($this),
129-
$assistantService->getMeta($basketDto, $product)
130-
);
123+
foreach ($cart->getBasketDto()->items() as $item) {
124+
foreach ($item->items() as $_item) {
125+
$product = $item->product();
126+
$transfers[] = $prepareService->transferLazy(
127+
$this,
128+
$product,
129+
Transfer::STATUS_PAID,
130+
$item->getPrice() ?? $product->getAmountProduct($this),
131+
$assistantService->getMeta($basketDto, $product)
132+
);
133+
}
131134
}
132135

133136
if (!$force) {

tests/Units/Domain/BasketTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ final class BasketTest extends TestCase
1717
public function testCount(): void
1818
{
1919
$item = new Item();
20-
$productDto1 = new ItemDto($item, 24);
21-
$productDto2 = new ItemDto($item, 26);
20+
$productDto1 = new ItemDto($item, 24, null);
21+
$productDto2 = new ItemDto($item, 26, null);
2222
$basket = new BasketDto([$productDto1, $productDto2], []);
2323

2424
self::assertEmpty($basket->meta());

tests/Units/Domain/ProductTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Bavix\Wallet\Models\Transaction;
1111
use Bavix\Wallet\Models\Transfer;
1212
use Bavix\Wallet\Models\Wallet;
13+
use Bavix\Wallet\Objects\Cart;
1314
use Bavix\Wallet\Test\Infra\Factories\BuyerFactory;
1415
use Bavix\Wallet\Test\Infra\Factories\ItemFactory;
1516
use Bavix\Wallet\Test\Infra\Factories\ItemWalletFactory;
@@ -260,6 +261,28 @@ public function testPayFreeOutOfStock(): void
260261
$buyer->payFree($product);
261262
}
262263

264+
public function testPayCustomPrice(): void
265+
{
266+
/**
267+
* @var Buyer $buyer
268+
* @var Item $product
269+
*/
270+
$buyer = BuyerFactory::new()->create();
271+
$product = ItemFactory::new()->create([
272+
'quantity' => 1,
273+
'price' => 5_000,
274+
]);
275+
276+
$buyer->deposit(1_000);
277+
self::assertSame(1_000, $buyer->balanceInt);
278+
279+
$cart = app(Cart::class)
280+
->withItem($product, price: 1_000);
281+
282+
$transfers = $buyer->payCart($cart);
283+
self::assertCount(1, $transfers);
284+
}
285+
263286
/**
264287
* @see https://github.com/bavix/laravel-wallet/issues/237
265288
*

0 commit comments

Comments
 (0)