Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Payment/Domain/Enum/ItemType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Paymentic\Sdk\Payment\Domain\Enum;

enum ItemType: string
{
case PRODUCT = 'PRODUCT';
case SHIPPING = 'SHIPPING';
case DISCOUNT = 'DISCOUNT';
case SURCHARGE = 'SURCHARGE';
case GIFT_CARD = 'GIFT_CARD';
}
13 changes: 13 additions & 0 deletions src/Payment/Domain/Enum/ProductType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Paymentic\Sdk\Payment\Domain\Enum;

enum ProductType: string
{
case PHYSICAL = 'PHYSICAL';
case DIGITAL = 'DIGITAL';
case SERVICE = 'SERVICE';
case VIRTUAL = 'VIRTUAL';
}
26 changes: 26 additions & 0 deletions src/Payment/Domain/ValueObject/CartItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Paymentic\Sdk\Payment\Domain\ValueObject;

use Paymentic\Sdk\Payment\Domain\Enum\ItemType;
use Paymentic\Sdk\Payment\Domain\Enum\ProductType;
use Paymentic\Sdk\Shared\Exception\InvalidValueException;

final readonly class CartItem
Expand All @@ -12,6 +14,14 @@ public function __construct(
public ?string $name = null,
public ?int $quantity = null,
public ?string $unitPrice = null,
public ?ItemType $type = null,
public ?ProductType $productType = null,
public ?string $sku = null,
public ?string $taxRate = null,
public ?string $taxAmount = null,
public ?string $url = null,
public ?string $imageUrl = null,
public ?string $totalAmount = null,
) {
if (null !== $quantity && $quantity <= 0) {
throw InvalidValueException::invalidQuantity($quantity);
Expand All @@ -20,6 +30,14 @@ public function __construct(
if (null !== $unitPrice && (! is_numeric($unitPrice) || (float) $unitPrice < 0)) {
throw InvalidValueException::invalidAmount($unitPrice);
}

if (null !== $taxAmount && (! is_numeric($taxAmount) || (float) $taxAmount < 0)) {
throw InvalidValueException::invalidAmount($taxAmount);
}

if (null !== $totalAmount && (! is_numeric($totalAmount) || (float) $totalAmount < 0)) {
throw InvalidValueException::invalidAmount($totalAmount);
}
}

/**
Expand All @@ -31,6 +49,14 @@ public function toArray(): array
'name' => $this->name,
'quantity' => $this->quantity,
'unitPrice' => $this->unitPrice,
'type' => $this->type?->value,
'productType' => $this->productType?->value,
'sku' => $this->sku,
'taxRate' => $this->taxRate,
'taxAmount' => $this->taxAmount,
'url' => $this->url,
'imageUrl' => $this->imageUrl,
'totalAmount' => $this->totalAmount,
], static fn ($value) => null !== $value);
}
}
116 changes: 116 additions & 0 deletions tests/Unit/Domain/ValueObject/CartItemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Paymentic\Tests\Unit\Domain\ValueObject;

use Paymentic\Sdk\Payment\Domain\Enum\ItemType;
use Paymentic\Sdk\Payment\Domain\Enum\ProductType;
use Paymentic\Sdk\Payment\Domain\ValueObject\CartItem;
use Paymentic\Sdk\Shared\Exception\InvalidValueException;
use PHPUnit\Framework\Attributes\Test;
Expand All @@ -18,11 +20,27 @@ public function createsWithAllFields(): void
name: 'Product Name',
quantity: 2,
unitPrice: '49.99',
type: ItemType::PRODUCT,
productType: ProductType::PHYSICAL,
sku: 'SKU-123',
taxRate: '23',
taxAmount: '11.50',
url: 'https://example.com/product',
imageUrl: 'https://example.com/image.jpg',
totalAmount: '99.98',
);

$this->assertSame('Product Name', $item->name);
$this->assertSame(2, $item->quantity);
$this->assertSame('49.99', $item->unitPrice);
$this->assertSame(ItemType::PRODUCT, $item->type);
$this->assertSame(ProductType::PHYSICAL, $item->productType);
$this->assertSame('SKU-123', $item->sku);
$this->assertSame('23', $item->taxRate);
$this->assertSame('11.50', $item->taxAmount);
$this->assertSame('https://example.com/product', $item->url);
$this->assertSame('https://example.com/image.jpg', $item->imageUrl);
$this->assertSame('99.98', $item->totalAmount);
}

#[Test]
Expand All @@ -33,6 +51,14 @@ public function createsWithNoFields(): void
$this->assertNull($item->name);
$this->assertNull($item->quantity);
$this->assertNull($item->unitPrice);
$this->assertNull($item->type);
$this->assertNull($item->productType);
$this->assertNull($item->sku);
$this->assertNull($item->taxRate);
$this->assertNull($item->taxAmount);
$this->assertNull($item->url);
$this->assertNull($item->imageUrl);
$this->assertNull($item->totalAmount);
}

#[Test]
Expand All @@ -42,6 +68,14 @@ public function convertsToArrayWithAllFields(): void
name: 'Test Product',
quantity: 3,
unitPrice: '19.99',
type: ItemType::SHIPPING,
productType: ProductType::DIGITAL,
sku: 'SKU-456',
taxRate: '8',
taxAmount: '1.60',
url: 'https://example.com/item',
imageUrl: 'https://example.com/item.png',
totalAmount: '21.59',
);

$array = $item->toArray();
Expand All @@ -50,6 +84,14 @@ public function convertsToArrayWithAllFields(): void
'name' => 'Test Product',
'quantity' => 3,
'unitPrice' => '19.99',
'type' => 'SHIPPING',
'productType' => 'DIGITAL',
'sku' => 'SKU-456',
'taxRate' => '8',
'taxAmount' => '1.60',
'url' => 'https://example.com/item',
'imageUrl' => 'https://example.com/item.png',
'totalAmount' => '21.59',
], $array);
}

Expand Down Expand Up @@ -116,4 +158,78 @@ public function acceptsValidUnitPrice(): void

$this->assertSame('0.00', $item->unitPrice);
}

#[Test]
public function throwsExceptionForInvalidTaxAmount(): void
{
$this->expectException(InvalidValueException::class);
$this->expectExceptionMessage('Amount must be a positive numeric string, got: "invalid"');

new CartItem(taxAmount: 'invalid');
}

#[Test]
public function throwsExceptionForNegativeTaxAmount(): void
{
$this->expectException(InvalidValueException::class);
$this->expectExceptionMessage('Amount must be a positive numeric string, got: "-5.00"');

new CartItem(taxAmount: '-5.00');
}

#[Test]
public function throwsExceptionForInvalidTotalAmount(): void
{
$this->expectException(InvalidValueException::class);
$this->expectExceptionMessage('Amount must be a positive numeric string, got: "abc"');

new CartItem(totalAmount: 'abc');
}

#[Test]
public function throwsExceptionForNegativeTotalAmount(): void
{
$this->expectException(InvalidValueException::class);
$this->expectExceptionMessage('Amount must be a positive numeric string, got: "-100.00"');

new CartItem(totalAmount: '-100.00');
}

#[Test]
public function acceptsAllItemTypes(): void
{
$types = [ItemType::PRODUCT, ItemType::SHIPPING, ItemType::DISCOUNT, ItemType::SURCHARGE, ItemType::GIFT_CARD];

foreach ($types as $type) {
$item = new CartItem(type: $type);
$this->assertSame($type, $item->type);
}
}

#[Test]
public function acceptsAllProductTypes(): void
{
$types = [ProductType::PHYSICAL, ProductType::DIGITAL, ProductType::SERVICE, ProductType::VIRTUAL];

foreach ($types as $type) {
$item = new CartItem(productType: $type);
$this->assertSame($type, $item->productType);
}
}

#[Test]
public function acceptsValidTaxAmount(): void
{
$item = new CartItem(taxAmount: '0.00');

$this->assertSame('0.00', $item->taxAmount);
}

#[Test]
public function acceptsValidTotalAmount(): void
{
$item = new CartItem(totalAmount: '150.50');

$this->assertSame('150.50', $item->totalAmount);
}
}