Attendance module

This commit is contained in:
Dharmaraj Shrestha 2024-04-16 17:23:35 +05:45
parent 2c2526ef72
commit bf44886663
11 changed files with 512 additions and 14 deletions

View File

@ -6,15 +6,24 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Modules\Attendance\Repositories\AttendanceRepository;
class AttendanceController extends Controller class AttendanceController extends Controller
{ {
private $attendanceRepository;
public function __construct(AttendanceRepository $attendanceRepository)
{
$this->attendanceRepository = $attendanceRepository;
}
/** /**
* Display a listing of the resource. * Display a listing of the resource.
*/ */
public function index() public function index()
{ {
return view('attendance::index'); $data['title'] = 'Attendance Lists';
$data['attendanceLists'] = $this->attendanceRepository->findAll();
return view('attendance::attendances.index', $data);
} }
/** /**
@ -22,7 +31,9 @@ class AttendanceController extends Controller
*/ */
public function create() public function create()
{ {
return view('attendance::create'); $data['title'] = 'Create Attendance';
$data['editable'] = false;
return view('attendance::attendances.create', $data);
} }
/** /**
@ -30,7 +41,17 @@ class AttendanceController extends Controller
*/ */
public function store(Request $request): RedirectResponse public function store(Request $request): RedirectResponse
{ {
// $request->merge([
'date' => $request->date ? $request->date : now()->format('Y-m-d'),
]);
try {
$this->attendanceRepository->create($request->all());
toastr()->success('Attendance Created Successfully');
} catch (\Throwable $th) {
toastr()->error($th->getMessage());
}
return redirect()->route('attendance.index');
} }
/** /**
@ -38,7 +59,7 @@ class AttendanceController extends Controller
*/ */
public function show($id) public function show($id)
{ {
return view('attendance::show'); return view('attendance::attendances.show');
} }
/** /**
@ -46,7 +67,17 @@ class AttendanceController extends Controller
*/ */
public function edit($id) public function edit($id)
{ {
return view('attendance::edit'); try {
$data['title'] = 'Edit Attendance';
$data['editable'] = true;
$data['attendance'] = $this->attendanceRepository->getAttendanceById($id);
} catch (\Throwable $th) {
toastr()->error($th->getMessage());
}
return view('attendance::attendances.edit', $data);
} }
/** /**
@ -54,7 +85,15 @@ class AttendanceController extends Controller
*/ */
public function update(Request $request, $id): RedirectResponse public function update(Request $request, $id): RedirectResponse
{ {
// try {
$this->attendanceRepository->update($id, $request->all());
toastr()->success('Attendance Updated Successfully');
} catch (\Throwable $th) {
toastr()->error($th->getMessage());
}
return redirect()->route('attendance.index');
} }
/** /**
@ -62,6 +101,12 @@ class AttendanceController extends Controller
*/ */
public function destroy($id) public function destroy($id)
{ {
// try {
$this->attendanceRepository->delete($id);
toastr()->success('Attendance Deleted Successfully');
} catch (\Throwable $th) {
toastr()->error($th->getMessage());
}
return redirect()->route('attendance.index');
} }
} }

View File

@ -0,0 +1,30 @@
<?php
namespace Modules\Attendance\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Modules\Attendance\Database\factories\AttendanceFactory;
class Attendance extends Model
{
use HasFactory;
protected $table = 'tbl_attendances';
protected $primaryKey = 'attendance_id';
/**
* The attributes that are mass assignable.
*/
protected $fillable = [
'clock_in_time',
'clock_out_time',
'work_from_type',
'date',
'status',
'total_hours',
'description',
'remarks',
'createdBy',
'updatedBy',
];
}

View File

@ -0,0 +1,12 @@
<?php
namespace Modules\Attendance\Repositories;
interface AttendanceInterface
{
public function findAll();
public function getAttendanceById($attendanceId);
public function delete($attendanceId);
public function create(array $attendanceDetails);
public function update($attendanceId, array $newDetails);
}

