migrate to gtea from bistbucket
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HRM\Repositories;
|
||||
|
||||
use App\Abstracts\EntityRepository;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Pagination\Paginator;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\HRM\Models\Attendance;
|
||||
use Modules\HRM\Models\AttendanceLog;
|
||||
|
||||
class AttendanceRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Attendance::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'employee_id',
|
||||
'date',
|
||||
'first_clock_in',
|
||||
'last_clock_out',
|
||||
'hours_worked',
|
||||
'status',
|
||||
'breaks',
|
||||
'notes',
|
||||
];
|
||||
|
||||
protected function getQuery(): Builder
|
||||
{
|
||||
return parent::getQuery();
|
||||
}
|
||||
|
||||
protected function getFilterData(array $filterData = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'perPage' => 10,
|
||||
'search' => '',
|
||||
'orderBy' => 'id',
|
||||
'order' => 'desc',
|
||||
'with_deleted' => false,
|
||||
], $filterData);
|
||||
}
|
||||
|
||||
public function getAttendanceQuery(): EloquentBuilder
|
||||
{
|
||||
return Attendance::with(['employee', 'logs']);
|
||||
}
|
||||
|
||||
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
|
||||
{
|
||||
$searchable = "%$searchedText%";
|
||||
|
||||
return $query->where("{$this->table}.status", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getAttendanceQuery();
|
||||
|
||||
if (! $filter['with_deleted']) {
|
||||
$query->whereNull("{$this->table}.deleted_at");
|
||||
}
|
||||
|
||||
if (! empty($filter['search'])) {
|
||||
$query = $this->filterSearchQuery($query, $filter['search']);
|
||||
}
|
||||
|
||||
return $query->orderBy($filter['orderBy'], $filter['order'])
|
||||
->paginate($filter['perPage']);
|
||||
}
|
||||
|
||||
public function getCount(array $filterData = []): int
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getQuery();
|
||||
|
||||
if (! $filter['with_deleted']) {
|
||||
$query->whereNull("{$this->table}.deleted_at");
|
||||
}
|
||||
|
||||
return $query->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* CREATE ATTENDANCE + LOGS
|
||||
*/
|
||||
public function create(array $data): Attendance
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
|
||||
$date = $data['date'];
|
||||
$employee = $data['employee_id'];
|
||||
|
||||
// Always fetch today attendance or create new
|
||||
$attendance = Attendance::firstOrNew([
|
||||
'employee_id' => $employee,
|
||||
'date' => $date,
|
||||
]);
|
||||
|
||||
$prepared = $this->prepareForDB($data, $attendance->exists ? $attendance : null);
|
||||
|
||||
// Save attendance
|
||||
$attendance->fill($prepared)->save();
|
||||
|
||||
// Insert Punch Logs
|
||||
if (! empty($data['clock_in'])) {
|
||||
$this->insertLog($attendance, 'in', $data['clock_in']);
|
||||
}
|
||||
|
||||
if (! empty($data['clock_out'])) {
|
||||
$this->insertLog($attendance, 'out', $data['clock_out']);
|
||||
}
|
||||
|
||||
// Recalculate working hours after logs
|
||||
$this->recalculateWorkedHours($attendance);
|
||||
|
||||
return $attendance;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* UPDATE ATTENDANCE + REBUILD LOGS
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
return DB::transaction(function () use ($id, $data) {
|
||||
|
||||
$attendance = Attendance::findOrFail($id);
|
||||
$prepared = $this->prepareForDB($data, $attendance);
|
||||
|
||||
$attendance->update($prepared);
|
||||
|
||||
// Remove old logs
|
||||
AttendanceLog::where('attendance_id', $id)->delete();
|
||||
|
||||
// Add new logs
|
||||
if (! empty($data['clock_in'])) {
|
||||
$this->insertLog($attendance, 'in', $data['clock_in']);
|
||||
}
|
||||
|
||||
if (! empty($data['clock_out'])) {
|
||||
$this->insertLog($attendance, 'out', $data['clock_out']);
|
||||
}
|
||||
|
||||
$this->recalculateWorkedHours($attendance);
|
||||
|
||||
return $this->getById($id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* MAP REQUEST TO DB FIELDS
|
||||
*/
|
||||
public function prepareForDB(array $data, ?object $item = null): array
|
||||
{
|
||||
$data = parent::prepareForDB($data, $item);
|
||||
|
||||
if (! $item) {
|
||||
$data['created_at'] = now();
|
||||
$data['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
} else {
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
if (isset($data['clock_in'])) {
|
||||
$data['first_clock_in'] = $data['clock_in'];
|
||||
unset($data['clock_in']);
|
||||
}
|
||||
|
||||
if (isset($data['clock_out'])) {
|
||||
$data['last_clock_out'] = $data['clock_out'];
|
||||
unset($data['clock_out']);
|
||||
}
|
||||
|
||||
if (isset($data['breaks']) && is_array($data['breaks'])) {
|
||||
$data['breaks'] = json_encode($data['breaks']);
|
||||
}
|
||||
|
||||
if (isset($data['notes']) && is_array($data['notes'])) {
|
||||
$data['notes'] = json_encode($data['notes']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* INSERT SINGLE PUNCH LOG ENTRY
|
||||
*/
|
||||
private function insertLog(Attendance $attendance, string $type, string $time)
|
||||
{
|
||||
if (empty($time)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dateTime = Carbon::parse($attendance->date.' '.$time)->format('Y-m-d H:i:s');
|
||||
|
||||
AttendanceLog::create([
|
||||
'attendance_id' => $attendance->id,
|
||||
'employee_id' => $attendance->employee_id,
|
||||
'restaurant_id' => $attendance->restaurant_id,
|
||||
'type' => $type, // in or out
|
||||
'punch_time' => $dateTime,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* RECALCULATE TOTAL WORKED HOURS BASED ON ALL LOGS
|
||||
*/
|
||||
private function recalculateWorkedHours(Attendance $attendance)
|
||||
{
|
||||
$logs = AttendanceLog::where('attendance_id', $attendance->id)
|
||||
->orderBy('punch_time')
|
||||
->get();
|
||||
|
||||
if ($logs->count() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$first = Carbon::parse($logs->first()->punch_time);
|
||||
$last = Carbon::parse($logs->last()->punch_time);
|
||||
|
||||
$hours = round($first->diffInMinutes($last) / 60, 2);
|
||||
|
||||
$attendance->update([
|
||||
'first_clock_in' => $first,
|
||||
'last_clock_out' => $last,
|
||||
'hours_worked' => $hours,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Attendance does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Attendance could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user