From ee7d0e1aa5fa6a4c633f522a3d4cfdbe72011bd3 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 19 May 2026 14:48:31 +0800 Subject: [PATCH] feat: improve employee lookup by branch_id and add sync debug reasons --- .../Api/AttendanceSyncController.php | 86 +++++++++++-------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/app/Http/Controllers/Api/AttendanceSyncController.php b/app/Http/Controllers/Api/AttendanceSyncController.php index a4a4cf20e..f52ccc521 100644 --- a/app/Http/Controllers/Api/AttendanceSyncController.php +++ b/app/Http/Controllers/Api/AttendanceSyncController.php @@ -77,53 +77,69 @@ class AttendanceSyncController extends Controller $firstEntry = $sorted->first(); $lastEntry = $sorted->last(); - // Note: Since this is an API, there is no Auth::user(). We use the Branch's creator. - // BiometricAttendanceController uses whereIn('created_by', getCompanyAndUsersId()) - // We just use where('created_by', $branch->created_by) or similar. - + // Note: Since this is an API, there is no Auth::user(). + // We find the employee by branch_id instead of created_by to avoid Admin vs HR mismatch. $employee = \App\Models\Employee::with('user') - ->where('created_by', $branch->created_by) + ->where('branch_id', $branch->id) ->where('biometric_emp_id', $firstEntry['emp_code']) ->first(); - if ($employee && $sorted->count() > 1) { - $attedanceDate = date('Y-m-d', strtotime($firstEntry['punch_time'])); - $clockInTime = date('H:i:s', strtotime($firstEntry['punch_time'])); - $clockOutTime = date('H:i:s', strtotime($lastEntry['punch_time'])); + if (!$employee) { + // Try fallback: maybe the employee isn't assigned to the branch but belongs to the same company + $employee = \App\Models\Employee::with('user') + ->where('created_by', $branch->created_by) + ->where('biometric_emp_id', $firstEntry['emp_code']) + ->first(); + } - $exists = \App\Models\AttendanceRecord::where('employee_id', $employee->user_id) - ->where('date', $attedanceDate) - ->exists(); + if ($employee) { + if ($sorted->count() > 1) { + $attedanceDate = date('Y-m-d', strtotime($firstEntry['punch_time'])); + $clockInTime = date('H:i:s', strtotime($firstEntry['punch_time'])); + $clockOutTime = date('H:i:s', strtotime($lastEntry['punch_time'])); - if (!$exists) { - $shift = \App\Models\Shift::where('id', $employee->shift_id)->where('status', 'active')->first() - ?? \App\Models\Shift::where('created_by', $branch->created_by)->where('status', 'active')->first(); - - $policy = \App\Models\AttendancePolicy::where('id', $employee->attendance_policy_id)->where('status', 'active')->first() - ?? \App\Models\AttendancePolicy::where('created_by', $branch->created_by)->where('status', 'active')->first(); - - $attendance = new \App\Models\AttendanceRecord(); - $attendance->employee_id = $employee->user_id; - $attendance->biometric_id = $firstEntry['id']; - $attendance->shift_id = $shift?->id; - $attendance->attendance_policy_id = $policy?->id; - $attendance->date = $attedanceDate; - $attendance->clock_in = $clockInTime; - $attendance->clock_out = $clockOutTime; - $attendance->created_by = $branch->created_by; - $attendance->save(); - - $attendance->fresh(); - $attendance->processAttendance(); - - $inserted++; + $exists = \App\Models\AttendanceRecord::where('employee_id', $employee->user_id) + ->where('date', $attedanceDate) + ->exists(); + + if (!$exists) { + $shift = \App\Models\Shift::where('id', $employee->shift_id)->where('status', 'active')->first() + ?? \App\Models\Shift::where('created_by', $branch->created_by)->where('status', 'active')->first(); + + $policy = \App\Models\AttendancePolicy::where('id', $employee->attendance_policy_id)->where('status', 'active')->first() + ?? \App\Models\AttendancePolicy::where('created_by', $branch->created_by)->where('status', 'active')->first(); + + $attendance = new \App\Models\AttendanceRecord(); + $attendance->employee_id = $employee->user_id; + $attendance->biometric_id = $firstEntry['id']; + $attendance->shift_id = $shift?->id; + $attendance->attendance_policy_id = $policy?->id; + $attendance->date = $attedanceDate; + $attendance->clock_in = $clockInTime; + $attendance->clock_out = $clockOutTime; + $attendance->created_by = $employee->created_by ?? $branch->created_by; + $attendance->save(); + + $attendance->fresh(); + $attendance->processAttendance(); + + $inserted++; + } else { + $skippedReasons[] = "Record already exists for Date: {$attedanceDate}"; + } + } else { + $skippedReasons[] = "Only 1 punch found for {$firstEntry['emp_code']} on " . date('Y-m-d', strtotime($firstEntry['punch_time'])) . " (Need Clock In and Out)"; } + } else { + $skippedReasons[] = "Employee with Biometric ID {$firstEntry['emp_code']} not found in Branch {$branch->id}"; } } + $debugMsg = empty($skippedReasons) ? "" : " | Skipped reasons: " . implode(', ', array_unique($skippedReasons)); + return response()->json([ 'success' => true, - 'message' => "Processed {$processed} unique daily records, Inserted {$inserted} new attendances.", + 'message' => "Processed {$processed} unique daily records, Inserted {$inserted} new attendances." . $debugMsg, ]); } }