Untitled
unknown
plain_text
8 months ago
65 kB
5
Indexable
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) {
http_response_code(403);
die('Direct access not allowed.');
}
class User
{
private AppContainer $container;
private PDO $db;
private $user_id;
private Permission $permission;
private Tenant $tenant;
private EmployeeWageRate $employeeWageRate;
private Mail $mail;
public function __construct(AppContainer $container)
{
$this->container = $container;
$this->db = $container->getDb();
$this->permission = $container->getPermission();
$this->tenant = $container->getTenant();
$this->employeeWageRate = $container->getEmployeeWageRate();
$this->mail = $container->getMail();
}
public function login($email, $password, $rememberMe=true)
{
try {
$sth = $this->db->prepare("SELECT * FROM Users WHERE LOWER(email) = LOWER(:email) AND is_active = 1 AND deleted_at IS NULL");
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
$user = $sth->fetch(PDO::FETCH_OBJ);
if (!$user) {
$this->insertLoginAttempt(null, 'failure', 'User: '.$email.' not found');
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 'error', 'message' => 'Invalid credentials.']);
}
$userId = $user->id;
$tenantId = $user->tenant_id;
$userRole = $user->role;
if ($user->is_blocked) {
$this->insertLoginAttempt($userId, 'failure', 'User is blocked');
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 'error', 'message' => 'Your account is blocked.']);
}
if (!password_verify($password, $user->password)) {
$this->increaseFailedLoginAttempts($userId);
if ($user->failed_login_attempts + 1 >= 5) {
$this->blockUser($userId);
}
$this->insertLoginAttempt($userId, 'failure', 'Invalid password');
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 'error', 'message' => 'Invalid credentials.']);
}
//delete
$this->resetFailedLoginAttempts($userId);
$this->insertLoginAttempt($userId, 'success', null);
$_SESSION['user_id'] = $userId;
$_SESSION['tenant_id'] = $tenantId;
$_SESSION['role'] = $userRole;
if ($rememberMe) {
$this->createRememberMeToken($userId, $tenantId);
}
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 'success', 'message' => 'Login successful.']);
} catch (PDOException $e) {
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
public function checkLogin(): object
{
try {
if (!isset($_COOKIE['remember_me'])) {
return (object) ['status' => 404, 'message' => 'remember_me not set.'];
}
$cookieParts = explode(':', $_COOKIE['remember_me']);
if (count($cookieParts) !== 4) {
return (object) ['status' => 400, 'message' => 'Invalid token format.'];
}
list($userId, $tenantId, $token, $hash) = $cookieParts;
$expectedHash = hash_hmac('sha256', "$userId:$tenantId:$token", 'secret_key');
if (!hash_equals($expectedHash, $hash)) {
return (object) ['status' => 403, 'message' => 'Invalid token signature.'];
}
$sth = $this->db->prepare("SELECT * FROM UserTokens WHERE user_id = :user_id AND token = :token");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':token', $token, PDO::PARAM_STR);
$sth->execute();
$row = $sth->fetch();
if ($sth->rowCount() > 0) {
$currentTime = time();
if ($currentTime < strtotime($row['expiry'])) {
$userData = $this->getUser($tenantId, $userId);
$_SESSION['user_id'] = $userId;
$_SESSION['tenant_id'] = $tenantId;
$_SESSION['role'] = $userData->data->role;
return (object) ['status' => 200, 'token' => $token];
} else {
setcookie('remember_me', '', time() - 3600, "/", "", true, true);
return (object) ['status' => 401, 'message' => 'Token expired.'];
}
}
return (object) ['status' => 403, 'message' => 'Data not found.'];
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
private function insertLoginAttempt($userId, $status, $failureReason = null)
{
try {
$sth = $this->db->prepare("
INSERT INTO LoginLogs (user_id, status, failure_reason, ip_address, user_agent)
VALUES (:user_id, :status, :failure_reason, :ip_address, :user_agent)
");
$sth->bindValue(':user_id', $userId, $userId ? PDO::PARAM_INT : PDO::PARAM_NULL);
$sth->bindValue(':status', $status, PDO::PARAM_STR);
$sth->bindValue(':failure_reason', $failureReason, PDO::PARAM_STR);
$sth->bindValue(':ip_address', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR);
$sth->bindValue(':user_agent', $_SERVER['HTTP_USER_AGENT'], PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'message' => 'Login log successfuly inserted.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to insert login log.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
private function increaseFailedLoginAttempts($userId)
{
try {
$sth = $this->db->prepare("UPDATE Users SET failed_login_attempts = failed_login_attempts + 1 WHERE id = :user_id");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'message' => 'Failed login attempts successfully updated.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to update failed login attempts.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
private function resetFailedLoginAttempts($userId)
{
try {
$sth = $this->db->prepare("UPDATE Users SET failed_login_attempts = 0 WHERE id = :user_id");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'message' => 'Failed login attempts successfully reset.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to reset failed login attempts.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
public function blockUser($userId)
{
try {
$sth = $this->db->prepare("UPDATE Users SET is_blocked = 1 WHERE id = :user_id");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'message' => 'User successfully blocked.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to block the user.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
public function unblockUser($userId)
{
try {
$sth = $this->db->prepare("UPDATE Users SET is_blocked = 0, failed_login_attempts = 0 WHERE id = :user_id");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'message' => 'User successfully unblocked.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to unblock the user.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
private function createRememberMeToken($userId, $tenantId)
{
try {
$token = bin2hex(random_bytes(32)); // 64-character token
$expiry = date('Y-m-d H:i:s', strtotime('+30 days'));
$sth = $this->db->prepare("SELECT COUNT(*) FROM UserTokens WHERE user_id = :user_id");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
$exists = $sth->fetchColumn() > 0;
if ($exists) {
$sth = $this->db->prepare("
UPDATE UserTokens
SET token = :token, expiry = :expiry
WHERE
tenant_id = :tenant_id AND
user_id = :user_id
");
} else {
$sth = $this->db->prepare("
INSERT INTO UserTokens (tenant_id, user_id, token, expiry)
VALUES (:tenant_id, :user_id, :token, :expiry)
");
}
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':token', $token, PDO::PARAM_STR);
$sth->bindValue(':expiry', $expiry, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
$cookieValue = $userId . ':' . $tenantId . ':' . $token;
$hashedValue = hash_hmac('sha256', $cookieValue, 'secret_key');
$cookieValue = $cookieValue . ':' . $hashedValue;
setcookie('remember_me', $cookieValue, strtotime($expiry), '/', '', true, true);
return json_encode(['status' => 'success', 'message' => 'Remember me token successfully inserted.']);
} else {
return json_encode(['status' => 'failure', 'message' => 'Failed to insert remember me token.']);
}
} catch (Exception $e) {
return json_encode(['status' => 'error', 'message' => 'Failed to create remember me token: ' . $e->getMessage()]);
}
}
public function logout()
{
try {
if (isset($_COOKIE['remember_me'])) {
$cookieValue = urldecode($_COOKIE['remember_me']);
$cookieParts = explode(':', $cookieValue);
$cookieParts = explode(':', $_COOKIE['remember_me']);
if (count($cookieParts) === 4) {
list($userId, $tenantId, $token, $hash) = $cookieParts;
$sth = $this->db->prepare("
DELETE FROM UserTokens
WHERE
tenant_id = :tenant_id AND
user_id = :user_id AND
token = :token
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':token', $token, PDO::PARAM_STR);
$sth->execute();
}
}
setcookie('remember_me', '', time() - 3600, '/', '', true, true);
unset($_SESSION['user_id']);
unset($_SESSION['tenant_id']);
session_destroy();
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 200, 'message' => 'Logout successful.']);
} catch (Exception $e) {
header('Content-Type: application/json; charset=utf-8');
return json_encode(['status' => 403, 'message' => 'Logout failed: ' . $e->getMessage()]);
}
}
public function setPassword($userId, $password, $newPassword1, $newPassword2)
{
try {
$password = password_hash($password, PASSWORD_DEFAULT);
$newPassword1 = password_hash($newPassword1, PASSWORD_DEFAULT);
$newPassword2 = password_hash($newPassword2, PASSWORD_DEFAULT);
if($newPassword1 != $newPassword2) {
return json_encode(['status' => 'failure', 'message' => 'Password 1 and 2 does not match.']);
}
$sth = $this->db->prepare('UPDATE Users SET password = :newPassword WHERE id = :user_id AND password = :password');
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':oldPassword', $password, PDO::PARAM_STR);
$sth->bindValue(':newPassword', $newPassword1, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
return json_encode(['status' => 200, 'message' => 'Password successfuly updated.']);
} else {
return json_encode(['status' => 403, 'message' => 'Failed to update the password.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Failed to update a password: ' . $e->getMessage()]);
}
}
public function getUser(int $tenantId, int $userId, ?int $employeeId = null): object
{
try {
$db = $this->container->getDb();
$query = "SELECT role FROM Users WHERE tenant_id = :tenant_id AND id = :user_id";
$roleStmt = $this->db->prepare($query);
$roleStmt->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$roleStmt->bindValue(':user_id', $userId, PDO::PARAM_INT);
$roleStmt->execute();
$userRole = $roleStmt->fetchColumn();
$useEmployeeId = ($employeeId !== null && in_array($userRole, ['ADMIN', 'ACCOUNTANT']));
$sth = $this->db->prepare("
SELECT
u.tenant_id,
u.email,
u.role,
u.employee_id_number,
u.first_name,
u.last_name,
u.gender,
u.language_id,
u.permanent_address,
u.permanent_postal_code,
u.permanent_city,
u.permanent_country_id,
u.temporary_address,
u.temporary_postal_code,
u.temporary_city,
u.temporary_country_id,
u.job_department_id,
u.job_position_id,
u.supervisor_user_id,
u.birth_date,
u.birth_place,
u.birth_country_id,
u.tax_number,
u.personal_id_number,
u.citizenship_country_id,
u.education,
u.base_gross_salary,
u.salary_bonus_1,
u.salary_bonus_2,
u.salary_bonus_3,
u.hourly_wage,
u.personal_email,
u.personal_phone_number,
u.work_email,
u.work_phone_number,
u.note,
u.is_active,
u.is_blocked,
u.employment_type_id,
u.default_location,
u.default_work_description,
CONCAT(u.first_name, ' ', u.last_name) AS user_full_name,
DATE_FORMAT(u.birth_date, '%d.%m.%Y') AS birth_date_formatted,
DATE_FORMAT(u.employment_date, '%d.%m.%Y') AS employment_date_formatted,
lbd.value AS default_lunch_break_duration,
COALESCE(FORMAT(cd.distance * 2, 2), NULL) AS commute_distance,
et.work_hours_capacity AS work_hours_capacity,
u.hours_balance,
REPLACE(FORMAT(u.hours_balance, 2), '.', ',') AS hours_balance_formatted,
CONCAT(
CASE
WHEN u.hours_balance < 0 THEN CONCAT('-', FLOOR(ABS(u.hours_balance)), ' h ')
ELSE CONCAT(FLOOR(u.hours_balance), ' h ')
END,
CASE
WHEN u.hours_balance < 0 THEN CONCAT(ROUND((ABS(u.hours_balance) - FLOOR(ABS(u.hours_balance))) * 60), ' min')
ELSE CONCAT(ROUND((u.hours_balance - FLOOR(u.hours_balance)) * 60), ' min')
END
) AS hours_minutes_balance_formatted,
CASE
WHEN u.is_active = 1 THEN 'Active'
ELSE 'Inactive'
END AS is_active_text,
CASE
WHEN u.is_blocked = 0 THEN 'Active'
ELSE 'Blocked'
END AS is_blocked_text,
u.employment_date,
DATE_FORMAT(COALESCE(ts.default_work_start_time, NOW()), '%H:%i:%s') AS default_work_start_time,
u.auto_log_work_hours,
DATE_FORMAT(u.auto_log_work_time_start, '%H:%i') AS auto_log_work_time_start,
u.password_reset,
u.allow_instant_work_log,
l.code AS language_code,
cb.name AS birth_country,
cc.name AS citizenship_country,
cpa.name AS permanent_country,
cta.name AS temporary_country,
et.type AS employment_type,
jd.job_department,
jb.job_position,
CONCAT(s.first_name, ' ', s.last_name) AS supervisor_full_name,
u.iban
FROM Users u
LEFT JOIN TenantLunchBreakDurations tlbd ON tlbd.employment_type_id = u.employment_type_id AND tlbd.is_default = 1 AND tlbd.tenant_id = :tenant_id
LEFT JOIN LunchBreakDuration lbd ON lbd.id = tlbd.lunch_break_duration_id
LEFT JOIN (
SELECT user_id, distance
FROM CommuteDistances
WHERE is_default = 1
) cd ON cd.user_id = u.id
LEFT JOIN EmploymentTypes et ON et.id = u.employment_type_id
LEFT JOIN TenantSettings ts ON ts.id = u.tenant_id
LEFT JOIN Languages l ON l.id = u.language_id
LEFT JOIN Countries cb ON cb.id = u.birth_country_id
LEFT JOIN Countries cc ON cc.id = u.citizenship_country_id
LEFT JOIN Countries cpa ON cpa.id = u.permanent_country_id
LEFT JOIN Countries cta ON cta.id = u.temporary_country_id
LEFT JOIN JobDepartments jd ON jd.id = u.job_department_id
LEFT JOIN JobPositions jb ON jb.id = u.job_position_id
LEFT JOIN Users s ON s.id = u.supervisor_user_id
WHERE
u.tenant_id = :tenant_id
AND u.id = :selected_user_id
AND u.deleted_at IS NULL
GROUP BY u.id;
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':selected_user_id', $useEmployeeId ? $employeeId : $userId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getUsers(int $tenantId, ?int $userId = null): object
{
try {
$sth = $this->db->prepare("
SELECT
u.*,
CONCAT(u.first_name, ' ', u.last_name) AS employee_full_name,
u.id,
u.tenant_id,
u.email,
role,
u.first_name,
u.last_name,
u.employment_type_id,
et.work_hours_capacity,
et.type,
u.employment_date,
u.auto_log_work_hours,
l.code AS language_code,
jd.job_department,
jp.job_position,
DATE_FORMAT(u.birth_date, '%d.%m.%Y') AS birth_date_formatted,
DATE_FORMAT(u.employment_date, '%d.%m.%Y') AS employment_date_formatted,
FORMAT(u.base_gross_salary, 2, 'de_DE') AS base_gross_salary_formatted
FROM Users u
LEFT JOIN EmploymentTypes et ON et.id = u.employment_type_id
LEFT JOIN Languages l ON l.id = u.language_id
LEFT JOIN JobDepartments jd ON jd.id = u.job_department_id
LEFT JOIN JobPositions jp ON jp.id = u.job_position_id
WHERE
u.tenant_id = :tenant_id AND
u.is_active = 1
ORDER BY et.work_hours_capacity DESC, employee_full_name ASC
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'No active users found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getSupervisors(int $tenantId, int $userId): object
{
try {
$sth = $this->db->prepare("
SELECT
u.id,
CONCAT(u.first_name, ' ', u.last_name) AS user_full_name
FROM Users u
WHERE
u.tenant_id = :tenant_id AND
u.is_active = 1 AND
u.is_supervisor = 1 AND
u.deleted_at IS NULL
GROUP BY u.id;
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getEmploymentTypes(int $tenantId, int $userId): object
{
try {
$sth = $this->db->prepare("
SELECT
et.*
FROM EmploymentTypes et
WHERE
et.is_active = 1
ORDER BY et.id;
");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
private function getuserIdByEmail(string $email): object
{
try {
$sth = $this->db->prepare("
SELECT id, tenant_id
FROM Users
WHERE
email = :email
");
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'user_id' => $result->id, 'tenant_id' => $result->tenant_id];
} else {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function changePassword(int $tenantId, int $userId, string $oldPassword, string $newPassword, string $confirmPassword): object
{
try {
$sth = $this->db->prepare("
SELECT password
FROM Users
WHERE id = :user_id AND tenant_id = :tenant_id
");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
$user = $sth->fetch(PDO::FETCH_OBJ);
if (!$user) {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
if (!password_verify($oldPassword, $user->password)) {
return (object) ['status' => 400, 'message' => 'Incorrect old password.'];
}
if ($newPassword !== $confirmPassword) {
return (object) ['status' => 400, 'message' => 'New password and confirmation do not match.'];
}
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
$sth = $this->db->prepare("
UPDATE Users
SET
password = :new_password,
password_reset = 1,
last_password_reset_date = NOW(),
modified_by = :modified_by,
modified_at = NOW()
WHERE id = :user_id AND tenant_id = :tenant_id
");
$sth->bindValue(':new_password', $hashedPassword, PDO::PARAM_STR);
$sth->bindValue(':modified_by', $userId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'message' => 'Password changed successfully.', 'translate' => 'password_changed_successfully'];
} else {
return (object) ['status' => 400, 'message' => 'Password change failed.', 'translate' => 'password_changed_failed'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function forgotPassword(string $email): object
{
try {
$mail = $this->container->getMail();
if ($this->checkUserEmailExists($email)) {
$userIdObject = $this->getuserIdByEmail($email);
$userId = $userIdObject->user_id;
$token = bin2hex(random_bytes(32));
$hashedToken = password_hash($token, PASSWORD_DEFAULT);
$expiresAt = date('Y-m-d H:i:s', strtotime('+1 hour'));
$sth = $this->db->prepare("DELETE FROM PasswordResets WHERE email = :email");
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
$sth = $this->db->prepare("
INSERT INTO PasswordResets (user_id, email, ip_address, user_agent, token, expires_at)
VALUES (:user_id, :email, :ip_address, :user_agent, :token, :expires_at)
");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->bindValue(':ip_address', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR);
$sth->bindValue(':user_agent', $_SERVER['HTTP_USER_AGENT'], PDO::PARAM_STR);
$sth->bindValue(':token', $hashedToken, PDO::PARAM_STR);
$sth->bindValue(':expires_at', $expiresAt, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
$mail->sendForgotPasswordToken($email, urlencode($token));
}
}
return (object) ['status' => 200, 'message' => 'If an account associated with the entered email exists, we will send further instructions to your email.', 'translate' => 'forgot_password_submited_text'];
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
} catch (Exception $e) {
return (object) ['status' => 500, 'message' => 'Error: ' . $e->getMessage()];
}
}
public function resetPassword(string $token, string $email, string $newPassword, string $confirmPassword): object
{
try {
$sth = $this->db->prepare("SELECT email, expires_at FROM PasswordResets WHERE token = :token");
$sth = $this->db->prepare("
SELECT token, email
FROM PasswordResets
WHERE
email = :email AND
expires_at >= NOW()");
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
$resetEntry = $sth->fetch(PDO::FETCH_ASSOC);
if (!$resetEntry) {
return (object) ['status' => 400, 'message' => 'Invalid or expired token. Please request a new password reset by using the "Forgot Password" feature again.', 'translate' => 'invalid_or_expired_token'];
}
if (!password_verify($token, $resetEntry['token'])) {
return (object) ['status' => 400, 'message' => 'Invalid token.', 'translate' => 'invalid_token'];
}
//$email = $resetEntry['email'];
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
$currentDateTime = date('Y-m-d H:i:s');
$sth = $this->db->prepare("
UPDATE Users
SET
password = :password,
password_reset = 1,
is_blocked = 0,
failed_login_attempts = 0,
last_password_reset_date = :last_password_reset_date
WHERE
email = :email AND
is_active = 1 AND
deleted_at IS NULL
");
$sth->bindValue(':password', $hashedPassword, PDO::PARAM_STR);
$sth->bindValue(':last_password_reset_date', $currentDateTime, PDO::PARAM_STR);
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'message' => 'Password successfully reset.', 'message' => 'password_reset_successfully'];
} else {
return (object) ['status' => 400, 'message' => 'Password reset failed.', 'translate' => 'password_reset_failed'];
}
}
catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getUserEmploymentType($userId)
{
try {
$sth = $this->db->prepare("
SELECT
*,
CONCAT(Users.first_name, ' ', Users.last_name) AS user_full_name
FROM Users
WHERE id = :user_id
");
$sth->bindValue(':user_id', $userId, PDO::PARAM_INT);
$sth->execute();
$user = $sth->fetch(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return json_encode(['status' => 'success', 'data' => $user]);
} else {
return json_encode(['status' => 'failure', 'message' => 'User not found.']);
}
} catch (PDOException $e) {
return json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
}
public function getNotificationReceivers($tenantId): object
{
try {
$sth = $this->db->prepare("
SELECT
u.email,
u.daily_summary_notification,
u.work_session_update_notification,
u.work_session_delete_notification,
l.code AS language_code
FROM Users u
LEFT JOIN Languages l ON l.id = u.language_id
WHERE
u.tenant_id = :tenant_id AND
u.role = 'ADMIN' AND
u.is_active = 1
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'User not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
// Admin section
public function insertEmployee(int $tenantId, int $userId, array $data): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new users');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new role has user');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new commute distances');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new employee annual leave');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
$canAddNewUser = $this->tenant->canAddNewUser($tenantId);
if ($canAddNewUser->status !== 200) {
return $canAddNewUser;
}
if ($this->checkUserEmailExists($data['login_email_address'])) {
return (object) ['status' => 409, 'message' => 'User with this email already exists.', 'translate' => 'user_email_exists'];
}
try {
$sth = $this->db->prepare("
INSERT INTO Users (
tenant_id,
email,
password,
first_name,
last_name,
birth_date,
birth_place,
birth_country_id,
citizenship_country_id,
employee_id_number,
personal_id_number,
tax_number,
education,
permanent_address,
permanent_postal_code,
permanent_city,
permanent_country_id,
temporary_address,
temporary_postal_code,
temporary_city,
temporary_country_id,
personal_email,
personal_phone_number,
work_email,
work_phone_number,
employment_type_id,
employment_date,
job_department_id,
job_position_id,
supervisor_user_id,
default_work_description,
iban,
is_active,
is_blocked,
note,
created_by,
created_at
) VALUES (
:tenant_id,
:login_email_address,
:password,
:first_name,
:last_name,
:birth_date,
:birth_place,
:birth_country_id,
:citizenship_country_id,
:employee_id_number,
:personal_id_number,
:tax_number,
:education,
:permanent_address,
:permanent_postal_code,
:permanent_city,
:permanent_country_id,
:temporary_address,
:temporary_postal_code,
:temporary_city,
:temporary_country_id,
:personal_email,
:personal_phone_number,
:work_email,
:work_phone_number,
:employment_type_id,
:employment_date,
:job_department_id,
:job_position_id,
:supervisor_user_id,
:default_work_description,
:iban,
:is_active,
:is_blocked,
:note,
:created_by,
NOW()
)");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':login_email_address', $data['login_email_address'], PDO::PARAM_STR);
$sth->bindValue(':password', password_hash($data['password'], PASSWORD_DEFAULT), PDO::PARAM_STR);
$sth->bindValue(':first_name', $data['first_name'], PDO::PARAM_STR);
$sth->bindValue(':last_name', $data['last_name'], PDO::PARAM_STR);
$sth->bindValue(':birth_date', $data['birth_date'], PDO::PARAM_STR);
$sth->bindValue(':birth_place', $data['birth_place'], PDO::PARAM_STR);
$sth->bindValue(':birth_country_id', $data['birth_country'], PDO::PARAM_STR);
$sth->bindValue(':citizenship_country_id', $data['citizenship_country'], PDO::PARAM_STR);
$sth->bindValue(':employee_id_number', $data['employee_id_number'], PDO::PARAM_STR);
$sth->bindValue(':personal_id_number', $data['personal_id_number'], PDO::PARAM_STR);
$sth->bindValue(':tax_number', $data['tax_number'], PDO::PARAM_STR);
$sth->bindValue(':education', $data['education'], PDO::PARAM_STR);
$sth->bindValue(':permanent_address', $data['permanent_address'], PDO::PARAM_STR);
$sth->bindValue(':permanent_postal_code', $data['permanent_postal_code'], PDO::PARAM_STR);
$sth->bindValue(':permanent_city', $data['permanent_city'], PDO::PARAM_STR);
$sth->bindValue(':permanent_country_id', $data['permanent_country'], PDO::PARAM_STR);
$sth->bindValue(':temporary_address', $data['temporary_address'], PDO::PARAM_STR);
$sth->bindValue(':temporary_postal_code', $data['temporary_postal_code'], PDO::PARAM_STR);
$sth->bindValue(':temporary_city', $data['temporary_city'], PDO::PARAM_STR);
$sth->bindValue(':temporary_country_id', $data['temporary_country'], PDO::PARAM_STR);
$sth->bindValue(':personal_email', $data['personal_email'], PDO::PARAM_STR);
$sth->bindValue(':personal_phone_number', $data['personal_phone_number'], PDO::PARAM_STR);
$sth->bindValue(':work_email', $data['work_email'], PDO::PARAM_STR);
$sth->bindValue(':work_phone_number', $data['work_phone_number'], PDO::PARAM_STR);
$sth->bindValue(':employment_type_id', $data['employment_type'], PDO::PARAM_STR);
$sth->bindValue(':employment_date', $data['employment_date'], PDO::PARAM_STR);
$sth->bindValue(':job_department_id', $data['job_department'], PDO::PARAM_STR);
$sth->bindValue(':job_position_id', $data['job_position'], PDO::PARAM_STR);
$sth->bindValue(':supervisor_user_id', $data['supervisor'], PDO::PARAM_STR);
$sth->bindValue(':default_work_description', $data['default_work_description'], PDO::PARAM_STR);
$sth->bindValue(':iban', $data['iban'], PDO::PARAM_STR);
$sth->bindValue(':is_active', $data['employee_status'], PDO::PARAM_STR);
$sth->bindValue(':is_blocked', $data['account_status'], PDO::PARAM_STR);
$sth->bindValue(':note', $data['note'], PDO::PARAM_STR);
$sth->bindValue(':created_by', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
$employeeId = $db->lastInsertId();
$employeeData = [
'user_id' => $employeeId,
'commute_location_id' => $data['commute_location_id'],
'distance' => $data['commute_distance'],
'is_default' => 1,
'annual_leave_year' => $data['annual_leave_year'],
'annual_leave_days' => $data['annual_leave_days'],
'effective_date' => $data['employment_date'],
'employee_id' => $employeeId,
'base_gross_salary' => $data['base_gross_salary'],
'salary_bonus_1' => $data['salary_bonus_1'],
'salary_bonus_1' => $data['salary_bonus_1'],
'salary_bonus_2' => $data['salary_bonus_2'],
'salary_bonus_3' => $data['salary_bonus_3'],
'hourly_wage' => $data['hourly_wage'],
'regular_overtime_hourly_rate' => $data['regular_overtime_hourly_rate'],
'special_overtime_hourly_rate' => $data['special_overtime_hourly_rate'],
];
$insertRoleHasUserStatus = $this->insertRoleHasUser($tenantId, $userId, $data['user_role'], $employeeId);
if($data['employment_type'] < 3) {
$insertCommuteDistanceStatus = $this->insertCommuteDistance($tenantId, $userId, $employeeData);
$insertEmployeeAnnualLeaveStatus = $this->insertEmployeeAnnualLeave($tenantId, $userId, $employeeData);
$employeeWageRateStatus = $this->employeeWageRate->insertEmployeeWageRate($tenantId, $userId, $employeeData);
if($insertCommuteDistanceStatus->status == 201 && $insertRoleHasUserStatus->status == 201 && $insertEmployeeAnnualLeaveStatus->status == 201 && $employeeWageRateStatus->status == 201) {
return (object) ['status' => 201, 'message' => 'Employee was successfully inserted.', 'translate' => 'employee_was_successfully_inserted'];
}
else {
return (object) ['status' => 404, 'message' => 'Error. Check for details.', 'insertCommuteDistanceStatus' => $insertCommuteDistanceStatus, 'insertRoleHasUserStatus' => $insertRoleHasUserStatus, 'insertEmployeeAnnualLeaveStatus' => $insertEmployeeAnnualLeaveStatus, 'employeeWageRateStatus' => $employeeWageRateStatus];
}
}
else {
return (object) ['status' => 201, 'message' => 'Employee was successfully inserted.', 'translate' => 'employee_was_successfully_inserted'];
}
} else {
return (object) ['status' => 404, 'message' => 'Error: employee not inserted successfully.', 'translate' => 'employee_not_inserted_successfully'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function checkUserEmailExists(string $email): bool
{
try {
$query = "
SELECT COUNT(*)
FROM Users
WHERE
email = :email AND
deleted_at IS NULL AND
is_active = 1
";
$sth = $this->db->prepare($query);
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->execute();
$count = $sth->fetchColumn();
return $count > 0;
} catch (PDOException $e) {
return false;
}
}
public function updateEmployee(int $tenantId, int $userId, array $data): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can update users');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
UPDATE Users
SET
first_name = :first_name,
last_name = :last_name,
birth_date = :birth_date,
birth_place = :birth_place,
birth_country_id = :birth_country_id,
citizenship_country_id = :citizenship_country_id,
employee_id_number = :employee_id_number,
personal_id_number = :personal_id_number,
tax_number = :tax_number,
education = :education,
permanent_address = :permanent_address,
permanent_postal_code = :permanent_postal_code,
permanent_city = :permanent_city,
permanent_country_id = :permanent_country_id,
temporary_address = :temporary_address,
temporary_postal_code = :temporary_postal_code,
temporary_city = :temporary_city,
temporary_country_id = :temporary_country_id,
personal_email = :personal_email,
personal_phone_number = :personal_phone_number,
work_email = :work_email,
work_phone_number = :work_phone_number,
employment_type_id = :employment_type_id,
employment_date = :employment_date,
job_department_id = :job_department_id,
job_position_id = :job_position_id,
supervisor_user_id = :supervisor_user_id,
base_gross_salary = :base_gross_salary,
salary_bonus_1 = :salary_bonus_1,
salary_bonus_2 = :salary_bonus_2,
salary_bonus_3 = :salary_bonus_3,
hourly_wage = :hourly_wage,
iban = :iban,
is_active = :is_active,
is_blocked = :is_blocked,
note = :note,
modified_by = :modified_by,
modified_at = NOW()
WHERE
tenant_id = :tenant_id AND
id = :employee_id
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':employee_id', $data['employee_id'], PDO::PARAM_STR);
$sth->bindValue(':modified_by', $userId, PDO::PARAM_INT);
$sth->bindValue(':first_name', $data['first_name'], PDO::PARAM_STR);
$sth->bindValue(':last_name', $data['last_name'], PDO::PARAM_STR);
$sth->bindValue(':birth_date', $data['birth_date'], PDO::PARAM_STR);
$sth->bindValue(':birth_place', $data['birth_place'], PDO::PARAM_STR);
$sth->bindValue(':birth_country_id', $data['birth_country'], PDO::PARAM_STR);
$sth->bindValue(':citizenship_country_id', $data['citizenship_country'], PDO::PARAM_STR);
$sth->bindValue(':employee_id_number', $data['employee_id_number'], PDO::PARAM_STR);
$sth->bindValue(':personal_id_number', $data['personal_id_number'], PDO::PARAM_STR);
$sth->bindValue(':tax_number', $data['tax_number'], PDO::PARAM_STR);
$sth->bindValue(':education', $data['education'], PDO::PARAM_STR);
$sth->bindValue(':permanent_address', $data['permanent_address'], PDO::PARAM_STR);
$sth->bindValue(':permanent_postal_code', $data['permanent_postal_code'], PDO::PARAM_STR);
$sth->bindValue(':permanent_city', $data['permanent_city'], PDO::PARAM_STR);
$sth->bindValue(':permanent_country_id', $data['permanent_country'], PDO::PARAM_STR);
$sth->bindValue(':temporary_address', $data['temporary_address'], PDO::PARAM_STR);
$sth->bindValue(':temporary_postal_code', $data['temporary_postal_code'], PDO::PARAM_STR);
$sth->bindValue(':temporary_city', $data['temporary_city'], PDO::PARAM_STR);
$sth->bindValue(':temporary_country_id', $data['temporary_country'], PDO::PARAM_STR);
$sth->bindValue(':personal_email', $data['personal_email'], PDO::PARAM_STR);
$sth->bindValue(':personal_phone_number', $data['personal_phone_number'], PDO::PARAM_STR);
$sth->bindValue(':work_email', $data['work_email'], PDO::PARAM_STR);
$sth->bindValue(':work_phone_number', $data['work_phone_number'], PDO::PARAM_STR);
$sth->bindValue(':employment_type_id', $data['employment_type'], PDO::PARAM_STR);
$sth->bindValue(':employment_date', $data['employment_date'], PDO::PARAM_STR);
$sth->bindValue(':job_department_id', $data['job_department'], PDO::PARAM_STR);
$sth->bindValue(':job_position_id', $data['job_position'], PDO::PARAM_STR);
$sth->bindValue(':supervisor_user_id', $data['supervisor'], PDO::PARAM_STR);
$sth->bindValue(':base_gross_salary', $data['base_gross_salary'], PDO::PARAM_STR);
$sth->bindValue(':salary_bonus_1', $data['salary_bonus_1'], PDO::PARAM_STR);
$sth->bindValue(':salary_bonus_2', $data['salary_bonus_2'], PDO::PARAM_STR);
$sth->bindValue(':salary_bonus_3', $data['salary_bonus_3'], PDO::PARAM_STR);
$sth->bindValue(':hourly_wage', $data['hourly_wage'], PDO::PARAM_STR);
$sth->bindValue(':iban', $data['iban'], PDO::PARAM_STR);
$sth->bindValue(':is_active', $data['employee_status'], PDO::PARAM_STR);
$sth->bindValue(':is_blocked', $data['account_status'], PDO::PARAM_STR);
$sth->bindValue(':note', $data['note'], PDO::PARAM_STR);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'message' => 'Employee was successfully updated.', 'translate' => 'employee_was_successfully_updated'];
} else {
return (object) ['status' => 404, 'message' => 'User not found.', 'translate' => 'user_not_found'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function deleteEmployee(int $tenantId, int $userId, int $employeeId): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can delete users');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
UPDATE Users
SET
deleted_by = :deleted_by,
is_active = 0,
deleted_at = NOW()
WHERE
tenant_id = :tenant_id AND
id = :employee_id
");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':employee_id', $employeeId, PDO::PARAM_INT);
$sth->bindValue(':deleted_by', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'message' => 'Employee was successfully deleted.', 'translate' => 'employee_was_successfully_deleted'];
} else {
return (object) ['status' => 404, 'message' => 'User not found.', 'translate' => 'user_not_found'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function insertCommuteDistance(int $tenantId, int $userId, array $data): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new commute distances');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
INSERT INTO CommuteDistances (
tenant_id,
commute_location_id,
user_id,
distance,
is_default,
created_by,
created_at
) VALUES (
:tenant_id,
:commute_location_id,
:user_id,
:distance,
:is_default,
:created_by,
NOW()
)");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':commute_location_id', $data['commute_location_id'], PDO::PARAM_INT);
$sth->bindValue(':user_id', $data['user_id'], PDO::PARAM_INT);
$sth->bindValue(':distance', $data['distance'], PDO::PARAM_STR);
$sth->bindValue(':is_default', $data['is_default'], PDO::PARAM_INT);
$sth->bindValue(':created_by', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 201, 'message' => 'Commute distance inserted successfully.', 'translate' => 'commute_distance_inserted_successfully'];
} else {
return (object) ['status' => 404, 'message' => 'Error: commute distance not inserted successfully.', 'translate' => 'commute_distance_not_inserted_successfully'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function insertRoleHasUser(int $tenantId, int $userId, int $roleId, int $employeeId): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new role has user');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
INSERT INTO RoleHasUser (
role_id,
tenant_id,
user_id
) VALUES (
:role_id,
:tenant_id,
:user_id
)");
$sth->bindValue(':role_id', $roleId, PDO::PARAM_INT);
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $employeeId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 201, 'message' => 'Role has been successfully allocated to user.', 'translate' => 'role_has_been_successfully_allocated_to_user'];
} else {
return (object) ['status' => 404, 'message' => 'Error: role was not successfully allocated to user.', 'translate' => 'role_was_not_successfully_allocated_to_user'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getUserRoles(int $tenantId, int $userId): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can view roles');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
SELECT
r.*
FROM Roles r
WHERE
r.is_active = 1
");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'Roles not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function insertEmployeeAnnualLeave(int $tenantId, int $userId, array $data): object
{
$permissionCheck = $this->permission->checkPermission($tenantId, $userId, 'Can add new role has user');
if ($permissionCheck->status !== 200) {
return $permissionCheck;
}
try {
$sth = $this->db->prepare("
INSERT INTO EmployeeAnnualLeave (
tenant_id,
user_id,
year,
annual_leave_days,
used_days,
is_expired,
created_by,
created_at
) VALUES (
:tenant_id,
:user_id,
:year,
:annual_leave_days,
:used_days,
:is_expired,
:created_by,
NOW()
)");
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $data['user_id'], PDO::PARAM_INT);
$sth->bindValue(':year', $data['annual_leave_year'], PDO::PARAM_STR);
$sth->bindValue(':annual_leave_days', $data['annual_leave_days'], PDO::PARAM_STR);
$sth->bindValue(':used_days', 0, PDO::PARAM_STR);
$sth->bindValue(':is_expired', 0, PDO::PARAM_INT);
$sth->bindValue(':created_by', $userId, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 201, 'message' => 'Annual leave been successfully allocated to user.', 'translate' => 'annual_leave_has_been_successfully_allocated_to_user'];
} else {
return (object) ['status' => 404, 'message' => 'Error: annual leave was not successfully allocated to user.', 'translate' => 'annual_leave_was_not_successfully_allocated_to_user'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function getEmployeesHoursBalance(int $tenantId, string $userId): object
{
try {
$query = "
SELECT
CONCAT(u.first_name, ' ', u.last_name) AS employee_full_name,
u.hours_balance AS posted_hours_balance,
FORMAT(u.hours_balance, 2, 'de_DE') AS posted_hours_balance_formatted,
IFNULL(SUM(ds.non_working_hours), 0) AS total_non_working_hours,
IFNULL(SUM(ds.surplus_hours), 0) AS total_surplus_hours,
IFNULL(SUM(ds.surplus_hours), 0) - IFNULL(SUM(ds.non_working_hours), 0) AS current_balance,
(u.hours_balance + (IFNULL(SUM(ds.surplus_hours), 0) - IFNULL(SUM(ds.non_working_hours), 0))) AS actual_hours_balance,
FORMAT((u.hours_balance + (IFNULL(SUM(ds.surplus_hours), 0) - IFNULL(SUM(ds.non_working_hours), 0))), 2, 'de_DE') AS actual_balance_formatted
FROM Users u
LEFT JOIN DailySummaries ds ON u.id = ds.user_id AND ds.date BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())
WHERE
u.tenant_id = :tenant_id AND
u.employment_type_id < 3 AND
u.is_active = 1 AND
u.deleted_at IS NULL AND
ds.deleted_at IS NULL
GROUP BY u.id
ORDER BY employee_full_name ASC;
";
$sth = $this->db->prepare($query);
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_OBJ);
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'data' => $result];
} else {
return (object) ['status' => 404, 'message' => 'Employees not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function updateUserHoursBalance(int $tenantId, int $userId, int $employeeId, float $hoursBalance): Object
{
try {
$query = "
UPDATE Users u
SET
u.hours_balance = :hours_balance,
u.modified_by = :modified_by,
u.modified_at = NOW()
WHERE
u.tenant_id = :tenant_id AND
u.id = :user_id AND
u.hours_balance >= 0
";
$sth = $this->db->prepare($query);
$sth->bindValue(':tenant_id', $tenantId, PDO::PARAM_INT);
$sth->bindValue(':modified_by', $userId, PDO::PARAM_INT);
$sth->bindValue(':user_id', $employeeId, PDO::PARAM_INT);
$sth->bindValue(':hours_balance', $hoursBalance, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
return (object) ['status' => 200, 'message' => 'Balance hours successfully updated.'];
} else {
return (object) ['status' => 404, 'message' => 'Employee not found.'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
public function checkUserIpAddress(int $tenantId, int $userId): Object
{
try {
$tenantSettings = $this->tenant->getTenantSettings($tenantId);
$companyIpAddress = $tenantSettings->data->company_ip;
$userIpAddress = $_SERVER['REMOTE_ADDR'];
if ($companyIpAddress == $userIpAddress ) {
return (object) ['status' => 200, 'userOnLocation' => true, 'message' => "You are at the company location.", 'translate' => 'you_are_at_the_company_location'];
} else {
return (object) ['status' => 200, 'userOnLocation' => false, 'message' => "You are not at the company location.", 'translate' => 'you_are_not_at_the_company_location'];
}
} catch (PDOException $e) {
return (object) ['status' => 500, 'message' => 'Database error: ' . $e->getMessage()];
}
}
}
?>Editor is loading...
Leave a Comment