+ + {{ __('Guthaben & Kontingent') }} + {{ __('Gutschriften ohne Zahlung — landen im Verlauf') }} + + + + + {{ __('Credit-Saldo') }} + + {{ number_format($creditBalance, 0, ',', '.') }} + + + + {{ __('Offene PM-Käufe/Gutschriften') }} + + {{ number_format($openPmPurchases, 0, ',', '.') }} + + + + {{ __('PM-Kontingent verbleibend') }} + + {{ $quotaRemaining === null ? __('Unbegrenzt') : number_format($quotaRemaining, 0, ',', '.') }} + + + + + + + {{ __('Credits gutschreiben') }} + + {{ __('Anzahl Credits') }} + + + + + {{ __('Grund (optional, erscheint im Ledger & Verlauf)') }} + + + + + {{ __('Credits gutschreiben') }} + + + + + {{ __('Freie Pressemitteilungen gutschreiben') }} + + {{ __('Anzahl PMs') }} + + + + + {{ __('Grund (optional, erscheint im Verlauf)') }} + + + + + {{ __('Freie PMs gutschreiben') }} + + + {{ __('Wird als bezahlter 0-€-Einzelkauf verbucht und beim Veröffentlichen regulär eingelöst.') }} + + + + +
{{ __('Rechnungsadresse') }} diff --git a/tests/Feature/Admin/AdminGrantTest.php b/tests/Feature/Admin/AdminGrantTest.php new file mode 100644 index 00000000..8388d1fd --- /dev/null +++ b/tests/Feature/Admin/AdminGrantTest.php @@ -0,0 +1,99 @@ +create(['name' => 'Admin Ada']); + $user = User::factory()->create(); + + app(AdminGrantService::class)->grantCredits($user, 500, $admin, 'Interne Nutzung'); + + expect(app(CreditWalletService::class)->balance($user))->toBe(500); + + $transaction = $user->creditWallet()->sole()->transactions()->sole(); + expect($transaction->type)->toBe(CreditTransactionType::Grant) + ->and($transaction->amount_credits)->toBe(500) + ->and($transaction->description)->toContain('Admin Ada') + ->and($transaction->description)->toContain('Interne Nutzung'); + + $event = ActivityEvent::query()->where('type', ActivityType::AdminGrant->value)->sole(); + expect($event->user_id)->toBe($user->id) + ->and($event->description)->toContain('500 Credits') + ->and($event->description)->toContain('ohne Zahlung') + ->and($event->meta['granted_by'])->toBe($admin->id); +}); + +test('an admin can grant free press releases that satisfy the booking gate', function () { + config(['billing.enforce_booking' => true]); + + $admin = User::factory()->create(); + $user = User::factory()->create(); + + expect($user->hasActiveBooking())->toBeFalse(); + + app(AdminGrantService::class)->grantFreePressReleases($user, 3, $admin, 'Eigene PMs'); + + $purchases = $user->singlePurchases()->get(); + expect($purchases)->toHaveCount(3) + ->and($purchases->first()->type)->toBe(SinglePurchaseType::SinglePm) + ->and($purchases->first()->status)->toBe(SinglePurchaseStatus::Paid) + ->and($purchases->first()->price_cents)->toBe(0) + ->and($purchases->first()->paid_at)->not->toBeNull(); + + $fresh = User::query()->find($user->id); + expect($fresh->hasActiveBooking())->toBeTrue() + ->and($fresh->openSinglePurchaseCount())->toBe(3) + ->and($fresh->pressReleaseQuotaRemaining())->toBe(3); + + $event = ActivityEvent::query()->where('type', ActivityType::AdminGrant->value)->sole(); + expect($event->description)->toContain('3 freie Pressemitteilung(en)') + ->and($event->meta['free_press_releases'])->toBe(3); +}); + +test('the user show page grants credits and free pms through the panel', function () { + /** @var TestCase $this */ + $this->seed(RolesAndPermissionsSeeder::class); + + $admin = User::factory()->create(['is_active' => true]); + $admin->assignRole('admin'); + $this->actingAs($admin); + + // Gutschrift auf das eigene Admin-Konto — der Live-Anwendungsfall. + LivewireVolt::test('admin.users.show', ['id' => $admin->id]) + ->set('grantCreditsAmount', 250) + ->set('grantCreditsNote', 'Eigenbedarf') + ->call('grantCredits') + ->assertHasNoErrors() + ->set('grantPmCount', 5) + ->call('grantFreePressReleases') + ->assertHasNoErrors(); + + expect(app(CreditWalletService::class)->balance($admin))->toBe(250) + ->and($admin->singlePurchases()->grantingSubmission()->count())->toBe(5); +}); + +test('the grant panel is not available without the users manage permission', function () { + /** @var TestCase $this */ + $this->seed(RolesAndPermissionsSeeder::class); + + $editor = User::factory()->create(['is_active' => true]); + $editor->assignRole('editor'); + $this->actingAs($editor); + + $this->get(route('admin.users.show', $editor->id))->assertForbidden(); +});