Travel reimburse feature added

This commit is contained in:
2026-07-07 22:48:57 +02:00
parent e1ef2456ea
commit 30269316b2
29 changed files with 21392 additions and 26 deletions

View File

@@ -2,6 +2,7 @@
namespace api\classes;
use DateTime;
use JetBrains\PhpStorm\NoReturn;
class API
@@ -91,7 +92,7 @@ class API
// When building a frontend page, you can still programmatically construct a builder array
// and set it via $_GET like so after the API class creation:
// $_GET['builder'] = [1 => ['where' => [0 => 'permission_uuid', 1 => $permission_uuid]]];
if ($this->request_method !== 'GET' || $this->user_type === 'frontend') {
if ($this->request_method !== 'GET') {
$this->disableBuilder();
}
@@ -335,6 +336,14 @@ class API
if (!is_array($value)) return false;
return $value;
case 'date':
if (!is_string($value)) return false;
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
return false;
}
[$year, $month, $day] = explode('-', $value);
return checkdate((int)$month, (int)$day, (int)$year);
default:
return false;
}
@@ -599,12 +608,7 @@ class API
if ($this->user_type === 'api') {
http_response_code($code);
header('Content-Type: application/json');
if ($code === 200) {
echo json_encode(reset($data));
} else {
echo json_encode($data);
}
echo json_encode($data);
exit;
}
@@ -682,6 +686,12 @@ class API
}
}
protected function isValidDate(string $date): bool
{
$dt = DateTime::createFromFormat('Y-m-d', $date);
return $dt && $dt->format('Y-m-d') === $date;
}
protected function buildDynamicQuery(string $tableName): array
{
$this->allowedGetColumns = $this->loadTableColumns($tableName);
@@ -699,20 +709,48 @@ class API
}
foreach ($_GET['builder'] as $builder) {
if (!isset($builder['where']) || !is_array($builder['where']) || count($builder['where']) !== 2) {
continue;
if (isset($builder['where']) && is_array($builder['where'])) {
if (count($builder['where']) !== 2) {
continue;
}
$column = $builder['where'][0];
$value = $builder['where'][1];
if (!in_array($column, $this->allowedGetColumns, true)) {
$this->apiOutput(400, ['error' => "The column $column is not allowed."]);
}
$whereClauses[] = "$column = ?";
$types .= 's';
$values[] = $value;
}
$column = $builder['where'][0];
$value = $builder['where'][1];
// BETWEEN (for DATE / range fields)
if (isset($builder['between']) && is_array($builder['between'])) {
if (!in_array($column, $this->allowedGetColumns, true)) {
$this->apiOutput(400, ['error' => 'The column ' . $column . ' is not allowed.']);
if (count($builder['between']) !== 3) {
continue;
}
$column = $builder['between'][0];
$from = $builder['between'][1];
$to = $builder['between'][2];
if (!in_array($column, $this->allowedGetColumns, true)) {
$this->apiOutput(400, ['error' => "The column $column is not allowed."]);
}
if (!$this->isValidDate($from) || !$this->isValidDate($to)) {
$this->apiOutput(400, ['error' => "Invalid date format for BETWEEN."]);
}
$whereClauses[] = "$column BETWEEN ? AND ?";
$types .= 'ss';
$values[] = $from;
$values[] = $to;
}
$whereClauses[] = "$column = ?";
$types .= 's';
$values[] = $value;
}
if (!empty($whereClauses)) {

View File

@@ -8,7 +8,7 @@ require_once 'API.php';
class API_companies extends API
{
public function updateCompanyState()
public function updateCompanyState(): void
{
$query = "UPDATE companies SET company_state = ? WHERE company_uuid = ?";
$stmt = $this->prepareStatement($query);
@@ -17,4 +17,13 @@ class API_companies extends API
$this->apiOutput(200, ['success' => 'company state successfully updated']);
}
}
public function getCompanies(): array
{
list($query, $types, $params) = $this->buildDynamicQuery('companies');
$items = $this->generalGetFunction($query, $types, $params, false, 'Companies');
return ($items);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace api\classes;
use api\classes\API;
use JetBrains\PhpStorm\NoReturn;
use PDO;
use api\classes\API_companies;
require_once 'API.php';
require_once 'API_companies.php';
class API_office_travel_reimburse extends API
{
#[NoReturn]
public function createTravelReimburse(): void
{
$query = " INSERT INTO office_travelreimburse (
reimburse_uuid,
user_uuid,
departure_postcode,
destination_postcode,
travel_distance,
travel_description,
travel_date,
office_travelreimburse_company_uuid,
office_travelreimburse_company_name,
homework
)
VALUES (UUID(),
:user_uuid,
:departure_postcode,
:destination_postcode,
:travel_distance,
:travel_description,
:travel_date,
:office_travelreimburse_company_uuid,
:office_travelreimburse_company_name,
:homework
)";
$stmt = $this->pdo->prepare($query);
$stmt->bindValue(':user_uuid', $this->data['user_uuid']);
$stmt->bindValue(':departure_postcode', $this->data['departure_postcode']);
$stmt->bindValue(':destination_postcode', $this->data['destination_postcode']);
$stmt->bindValue(':travel_distance', $this->data['travel_distance']);
$stmt->bindValue(':travel_date', $this->data['travel_date']);
$stmt->bindValue(':office_travelreimburse_company_uuid', $this->data['office_travelreimburse_company_uuid']);
$stmt->bindValue(':office_travelreimburse_company_name', $this->data['office_travelreimburse_company_name']);
$stmt->bindValue(':homework', $this->data['homework']);
// Optional fields
$stmt->bindValue(':travel_description', $this->data['travel_description'] ?? null, $this->data['travel_description'] ?? null ? PDO::PARAM_STR : PDO::PARAM_NULL);
$stmt->execute();
$this->apiOutput(200, ['success' => 'Travel reimburse added.']);
}
public function getTravelReimburse(): array
{
list($query, $types, $params) = $this->buildDynamicQuery('office_travelreimburse');
$items = $this->generalGetFunction($query, $types, $params, false, 'TravelReimburse');
return ($items);
}
#[NoReturn]
public function updateTravelReimburse(): void
{
$query = "UPDATE office_travelreimburse SET
user_uuid = :user_uuid,
departure_postcode = :departure_postcode,
destination_postcode = :destination_postcode,
travel_date = :travel_date,
travel_distance = :travel_distance,
travel_description = :travel_description,
office_travelreimburse_company_uuid = :office_travelreimburse_company_uuid,
office_travelreimburse_company_name = :office_travelreimburse_company_name,
homework = :homework
WHERE reimburse_uuid = :reimburse_uuid";
$stmt = $this->pdo->prepare($query);
$stmt->bindValue(':reimburse_uuid', $this->data['reimburse_uuid'], PDO::PARAM_STR);
$stmt->bindValue(':user_uuid', $this->data['user_uuid'], PDO::PARAM_STR);
$stmt->bindValue(':departure_postcode', $this->data['departure_postcode'], PDO::PARAM_STR);
$stmt->bindValue(':destination_postcode', $this->data['destination_postcode'], PDO::PARAM_STR);
$stmt->bindValue(':travel_date', $this->data['travel_date'], PDO::PARAM_STR);
$stmt->bindValue(':travel_distance', $this->data['travel_distance'], PDO::PARAM_INT);
$stmt->bindValue(':office_travelreimburse_company_uuid', $this->data['office_travelreimburse_company_uuid'], PDO::PARAM_STR);
$stmt->bindValue(':office_travelreimburse_company_name', $this->data['office_travelreimburse_company_name'], PDO::PARAM_STR);
$stmt->bindValue(':homework', $this->data['homework'], PDO::PARAM_BOOL);
// Optional fields
$stmt->bindValue(':travel_description', $this->data['travel_description'] ?? null, isset($this->data['travel_description']) && $this->data['travel_description'] !== null ? PDO::PARAM_STR : PDO::PARAM_NULL);
$stmt->execute();
if ($stmt->rowCount() === 0) {
$check = $this->pdo->prepare(
"SELECT 1 FROM office_travelreimburse WHERE reimburse_uuid = :uuid"
);
$check->execute([
':uuid' => $this->data['reimburse_uuid']
]);
if (!$check->fetchColumn()) {
$this->apiOutput(404, ['error' => 'Travel reimbursement not found.']);
}
}
$this->apiOutput(200, ['success' => 'Travel reimbursement updated.']);
}
#[NoReturn]
public function deleteTravelReimburse(): void
{
$query = "DELETE FROM office_travelreimburse WHERE reimburse_uuid = ? AND user_uuid = ?";
$stmt = $this->prepareStatement($query);
$stmt->bind_param('ss', $this->data['reimburse_uuid'], $_SESSION['user']['user_uuid']);
$this->executeStatement($stmt);
if ($stmt->affected_rows === 0) {
$stmt->close();
$this->apiOutput(403, ['error' => 'Travel reimbursement not found or you do not have permission to delete it.']);
}
$stmt->close();
$this->apiOutput(200, ['success' => 'Travel reimburse removed.']);
}
public function setTravelReimburseCompany(): void
{
$API_companies = new API_companies();
if (!empty($GLOBALS['modules_enabled']['customers'])) {
$companies = $API_companies->getCompanies();
$companyUuid = $this->postedData['office_travelreimburse_company_uuid'] ?? null;
if ($companyUuid) {
foreach ($companies as $company) {
if ($company['company_uuid'] === $companyUuid) {
$this->postedData['office_travelreimburse_company_name'] = $company['company_name'];
break;
}
}
}
}
}
}

View File

@@ -28,4 +28,30 @@ class API_portalsettings extends API
return ($items);
}
public function updatePortalSettingsOfficeTravelReimburse()
{
$setParts = [
'office_travelreimburse_cents_homework_incl = :homework_incl',
'office_travelreimburse_cents_homework_excl = :homework_excl',
'office_travelreimburse_cents_business_incl = :business_incl',
'office_travelreimburse_cents_business_excl = :business_excl',
];
$params = [
':homework_incl' => $this->data['office_travelreimburse_cents_homework_incl'],
':homework_excl' => $this->data['office_travelreimburse_cents_homework_excl'],
':business_incl' => $this->data['office_travelreimburse_cents_business_incl'],
':business_excl' => $this->data['office_travelreimburse_cents_business_excl'],
':portal_uuid' => $this->data['portal_uuid'],
];
$query = "UPDATE system_settings SET " . implode(", ", $setParts) . "
WHERE portal_uuid = :portal_uuid";
$stmt = $this->pdo->prepare($query);
$stmt->execute($params);
$this->apiOutput(200, ['success' => 'portal settings updated successfully.']);
}
}