mivita/tests/Feature/AboUserRetryTest.php
Kevin ee04146217 Abo Einmalprodukte: Phase 4 - Ausfuehrung, Purge & User-Retry
- UserMakeOrder: bestaetigte Einmal-Artikel in den Yard, is_abo_addon
  auf ShoppingOrderItem; amount bleibt reiner Abo-Betrag (Reihenfolge)
- AboOneTimeService::purgeAfterExecution: loescht alle Einmal-Artikel
  und rechnet Comp-Produkte neu - nur im Erfolgszweig (Cron + Retry)
- User-Retry in Sales Center und Portal mit Berechtigungspruefung,
  gemeinsames Confirm-Modal; Admin-Retry unveraendert
- Tests: AboMakeOrderOneTimeTest, AboUserRetryTest; Plan-Doku Phase 4

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 15:32:27 +00:00

78 lines
2.5 KiB
PHP

<?php
use App\Http\Controllers\User\AboController;
use App\Models\UserAbo;
use App\Repositories\AboRepository;
use App\Services\AboRetryPaymentService;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Route;
use Symfony\Component\HttpKernel\Exception\HttpException;
use function Pest\Laravel\mock;
uses(Tests\TestCase::class, RefreshDatabase::class);
function makeRetryOwnerAbo(): array
{
$owner = User::forceCreate([
'email' => 'owner-'.uniqid('', true).'@example.com',
'password' => bcrypt('secret'),
'lang' => 'de',
]);
$abo = UserAbo::create([
'user_id' => $owner->id,
'member_id' => $owner->id,
'shopping_user_id' => 1,
'is_for' => 'me',
'email' => $owner->email,
'payone_userid' => 900300,
'clearingtype' => 'cc',
'active' => true,
'status' => 3,
'abo_interval' => 5,
'next_date' => now()->toDateString(),
]);
return ['owner' => $owner, 'abo' => $abo];
}
it('führt den User-Retry für den eigenen Abo aus und leitet zur Detailseite zurück', function () {
// Domain-Routen werden hostabhängig geladen; Stub für den Redirect der Methode.
Route::get('/user/abos/detail/{view}/{id}', fn () => '')->name('user_abos_detail');
app('router')->getRoutes()->refreshNameLookups();
$fixture = makeRetryOwnerAbo();
$this->actingAs($fixture['owner']);
mock(AboRetryPaymentService::class)
->shouldReceive('retry')
->once()
->andReturn(['success' => true, 'message' => 'OK']);
$controller = new AboController(app(AboRepository::class));
$response = $controller->retryPayment('me', $fixture['abo']->id, app(AboRetryPaymentService::class));
expect($response->getTargetUrl())->toContain('/user/abos/detail/me/'.$fixture['abo']->id);
expect(session('alert-success'))->toBe('OK');
});
it('verhindert den User-Retry für ein fremdes Abo (403)', function () {
$fixture = makeRetryOwnerAbo();
$stranger = User::forceCreate([
'email' => 'stranger-'.uniqid('', true).'@example.com',
'password' => bcrypt('secret'),
'lang' => 'de',
]);
$this->actingAs($stranger);
$service = mock(AboRetryPaymentService::class);
$service->shouldNotReceive('retry');
$controller = new AboController(app(AboRepository::class));
expect(fn () => $controller->retryPayment('me', $fixture['abo']->id, $service))
->toThrow(HttpException::class);
});