View File

@ -0,0 +1,35 @@
<?php
namespace Modules\Attendance\Repositories;
use Modules\Attendance\Models\Attendance;
class AttendanceRepository implements AttendanceInterface
{
public function findAll()
{
return Attendance::get();
}
public function getAttendanceById($attendanceId)
{
return Attendance::findOrFail($attendanceId);
}
public function delete($attendanceId)
{
Attendance::destroy($attendanceId);
}
public function create(array $attendanceDetails)
{
return Attendance::create($attendanceDetails);
}
public function update($attendanceId, array $newDetails)
{
return Attendance::where('attendance_id', $attendanceId)->update($newDetails);
}
}

View File

@ -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('tbl_attendances', function (Blueprint $table) {
$table->unsignedTinyInteger('attendance_id')->autoIncrement();
$table->unsignedBigInteger('employee_id')->nullable();
$table->time('clock_in_time')->nullable();
$table->time('clock_out_time')->nullable();
$table->string('work_from_type')->nullable();
$table->date('date')->nullable();
$table->integer('status')->nullable();
$table->integer('total_hours')->nullable();
$table->mediumText('description')->nullable();
$table->mediumText('remarks')->nullable();
$table->unsignedBigInteger('createdBy')->nullable();
$table->unsignedBigInteger('updatedBy')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('tbl_attendances');
}
};

View File

