providerForNewCheckout()) ->toBe(PaymentProvider::Payone); }); it('reads the active provider for new checkouts from the settings switch', function () { Setting::setContentBySlug(PaymentProviderManager::SETTING_SLUG, 'stripe', 'text'); expect(app(PaymentProviderManager::class)->providerForNewCheckout()) ->toBe(PaymentProvider::Stripe); }); it('falls back to payone for unknown switch values', function () { Setting::setContentBySlug(PaymentProviderManager::SETTING_SLUG, 'klarna', 'text'); expect(app(PaymentProviderManager::class)->providerForNewCheckout()) ->toBe(PaymentProvider::Payone); }); // --- Bestandsvorgänge: Anbieter aus der Spalte, schalterunabhängig --- it('backfills existing abos with payone as their provider', function () { $abo = makeMeAbo(); expect($abo->fresh()->payment_provider)->toBe('payone'); }); it('resolves the provider of an existing abo from its column even when the switch says stripe', function () { Setting::setContentBySlug(PaymentProviderManager::SETTING_SLUG, 'stripe', 'text'); $abo = makeMeAbo(); expect(app(PaymentProviderManager::class)->providerFor($abo->fresh())) ->toBe(PaymentProvider::Payone); }); it('resolves a stripe abo and a stripe shopping payment from their columns', function () { $abo = makeMeAbo(); $abo->update(['payment_provider' => 'stripe']); $payment = new ShoppingPayment(['payment_provider' => 'stripe']); $manager = app(PaymentProviderManager::class); expect($manager->providerFor($abo->fresh()))->toBe(PaymentProvider::Stripe) ->and($manager->providerFor($payment))->toBe(PaymentProvider::Stripe); }); // --- Gateway-Auflösung --- it('resolves the payone gateway adapter for the payone provider', function () { $gateway = app(PaymentProviderManager::class)->gateway(PaymentProvider::Payone); expect($gateway)->toBeInstanceOf(PayoneGateway::class) ->and($gateway)->toBeInstanceOf(PaymentGatewayInterface::class) ->and($gateway->provider())->toBe(PaymentProvider::Payone); }); it('rejects the stripe gateway until it is implemented', function () { app(PaymentProviderManager::class)->gateway(PaymentProvider::Stripe); })->throws(RuntimeException::class); // --- AboChargeResult-Mapping --- it('maps an approved payone result to a successful charge result', function () { $result = AboChargeResult::fromPayoneResult( PayonePaymentResult::fromResponse(['status' => 'APPROVED', 'txid' => 'tx-123']) ); expect($result->success)->toBeTrue() ->and($result->provider)->toBe(PaymentProvider::Payone) ->and($result->status)->toBe('APPROVED') ->and($result->transactionId)->toBe('tx-123') ->and($result->errorMessage)->toBeNull(); }); it('maps a declined payone result with its error messages', function () { $result = AboChargeResult::fromPayoneResult(PayonePaymentResult::fromResponse([ 'status' => 'ERROR', 'errormessage' => 'Card declined', 'customermessage' => 'Bitte andere Karte verwenden.', ])); expect($result->success)->toBeFalse() ->and($result->status)->toBe('ERROR') ->and($result->errorMessage)->toBe('Card declined') ->and($result->customerMessage)->toBe('Bitte andere Karte verwenden.'); }); // --- PayoneGateway delegiert 1:1 an den bestehenden Service --- it('delegates abo charges to the payone payment service', function () { $abo = new UserAbo; $order = new ShoppingOrder; $shoppingUser = new ShoppingUser; $service = Mockery::mock(PayonePaymentService::class); $service->shouldReceive('chargeAbo') ->once() ->with($abo, $order, $shoppingUser, 1999, 'EUR') ->andReturn(PayonePaymentResult::fromResponse(['status' => 'APPROVED', 'txid' => 'tx-9'])); $result = (new PayoneGateway($service))->chargeAbo($abo, $order, $shoppingUser, 1999, 'EUR'); expect($result->success)->toBeTrue() ->and($result->transactionId)->toBe('tx-9'); }); // --- Cron-Guard: kein Fremd-Provider durch den PAYONE-Pfad --- it('blocks abo charging in the cron for non-payone providers', function () { $abo = makeMeAbo(); $abo->update(['payment_provider' => 'stripe']); (new UserMakeOrder($abo->fresh()))->makePayment(); })->throws(RuntimeException::class, 'noch nicht implementiert');