forked from admin/services_core
update api ticket type
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Audit;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Audit\AuditLogFilterRequest;
|
||||
use App\Http\Resources\Audit\AuditLogResource;
|
||||
use App\Services\Audit\AuditLogService;
|
||||
|
||||
class AuditLogController extends ApiController
|
||||
{
|
||||
protected $service;
|
||||
|
||||
public function __construct(AuditLogService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function index(AuditLogFilterRequest $request)
|
||||
{
|
||||
$data = $this->service->list(
|
||||
$request->validated()
|
||||
);
|
||||
|
||||
return $this->success(
|
||||
AuditLogResource::collection($data),
|
||||
'Data audit log berhasil diambil'
|
||||
);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$data = $this->service->detail($id);
|
||||
|
||||
return $this->success(
|
||||
new AuditLogResource($data),
|
||||
'Detail audit log berhasil diambil'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,21 +18,24 @@ class TicketTypeController extends ApiController
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$data = TicketType::latest()->paginate(
|
||||
$request->get('per_page', 10)
|
||||
$data = $this->service->list(
|
||||
$request->all()
|
||||
);
|
||||
|
||||
return $this->success($data);
|
||||
return $this->success(
|
||||
TicketTypeResource::collection($data),
|
||||
'Data Ticket Type berhasil diambil'
|
||||
);
|
||||
}
|
||||
|
||||
public function store(StoreTicketTypeRequest $request)
|
||||
{
|
||||
$type = $this->service->create(
|
||||
$data = $this->service->create(
|
||||
$request->validated()
|
||||
);
|
||||
|
||||
return $this->created(
|
||||
new TicketTypeResource($type),
|
||||
new TicketTypeResource($data),
|
||||
'Ticket Type berhasil dibuat'
|
||||
);
|
||||
}
|
||||
@@ -40,7 +43,8 @@ class TicketTypeController extends ApiController
|
||||
public function show(TicketType $ticket_type)
|
||||
{
|
||||
return $this->success(
|
||||
new TicketTypeResource($ticket_type)
|
||||
new TicketTypeResource($ticket_type),
|
||||
'Detail Ticket Type berhasil diambil'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,13 +52,13 @@ class TicketTypeController extends ApiController
|
||||
UpdateTicketTypeRequest $request,
|
||||
TicketType $ticket_type
|
||||
) {
|
||||
$type = $this->service->update(
|
||||
$data = $this->service->update(
|
||||
$ticket_type,
|
||||
$request->validated()
|
||||
);
|
||||
|
||||
return $this->updated(
|
||||
new TicketTypeResource($type),
|
||||
new TicketTypeResource($data),
|
||||
'Ticket Type berhasil diupdate'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Audit;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AuditLogFilterRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
|
||||
'module' => [
|
||||
'nullable',
|
||||
'string'
|
||||
],
|
||||
|
||||
'action' => [
|
||||
'nullable',
|
||||
'string'
|
||||
],
|
||||
|
||||
'user_id' => [
|
||||
'nullable',
|
||||
'integer'
|
||||
],
|
||||
|
||||
'tenant_id' => [
|
||||
'nullable',
|
||||
'integer'
|
||||
],
|
||||
|
||||
'per_page' => [
|
||||
'nullable',
|
||||
'integer',
|
||||
'min:1',
|
||||
'max:100'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,81 @@ class StoreTicketTypeRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'required|string|max:50|unique:ticket_types,code',
|
||||
'name' => 'required|string|max:100',
|
||||
'need_approval' => 'boolean',
|
||||
'sla_minutes' => 'nullable|integer'
|
||||
|
||||
'code' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:50',
|
||||
'unique:ticket_types,code'
|
||||
],
|
||||
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:100'
|
||||
],
|
||||
|
||||
'need_approval' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'sla_minutes' => [
|
||||
'nullable',
|
||||
'integer',
|
||||
'min:1'
|
||||
],
|
||||
|
||||
'require_photo' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'require_material' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'need_customer' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'need_incident_type' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
|
||||
'need_approval' => filter_var(
|
||||
$this->need_approval,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'require_photo' => filter_var(
|
||||
$this->require_photo,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'require_material' => filter_var(
|
||||
$this->require_material,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'need_customer' => filter_var(
|
||||
$this->need_customer,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'need_incident_type' => filter_var(
|
||||
$this->need_incident_type,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Requests\TicketType;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateTicketTypeRequest extends FormRequest
|
||||
{
|
||||
@@ -23,10 +24,82 @@ class UpdateTicketTypeRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'sometimes|string|max:50|unique:ticket_types,code,' . $this->route('ticket_type'),
|
||||
'name' => 'sometimes|string|max:100',
|
||||
'need_approval' => 'sometimes|boolean',
|
||||
'sla_minutes' => 'nullable|integer'
|
||||
|
||||
'code' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:50',
|
||||
Rule::unique('ticket_types', 'code')
|
||||
->ignore($this->ticket_type->id)
|
||||
],
|
||||
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:100'
|
||||
],
|
||||
|
||||
'need_approval' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'sla_minutes' => [
|
||||
'nullable',
|
||||
'integer',
|
||||
'min:1'
|
||||
],
|
||||
|
||||
'require_photo' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'require_material' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'need_customer' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
],
|
||||
|
||||
'need_incident_type' => [
|
||||
'nullable',
|
||||
'boolean'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
|
||||
'need_approval' => filter_var(
|
||||
$this->need_approval,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'require_photo' => filter_var(
|
||||
$this->require_photo,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'require_material' => filter_var(
|
||||
$this->require_material,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'need_customer' => filter_var(
|
||||
$this->need_customer,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
|
||||
'need_incident_type' => filter_var(
|
||||
$this->need_incident_type,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Audit;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class AuditLogResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
|
||||
'id' => $this->id,
|
||||
|
||||
'user_id' => $this->user_id,
|
||||
|
||||
'tenant_id' => $this->tenant_id,
|
||||
|
||||
'module' => $this->module,
|
||||
|
||||
'action' => $this->action,
|
||||
|
||||
'table_name' => $this->table_name,
|
||||
|
||||
'record_id' => $this->record_id,
|
||||
|
||||
'old_values' => $this->old_values,
|
||||
|
||||
'new_values' => $this->new_values,
|
||||
|
||||
'description' => $this->description,
|
||||
|
||||
'ip_address' => $this->ip_address,
|
||||
|
||||
'created_at' => $this->created_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,10 @@ class TicketTypeResource extends JsonResource
|
||||
'name' => $this->name,
|
||||
'need_approval' => $this->need_approval,
|
||||
'sla_minutes' => $this->sla_minutes,
|
||||
'require_photo' => $this->require_photo,
|
||||
'require_material' => $this->require_material,
|
||||
'need_customer' => $this->need_customer,
|
||||
'need_incident_type' => $this->need_incident_type,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AuditLog extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'tenant_id',
|
||||
'module',
|
||||
'action',
|
||||
'table_name',
|
||||
'record_id',
|
||||
'old_values',
|
||||
'new_values',
|
||||
'ip_address',
|
||||
'user_agent',
|
||||
'description'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'old_values' => 'array',
|
||||
'new_values' => 'array',
|
||||
'created_at' => 'datetime'
|
||||
];
|
||||
}
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Auditable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Ticket extends Model
|
||||
{
|
||||
use Auditable;
|
||||
|
||||
protected $fillable = [
|
||||
'ticket_no',
|
||||
'ticket_type_id',
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Auditable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class TicketIncidentType extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use Auditable;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Auditable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketType extends Model
|
||||
{
|
||||
use Auditable;
|
||||
|
||||
protected $table = 'ticket_types';
|
||||
|
||||
protected $fillable = [
|
||||
@@ -16,6 +19,7 @@ class TicketType extends Model
|
||||
'require_photo',
|
||||
'require_material',
|
||||
'need_customer',
|
||||
'need_incident_type'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -23,6 +27,7 @@ class TicketType extends Model
|
||||
'require_photo' => 'boolean',
|
||||
'require_material' => 'boolean',
|
||||
'need_customer' => 'boolean',
|
||||
'need_incident_type' => 'boolean'
|
||||
];
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
// use App\Traits\Auditable;
|
||||
|
||||
|
||||
class User extends Authenticatable
|
||||
@@ -14,6 +15,7 @@ class User extends Authenticatable
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
use HasApiTokens;
|
||||
// use Audittable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Audit;
|
||||
|
||||
use App\Models\AuditLog;
|
||||
|
||||
class AuditLogService
|
||||
{
|
||||
public function list(array $filters = [])
|
||||
{
|
||||
$query = AuditLog::query();
|
||||
|
||||
if (!empty($filters['module'])) {
|
||||
$query->where('module', $filters['module']);
|
||||
}
|
||||
|
||||
if (!empty($filters['action'])) {
|
||||
$query->where('action', $filters['action']);
|
||||
}
|
||||
|
||||
if (!empty($filters['user_id'])) {
|
||||
$query->where('user_id', $filters['user_id']);
|
||||
}
|
||||
|
||||
if (!empty($filters['tenant_id'])) {
|
||||
$query->where('tenant_id', $filters['tenant_id']);
|
||||
}
|
||||
|
||||
return $query
|
||||
->latest('id')
|
||||
->paginate(
|
||||
$filters['per_page'] ?? 20
|
||||
);
|
||||
}
|
||||
|
||||
public function detail($id)
|
||||
{
|
||||
return AuditLog::findOrFail($id);
|
||||
}
|
||||
|
||||
public static function log(
|
||||
string $module,
|
||||
string $action,
|
||||
?string $tableName = null,
|
||||
?int $recordId = null,
|
||||
?array $oldValues = null,
|
||||
?array $newValues = null,
|
||||
?string $description = null
|
||||
): void {
|
||||
|
||||
AuditLog::create([
|
||||
'user_id' => auth()->id(),
|
||||
'tenant_id' => request()->header('X-Tenant-Id'),
|
||||
|
||||
'module' => $module,
|
||||
'action' => $action,
|
||||
|
||||
'table_name' => $tableName,
|
||||
'record_id' => $recordId,
|
||||
|
||||
'old_values' => $oldValues,
|
||||
'new_values' => $newValues,
|
||||
|
||||
'ip_address' => request()->ip(),
|
||||
'user_agent' => request()->userAgent(),
|
||||
|
||||
'description' => $description,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,50 @@ use App\Models\TicketType;
|
||||
|
||||
class TicketTypeService
|
||||
{
|
||||
public function list(array $filters = [])
|
||||
{
|
||||
return TicketType::query()
|
||||
->when(
|
||||
!empty($filters['search']),
|
||||
fn($q) => $q->where(function ($x) use ($filters) {
|
||||
|
||||
$x->where(
|
||||
'code',
|
||||
'ILIKE',
|
||||
"%{$filters['search']}%"
|
||||
)
|
||||
->orWhere(
|
||||
'name',
|
||||
'ILIKE',
|
||||
"%{$filters['search']}%"
|
||||
);
|
||||
})
|
||||
)
|
||||
->latest('id')
|
||||
->paginate(
|
||||
$filters['per_page'] ?? 10
|
||||
);
|
||||
}
|
||||
|
||||
public function create(array $data): TicketType
|
||||
{
|
||||
return TicketType::create($data);
|
||||
}
|
||||
|
||||
public function update(TicketType $type, array $data): TicketType
|
||||
{
|
||||
$type->update($data);
|
||||
return $type->fresh();
|
||||
public function update(
|
||||
TicketType $ticketType,
|
||||
array $data
|
||||
): TicketType {
|
||||
|
||||
$ticketType->update($data);
|
||||
|
||||
return $ticketType->fresh();
|
||||
}
|
||||
|
||||
public function delete(TicketType $type): bool
|
||||
{
|
||||
return $type->delete();
|
||||
public function delete(
|
||||
TicketType $ticketType
|
||||
): bool {
|
||||
|
||||
return $ticketType->delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use App\Services\Audit\AuditLogService;
|
||||
|
||||
trait Auditable
|
||||
{
|
||||
protected static function bootAuditable()
|
||||
{
|
||||
static::created(function ($model) {
|
||||
|
||||
AuditLogService::log(
|
||||
module: strtolower(class_basename($model)),
|
||||
action: 'create',
|
||||
tableName: $model->getTable(),
|
||||
recordId: $model->id,
|
||||
newValues: $model->toArray()
|
||||
);
|
||||
});
|
||||
|
||||
static::updated(function ($model) {
|
||||
|
||||
AuditLogService::log(
|
||||
module: strtolower(class_basename($model)),
|
||||
action: 'update',
|
||||
tableName: $model->getTable(),
|
||||
recordId: $model->id,
|
||||
oldValues: $model->getOriginal(),
|
||||
newValues: $model->getAttributes()
|
||||
);
|
||||
});
|
||||
|
||||
static::deleted(function ($model) {
|
||||
|
||||
AuditLogService::log(
|
||||
module: strtolower(class_basename($model)),
|
||||
action: 'delete',
|
||||
tableName: $model->getTable(),
|
||||
recordId: $model->id,
|
||||
oldValues: $model->toArray()
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
if (!Schema::hasColumn('users', 'username')) {
|
||||
$table->string('username')->nullable()->unique()->after('name');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('users', 'status')) {
|
||||
$table->enum('status', [
|
||||
'active',
|
||||
'inactive',
|
||||
'suspended'
|
||||
])->default('active');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('users', 'last_login_at')) {
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
$table->dropColumn([
|
||||
'username',
|
||||
'status',
|
||||
'last_login_at'
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('tenants', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->string('tenant_code')->unique();
|
||||
|
||||
$table->string('tenant_name');
|
||||
|
||||
$table->string('phone')->nullable();
|
||||
|
||||
$table->string('email')->nullable();
|
||||
|
||||
$table->text('address')->nullable();
|
||||
|
||||
$table->enum('status', [
|
||||
'active',
|
||||
'inactive'
|
||||
])->default('active');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tenants');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_tenants', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('user_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreignId('tenant_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->boolean('is_default')
|
||||
->default(false);
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique([
|
||||
'user_id',
|
||||
'tenant_id'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_tenants');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('menu_lists', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('parent_id')
|
||||
->nullable()
|
||||
->constrained('menu_lists')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->string('name');
|
||||
|
||||
$table->string('slug')->unique();
|
||||
|
||||
$table->string('url')->nullable();
|
||||
|
||||
$table->string('icon')->nullable();
|
||||
|
||||
$table->string('component')->nullable();
|
||||
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->boolean('is_active')->default(true);
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('menu_lists');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('menu_groups', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->string('name')->unique();
|
||||
|
||||
$table->text('description')->nullable();
|
||||
|
||||
$table->boolean('is_active')->default(true);
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('menu_groups');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('menu_group_menus', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('menu_group_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreignId('menu_id')
|
||||
->constrained('menu_lists')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->boolean('can_view')->default(false);
|
||||
|
||||
$table->boolean('can_create')->default(false);
|
||||
|
||||
$table->boolean('can_update')->default(false);
|
||||
|
||||
$table->boolean('can_delete')->default(false);
|
||||
|
||||
$table->boolean('can_approve')->default(false);
|
||||
|
||||
$table->boolean('can_export')->default(false);
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique([
|
||||
'menu_group_id',
|
||||
'menu_id'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('menu_group_menus');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_menu_groups', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('user_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreignId('menu_group_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreignId('tenant_id')
|
||||
->nullable()
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique([
|
||||
'user_id',
|
||||
'menu_group_id',
|
||||
'tenant_id'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_menu_groups');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_profiles', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('user_id')
|
||||
->unique()
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->string('nik', 30)->nullable();
|
||||
|
||||
$table->string('phone', 30)->nullable();
|
||||
|
||||
$table->text('address')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('provinsi_id')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('kabupaten_id')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('kecamatan_id')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('desa_id')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_profiles');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('wilayah_provinsi', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->string('kode', 20)->unique();
|
||||
|
||||
$table->string('nama');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('wilayah_provinsi');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('wilayah_kabupaten', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('provinsi_id')
|
||||
->constrained('wilayah_provinsi')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->string('kode', 20)->unique();
|
||||
|
||||
$table->string('nama');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('wilayah_kabupaten');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('wilayah_kecamatan', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('kabupaten_id')
|
||||
->constrained('wilayah_kabupaten')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->string('kode', 20)->unique();
|
||||
|
||||
$table->string('nama');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('wilayah_kecamatan');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('wilayah_desa', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('kecamatan_id')
|
||||
->constrained('wilayah_kecamatan')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->string('kode', 20)->unique();
|
||||
|
||||
$table->string('nama');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('wilayah_desa');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('audit_logs', function (Blueprint $table) {
|
||||
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('user_id')
|
||||
->nullable()
|
||||
->constrained('users')
|
||||
->nullOnDelete();
|
||||
|
||||
$table->foreignId('tenant_id')
|
||||
->nullable()
|
||||
->constrained('tenants')
|
||||
->nullOnDelete();
|
||||
|
||||
$table->string('module', 100);
|
||||
|
||||
$table->string('action', 50);
|
||||
|
||||
$table->string('table_name', 100)
|
||||
->nullable();
|
||||
|
||||
$table->unsignedBigInteger('record_id')
|
||||
->nullable();
|
||||
|
||||
$table->json('old_values')
|
||||
->nullable();
|
||||
|
||||
$table->json('new_values')
|
||||
->nullable();
|
||||
|
||||
$table->string('ip_address', 50)
|
||||
->nullable();
|
||||
|
||||
$table->text('user_agent')
|
||||
->nullable();
|
||||
|
||||
$table->text('description')
|
||||
->nullable();
|
||||
|
||||
$table->timestamp('created_at')
|
||||
->useCurrent();
|
||||
|
||||
$table->index('user_id');
|
||||
$table->index('tenant_id');
|
||||
$table->index('module');
|
||||
$table->index('action');
|
||||
$table->index('record_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('audit_logs');
|
||||
}
|
||||
};
|
||||
@@ -8,6 +8,7 @@ use App\Http\Controllers\Ticket\TicketTypeController;
|
||||
use App\Http\Controllers\Ticket\TicketWorkflowController;
|
||||
use App\Http\Controllers\Ticket\TicketIncidentTypeController;
|
||||
use App\Http\Controllers\Material\MaterialController;
|
||||
use App\Http\Controllers\Audit\AuditLogController;
|
||||
|
||||
Route::post('/login', [AuthController::class, 'login']);
|
||||
|
||||
@@ -70,5 +71,14 @@ Route::middleware('auth:sanctum')->group(function () {
|
||||
|
||||
});
|
||||
|
||||
Route::prefix('audit-logs')
|
||||
->controller(AuditLogController::class)
|
||||
->group(function () {
|
||||
|
||||
Route::get('/', 'index');
|
||||
|
||||
Route::get('/{id}', 'show');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user