@ -0,0 +1,23 @@
@extends('layouts.app')
@section('content')
<div class="page-content">
<div class="container-fluid">
<!-- start page title -->
@include('layouts.partials.breadcrumb', ['title' => $title])
<!-- end page title -->
<div class='card'>
<div class='card-body'>
{{ html()->form('POST')->route('attendance.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
@include('attendance::partials.attendances.action')
{{ html()->form()->close() }}
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,23 @@
@extends('layouts.app')
@section('content')
<div class="page-content">
<div class="container-fluid">
<!-- start page title -->
@include('layouts.partials.breadcrumb', ['title' => $title])
<!-- end page title -->
<div class='card'>
<div class='card-body'>
{{ html()->modelForm($attendance, 'PUT')->route('attendance.update', $attendance->attendance_id)->class(['needs-validation'])->attributes(['novalidate'])->open() }}
@include('attendance::partials.attendances.action')
{{ html()->form()->close() }}
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,238 @@
@extends('layouts.app')
@section('content')
<div class="page-content">
<div class="container-fluid">
<!-- start page title -->
@include('layouts.partials.breadcrumb', ['title' => $title])
<!-- end page title -->
<div class="card">
<div class="card-header align-items-center d-flex">
<h5 class="card-title flex-grow-1 mb-0">{{ $title }}</h5>
<div class="flex-shrink-0">
<a href="{{ route('attendance.create') }}" class="btn btn-success waves-effect waves-light"><i
class="ri-add-fill me-1 align-bottom"></i>Mark Attendance</a>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table class="dataTable table-bordered table-hover mt-3 table" id="example">
<thead class="thead-light">
<tr>
<th class="px-2" style="vertical-align: middle;">Employee</th>
<th class="f-11 pl-1 pr-2">1
<br>
<span class="text-dark-grey f-10">
Mon
</span>
</th>
<th class="f-11 pl-1 pr-2">2
<br>
<span class="text-dark-grey f-10">
Tue
</span>
</th>
<th class="f-11 pl-1 pr-2">3
<br>
<span class="text-dark-grey f-10">
Wed
</span>
</th>
<th class="f-11 pl-1 pr-2">4
<br>
<span class="text-dark-grey f-10">
Thu
</span>
</th>
<th class="f-11 pl-1 pr-2">5
<br>
<span class="text-dark-grey f-10">
Fri
</span>
</th>
<th class="f-11 pl-1 pr-2">6
<br>
<span class="text-dark-grey f-10">
Sat
</span>
</th>
<th class="f-11 pl-1 pr-2">7
<br>
<span class="text-dark-grey f-10">
Sun
</span>
</th>
<th class="f-11 pl-1 pr-2">8
<br>
<span class="text-dark-grey f-10">
Mon
</span>
</th>
<th class="f-11 pl-1 pr-2">9
<br>
<span class="text-dark-grey f-10">
Tue
</span>
</th>
<th class="f-11 pl-1 pr-2">10
<br>
<span class="text-dark-grey f-10">
Wed
</span>
</th>
<th class="f-11 pl-1 pr-2">11
<br>
<span class="text-dark-grey f-10">
Thu
</span>
</th>
<th class="f-11 pl-1 pr-2">12
<br>
<span class="text-dark-grey f-10">
Fri
</span>
</th>
<th class="f-11 pl-1 pr-2">13
<br>
<span class="text-dark-grey f-10">
Sat
</span>
</th>
<th class="f-11 pl-1 pr-2">14
<br>
<span class="text-dark-grey f-10">
Sun
</span>
</th>
<th class="f-11 pl-1 pr-2">15
<br>
<span class="text-dark-grey f-10">
Mon
</span>
</th>
<th class="f-11 pl-1 pr-2">16
<br>
<span class="text-dark-grey f-10">
Tue
</span>
</th>
<th class="f-11 pl-1 pr-2">17
<br>
<span class="text-dark-grey f-10">
Wed
</span>
</th>
<th class="f-11 pl-1 pr-2">18
<br>
<span class="text-dark-grey f-10">
Thu
</span>
</th>
<th class="f-11 pl-1 pr-2">19
<br>
<span class="text-dark-grey f-10">
Fri
</span>
</th>
<th class="f-11 pl-1 pr-2">20
<br>
<span class="text-dark-grey f-10">
Sat
</span>
</th>
<th class="f-11 pl-1 pr-2">21
<br>
<span class="text-dark-grey f-10">
Sun
</span>
</th>
<th class="f-11 pl-1 pr-2">22
<br>
<span class="text-dark-grey f-10">
Mon
</span>
</th>
<th class="f-11 pl-1 pr-2">23
<br>
<span class="text-dark-grey f-10">
Tue
</span>
</th>
<th class="f-11 pl-1 pr-2">24
<br>
<span class="text-dark-grey f-10">
Wed
</span>
</th>
<th class="f-11 pl-1 pr-2">25
<br>
<span class="text-dark-grey f-10">
Thu
</span>
</th>
<th class="f-11 pl-1 pr-2">26
<br>
<span class="text-dark-grey f-10">
Fri
</span>
</th>
<th class="f-11 pl-1 pr-2">27
<br>
<span class="text-dark-grey f-10">
Sat
</span>
</th>
<th class="f-11 pl-1 pr-2">28
<br>
<span class="text-dark-grey f-10">
Sun
</span>
</th>
<th class="f-11 pl-1 pr-2">29
<br>
<span class="text-dark-grey f-10">
Mon
</span>
</th>
<th class="f-11 pl-1 pr-2">30
<br>
<span class="text-dark-grey f-10">
Tue
</span>
</th>
<th class="px-2 text-right">Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="w-10 px-2">
<div class="align-items-center mw-50">
<div class="text-truncate">
<h5 class="f-12 mb-0">
<a href="https://demo.worksuite.biz/account/employees/1" class="text-darkest-grey">Mr.
Fletcher Berge <span class="badge badge-secondary ml-1 pr-1">It's you</span></a>
</h5>
<p class="f-12 text-dark-grey mb-0">
Junior
</p>
</div>
</div>
</td>
<td class="text-dark f-w-500 attendance-total w-100 px-2 text-right">
0 / <span class="text-lightest">30</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,32 @@
<div class="row gy-3">
<div class="col-lg-4 col-md-6">
{{ html()->label('Employee')->class('form-label') }}
{{ html()->select('employee_id')->class('form-select')->placeholder('Select Employee') }}
</div>
<div class="col-lg-4 col-md-6">
{{ html()->label('Clock In')->class('form-label') }}
{{ html()->time('clock_in_time')->class('form-control') }}
</div>
<div class="col-lg-4 col-md-6">
{{ html()->label('Clock Out')->class('form-label') }}
{{ html()->time('clock_out_time')->class('form-control') }}
</div>
<div class="col-lg-4 col-md-6">
{{ html()->label('Date')->class('form-label') }}
{{ html()->date('date')->class('form-control')->placeholder('Attendance Date') }}
</div>
<div class="col-lg-4 col-md-6">
{{ html()->label('Working From')->class('form-label') }}
{{ html()->select('work_from_type', ['home' => 'Home', 'office' => 'Office', 'other' => 'Other'])->class('form-select')->placeholder('Working From') }}
</div>
<div class="text-end">
{{ html()->button($editable ? 'Update' : 'Mark Attendance', 'submit')->class('btn btn-success') }}
</div>
</div>

View File

@ -123,7 +123,9 @@
<script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js"></script> <script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js"></script>
<script src="{{ asset('assets/libs/fullcalendar/index.global.min.j') }}s"></script> <script src="{{ asset('assets/libs/fullcalendar/index.global.min.js') }}"></script>
<script src="{{ asset('assets/libs/choices.js') }}"></script>
<script src="{{ asset('assets/js/pages/calendar.init.js') }}"></script> <script src="{{ asset('assets/js/pages/calendar.init.js') }}"></script>

View File

@ -39,6 +39,7 @@
aria-controls="MenuOne"> aria-controls="MenuOne">
<i class="ri-building-2-line"></i> <span data-key="t-companies">Company Setup</span> <i class="ri-building-2-line"></i> <span data-key="t-companies">Company Setup</span>
</a> </a>
<div class="menu-dropdown collapse" id="MenuOne"> <div class="menu-dropdown collapse" id="MenuOne">
<ul class="nav nav-sm flex-column"> <ul class="nav nav-sm flex-column">
@ -51,7 +52,22 @@
<a href="{{ route('company.index') }}" <a href="{{ route('company.index') }}"
class="nav-link @if (\Request::is('company') || \Request::is('company/*')) active @endif">Company</a> class="nav-link @if (\Request::is('company') || \Request::is('company/*')) active @endif">Company</a>
</li> </li>
</ul>
</div>
</li>
<li class="nav-item">
<a class="nav-link menu-link" href="#MenuAttendance" data-bs-toggle="collapse" role="button"
aria-expanded="false" aria-controls="MenuAttendance">
<i class="ri-shopping-cart-2-line"></i> <span data-key="t-attendances">Attendance</span>
</a>
<div class="menu-dropdown collapse" id="MenuAttendance">
<ul class="nav nav-sm flex-column">
<li class="nav-item">
<a href="{{ route('attendance.index') }}"
class="nav-link @if (\Request::is('attendance')) active @endif">Attendance Report</a>
</li>
</ul> </ul>
</div> </div>
@ -100,6 +116,7 @@
<div class="menu-dropdown collapse" id="leave"> <div class="menu-dropdown collapse" id="leave">
<ul class="nav nav-sm flex-column"> <ul class="nav nav-sm flex-column">
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('leaveType.index') }}" <a href="{{ route('leaveType.index') }}"
class="nav-link @if (\Request::is('leavetype') || \Request::is('leavetype/*')) active @endif">Leave Type</a> class="nav-link @if (\Request::is('leavetype') || \Request::is('leavetype/*')) active @endif">Leave Type</a>
@ -110,6 +127,10 @@
class="nav-link @if (\Request::is('leave') || \Request::is('leave/*')) active @endif">Apply Leave</a> class="nav-link @if (\Request::is('leave') || \Request::is('leave/*')) active @endif">Apply Leave</a>
</li> </li>
<li class="nav-item">
<a href="" class="nav-link @if (\Request::is('leaveReport') || \Request::is('leaveReport/*')) active @endif">Leave Report</a>
</li>
</ul> </ul>
</div> </div>
</li> </li>