Commit caf2415d by Hannah Zahra

First Update

parent 548d61e1
...@@ -10,6 +10,7 @@ final class Permission extends Enum ...@@ -10,6 +10,7 @@ final class Permission extends Enum
const OptionTwo = 1; const OptionTwo = 1;
const OptionThree = 2; const OptionThree = 2;
// ACL -new // ACL -new
// semua nama sama
const APPLY_LEAVE = 'APPLY_LEAVE'; const APPLY_LEAVE = 'APPLY_LEAVE';
const SOKONG = 'SOKONG'; const SOKONG = 'SOKONG';
const LULUS = 'LULUS'; const LULUS = 'LULUS';
...@@ -26,6 +27,10 @@ final class Permission extends Enum ...@@ -26,6 +27,10 @@ final class Permission extends Enum
const MANAGE_ROLE = 'epicentrum::manage-role'; const MANAGE_ROLE = 'epicentrum::manage-role';
// asasd // asasd
// hannah punya ----------------------
const APPLY_CLAIM = 'APPLY_CLAIM';
const HRVIEW = "HRVIEW";
const TRY_PERMISSION = "TRY_PERMISSION";
//should added to in table:acl_permission //should added to in table:acl_permission
} }
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('lkp_jenis_kenderaans', function (Blueprint $table) {
$table->id();
$table->string('name', 100); // e.g. Kereta, Motosikal
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('lkp_jenis_kenderaans');
}
};
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('project', function (Blueprint $table) {
$table->id();
$table->string('project_code', 20)->unique();
$table->string('project_name', 200);
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('project');
}
};
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::create('claims', function (Blueprint $table) {
$table->id();
$table->date('claim_date');
// Vehicle type FK
$table->unsignedBigInteger('jenis_kenderaan_id');
$table->foreign('jenis_kenderaan_id')->references('id')->on('lkp_jenis_kenderaans')->onDelete('cascade');
// Project FK
$table->unsignedBigInteger('project_id');
$table->foreign('project_id')->references('id')->on('lkp_project');
// distance_from is always "Pejabat"
$table->string('distance_from')->default('Pejabat');
// User input fields
$table->string('distance_to');
$table->string('description')->nullable();
$table->decimal('total_mileage', 8, 2);
$table->decimal('toll_amount', 8, 2)->nullable();
$table->decimal('others_amount', 8, 2)->nullable();
$table->string('others_description')->nullable();
$table->decimal('calculated_amount', 10, 2)->nullable(); // system auto-calculated RM
$table->decimal('penalty_amount', 10, 2)->default(0); // system-applied penalty if late
$table->string('penalty_reason')->nullable();
$table->decimal('total_claim_amount', 10, 2)->default(0);
// Claim status (workflow)
$table->enum('status', [
'Diproses', // submitted by staff
'Disokong', // verified by PM/HOD
'Disahkan', // approved by Project Director/BOD
'Disemak', // reviewed by Finance
'Diluluskan', // approved by Finance Director
'Ditolak', // rejected
'Dibetulkan', // corrected by Finance
'Dibayar' // final paid
])->default('Diproses');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('claims');
}
};
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Seeder;
class JenisKenderaanSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('jenis_kenderaans')->insert([
['name' => 'Kereta'],
['name' => 'Motosikal'],
]);
}
}
@extends('ui::layouts.app')
@section('content')
<style>
body {
background-color: #f0f2f5;
}
.ui.container {
max-width: 70% !important;
margin-top: 2rem;
}
.ui.segment {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
</style>
<div class="ui container">
<h2 class="ui header">Maklumat Tuntutan</h2>
<div class="ui segment">
<table class="ui definition table">
<tr>
<td>Tarikh Tuntutan</td>
<td>{{ $claim->claim_date }}</td>
</tr>
<tr>
<td>Jenis Kenderaan</td>
<td>{{ $claim->jenisKenderaan->name ?? '-' }}</td>
</tr>
<tr>
<td>Nama Projek</td>
<td>{{ $claim->project->p_project_description ?? '-' }}</td>
</tr>
<tr>
<td>Butiran Tuntutan</td>
<td>{{ $claim->description ?? '-' }}</td>
</tr>
<tr>
<td>Jarak Dari</td>
<td>{{ $claim->distance_from ?? '-' }}</td>
</tr>
<tr>
<td>Jarak Ke</td>
<td>{{ $claim->distance_to ?? '-' }}</td>
</tr>
<tr>
<td>Jumlah Perbatuan (KM)</td>
<td>{{ $claim->total_mileage }} km</td>
</tr>
<tr>
<td>Jumlah Perbatuan Layak Tuntut</td>
<td>{{ $claim->claimable_mileage ?? 0 }} km</td>
</tr>
<tr>
<td>Jumlah Tuntutan Perjalanan (RM)</td>
<td>RM {{ number_format($claim->calculated_amount ?? 0, 2) }}</td>
</tr>
<tr>
<td>Toll (RM)</td>
<td>RM {{ number_format($claim->toll_amount ?? 0, 2) }}</td>
</tr>
<tr>
<td>Lain-lain (RM)</td>
<td>RM {{ number_format($claim->others_amount ?? 0, 2) }}</td>
</tr>
<tr>
<td>Butiran Lain-lain</td>
<td>{{ $claim->others_description ?? '-' }}</td>
</tr>
<tr>
<td>Penalti (RM) (Jika Ada)</td>
@if ($claim->penalty_amount > 0)
<td>RM {{ number_format($claim->penalty_amount, 2) }}</td>
@elseif (Str::contains($claim->penalty_reason, 'Budi Bicara'))
<td><span style="color: orange;">Tertakluk kepada BOD</span></td>
@else
<td>RM 0.00</td>
@endif
</tr>
<tr>
<td>Sebab Penalti</td>
<td>{{ $claim->penalty_reason ?? '-' }}</td>
</tr>
<tr>
<td><strong>Jumlah Keseluruhan Tuntutan (RM)</strong></td>
<td><strong>RM {{ number_format($claim->total_claim_amount ?? 0, 2) }}</strong></td>
</tr>
<tr>
<td><strong>Status</strong></td>
<td><strong>{{ $claim->status }}</strong></td>
</tr>
</table>
</div>
<a href="{{ route('mileage::applications.index') }}" class="ui button">
Kembali
</a>
</div>
@endsection
...@@ -94,6 +94,14 @@ ...@@ -94,6 +94,14 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
@if (auth()->user()->can('HRVIEWS'))
<div>HR je leh nampak</div>
@endif
@if (auth()->user()->can('TRY_PERMISSION'))
<div>try try try</div>
@endif
</div> </div>
</div> </div>
</div> </div>
......
@extends('ui::layouts.app')
@section('content')
<h1 class="ui header">Senarai Users</h1>
{!!
Suitable::source($items)
->title(__('Senarai Users'))
->columns([
\Laravolt\Suitable\Columns\Numbering::make('No'),
['header' => __('Nama'), 'field' => 'name', 'sortable' => true],
['header' => __('Tarikh Hari ini'), 'raw' => function($items){return date("d-m-Y");}, 'sortable' => true],
['header' => __('Terperinci'), 'raw' => function($items){
return "<div class='ui small basic icon buttons'><a href='/applications/".$items->id."' class='ui button'><i class='file icon'></i></a></div>";
}]
])
->render()
!!}
@endsection
<?php <?php
use Illuminate\Support\Facades\Route;
use Portal\Mileage\Http\Controllers\ApplyformController;
use Portal\Mileage\Http\Controllers\ApplicationsController;
Route::group( Route::group(
[ [
'namespace' => '\Portal\Mileage\Http\Controllers', 'namespace' => '\Portal\Mileage\Http\Controllers',
...@@ -8,9 +12,12 @@ ...@@ -8,9 +12,12 @@
'middleware' => ['web', 'auth'], 'middleware' => ['web', 'auth'],
], ],
function () { function () {
Route::resource('applyform', 'ApplyformController'); // resource for applyform
Route::resource('applications', 'ApplicationsController'); Route::resource('applyform', ApplyformController::class);
Route::post('apply/save',['uses' => 'ApplyformController@save','as' => 'apply.save']);
// resource for application
Route::resource('applications', ApplicationsController::class);
} }
); );
......
...@@ -2,28 +2,209 @@ ...@@ -2,28 +2,209 @@
namespace Portal\Mileage\Http\Controllers; namespace Portal\Mileage\Http\Controllers;
use Portal\Mileage\Model\Users;
use Portal\Mileage\Model\Project;
use Portal\Mileage\Model\JenisKenderaan;
use Portal\Mileage\Model\Claim;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Redirect;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use Portal\Mileage\Model\Users;
class ApplicationsController extends Controller class ApplicationsController extends Controller
{ {
public function __construct()
{
//
}
public function __construct() public function index()
{ {
// Show all claims
} $claims = Claim::with(['project', 'jenisKenderaan'])->latest()->get();
$projects = Project::all();
$jenisKenderaan = JenisKenderaan::all();
return view('mileage::application.index', compact('claims', 'projects', 'jenisKenderaan'));
}
public function store(Request $request)
{
$validated = $request->validate([
'claim_date' => 'required|date|before_or_equal:today',
'jenis_kenderaan_id' => 'required|exists:lkp_jenis_kenderaans,id',
'project_id' => 'required|exists:lkp_project,id',
'description' => 'required',
'distance_from' => 'required',
'distance_to' => 'required',
'total_mileage' => 'required|numeric',
'toll_amount' => 'nullable|numeric',
'others_amount' => 'nullable|numeric',
'others_description' => 'nullable|string|max:255',
]);
public function index() // calculation logic
$claimableMileage = max(0, $validated['total_mileage'] - 40);
if ($validated['jenis_kenderaan_id'] == 1) { // Car
$rate = $claimableMileage <= 500 ? 0.55 : 0.50;
} else {
$rate = 0.30;
}
$calculatedAmount = $claimableMileage * $rate;
$calculatedAmount += floatval($validated['toll_amount'] ?? 0);
$calculatedAmount += floatval($validated['others_amount'] ?? 0);
$validated['calculated_amount'] = $calculatedAmount;
$validated['claimable_mileage'] = $claimableMileage;
// penalty
$claimDate = Carbon::parse($validated['claim_date']);
$monthsDiff = $claimDate->diffInMonths(Carbon::now());
if ($monthsDiff <= 3) {
$penalty = 0;
$penaltyReason = 'Tiada penalti (≤ 3 bulan)';
} elseif ($monthsDiff <= 6) {
$penalty = $calculatedAmount * 0.10;
$penaltyReason = 'Lewat hantar ≤ 6 bulan (10%)';
} else {
$penalty = $calculatedAmount * 0.30;
$penaltyReason = 'Lewat hantar > 6 bulan (30%)';
}
$validated['penalty_amount'] = $penalty;
$validated['penalty_reason'] = $penaltyReason;
$validated['total_claim_amount'] = $calculatedAmount - $penalty;
$validated['status'] = 'Diproses'; // default status when first submitted
// IMPORTANT: assign created model to $claim so we can return/use it
$claim = Claim::create($validated);
// If front-end sent AJAX and expects JSON with claim data:
if ($request->ajax()) {
return response()->json([
'success' => true,
'message' => 'Claim submitted successfully!',
'claim' => $claim->load(['project', 'jenisKenderaan']),
]);
}
return redirect()->route('mileage::applications.index')
->with('success', 'Claim submitted successfully!');
}
public function edit($id)
{
$claim = Claim::findOrFail($id);
$projects = \Portal\Mileage\Model\Project::all();
$jenisKenderaan = \Portal\Mileage\Model\JenisKenderaan::all();
return view('mileage::applications.edit', compact('claim','projects','jenisKenderaan'));
}
public function update(Request $request, $id)
{
$claim = Claim::findOrFail($id);
if (auth()->user()->hasRole('Project Manager')) {
$claim->status = 'Disokong';
}
elseif (auth()->user()->hasRole('HOD')) {
$claim->status = 'Disokong';
}
elseif (auth()->user()->hasRole('Project Director')) {
$claim->status = 'Disahkan';
}
elseif (auth()->user()->hasRole('Finance')) {
$claim->status = 'Disemak';
}
elseif (auth()->user()->hasRole('Finance Director')) {
$claim->status = 'Diluluskan';
}
$validated = $request->validate([
'claim_date' => 'required|date',
'jenis_kenderaan_id' => 'required|exists:lkp_jenis_kenderaans,id',
'project_id' => 'required|exists:lkp_project,id',
'description' => 'required',
'distance_from' => 'nullable',
'distance_to' => 'nullable',
'total_mileage' => 'required|numeric',
'toll_amount' => 'nullable|numeric',
'others_amount' => 'nullable|numeric',
'others_description' => 'nullable|string|max:255',
]);
// calculation logic (same as store)
$claimableMileage = max(0, $validated['total_mileage'] - 40);
if ($validated['jenis_kenderaan_id'] == 1) {
$rate = $claimableMileage <= 500 ? 0.55 : 0.50;
} else {
$rate = 0.30;
}
$calculatedAmount = $claimableMileage * $rate;
$calculatedAmount += floatval($validated['toll_amount'] ?? 0);
$calculatedAmount += floatval($validated['others_amount'] ?? 0);
$validated['calculated_amount'] = $calculatedAmount;
$validated['claimable_mileage'] = $claimableMileage;
// penalty
$claimDate = Carbon::parse($validated['claim_date']);
$now = Carbon::now();
$monthsDiff = $claimDate->diffInMonths($now);
if ($monthsDiff < 1) {
$penalty = 0;
$penaltyReason = 'Tiada penalti (≤ 1 bulan)';
} elseif ($monthsDiff <= 3) {
$penalty = $calculatedAmount * 0.10;
$penaltyReason = 'Lewat hantar > 1 bulan & ≤ 3 bulan (10% Penalti)';
} elseif ($monthsDiff <= 6) {
$penalty = $calculatedAmount * 0.30;
$penaltyReason = 'Lewat hantar > 3 bulan & ≤ 6 bulan (30% Penalti)';
} else {
$penalty = 0;
$penaltyReason = 'Melebihi 6 bulan (Tertakluk kepada budi bicara Lembaga Pengarah)';
// Optionally: $validated['status'] = 'Untuk Kelulusan BOD';
}
$validated['penalty_amount'] = $penalty;
$validated['penalty_reason'] = $penaltyReason;
$validated['total_claim_amount'] = $calculatedAmount - $penalty;
// update the model
$claim->update($validated);
if ($request->ajax()) {
return response()->json([
'success' => true,
'message' => 'Claim updated successfully!',
'claim' => $claim->load(['project', 'jenisKenderaan']),
]);
}
return redirect()->route('mileage::applications.index')->with('success', 'Claim updated successfully!');
}
public function destroy($id)
{
$claim = Claim::findOrFail($id);
$claim->delete();
return redirect()->route('mileage::applications.index')->with('success', 'Claim deleted successfully!');
}
public function show($id)
{ {
$items = Users::paginate(10); $claim = Claim::with(['project', 'jenisKenderaan'])->findOrFail($id);
return view('mileage::application.show', compact('claim'));
return view('mileage::application.index',compact('items'));
} }
} }
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
namespace Portal\Mileage\Http\Controllers; namespace Portal\Mileage\Http\Controllers;
use Portal\Mileage\Model\Project;
use Portal\Mileage\Model\JenisKenderaan;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use File; use File;
...@@ -18,14 +21,21 @@ public function __construct() ...@@ -18,14 +21,21 @@ public function __construct()
} }
public function index() public function index()
{ {
$projects = Project::all();
return view('mileage::applyform.index'); $jenisKenderaan = JenisKenderaan::all();
return view('mileage::applyform.index', compact('projects','jenisKenderaan'));
} }
public function create()
{
$projects = Project::all();
return view('mileage::applyform.index', compact('projects'));
}
public function save(Request $request) public function save(Request $request)
{ {
return null; return null;
......
...@@ -15,6 +15,12 @@ public function __construct() ...@@ -15,6 +15,12 @@ public function __construct()
public function index() public function index()
{ {
// logic filter role kat user yang nak login
if (auth()->user()->hasRole(['Administrator'])){
// allow access to dashboard
}
$staff = Users::where('employeeCode',auth()->user()->employeeCode) $staff = Users::where('employeeCode',auth()->user()->employeeCode)
->with('staffinfo') ->with('staffinfo')
......
<?php
namespace Portal\Mileage\Model;
use Portal\Mileage\Model\Project;
use Portal\Mileage\Model\JenisKenderaan;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Claim extends Model
{
protected $fillable = [
'claim_date', 'jenis_kenderaan_id', 'project_id', 'description',
'distance_from', 'distance_to',
'total_mileage', 'toll_amount', 'others_amount', 'others_description',
'calculated_amount','penalty_amount', 'penalty_reason', 'total_claim_amount',
'status',
];
public function project()
{
return $this->belongsTo(Project::class, 'project_id', 'id', 'p_project_description');
}
public function jenisKenderaan()
{
return $this->belongsTo(JenisKenderaan::class, 'jenis_kenderaan_id', 'id');
}
}
<?php
namespace Portal\Mileage\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class JenisKenderaan extends Model
{
protected $table = 'lkp_jenis_kenderaans';
protected $fillable = ['name'];
public function claims()
{
return $this->hasMany(Claim::class, 'jenis_kenderaan_id', 'id');
}
}
<?php
namespace Portal\Mileage\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Project extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'lkp_project'; // because your SQL uses singular
// Primary key
protected $primaryKey = 'id';
// Mass assignable fields
protected $fillable = [
'p_project_code',
'p_project_description',
'p_project_task_team',
'p_project_director',
'p_project_type',
'p_total_hours',
'p_total_days',
'p_project_task_stage',
'p_project_sts',
'start_date',
'end_date',
'created_at',
'updated_at',
'updated_by',
'deleted_at'
];
// Tell Laravel which columns are dates
protected $dates = [
'start_date',
'end_date',
'created_at',
'updated_at',
'deleted_at'
];
// Relationship with claims
public function claims()
{
return $this->hasMany(Claim::class, 'project_id');
}
}
...@@ -22,10 +22,10 @@ class StaffInfo extends Model ...@@ -22,10 +22,10 @@ class StaffInfo extends Model
* @return void * @return void
* @author * @author
**/ **/
public function lkpdepartment() // public function lkpdepartment()
{ // {
return $this->belongsTo('Portal\Mileage\Model\Cuti\LkpDepartment','fk_lkp_department'); // return $this->belongsTo('Portal\Mileage\Model\Cuti\LkpDepartment','fk_lkp_department');
} // }
/** /**
* undocumented function * undocumented function
......
...@@ -84,17 +84,17 @@ protected function menu() ...@@ -84,17 +84,17 @@ protected function menu()
->data('icon', 'home') ->data('icon', 'home')
->active('home/*'); ->active('home/*');
$menu = $menus->add(__('Borang Permohonan'))->data('icon', 'align justify'); $menu = $menus->add(__('Borang Permohonan Mileage Claim'))->data('icon', 'align justify');
$now = Carbon::today()->format('Y-m-d'); $now = Carbon::today()->format('Y-m-d');
$menu->add(__('Permohonan Cuti Rehat'), route('mileage::applyform.index')) $menu->add(__('Permohonan Mileage Claim'), route('mileage::applyform.index'))
->data('icon', 'edit outline') ->data('icon', 'edit outline')
->active('applyform/*') ->active('applyform/*')
->data('permission', Permission::APPLY_LEAVE); ->data('permission', Permission::APPLY_CLAIM);
$menu = $menus->add(__('Senarai Permohonan'))->data('icon', 'align justify'); $menu = $menus->add(__('Senarai Permohonan'))->data('icon', 'align justify');
$menu->add(__('Senarai Permohonan Cuti'), route('mileage::applications.index')) $menu->add(__('Senarai Permohonan Mileage Claim'), route('mileage::applications.index'))
->data('icon', 'bars') ->data('icon', 'bars')
->active('applications/*'); ->active('applications/*');
......
...@@ -66,11 +66,11 @@ protected function menu() ...@@ -66,11 +66,11 @@ protected function menu()
$menu = $menus->add(__('Pengurusan Sistem'))->data('icon', 'align justify'); $menu = $menus->add(__('Pengurusan Sistem'))->data('icon', 'align justify');
$menu->add(__('User Management'), route('overide::overide.user')) $menu->add(__('User Management'), route('overide::overide.user'))
->data('icon', 'circle outline') ->data('icon', 'circle')
->active('users/*') ->active('users/*')
->data('permission', Permission::MANAGE_USER); ->data('permission', Permission::MANAGE_USER);
$menu->add(__('Roles Management'), route('overide::roles.index')) $menu->add(__('Roles Management'), route('overide::roles.index'))
->data('icon', 'circle outline') ->data('icon', 'circle')
->active('users/*') ->active('users/*')
->data('permission', Permission::MANAGE_ROLE); ->data('permission', Permission::MANAGE_ROLE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment