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
35 changes: 35 additions & 0 deletions app/Data/Billing/CreditPackDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace App\Data\Billing;

final readonly class CreditPackDto
{
public function __construct(
public string $key,
public string $label,
public int $credits,
public string $stripePriceId,
public string $description,
) {}

public static function fromConfig(string $key, array $config): self
{
$required = ['label', 'credits', 'stripe_price_id', 'description'];

foreach ($required as $field) {
if (! array_key_exists($field, $config)) {
throw new \InvalidArgumentException("Missing required credit pack config key: {$field}");
}
}

return new self(
key: $key,
label: $config['label'],
credits: $config['credits'],
stripePriceId: $config['stripe_price_id'],
description: $config['description'],
);
}
}
27 changes: 27 additions & 0 deletions tests/Unit/Billing/CreditPackDtoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

use App\Data\Billing\CreditPackDto;

it('creates credit pack dto from config array', function () {
$dto = CreditPackDto::fromConfig('small', [
'label' => '500 Credits',
'credits' => 500,
'stripe_price_id' => 'price_small',
'description' => 'Good for occasional conversions.',
]);

expect($dto->key)->toBe('small');
expect($dto->label)->toBe('500 Credits');
expect($dto->credits)->toBe(500);
expect($dto->stripePriceId)->toBe('price_small');
expect($dto->description)->toBe('Good for occasional conversions.');
});

it('throws on missing required config keys', function () {
CreditPackDto::fromConfig('small', [
'label' => '500 Credits',
'credits' => 500,
]);
})->throws(InvalidArgumentException::class);