Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mileage-claim
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
trainee
mileage-claim
Commits
caf2415d
Commit
caf2415d
authored
Sep 26, 2025
by
Hannah Zahra
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
First Update
parent
548d61e1
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1225 additions
and
142 deletions
+1225
-142
app/Enums/Permission.php
+5
-0
database/migrations/2025_09_22_033202_create_jenis_kenderaans_table.php
+32
-0
database/migrations/2025_09_22_040356_create_project_table.php
+34
-0
database/migrations/2025_09_22_042439_create_claims_table.php
+60
-0
database/seeders/JenisKenderaanSeeder.php
+23
-0
packages/portal/mileage/resources/views/application/index.blade.php
+285
-14
packages/portal/mileage/resources/views/application/show.blade.php
+99
-0
packages/portal/mileage/resources/views/applyform/index.blade.php
+326
-105
packages/portal/mileage/resources/views/dashboard/pegawai.blade.php
+8
-0
packages/portal/mileage/resources/views/users_list/index.blade.php
+23
-0
packages/portal/mileage/routes/web.php
+10
-3
packages/portal/mileage/src/Http/Controllers/ApplicationsController.php
+189
-8
packages/portal/mileage/src/Http/Controllers/ApplyformController.php
+12
-2
packages/portal/mileage/src/Http/Controllers/DashboardController.php
+6
-0
packages/portal/mileage/src/Model/Claim.php
+32
-0
packages/portal/mileage/src/Model/JenisKenderaan.php
+18
-0
packages/portal/mileage/src/Model/Project.php
+53
-0
packages/portal/mileage/src/Model/StaffInfo.php
+4
-4
packages/portal/mileage/src/ServiceProvider.php
+4
-4
packages/portal/overide/src/ServiceProvider.php
+2
-2
No files found.
app/Enums/Permission.php
View file @
caf2415d
...
...
@@ -10,6 +10,7 @@ final class Permission extends Enum
const
OptionTwo
=
1
;
const
OptionThree
=
2
;
// ACL -new
// semua nama sama
const
APPLY_LEAVE
=
'APPLY_LEAVE'
;
const
SOKONG
=
'SOKONG'
;
const
LULUS
=
'LULUS'
;
...
...
@@ -26,6 +27,10 @@ final class Permission extends Enum
const
MANAGE_ROLE
=
'epicentrum::manage-role'
;
// asasd
// hannah punya ----------------------
const
APPLY_CLAIM
=
'APPLY_CLAIM'
;
const
HRVIEW
=
"HRVIEW"
;
const
TRY_PERMISSION
=
"TRY_PERMISSION"
;
//should added to in table:acl_permission
}
database/migrations/2025_09_22_033202_create_jenis_kenderaans_table.php
0 → 100644
View file @
caf2415d
<?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'
);
}
};
database/migrations/2025_09_22_040356_create_project_table.php
0 → 100644
View file @
caf2415d
<?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'
);
}
};
database/migrations/2025_09_22_042439_create_claims_table.php
0 → 100644
View file @
caf2415d
<?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'
);
}
};
database/seeders/JenisKenderaanSeeder.php
0 → 100644
View file @
caf2415d
<?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'
],
]);
}
}
packages/portal/mileage/resources/views/application/index.blade.php
View file @
caf2415d
@
extends
(
'ui::layouts.app'
)
@
section
(
'content'
)
<
style
type
=
"text/css"
>
body
{
background
-
color
:
#f0f2f5;
}
<
h1
class
="
ui
header
">Senarai Users</h1>
.
ui
.
container
{
max
-
width
:
100
%
!
important
;
overflow
-
x
:
hidden
;
padding
:
0
5
rem
0
2
rem
;
box
-
sizing
:
border
-
box
;
}
{!!
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
>
";
}]
.
ui
.
segments
{
margin
-
top
:
2
rem
;
}
])
->render()
!!}
.
ui
.
segment
{
box
-
shadow
:
0
4
px
6
px
rgba
(
0
,
0
,
0
,
0.1
);
}
@
keyframes
spin
{
to
{
transform
:
rotate
(
360
deg
);
}
}
#loader {
position
:
fixed
;
top
:
0
;
left
:
0
;
width
:
100
%
;
height
:
100
%
;
display
:
none
;
align
-
items
:
center
;
justify
-
content
:
center
;
background
:
rgba
(
0
,
0
,
0
,
0.5
);
z
-
index
:
9999
;
}
#loader div {
margin
-
top
:
20
%
;
margin
-
left
:
45
%
;
width
:
60
px
;
height
:
60
px
;
border
:
6
px
solid
#fff;
border
-
top
:
6
px
solid
transparent
;
border
-
radius
:
50
%
;
animation
:
spin
1
s
linear
infinite
;
}
</
style
>
<
div
id
=
"loader"
><
div
></
div
></
div
>
<
div
class
="
ui
container
">
<h2 class="
ui
header
">All Claims</h2>
@if(session('success'))
<div class="
ui
positive
message
">
{{ session('success') }}
</div>
@endif
<table class="
ui
celled
table
">
<thead>
<tr>
<th>No.</th>
<th>Tarikh Tuntutan</th>
<th>Nama Projek</th>
<th>Jenis Kenderaan</th>
<th>Jumlah Tuntutan (RM)</th>
<th>Status</th>
<th>Tindakan</th>
</tr>
</thead>
<tbody>
@foreach(
$claims
as
$claim
)
<tr>
<td>{{
$loop->iteration
}}</td>
<td>{{
$claim->claim_date
}}</td>
<td>{{
$claim->project
->p_project_description ?? '-' }}</td>
<td>{{
$claim->jenisKenderaan
->name ?? '-' }}</td>
<td>RM {{ number_format(
$claim->total_claim_amount
, 2) }}</td>
<td>{{
$claim->status
}}</td>
<td>
<a href="
{{
route
(
'mileage::applications.show'
,
$claim
->
id
)
}}
" class="
ui
blue
button
tiny
">
Lihat
</a>
<!-- Edit button (opens modal) -->
<button class="
ui
yellow
button
tiny
editBtn
" style="
margin
-
bottom
:
10
px
"
data-id="
{{
$claim
->
id
}}
"
data-date="
{{
$claim
->
claim_date
}}
"
data-project="
{{
$claim
->
project_id
}}
"
data-vehicle="
{{
$claim
->
jenis_kenderaan_id
}}
"
data-description="
{{
$claim
->
description
}}
"
data-mileage="
{{
$claim
->
total_mileage
}}
"
data-toll="
{{
$claim
->
toll_amount
}}
"
data-others="
{{
$claim
->
others_amount
}}
"
data-othersdesc="
{{
$claim
->
others_description
}}
">
Kemaskini
</button>
<span>
<!-- Delete button -->
<form action="
{{
route
(
'mileage::applications.destroy'
,
$claim
->
id
)
}}
" method="
POST
" style="
display
:
inline
;
">
@csrf
@method('DELETE')
<button type="
submit
" class="
ui
red
button
tiny
" onclick="
return
confirm
(
'Are you sure you want to delete this claim?'
)
">Padam</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<!-- Edit Modal -->
<div id="
editModal
" class="
ui
modal
">
<i class="
close
icon
"></i>
<div class="
header
">Kemaskini Tuntutan</div>
<div class="
content
">
<form class="
ui
form
" id="
editForm
" method="
POST
">
@csrf
@method('PUT')
<input type="
hidden
" id="
editId
" name="
id
">
<div class="
field
">
<label>Tarikh Tuntutan</label>
<input type="
date
" name="
claim_date
" id="
editDate
">
</div>
<div class="
field
">
<label>Nama Projek</label>
<select class="
ui
dropdown
" name="
project_id
" id="
editProject
">
@foreach(
$projects
as
$project
)
<option value="
{{
$project
->
id
}}
">{{
$project->p_project_description
}}</option>
@endforeach
</select>
</div>
<div class="
field
">
<label>Jenis Kenderaan</label>
<select class="
ui
dropdown
" name="
jenis_kenderaan_id
" id="
editVehicle
">
@foreach(
$jenisKenderaan
as
$vehicle
)
<option value="
{{
$vehicle
->
id
}}
">{{
$vehicle->name
}}</option>
@endforeach
</select>
</div>
<div class="
field
">
<label>Butiran Tuntutan</label>
<input type="
text
" name="
description
" id="
editDescription
">
</div>
<div class="
field
">
<label>Jumlah Perbatuan (KM)</label>
<input type="
number
" name="
total_mileage
" id="
editDistance
">
</div>
<div class="
field
">
<label>Toll (RM)</label>
<input type="
number
" name="
toll_amount
" id="
editToll
">
</div>
<div class="
field
">
<label>Lain-lain (RM)</label>
<input type="
number
" name="
others_amount
" id="
editOthers
">
</div>
<div class="
field
">
<label>Butiran Lain-lain</label>
<input type="
text
" name="
others_description
" id="
editOthersDescription
">
</div>
<button type="
submit
" class="
ui
green
button
">Update</button>
</form>
</div>
</div>
<!-- Script to handle modal -->
<script src="
https
://
code
.
jquery
.
com
/
jquery
-
3.7
.
1.
min
.
js
"></script>
<script src="
https
://
cdnjs
.
cloudflare
.
com
/
ajax
/
libs
/
fomantic
-
ui
/
2.9
.
3
/
semantic
.
min
.
js
"></script>
<script>
$(document).ready(function() {
// Ensure ajax sends X-CSRF-TOKEN
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="
csrf
-
token
"]').attr('content')
}
});
// initialize Semantic UI dropdowns and modal
$('.ui.dropdown').dropdown();
$('#editModal').modal({ autofocus: false });
// delegate click (works if rows are dynamic)
$(document).on('click', '.editBtn', function() {
// quick debug: uncomment if modal doesn't open
// console.log('Edit clicked', $(this).data());
let
$btn
= $(this);
let id =
$btn
.data('id');
let date =
$btn
.data('date');
let project =
$btn
.data('project');
let vehicle =
$btn
.data('vehicle');
let description =
$btn
.data('description');
let mileage =
$btn
.data('mileage');
let toll =
$btn
.data('toll');
let others =
$btn
.data('others');
let othersdesc =
$btn
.data('othersdesc');
// set simple inputs
$('#editId').val(id);
$('#editDate').val(date || '');
$('#editDescription').val(description || '');
$('#editDistance').val(mileage ?? '');
$('#editToll').val(toll ?? '');
$('#editOthers').val(others ?? '');
$('#editOthersDescription').val(othersdesc ?? '');
// set semantic ui dropdown selected values
$('#editProject').dropdown('set selected', project || '');
$('#editVehicle').dropdown('set selected', vehicle || '');
if (others && others > 0) {
$('#editOthersDescription').prop('readonly', false);
} else {
$('#editOthersDescription').val('').prop('readonly', true);
}
// show modal
$('#editModal').modal('show');
});
// AJAX submit update (uses route() helper safely by replacing :id)
$('#editForm').submit(function(e) {
e.preventDefault();
let id = $('#editId').val();
let date = $('#editDate').val();
let project = $('#editProject').val();
let vehicle = $('#editVehicle').val();
let description = $('#editDescription').val();
let mileage = $('#editDistance').val();
let toll = $('#editToll').val();
let others = $('#editOthers').val();
let othersDesc = $('#editOthersDescription').val();
// check required fields
if (!date || !project || !vehicle || !description || !mileage) {
alert('Sila isi semua ruangan wajib.');
return;
}
// check Butiran Lain-lain rule
if (others && others > 0 && (!othersDesc || othersDesc === '-')) {
alert('Sila isi Butiran Lain-lain kerana anda mempunyai jumlah Lain-lain.');
return;
}
let formData = $(this).serialize(); // contains _token
$.ajax({
url: "
{{
route
(
'mileage::applications.update'
,
':id'
)
}}
".replace(':id', id),
type: 'POST',
data: formData + '&_method=PUT',
beforeSend: function() {
$('#editModal').modal('hide');
$("
#loader").show();
},
complete
:
function
()
{
$
(
"#loader"
)
.
hide
();
},
success
:
function
(
response
)
{
if
(
response
&&
response
.
success
)
{
alert
(
response
.
message
||
'Claim updated successfully'
);
setTimeout
(
function
()
{
location
.
reload
();
},
300
);
}
else
{
alert
(
'Unexpected response from server.'
);
}
},
error
:
function
(
xhr
)
{
let
msg
=
"Update failed."
;
if
(
xhr
.
responseJSON
)
{
if
(
xhr
.
responseJSON
.
message
)
msg
=
xhr
.
responseJSON
.
message
;
else
if
(
xhr
.
responseJSON
.
errors
)
{
let
errors
=
xhr
.
responseJSON
.
errors
;
msg
=
Object
.
keys
(
errors
)
.
map
(
k
=>
errors
[
k
][
0
])
.
join
(
"
\n
"
);
}
}
else
{
msg
=
xhr
.
status
+
' '
+
xhr
.
statusText
;
}
alert
(
msg
);
}
});
});
});
</
script
>
@
endsection
packages/portal/mileage/resources/views/application/show.blade.php
0 → 100644
View file @
caf2415d
@
extends
(
'ui::layouts.app'
)
@
section
(
'content'
)
<
style
>
body
{
background
-
color
:
#f0f2f5;
}
.
ui
.
container
{
max
-
width
:
70
%
!
important
;
margin
-
top
:
2
rem
;
}
.
ui
.
segment
{
box
-
shadow
:
0
4
px
6
px
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
packages/portal/mileage/resources/views/applyform/index.blade.php
View file @
caf2415d
@
extends
(
'ui::layouts.app'
)
@
push
(
'style'
)
<
link
href
=
"{{ asset('web/vendor/fullcalendar/fullcalendar.min.css') }}"
rel
=
"stylesheet"
>
<
link
href
=
"{{ asset('web/vendor/fullcalendar/fullcalendar.print.min.css') }}"
rel
=
"stylesheet"
media
=
'print'
>
<
link
rel
=
"stylesheet"
href
=
"https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.3/semantic.min.css"
>
<
style
type
=
"text/css"
>
.
aqua
-
custom
{
background
:
linear
-
gradient
(
-
45
deg
,
#00d2ff 0%, #3a47d5 100%) !important;
body
{
background
-
color
:
#f0f2f5;
}
.
ui
.
container
{
max
-
width
:
100
%
!
important
;
/* never exceed viewport */
overflow
-
x
:
hidden
;
/* cut accidental overflow */
padding
:
0
5
rem
0
2
rem
;
/* breathing space from right */
box
-
sizing
:
border
-
box
;
/* include padding in width calc */
}
.
ui
.
segments
{
margin
-
top
:
2
rem
;
}
.
ui
.
segment
{
box
-
shadow
:
0
4
px
6
px
rgba
(
0
,
0
,
0
,
0.1
);
}
.
red
-
custom
{
background
:
linear
-
gradient
(
-
45
deg
,
#daae51 0%, #d53369 100%) !important;
.
ui
.
form
.
inline
.
field
{
display
:
flex
;
flex
-
wrap
:
wrap
;
/* allow wrapping instead of pushing right */
gap
:
0.5
rem
;
/* spacing between label & field */
width
:
100
%
;
/* force row within parent */
box
-
sizing
:
border
-
box
;
}
.
orange
-
custom
{
background
:
linear
-
gradient
(
-
45
deg
,
#fcff9e 0%, #c67700 100%) !important;
.
ui
.
form
.
inline
.
field
>
label
.
three
-
wide
{
flex
:
0
0
2
rem
;
/* reserve space for label */
margin
-
right
:
50
px
;
max
-
width
:
30
%
;
/* but never hog the full row */
min
-
width
:
8
rem
;
white
-
space
:
normal
;
word
-
break
:
break
-
word
;
}
.
green
-
custom
{
background
:
linear
-
gradient
(
-
45
deg
,
#6a6b5f 0%, #b9b4ad 100%) !important;
.
ui
.
form
.
inline
.
field
.
eight
.
wide
.
field
{
flex
:
1
1
auto
;
/* take remaining space */
min
-
width
:
0
;
/* shrink properly */
max
-
width
:
100
%
;
/* don’t spill outside */
box
-
sizing
:
border
-
box
;
}
.
yellow
-
custom
{
background
:
linear
-
gradient
(
-
45
deg
,
#c5b617 0%, #f6f309 100%) !important;
@
media
(
max
-
width
:
768
px
)
{
.
ui
.
form
.
inline
.
field
{
flex
-
direction
:
column
!
important
;
align
-
items
:
flex
-
start
!
important
;
}
.
ui
.
form
.
inline
.
field
>
label
.
three
-
wide
,
.
ui
.
form
.
inline
.
field
.
eight
.
wide
.
field
{
width
:
100
%
!
important
;
max
-
width
:
100
%
!
important
;
}
}
</
style
>
@
endpush
@
section
(
'content'
)
<
div
class
="
ui
container
">
<div class="
ui
segments
">
<div class="
ui
segment
">
<p>Pemohonan Cuti Rehat</p
>
<h2 class="
ui
header
" style="
margin
:
10
px
">Permohonan Tuntutan Perjalanan</h2
>
</div>
<div class="
ui
secondary
segment
">
{!! Form::post(route('mileage::apply.save', null))->id('applyForm') !!}
<div class="
ui
secondary
segment
">
<form class="
ui
form
" id="
claimForm
" action="
{{
route
(
'mileage::applications.store'
)
}}
" method="
POST
">
@csrf
{{-- Maklumat Tuntutan --}}
<div class="
ui
segment
">
<div class="
column
">
<p>Maklumat Permohonan Cuti</p>
<p>Maklumat Tuntutan</p>
<div class="
ui
segment
">
<div class="
ui
form
">
<div class="
inline
field
">
<label class="
three
wide
field
">Jumlah Kelayakan Tahun Semasa</label>
<input class="
twelve
wide
field
" type="
text
" placeholder="" value="" name="" readonly>
</div>
<div class="
inline
field
">
<label class="
three
wide
field
">Cuti Dibawa Dari Tahun Lepas</label>
<input class="
twelve
wide
field
" type="
text
" placeholder="" value="" name="" readonly>
</div>
<div class="
inline
field
">
<label class="
three
wide
field
">Jumlah Kelayakan</label>
<input class="
twelve
wide
field
" type="
text
" placeholder="
Jumlah
" name="
entitlement
" value="" readonly>
<label><a class="
mini
ui
red
tag
label
">Nota : Jumlah kelayakan adalah jumlah sebelum pelarasan</a>
<h6></h6>
</label>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Tarikh</label>
<div class="
eight
wide
field
ui
calendar
" id="
claim_date
">
<div class="
ui
input
left
icon
">
<i class="
calendar
icon
"></i>
<input type="
text
" name="
claim_date
" id="
date
" placeholder="
Tarikh
Tuntutan
" required readonly>
</div>
<div class="
inline
field
">
<label class="
three
wide
field
">Baki</label>
<input class="
twelve
wide
field
" type="
text
" placeholder="" value="" name="
balance
" readonly>
</div>
<div class="
inline
field
">
<label class="
three
wide
field
">Jumlah Permohonan Cuti Yang Belum Diluluskan</label>
<input class="
twelve
wide
field
" type="
text
" placeholder="" value="" name="" readonly>
</div>
<div class="
inline
field
required
" id="
select
-
lv
-
type111
">
<label class="
three
wide
field
">Jenis Cuti </label>
<select class="
ui
search
dropdown
" name="
leave_type
" id="
select
-
lv
-
type
">
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Jenis Kenderaan</label>
<select class="
ui
dropdown
eight
wide
field
" name="
jenis_kenderaan_id
" id="
jenis_kenderaan_id
" required>
<option value="">Sila Pilih</option>
<option value="
1
" selected="
true
">Cuti Rehat</option>
@foreach(
$jenisKenderaan
as
$jk
)
<option value="
{{
$jk
->
id
}}
">{{
$jk->name
}}</option>
@endforeach
</select>
</div>
<div class="
inline
fields
">
<label class="
three
wide
field
">Tarikh Mula Cuti<font color="
red
">*</font></label>
<div class="
twelve
wide
field
calendar
" id="
start_date
">
<div class="
ui
input
left
icon
">
<i class="
calendar
icon
"></i>
<input type="
text
" name="
start_date
" id="
awal
"
placeholder="
Tarikh
Mula
Cuti
" required readonly>
</div>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Nama Projek<font color="
red
">*</font></label>
<select class="
ui
search
dropdown
eight
wide
field
" name="
project_id
" id="
project_select
" required>
<option value="">Sila Pilih Projek</option>
@foreach(
$projects
as
$project
)
<option value="
{{
$project
->
id
}}
">{{
$project->p_project_description
}}</option>
@endforeach
</select>
</div>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Butiran Tuntutan<font color="
red
">*</font></label>
<input class="
eight
wide
field
" name="
description
" type="
text
" placeholder="
Cth
:
Mesyuarat
Projek
B
" required>
</div>
<div class="
inline
fields
" id="
div_enddate
">
<label class="
three
wide
field
">Tarikh Akhir Cuti<font color="
red
">*</font></label>
<div class="
twelve
wide
field
calendar
" id="
end_date
">
<div class="
ui
input
left
icon
">
<i class="
calendar
icon
"></i>
<input type="
text
" name="
end_date
" id="
akhir
" placeholder="
Tarikh
Akhir
Cuti
"
readonly>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Jarak Dari</label>
<select class="
ui
search
dropdown
eight
wide
field
" name="
distance_from
">
<option value="">Sila Pilih Lokasi</option>
<option value="
office
">Pejabat</option>
</select>
</div>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Jarak Ke</label>
<input class="
eight
wide
field
" name="
distance_to
" type="
text
" placeholder="
Cth
:
Pejabat
PPJ
" required>
</div>
<div class="
inline
field
required
">
<label class="
three
-
wide
field
">Jumlah Perbatuan (KM)</label>
<input class="
eight
wide
field
" name="
total_mileage
" id="
total_mileage
" type="
number
" step="
0.01
" placeholder="
Cth
:
120.50
" required>
</div>
<div class="
inline
field
" id="
div_total_day
">
<label class="
three
wide
field
">Jumlah Hari Bercuti</label>
<input class="
twelve
wide
field
" id="
total_day
" name="
total_day
" type="
text
"
placeholder="">
<div class="
inline
field
">
<label class="
three
-
wide
field
">Toll (RM)</label>
<input class="
eight
wide
field
" name="
toll_amount
" id="
toll_amount
" type="
number
" step="
0.01
" placeholder="
Cth
:
15.00
">
</div>
<div class="
inline
field
" id="
total_day_new
"></div>
<div class="
inline
field
">
<label class="
three
wide
field
">Alasan Bercuti<font color="
red
">*</font>
</label>
<input class="
twelve
wide
field
" name="
reason
" type="
text
" placeholder="
">
<label class="
three
-
wide
field
">Lain-lain (RM)
</label>
<input class="
eight
wide
field
" name="
others_amount
" id="
others_amount
" type="
number
" step="
0.01
" placeholder="
Cth
:
0.00
">
</div>
<div class="
inline
field
required
" id="
others_description_wrapper
" style="
display
:
none
;
">
<label class="
three
-
wide
field
">Butiran Lain-lain</label>
<input class="
eight
wide
field
" name="
others_description
" id="
others_description
" type="
text
" placeholder="
Nyatakan
butiran
lain
-
lain
">
</div>
</div>
</div>
</div>
<button class="
ui
button
" id="
btn_hantar
" type="
submit
" onclick="
block
()
">Seterusnya</button>
{{-- Rumusan Tuntutan --}}
<div class="
ui
segment
">
<div class="
column
">
<p>Senarai Nama Penyokong dan Pelulus Pegawai Pemohon Cuti</p>
<div class="
ui
two
column
stackable
grid
">
<div class="
column
">
<div class="
ui
tertiary
inverted
red
segment
">
<div class="
ui
">
<p>Penyokong Cuti</p>
<p></p>
<p></p>
</div>
</div>
</div>
<div class="
column
">
<div class="
ui
tertiary
inverted
red
segment
">
<div class="
ui
">
<p>Pelulus Cuti</p>
<p></p>
<p></p>
</div>
</div>
</div>
</div>
<p>Rumusan Tuntutan</p>
<div class="
ui
segment
">
<table class="
ui
celled
table
">
<tbody>
<tr>
<td>Jumlah Perbatuan Layak Tuntut</td>
<td id="
claimable_mileage
">0 KM</td>
</tr>
<tr>
<td>Jumlah Tuntutan Perjalanan (RM)</td>
<td id="
mileage_claim_amount
">RM 0.00</td>
</tr>
<tr>
<td>Toll (RM)</td>
<td id="
toll_claim_amount
">RM 0.00</td>
</tr>
<tr>
<td>Lain-lain (RM)</td>
<td id="
others_claim_amount
">RM 0.00</td>
</tr>
<tr>
<td>Penalti (RM) (Jika Ada)</td>
<td id="
penalty_claim_amount
">RM 0.00</td>
</tr>
<tr>
<td>Sebab Penalti (Jika Ada)</td>
<td id="
penalty_reason
">-</td>
</tr>
<tr>
<td><strong>Jumlah Keseluruhan Tuntutan (RM)</strong></td>
<td><strong id="
total_claim_amount
">RM 0.00</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
{!! Form::close() !!}
<!-- Hidden inputs to send calculated values to server -->
<input type="
hidden
" name="
claimable_mileage
" id="
claimable_mileage_input
" value="
0
">
<input type="
hidden
" name="
mileage_claim_amount
" id="
mileage_claim_amount_input
" value="
0.00
">
<input type="
hidden
" name="
total_claim_amount
" id="
total_claim_amount_input
" value="
0.00
">
<input type="
hidden
" name="
toll_amount
" id="
toll_amount_input
" value="
0.00
">
<input type="
hidden
" name="
others_amount
" id="
others_amount_input
" value="
0.00
">
<button class="
ui
primary
button
blue
" type="
submit
" id="
btn_hantar
">Seterusnya</button>
</form>
</div>
</div>
</div>
@endsection
@push('script')
<script src="
{{
asset
(
'web/vendor/fullcalendar/lib/moment.min.js'
)
}}
"></script>
<script src="
{{
asset
(
'web/vendor/fullcalendar/fullcalendar.min.js'
)
}}
"></script>
<script src="
{{
asset
(
'web/vendor/fullcalendar/locale/ms-my.js'
)
}}
"></script>
<script src="
https
://
code
.
jquery
.
com
/
jquery
-
3.7
.
1.
min
.
js
"></script>
<script src="
https
://
cdnjs
.
cloudflare
.
com
/
ajax
/
libs
/
fomantic
-
ui
/
2.9
.
3
/
semantic
.
min
.
js
"></script>
<script src="
https
://
cdnjs
.
cloudflare
.
com
/
ajax
/
libs
/
jquery
.
blockUI
/
2.70
/
jquery
.
blockUI
.
js
"></script>
<script>
$(document).ready(function() {
// Initialize dropdowns & calendar
$('.ui.dropdown').dropdown();
$('#claim_date').calendar({
type: 'date',
maxDate: new Date(), // Prevent selecting future dates
formatter: {
date: function (date) {
if (!date) return '';
let day = date.getDate();
let month = date.getMonth() + 1;
let year = date.getFullYear();
return year + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day;
}
},
onChange: function(date, text) {
$('#date').val(text);
}
});
// Calculate total claim
$('#total_mileage, #toll_amount, #others_amount, #jenis_kenderaan_id').on('input change', function() {
calculateTotalClaim();
});
$('#others_amount').on('input', function() {
let val = parseFloat($(this).val()) || 0;
if (val > 0) {
$('#others_description_wrapper').slideDown();
$('#others_description').prop('required', true);
} else {
$('#others_description_wrapper').slideUp();
$('#others_description').prop('required', false).val('');
}
});
function block() {
$.blockUI({
message: 'Sila Tunggu'
function calculateTotalClaim() {
const vehicleType = $('#jenis_kenderaan_id').val();
let mileage = parseFloat($('#total_mileage').val()) || 0;
const toll = parseFloat($('#toll_amount').val()) || 0;
const others = parseFloat($('#others_amount').val()) || 0;
const vehicleRates = {
'1': { type: 'Kereta', baseRate: 0.55, higherMileageRate: 0.50 },
'2': { type: 'Motosikal', baseRate: 0.30 }
};
let rate = 0, claimableMileage = 0, mileageClaimAmount = 0;
if (vehicleRates[vehicleType]) {
claimableMileage = Math.max(0, mileage - 40);
if (vehicleRates[vehicleType].type === 'Kereta') {
rate = (claimableMileage <= 500) ? vehicleRates[vehicleType].baseRate : vehicleRates[vehicleType].higherMileageRate;
} else {
rate = vehicleRates[vehicleType].baseRate;
}
mileageClaimAmount = claimableMileage * rate;
}
// --- Penalty calculation ---
let penalty = 0, penaltyReason = "
-
";
const claimDate = $('#date').val();
if (claimDate) {
const claimMoment = new Date(claimDate);
const now = new Date();
// calculate month difference
const monthsDiff = (now.getFullYear() - claimMoment.getFullYear()) * 12 +
(now.getMonth() - claimMoment.getMonth());
if (monthsDiff <= 1) {
penalty = 0;
penaltyReason = "
-
";
} else if (monthsDiff > 1 && monthsDiff <= 3) {
penalty = mileageClaimAmount * 0.10;
penaltyReason = "
Lewat
hantar
lebih
1
bulan
tetapi
≤
3
bulan
(
10
%
)
";
} else if (monthsDiff > 3 && monthsDiff <= 6) {
penalty = mileageClaimAmount * 0.30;
penaltyReason = "
Lewat
hantar
lebih
3
bulan
tetapi
≤
6
bulan
(
30
%
)
";
} else if (monthsDiff > 6) {
penaltyReason = "
Lewat
lebih
6
bulan
-
Tertakluk
kepada
budi
bicara
Lembaga
Pengarah
";
// prevent submission for >6 months
$('#btn_hantar').prop('disabled', true);
showCustomAlert("
Tuntutan
lebih
daripada
6
bulan
tidak
boleh
dihantar
.
Sila
rujuk
Lembaga
Pengarah
.
");
} else {
$('#btn_hantar').prop('disabled', false);
}
}
const totalClaim = mileageClaimAmount + toll + others - penalty;
// Update visible summary
$('#claimable_mileage').text(claimableMileage.toFixed(2) + ' KM');
$('#mileage_claim_amount').text('RM ' + mileageClaimAmount.toFixed(2));
$('#toll_claim_amount').text('RM ' + toll.toFixed(2));
$('#others_claim_amount').text('RM ' + others.toFixed(2));
$('#penalty_claim_amount').text('RM ' + penalty.toFixed(2));
$('#penalty_reason').text(penaltyReason);
$('#total_claim_amount').text('RM ' + totalClaim.toFixed(2));
// Update hidden inputs
$('#claimable_mileage_input').val(claimableMileage.toFixed(2));
$('#mileage_claim_amount_input').val(mileageClaimAmount.toFixed(2));
$('#toll_amount_input').val(toll.toFixed(2));
$('#others_amount_input').val(others.toFixed(2));
$('#total_claim_amount_input').val(totalClaim.toFixed(2));
}
// show modal on form submit, but prevent regular submit
$('#claimForm').on('submit', function(e) {
e.preventDefault();
// client-side required checks (keep yours or extend)
const requiredFields = [
'#date',
'#jenis_kenderaan_id',
'input[name="
description
"]',
'select[name="
distance_from
"]',
'input[name="
distance_to
"]',
'#total_mileage',
'#project_select'
];
let allFieldsFilled = requiredFields.every(field => {
const val = $(field).val();
return val !== null && val.toString().trim() !== '';
});
setTimeout(unBlock, 8000);
if (!allFieldsFilled) {
showCustomAlert("
Sila
isi
semua
maklumat
yang
bertanda
*
");
return;
}
// build modal HTML (remove previous first)
$('#claimSummaryModal').remove();
const claimDate = $('#date').val();
const vehicleTypeText = $('#jenis_kenderaan_id option:selected').text();
const projectText = $('#project_select option:selected').text();
const description = $('input[name="
description
"]').val();
const distanceFrom = $('select[name="
distance_from
"] option:selected').text();
const distanceTo = $('input[name="
distance_to
"]').val();
const claimableMileage = $('#claimable_mileage_input').val() || '0';
const mileageClaimAmount = $('#mileage_claim_amount_input').val() || '0.00';
const toll = $('#toll_amount_input').val() || '0.00';
const others = $('#others_amount_input').val() || '0.00';
const penalty = parseFloat($('#penalty_claim_amount').text().replace('RM ', '')) || 0;
const penaltyReason = $('#penalty_reason').text() || "
-
";
const totalClaim = $('#total_claim_amount_input').val() || '0.00';
const summaryHtml = `
<div class="
ui
mini
modal
" id="
claimSummaryModal
">
<div class="
header
">Ringkasan Tuntutan Anda</div>
<div class="
content
">
<p><strong>Tarikh:</strong> ${claimDate}</p>
<p><strong>Jenis Kenderaan:</strong> ${vehicleTypeText}</p>
<p><strong>Projek:</strong> ${projectText}</p>
<p><strong>Butiran Tuntutan:</strong> ${description}</p>
<p><strong>Dari:</strong> ${distanceFrom}</p>
<p><strong>Ke:</strong> ${distanceTo}</p>
<p><strong>Jumlah Perbatuan Layak Tuntut:</strong> ${claimableMileage} KM</p>
<p><strong>Jumlah Tuntutan Perjalanan:</strong> RM ${parseFloat(mileageClaimAmount).toFixed(2)}</p>
<p><strong>Toll:</strong> RM ${parseFloat(toll).toFixed(2)}</p>
<p><strong>Lain-lain:</strong> RM ${parseFloat(others).toFixed(2)}</p>
<p><strong>Butiran Lain-lain: </strong>${$('#others_description').val() ? `(${ $('#others_description').val() })` : '' }</p>
<p><strong>Penalti (Jika Ada):</strong> ${$('#penalty_claim_amount').text()}</p>
<p><strong>Sebab Penalti:</strong> ${$('#penalty_reason').text()}</p>
<p><strong>Jumlah Keseluruhan Tuntutan:</strong> RM ${parseFloat(totalClaim).toFixed(2)}</p>
</div>
<div class="
actions
">
<div class="
ui
button
" id="
editClaim
">Edit</div>
<div class="
ui
green
approve
button
" id="
confirmClaim
">Confirm</div>
</div>
</div>`;
$('body').append(summaryHtml);
// show modal; onApprove -> do AJAX POST to store route, then redirect to show page
$('#claimSummaryModal').modal({
onApprove: function() {
$('#claimForm')[0].submit(); // normal form submit
return false; // stop modal from auto-closing twice
}
}).modal('show');
// Edit: hide modal to edit fields
$('#editClaim').on('click', function() {
$('#claimSummaryModal').modal('hide');
});
});
calculateTotalClaim();
});
</script>
@endpush
packages/portal/mileage/resources/views/dashboard/pegawai.blade.php
View file @
caf2415d
...
...
@@ -94,6 +94,14 @@
</tr>
</tbody>
</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>
...
...
packages/portal/mileage/resources/views/users_list/index.blade.php
0 → 100644
View file @
caf2415d
@
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
packages/portal/mileage/routes/web.php
View file @
caf2415d
<?php
use
Illuminate\Support\Facades\Route
;
use
Portal\Mileage\Http\Controllers\ApplyformController
;
use
Portal\Mileage\Http\Controllers\ApplicationsController
;
Route
::
group
(
[
'namespace'
=>
'\Portal\Mileage\Http\Controllers'
,
...
...
@@ -8,9 +12,12 @@
'middleware'
=>
[
'web'
,
'auth'
],
],
function
()
{
Route
::
resource
(
'applyform'
,
'ApplyformController'
);
Route
::
resource
(
'applications'
,
'ApplicationsController'
);
Route
::
post
(
'apply/save'
,[
'uses'
=>
'ApplyformController@save'
,
'as'
=>
'apply.save'
]);
// resource for applyform
Route
::
resource
(
'applyform'
,
ApplyformController
::
class
);
// resource for application
Route
::
resource
(
'applications'
,
ApplicationsController
::
class
);
}
);
...
...
packages/portal/mileage/src/Http/Controllers/ApplicationsController.php
View file @
caf2415d
...
...
@@ -2,28 +2,209 @@
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\Http\Request
;
use
Redirect
;
use
Carbon\Carbon
;
use
DB
;
use
Portal\Mileage\Model\Users
;
class
ApplicationsController
extends
Controller
{
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'
,
]);
// calculation logic
$claimableMileage
=
max
(
0
,
$validated
[
'total_mileage'
]
-
40
);
public
function
index
()
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
)
{
$items
=
Users
::
paginate
(
10
);
$claim
=
Claim
::
findOrFail
(
$id
);
$projects
=
\Portal\Mileage\Model\Project
::
all
();
$jenisKenderaan
=
\Portal\Mileage\Model\JenisKenderaan
::
all
();
return
view
(
'mileage::application.index'
,
compact
(
'items'
));
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
)
{
$claim
=
Claim
::
with
([
'project'
,
'jenisKenderaan'
])
->
findOrFail
(
$id
);
return
view
(
'mileage::application.show'
,
compact
(
'claim'
));
}
}
packages/portal/mileage/src/Http/Controllers/ApplyformController.php
View file @
caf2415d
...
...
@@ -2,6 +2,9 @@
namespace
Portal\Mileage\Http\Controllers
;
use
Portal\Mileage\Model\Project
;
use
Portal\Mileage\Model\JenisKenderaan
;
use
Illuminate\Routing\Controller
;
use
Illuminate\Http\Request
;
use
File
;
...
...
@@ -18,14 +21,21 @@ public function __construct()
}
public
function
index
()
{
$projects
=
Project
::
all
();
$jenisKenderaan
=
JenisKenderaan
::
all
();
return
view
(
'mileage::applyform.index'
);
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
)
{
return
null
;
...
...
packages/portal/mileage/src/Http/Controllers/DashboardController.php
View file @
caf2415d
...
...
@@ -15,6 +15,12 @@ public function __construct()
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
)
->
with
(
'staffinfo'
)
...
...
packages/portal/mileage/src/Model/Claim.php
0 → 100644
View file @
caf2415d
<?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'
);
}
}
packages/portal/mileage/src/Model/JenisKenderaan.php
0 → 100644
View file @
caf2415d
<?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'
);
}
}
packages/portal/mileage/src/Model/Project.php
0 → 100644
View file @
caf2415d
<?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'
);
}
}
packages/portal/mileage/src/Model/StaffInfo.php
View file @
caf2415d
...
...
@@ -22,10 +22,10 @@ class StaffInfo extends Model
* @return void
* @author
**/
public
function
lkpdepartment
()
{
return
$this
->
belongsTo
(
'Portal\Mileage\Model\Cuti\LkpDepartment'
,
'fk_lkp_department'
);
}
//
public function lkpdepartment()
//
{
//
return $this->belongsTo('Portal\Mileage\Model\Cuti\LkpDepartment','fk_lkp_department');
//
}
/**
* undocumented function
...
...
packages/portal/mileage/src/ServiceProvider.php
View file @
caf2415d
...
...
@@ -84,17 +84,17 @@ protected function menu()
->
data
(
'icon'
,
'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'
);
$menu
->
add
(
__
(
'Permohonan
Cuti Rehat
'
),
route
(
'mileage::applyform.index'
))
$menu
->
add
(
__
(
'Permohonan
Mileage Claim
'
),
route
(
'mileage::applyform.index'
))
->
data
(
'icon'
,
'edit outline'
)
->
active
(
'applyform/*'
)
->
data
(
'permission'
,
Permission
::
APPLY_
LEAVE
);
->
data
(
'permission'
,
Permission
::
APPLY_
CLAIM
);
$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'
)
->
active
(
'applications/*'
);
...
...
packages/portal/overide/src/ServiceProvider.php
View file @
caf2415d
...
...
@@ -66,11 +66,11 @@ protected function menu()
$menu
=
$menus
->
add
(
__
(
'Pengurusan Sistem'
))
->
data
(
'icon'
,
'align justify'
);
$menu
->
add
(
__
(
'User Management'
),
route
(
'overide::overide.user'
))
->
data
(
'icon'
,
'circle
outline
'
)
->
data
(
'icon'
,
'circle'
)
->
active
(
'users/*'
)
->
data
(
'permission'
,
Permission
::
MANAGE_USER
);
$menu
->
add
(
__
(
'Roles Management'
),
route
(
'overide::roles.index'
))
->
data
(
'icon'
,
'circle
outline
'
)
->
data
(
'icon'
,
'circle'
)
->
active
(
'users/*'
)
->
data
(
'permission'
,
Permission
::
MANAGE_ROLE
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment