geschenkgutscheine implementiert ("Paket verschenken"). Neuer Upload-Provider: Sparkbooth.

This commit is contained in:
Codex Agent
2025-12-07 16:54:58 +01:00
parent 3f3c0f1d35
commit 046e2fe3ec
50 changed files with 2422 additions and 130 deletions

View File

@@ -0,0 +1,62 @@
<?php
namespace Tests\Unit;
use App\Services\GiftVouchers\GiftVoucherCheckoutService;
use App\Services\Paddle\PaddleClient;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;
class GiftVoucherCheckoutServiceTest extends TestCase
{
use RefreshDatabase;
public function test_it_lists_tiers_with_checkout_flag(): void
{
config()->set('gift-vouchers.tiers', [
['key' => 'gift-a', 'label' => 'A', 'amount' => 10, 'currency' => 'EUR', 'paddle_price_id' => 'pri_a'],
['key' => 'gift-b', 'label' => 'B', 'amount' => 20, 'currency' => 'EUR', 'paddle_price_id' => null],
]);
$service = $this->app->make(GiftVoucherCheckoutService::class);
$tiers = $service->tiers();
$this->assertCount(2, $tiers);
$this->assertTrue($tiers[0]['can_checkout']);
$this->assertFalse($tiers[1]['can_checkout']);
}
public function test_it_creates_checkout_link_with_metadata(): void
{
config()->set('gift-vouchers.tiers', [
['key' => 'gift-a', 'label' => 'A', 'amount' => 10, 'currency' => 'EUR', 'paddle_price_id' => 'pri_a'],
]);
$client = Mockery::mock(PaddleClient::class);
$client->shouldReceive('post')
->once()
->with('/checkout/links', Mockery::on(function ($payload) {
return $payload['items'][0]['price_id'] === 'pri_a'
&& $payload['customer_email'] === 'buyer@example.com'
&& $payload['metadata']['type'] === 'gift_voucher';
}))
->andReturn(['data' => ['url' => 'https://paddle.test/checkout/123', 'expires_at' => '2025-12-31T00:00:00Z', 'id' => 'chk_123']]);
$this->app->instance(PaddleClient::class, $client);
$service = $this->app->make(GiftVoucherCheckoutService::class);
$checkout = $service->create([
'tier_key' => 'gift-a',
'purchaser_email' => 'buyer@example.com',
'recipient_email' => 'friend@example.com',
'recipient_name' => 'Friend',
'message' => 'Hi',
]);
$this->assertSame('https://paddle.test/checkout/123', $checkout['checkout_url']);
$this->assertSame('chk_123', $checkout['id']);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Tests\Unit;
use App\Enums\CouponType;
use App\Jobs\SyncCouponToPaddle;
use App\Models\Coupon;
use App\Models\GiftVoucher;
use App\Models\Package;
use App\Services\GiftVouchers\GiftVoucherService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Bus;
use Tests\TestCase;
class GiftVoucherServiceTest extends TestCase
{
use RefreshDatabase;
public function test_it_issues_voucher_and_coupon_from_paddle_payload(): void
{
$package = Package::factory()->create([
'type' => 'endcustomer',
'paddle_price_id' => 'pri_pkg_001',
'price' => 59,
]);
$payload = [
'id' => 'txn_123',
'event_type' => 'transaction.completed',
'currency_code' => 'EUR',
'totals' => [
'grand_total' => [
'amount' => 5900,
],
],
'metadata' => [
'type' => 'gift_card',
'purchaser_email' => 'buyer@example.com',
'recipient_email' => 'friend@example.com',
'recipient_name' => 'Friend',
'message' => 'Happy Day',
],
'checkout_id' => 'chk_abc',
];
Bus::fake([SyncCouponToPaddle::class]);
$service = $this->app->make(GiftVoucherService::class);
$voucher = $service->issueFromPaddle($payload);
$this->assertInstanceOf(GiftVoucher::class, $voucher);
$this->assertSame(59.00, (float) $voucher->amount);
$this->assertNotNull($voucher->coupon);
$this->assertSame($voucher->code, $voucher->coupon->code);
$this->assertTrue($voucher->expires_at->greaterThan(now()->addYears(4)));
$this->assertTrue($voucher->coupon->packages()->whereKey($package->id)->exists());
Bus::assertDispatched(SyncCouponToPaddle::class);
}
public function test_redeeming_coupon_marks_voucher_redeemed(): void
{
$voucher = GiftVoucher::factory()->create([
'status' => GiftVoucher::STATUS_ISSUED,
'amount' => 29,
]);
$coupon = Coupon::factory()->create([
'code' => $voucher->code,
'type' => CouponType::FLAT,
'amount' => 29,
'currency' => 'EUR',
'paddle_discount_id' => null,
]);
$voucher->coupon()->associate($coupon)->save();
$service = $this->app->make(GiftVoucherService::class);
$service->markRedeemed($coupon, 'txn_999');
$this->assertSame(GiftVoucher::STATUS_REDEEMED, $voucher->refresh()->status);
$this->assertNotNull($voucher->redeemed_at);
}
}