1
0

update api ticket type

This commit is contained in:
Wian Drs
2026-06-25 17:11:48 +07:00
parent ad472a9880
commit af1c98b38b
29 changed files with 1097 additions and 34 deletions
@@ -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'
);
}
@@ -67,4 +71,4 @@ class TicketTypeController extends ApiController
'Ticket Type berhasil dihapus'
);
}
}
}
@@ -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,
];
}
}
@@ -15,13 +15,17 @@ class TicketTypeResource extends JsonResource
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'code' => $this->code,
'name' => $this->name,
'id' => $this->id,
'code' => $this->code,
'name' => $this->name,
'need_approval' => $this->need_approval,
'sla_minutes' => $this->sla_minutes,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'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,
];
}
}
+30
View File
@@ -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'
];
}
+3
View File
@@ -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
View File
@@ -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',
+9 -4
View File
@@ -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,13 +19,15 @@ class TicketType extends Model
'require_photo',
'require_material',
'need_customer',
'need_incident_type'
];
protected $casts = [
'need_approval' => 'boolean',
'require_photo' => 'boolean',
'need_approval' => 'boolean',
'require_photo' => 'boolean',
'require_material' => 'boolean',
'need_customer' => 'boolean',
'need_customer' => 'boolean',
'need_incident_type' => 'boolean'
];
/*
@@ -38,4 +43,4 @@ class TicketType extends Model
'ticket_type_id'
);
}
}
}
+2
View File
@@ -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.
+70
View File
@@ -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,
]);
}
}
+38 -7
View File
@@ -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();
}
}
+45
View File
@@ -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()
);
});
}
}