106 lines
3.6 KiB
PHP
106 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use App\Models\Branch;
|
|
use App\Models\AttendanceEmployee;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class AttendanceSyncController extends Controller
|
|
{
|
|
public function sync(Request $request)
|
|
{
|
|
// 1. Verify API Key
|
|
$apiKey = $request->header('X-API-Key') ?? $request->input('api_key');
|
|
// You should store a master API key in your .env like ZKTECO_SYNC_KEY=xxx
|
|
$validKey = env('ZKTECO_SYNC_KEY', 'default_secure_sync_key_123');
|
|
|
|
if ($apiKey !== $validKey) {
|
|
Log::warning('Unauthorized ZKTeco sync attempt', ['ip' => $request->ip()]);
|
|
return response()->json(['error' => 'Unauthorized'], 401);
|
|
}
|
|
|
|
$branchId = $request->input('branch_id');
|
|
$zktecoIp = $request->input('zkteco_ip');
|
|
$attendances = $request->input('attendances', []);
|
|
|
|
if (empty($attendances)) {
|
|
return response()->json(['message' => 'No attendance records provided'], 400);
|
|
}
|
|
|
|
// 2. Find the branch
|
|
$branchQuery = Branch::query();
|
|
if ($branchId) {
|
|
$branchQuery->where('id', $branchId);
|
|
} elseif ($zktecoIp) {
|
|
$branchQuery->where('zkteco_ip', $zktecoIp);
|
|
} else {
|
|
return response()->json(['error' => 'Must provide branch_id or zkteco_ip'], 400);
|
|
}
|
|
|
|
$branch = $branchQuery->first();
|
|
|
|
if (!$branch) {
|
|
return response()->json(['error' => 'Branch not found'], 404);
|
|
}
|
|
|
|
// 3. Process the logs (same logic as BiometricAttendanceController)
|
|
$processed = 0;
|
|
$inserted = 0;
|
|
|
|
foreach ($attendances as $record) {
|
|
$processed++;
|
|
// Typical payload from zklib-js: { userSn: 1, deviceUserId: '1', recordTime: '2023-10-14 08:30:00' }
|
|
$empCode = $record['deviceUserId'] ?? $record['id'] ?? null;
|
|
$punchTime = $record['recordTime'] ?? $record['timestamp'] ?? null;
|
|
|
|
if (!$empCode || !$punchTime) {
|
|
continue;
|
|
}
|
|
|
|
// Find employee by emp_code inside this branch's company
|
|
$employee = \App\Models\Employee::where('emp_code', $empCode)
|
|
->where('created_by', $branch->created_by)
|
|
->first();
|
|
|
|
if (!$employee) {
|
|
continue;
|
|
}
|
|
|
|
// Parse date and time
|
|
$ts = strtotime($punchTime);
|
|
$date = date('Y-m-d', $ts);
|
|
$time = date('H:i:s', $ts);
|
|
|
|
// Check if record already exists to prevent duplicates
|
|
$exists = AttendanceEmployee::where('employee_id', $employee->id)
|
|
->where('date', $date)
|
|
->where('clock_in', $time)
|
|
->exists();
|
|
|
|
if (!$exists) {
|
|
AttendanceEmployee::create([
|
|
'employee_id' => $employee->id,
|
|
'date' => $date,
|
|
'status' => 'Present',
|
|
'clock_in' => $time,
|
|
'clock_out' => '00:00:00',
|
|
'late' => '00:00:00',
|
|
'early_leaving' => '00:00:00',
|
|
'overtime' => '00:00:00',
|
|
'total_rest' => '00:00:00',
|
|
'created_by' => $branch->created_by,
|
|
]);
|
|
$inserted++;
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => "Processed {$processed} records, Inserted {$inserted} new attendances.",
|
|
]);
|
|
}
|
|
}
|