feat(currency): implement role-based access control, exports, and tests for currency management
- Menambahkan validasi Role-based Access Control (RBAC) untuk tindakan CRUD mata uang: 1. Validasi untuk `read`, `create`, `update`, dan `delete` pada CurrencyController. 2. Menambahkan metode `getUser()` untuk memperoleh user terautentikasi. 3. Menangani respon dengan HTTP status `403 Forbidden` jika tidak memiliki izin. - Memperbaiki rute dan logika `store` serta `update`: 1. Validasi terhadap atribut `code` disesuaikan dengan skenario update (menggunakan ID). 2. Menambahkan metode `authorize()` pada CurrencyRequest untuk memastikan izin aksi sesuai role (CRUD spesifik). - Perubahan pada view blade: 1. Menambahkan validasi izin sebelum rendering tombol `Tambah`, `Hapus`, `Export`, dan `Edit`. 2. Menambahkan logika dinamis untuk izin terkait. - Tambahan logika pada export ke Excel: 1. Validasi izin untuk `basic-data.export` sebelum mengunduh file. - Test Feature dengan PHPUnit: 1. Menambahkan test coverage untuk tindakan CRUD, validasi izin role, dan ekspor data. 2. Menggunakan database segar dengan RefreshDatabase. - Refactor penggunaan model Currency di `CurrencyExport` agar sesuai namespace setelah modifikasi. - Respon di `destroy` dan `deleteMultiple` dikembalikan dalam format JSON untuk standardisasi. - Memastikan test mencakup berbagai skenario: 1. User dengan izin vs tanpa izin. 2. Operasi data valid dan tidak valid. Penyesuaian ini meningkatkan keamanan dan manajemen peran pada modul Currency, serta memastikan pengujian yang mendalam terhadap semua fitur baru. Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Modules\Lpj\Models\Currency;
|
||||
use Modules\Basicdata\Models\Currency;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
|
||||
class CurrencyExport implements WithColumnFormatting, WithHeadings, FromCollection, withMapping
|
||||
|
||||
@@ -12,15 +12,35 @@
|
||||
|
||||
class CurrencyController extends Controller
|
||||
{
|
||||
public $user;
|
||||
/**
|
||||
* Get the authenticated user.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
protected function getUser()
|
||||
{
|
||||
return \Illuminate\Support\Facades\Auth::guard('web')->user();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.read')) {
|
||||
abort(403, 'Sorry! You are not allowed to view currencies.');
|
||||
}
|
||||
|
||||
return view('basicdata::currency.index');
|
||||
}
|
||||
|
||||
public function store(CurrencyRequest $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to create currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create currencies.');
|
||||
}
|
||||
|
||||
$validate = $request->validated();
|
||||
|
||||
if ($validate) {
|
||||
@@ -40,17 +60,35 @@
|
||||
|
||||
public function create()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to create currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create currencies.');
|
||||
}
|
||||
|
||||
return view('basicdata::currency.create');
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to update currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update currencies.');
|
||||
}
|
||||
|
||||
$currency = Currency::find($id);
|
||||
return view('basicdata::currency.create', compact('currency'));
|
||||
}
|
||||
|
||||
public function update(CurrencyRequest $request, $id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to update currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update currencies.');
|
||||
}
|
||||
|
||||
$validate = $request->validated();
|
||||
|
||||
if ($validate) {
|
||||
@@ -71,28 +109,42 @@
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to delete currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.delete')) {
|
||||
return response()->json(['success' => false, 'message' => 'Sorry! You are not allowed to delete currencies.'], 403);
|
||||
}
|
||||
|
||||
try {
|
||||
// Delete from database
|
||||
$currency = Currency::find($id);
|
||||
$currency->delete();
|
||||
|
||||
echo json_encode(['success' => true, 'message' => 'Currency deleted successfully']);
|
||||
return response()->json(['success' => true, 'message' => 'Currency deleted successfully']);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'message' => 'Failed to delete currency']);
|
||||
return response()->json(['success' => false, 'message' => 'Failed to delete currency']);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteMultiple(Request $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to delete currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.delete')) {
|
||||
return response()->json(['success' => false, 'message' => 'Sorry! You are not allowed to delete currencies.'], 403);
|
||||
}
|
||||
|
||||
$ids = $request->input('ids');
|
||||
Currency::whereIn('id', $ids)->delete();
|
||||
return response()->json(['message' => 'Currencies deleted successfully']);
|
||||
return response()->json(['success' => true, 'message' => 'Currencies deleted successfully']);
|
||||
}
|
||||
|
||||
public function dataForDatatables(Request $request)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('currency.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view users.');
|
||||
// Check if the authenticated user has the required permission to view currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.read')) {
|
||||
return response()->json(['success' => false, 'message' => 'Sorry! You are not allowed to view currencies.'], 403);
|
||||
}
|
||||
|
||||
// Retrieve data from the database
|
||||
@@ -153,6 +205,12 @@
|
||||
|
||||
public function export()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to export currencies
|
||||
$user = $this->getUser();
|
||||
if (is_null($user) || !$user->can('basic-data.export')) {
|
||||
abort(403, 'Sorry! You are not allowed to export currencies.');
|
||||
}
|
||||
|
||||
return Excel::download(new CurrencyExport, 'currency.xlsx');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
];
|
||||
|
||||
if ($this->method() == 'PUT') {
|
||||
$rules['code'] = 'required|string|max:3|unique:currencies,code,' . $this->id;
|
||||
$id = $this->id ? (int)$this->id : null;
|
||||
$rules['code'] = 'required|string|max:3|unique:currencies,code,' . $id;
|
||||
} else {
|
||||
$rules['code'] = 'required|string|max:3|unique:currencies,code';
|
||||
}
|
||||
@@ -37,6 +38,14 @@
|
||||
public function authorize()
|
||||
: bool
|
||||
{
|
||||
$user = auth()->guard('web')->user();
|
||||
|
||||
if ($this->method() == 'PUT') {
|
||||
return $user && $user->can('basic-data.update');
|
||||
} elseif ($this->method() == 'POST') {
|
||||
return $user && $user->can('basic-data.create');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,75 +6,83 @@
|
||||
|
||||
@section('content')
|
||||
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
|
||||
@if(isset($currency->id))
|
||||
<form action="{{ route('basicdata.currency.update', $currency->id) }}" method="POST">
|
||||
<form method="POST" action="{{ isset($currency->id) ? route('basicdata.currency.update', $currency->id) : route('basicdata.currency.store') }}">
|
||||
@csrf
|
||||
@if(isset($currency->id))
|
||||
<input type="hidden" name="id" value="{{ $currency->id }}">
|
||||
@method('PUT')
|
||||
@else
|
||||
<form method="POST" action="{{ route('basicdata.currency.store') }}">
|
||||
@endif
|
||||
@csrf
|
||||
<div class="card pb-2.5">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
{{ isset($currency->id) ? 'Edit' : 'Tambah' }} Currency
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('basicdata.currency.index') }}" class="btn btn-xs btn-info"><i class="ki-filled ki-exit-left"></i> Back</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body grid gap-5">
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Code
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('code') border-danger bg-danger-light @enderror" type="text" name="code" value="{{ $currency->code ?? '' }}">
|
||||
@error('code')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Name
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('name') border-danger bg-danger-light @enderror" type="text" name="name" value="{{ $currency->name ?? '' }}">
|
||||
@error('name')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Symbol
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('symbol') border-danger bg-danger-light @enderror" type="text" name="symbol" value="{{ $currency->symbol ?? '' }}">
|
||||
@error('symbol')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Decimal Places
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('decimal_places') border-danger bg-danger-light @enderror" type="number" min="0" max="3" name="decimal_places" value="{{ $currency->decimal_places ?? '' }}">
|
||||
@error('decimal_places')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="card pb-2.5">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
{{ isset($currency->id) ? 'Edit' : 'Tambah' }} Currency
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('basicdata.currency.index') }}" class="btn btn-xs btn-info"><i class="ki-filled ki-exit-left"></i> Back</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body grid gap-5">
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Code
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('code') border-danger bg-danger-light @enderror" type="text" name="code" value="{{ $currency->code ?? '' }}">
|
||||
@error('code')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Name
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('name') border-danger bg-danger-light @enderror" type="text" name="name" value="{{ $currency->name ?? '' }}">
|
||||
@error('name')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Symbol
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('symbol') border-danger bg-danger-light @enderror" type="text" name="symbol" value="{{ $currency->symbol ?? '' }}">
|
||||
@error('symbol')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Decimal Places
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('decimal_places') border-danger bg-danger-light @enderror" type="number" min="0" max="3" name="decimal_places" value="{{ $currency->decimal_places ?? '' }}">
|
||||
@error('decimal_places')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@if(isset($currency->id))
|
||||
@can('basic-data.update')
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
@endcan
|
||||
@else
|
||||
@can('basic-data.create')
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
@endcan
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -19,9 +19,15 @@
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<div class="h-[24px] border border-r-gray-200"></div>
|
||||
@can('basic-data.export')
|
||||
<a class="btn btn-sm btn-light" href="{{ route('basicdata.currency.export') }}"> Export to Excel </a>
|
||||
@endcan
|
||||
@can('basic-data.create')
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('basicdata.currency.create') }}"> Tambah Mata Uang </a>
|
||||
@endcan
|
||||
@can('basic-data.delete')
|
||||
<button class="btn btn-sm btn-danger hidden" id="deleteSelected" onclick="deleteSelectedRows()">Delete Selected</button>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,14 +184,22 @@
|
||||
actions: {
|
||||
title: 'Status',
|
||||
render: (item, data) => {
|
||||
return `<div class="flex flex-nowrap justify-center">
|
||||
<a class="btn btn-sm btn-icon btn-clear btn-info" href="basic-data/mata-uang/${data.id}/edit">
|
||||
let html = `<div class="flex flex-nowrap justify-center">`;
|
||||
|
||||
@can('basic-data.update')
|
||||
html += `<a class="btn btn-sm btn-icon btn-clear btn-info" href="basic-data/mata-uang/${data.id}/edit">
|
||||
<i class="ki-outline ki-notepad-edit"></i>
|
||||
</a>
|
||||
<a onclick="deleteData(${data.id})" class="delete btn btn-sm btn-icon btn-clear btn-danger">
|
||||
</a>`;
|
||||
@endcan
|
||||
|
||||
@can('basic-data.delete')
|
||||
html += `<a onclick="deleteData(${data.id})" class="delete btn btn-sm btn-icon btn-clear btn-danger">
|
||||
<i class="ki-outline ki-trash"></i>
|
||||
</a>
|
||||
</div>`;
|
||||
</a>`;
|
||||
@endcan
|
||||
|
||||
html += `</div>`;
|
||||
return html;
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -227,4 +241,3 @@
|
||||
window.dataTable = dataTable;
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
320
tests/Feature/CurrencyControllerTest.php
Normal file
320
tests/Feature/CurrencyControllerTest.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Basicdata\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Modules\Basicdata\Models\Currency;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
|
||||
class CurrencyControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $user;
|
||||
protected $adminRole;
|
||||
protected $currency;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create permission group first
|
||||
$permissionGroup = PermissionGroup::create([
|
||||
'name' => 'basic-data',
|
||||
'slug' => 'basic-data'
|
||||
]);
|
||||
|
||||
// Create permissions with permission_group_id
|
||||
Permission::create([
|
||||
'name' => 'basic-data.create',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'basic-data.read',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'basic-data.update',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'basic-data.delete',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'basic-data.export',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create admin role with all permissions
|
||||
$this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$this->adminRole->givePermissionTo(Permission::all());
|
||||
|
||||
// Create a user with admin role
|
||||
$this->user = User::factory()->create();
|
||||
$this->user->assignRole($this->adminRole);
|
||||
|
||||
// Create a currency for testing
|
||||
$this->currency = Currency::create([
|
||||
'code' => 'USD',
|
||||
'name' => 'US Dollar',
|
||||
'symbol' => '$',
|
||||
'decimal_places' => 2,
|
||||
'created_by' => null,
|
||||
'updated_by' => null,
|
||||
'deleted_by' => null,
|
||||
'authorized_by' => null
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_view_currencies_index()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('basicdata.currency.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_view_currencies_index()
|
||||
{
|
||||
// Create a role without permissions
|
||||
$role = Role::create(['name' => 'viewer', 'guard_name' => 'web']);
|
||||
|
||||
// Create a user with the viewer role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('basicdata.currency.index'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_create_currency()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('basicdata.currency.create'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_create_currency()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('basicdata.currency.create'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_store_currency()
|
||||
{
|
||||
$currencyData = [
|
||||
'code' => 'EUR',
|
||||
'name' => 'Euro',
|
||||
'symbol' => '€',
|
||||
'decimal_places' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->post(route('basicdata.currency.store'), $currencyData);
|
||||
|
||||
$response->assertRedirect(route('basicdata.currency.index'));
|
||||
|
||||
// Only check the fields we're explicitly setting
|
||||
$this->assertDatabaseHas('currencies', [
|
||||
'code' => 'EUR',
|
||||
'name' => 'Euro',
|
||||
'symbol' => '€',
|
||||
'decimal_places' => 2
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_store_currency()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$currencyData = [
|
||||
'code' => 'EUR',
|
||||
'name' => 'Euro',
|
||||
'symbol' => '€',
|
||||
'decimal_places' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post(route('basicdata.currency.store'), $currencyData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('currencies', [
|
||||
'code' => 'EUR',
|
||||
'name' => 'Euro'
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_edit_currency()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('basicdata.currency.edit', $this->currency->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_edit_currency()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('basicdata.currency.edit', $this->currency->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_update_currency()
|
||||
{
|
||||
$updatedData = [
|
||||
'id' => $this->currency->id, // Include the ID in the request
|
||||
'code' => 'GBP',
|
||||
'name' => 'British Pound',
|
||||
'symbol' => '£',
|
||||
'decimal_places' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->put(route('basicdata.currency.update', $this->currency->id), $updatedData);
|
||||
|
||||
$response->assertRedirect(route('basicdata.currency.index'));
|
||||
|
||||
// Only check the fields we're explicitly setting
|
||||
$this->assertDatabaseHas('currencies', [
|
||||
'id' => $this->currency->id,
|
||||
'code' => 'GBP',
|
||||
'name' => 'British Pound',
|
||||
'symbol' => '£',
|
||||
'decimal_places' => 2
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_update_currency()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$updatedData = [
|
||||
'id' => $this->currency->id, // Include the ID in the request
|
||||
'code' => 'GBP',
|
||||
'name' => 'British Pound',
|
||||
'symbol' => '£',
|
||||
'decimal_places' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->put(route('basicdata.currency.update', $this->currency->id), $updatedData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
|
||||
// Verify the currency wasn't updated - check that it still has the original values
|
||||
$this->assertDatabaseHas('currencies', [
|
||||
'id' => $this->currency->id,
|
||||
'code' => 'USD', // Original value
|
||||
'name' => 'US Dollar' // Original value
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_delete_currency()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->delete(route('basicdata.currency.destroy', $this->currency->id));
|
||||
|
||||
$response->assertJson(['success' => true]);
|
||||
$this->assertSoftDeleted($this->currency);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_delete_currency()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->delete(route('basicdata.currency.destroy', $this->currency->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseHas('currencies', ['id' => $this->currency->id, 'deleted_at' => null]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_export_currencies()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('basicdata.currency.export'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_export_currencies()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('basic-data.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('basicdata.currency.export'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user