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>
This commit is contained in:
parent
8288ea59ac
commit
ee04146217
14 changed files with 536 additions and 19 deletions
78
tests/Feature/AboUserRetryTest.php
Normal file
78
tests/Feature/AboUserRetryTest.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?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);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue